Extending the Lotus Notes Search bar

With the recently released Multiple Database Search plug-in you will see an example of how to implement the “com.ibm.rcp.search.engines.searchEngines” extension point.  This extension puts a new search entry in the search toolbar dropdown:

You can look at the plugin.xml in the project to see the extension definition.  Let’s walk through how this extension is configured:

//The first extension declares the engine 
<extension point="com.ibm.rcp.search.engines.searchEngines">
 <searchEngine
     data="1073873011"                                // Initialization data given to the class, we dont use this really
     engine="org.openntf.mailsearch.SearchEngine"     // The class name for our engine
     global="true"                                    // We want our engine to always be available
     hasResults="true"                                // We will use the regular search UI page
     icon="icon/dbicon1.gif"                          // Our icon in the drop down menu
     id="org.openntf.mailsearch.SearchEngine"         // the id of our engine
     label="Multiple DB Search"                       // The label for our engine (shows in the drop down)
     type="other"/>                                   // We are not a regular type so just put other
</extension>
//The next extension actually adds the engine to the UI, it is pretty self explanatory
<extension point="com.ibm.rcp.search.ui.searchBarSets">
  <searchBarSet
     id="org.openntf.mailsearch.SearchEngine"
     label="Multiple DB Search"
     visible="true">
     <searchBarItem
        engineID="org.openntf.mailsearch.SearchEngine"
        id="org.openntf.mailsearch.SearchEngine.item" />
  </searchBarSet>
</extension>

The engine parameter is really the key parameter as it points the search framework to our class that does the heavy lifting.  The class is what is responsible for actually executing the search across the selected databases.  Following this sample you can now create a search to essentially anything that Java code has access to.

Our search engine uses multiple threads to search across the databases.  Since the back-end Java API’s can be accessed from multiple threads this makes it a pretty big advantage performance wise.  If your databases are also full text indexed, you will see some pretty impressive performance with this technique.  I will save the threading discussion for another post…

Advertisements

Dojo.query and forEach loop, a powerful combination

In the latest version of the attachment viewer -which has not been published yet – I had to really think through the Zip file provider.  The problem is the zip file is a collection of other files – so the one provider had to really know how to call the other file providers for each of the entries in the archive.  This got a little tricky with the providers that used dynamic JavaScript like dojox.embed.Quicktime or the Flash player.  The problem was the fact the zip file is simply called once and you have to do pretty much everything in the callbacks that are provided in the extension.  So I actually had to use both the writeHTML() and the getScript() methods in order to get this to work.  Here is what I did; when I was iterating through each file in the archive I checked to see if there was a file provider for that type by querying the OSGI extension.  I would then process the file the same way as the framework does, by calling each providers writeHTML().  This doesn’t work for the providers that are script based however.  So what I did to get around this was write out <div> blocks with a special class, “zip_script”, and then in the Zip providers getScript() method I would simply look for those using dojo.query and then iterate through all of the nodes that had that class.  I would then call the applicable script for each of the file types.  In the writeHTML() I write out the extension (like .jpg), the URL to the content, and the id of the <div>.  This is enough information for the Zip script to dynamically call the JavaScript for those special extensions because you only need the URL of the content and the node ID for where the content will be placed.  You can see in the code below I call a function called “getScript()” in the JavaScript which is part of the framework and returns me the function for that extension type.  If an extension exists, I simply call the function associated with the file extension.

You can also see where I use the dojo.query and forEach loop combination. The query looks for all nodes with the class “zip_script” and then iterates through those nodes.

{
type:".zip",
f :function (id, url){

    dojo.query(".zip_script").forEach(function(node, index, arr){

    var id = node.getAttribute("id");
    var ext = node.getAttribute("ext");
    var url = node.getAttribute("url");

    var func = getScript(ext);
    if (func != null)
        func(id, url);
});
}

So to end, the dojo.query.forEach combination is a pretty powerful method and can save a lot of JavaScript.

Searching mail and archives together

I am in the process of making what you are about to read an OpenNTF contribution but in the meantime I wanted to get some feed back on what I have come up with so far.  I wanted to extend the Lotus Notes client search with a Java plug-in that can be used in any version of Lotus Notes 8.x.  The first attempt here will really be to satisfy a customers direct need – which is basically search mail and any database stored in the local data directory under the “archives” folder.  We of course will make this configurable with a preference page and Eclipse preferences – which can then be controlled by an administrator through policies.

Search can be extended in a couple of places.  You can add your engine to the global search bar:

And the search option can show up in the right click menu when text is selected:

Continuing on, here is what I created and I figured I would just post some of the code here to give people a feel for how easy this really was.  I will go into detail about the search extension points in a later post; but what I really wanted to communicate here is I used basic back-end Java classes to accomplish this and I essentially relied on the Database Java object to do all of the search types.  The first thing I had to do was collect the results from the mail database and then iterate through all of the databases under the “archives” folder.  I gave the end user five different options for how to search, I started with Full Text but that can be very slow if your files are not indexed and then I added several other mechanisms:

  • Full Text
  • Body Field
  • Subject Field
  • Body and Subject Fields
  • Body and From Fields

As shown on the right, these options then show in the search page for the user to select how the database should be searched.

The main code is pretty simple, as I iterate through all databases I just pass the database and SearchQuery object into this private method and call the appropriate Search method on the Database object with the corresponding string or formula.  You can get an idea of it just by reading the code:

private DocumentCollection search(Database db, SearchQuery arg0) {
   try {
      if (arg0.getLocationID().equals("0"))  // Full Text
          return db.FTSearch(arg0.getText());
      else if (arg0.getLocationID().equals("1")) {  // Body Field
          return db.search("@Contains(Body; "" + arg0.getText() + "")");
      } else if (arg0.getLocationID().equals("2")) {  // Subject Field
          return db.search("@Contains(Subject; "" + arg0.getText() + "")");
      } else if (arg0.getLocationID().equals("3")) {  // Body and Subject fields
          return db.search("@Contains(Body; "" + arg0.getText() + "") | @Contains(Subject; "" + arg0.getText() + "")");
      } else if (arg0.getLocationID().equals("4")) {  // Body and From fields
          return db.search("@Contains(Body; "" + arg0.getText() + "") | @Contains(From; "" + arg0.getText() + "")");
      }

   } catch (NotesException e) {
      e.printStackTrace();
   }

   return null;
 }

You will notice I used the FTSearch method for the Full Text option and then I use the basic search method with a formula for the others.  After this method is called I then take all of the results and put them in a sorted collection by date – newer ones first.  This kind of stuff can also be controlled by preferences.

So, I have heard this request many times and now I ask, would an OpenNTF contribution using this approach be acceptable for the near term?

Extending Notes with new view context menus and text selection context menus

Over the last few weeks I have received several Eclipse questions for how business partners and customers can extend Notes 8 in new ways.  The following two posts should answer some of those questions.  The first post shows how you can extend the right click menu for a text selection in a Notes document while the second post explains how you can extend the right click menu in a Notes view entry.

How to extend the right click text selection menu in a Notes Document

Adding right click options to your Notes 8 mail box entries with Eclipse

Would you like to extend your Domino server with an Eclipse plug-in?

You can extend your Domino server many ways today – new processes, DLL’s, agents, servlets, etc.  But what about writing an Eclipse plug-in?  The first things that come to mind is writing new AdminP requests in Java/Eclipse would be really neat.  I can imagine a simple Eclipse extension point to extend AdminP and viola – you just install the plugin and you get a new AdminP handler.

You could go on to have all kinds of extension points via Eclipse – new HTTP server extensions, your own process or protocol handler, a new thread to work on queues – the ideas are limitless.  The struggle is, I am not sure there is a lot of demand for this sort of thing.

I also don’t how companies are out there writing things for the Domino server in this manner and I don’t know how many of you are Java/Eclipse programmers.  People probably just write agents to do most of these kinds of things but it would be interested to hear feedback about this concept.  Lastly, I have not talked to anyone on the Domino server team so I am not sure if this has already been asked for or is in the roadmap so I would like to hear you comments in this space.  Thanks.

New Edit:

Go ahead and vote on IdeaJam for this feature.