<< June 2010 | Home | August 2010 >>

How to extend Notes 8: using LiveText with capture groups

I get so many question on how to extend Notes 8 that I finally decided to create a series of blog posts on how to do it. All the posts in the series may be found under the extending_notes8 tag. In this post you'll need familiarity with how MyWidgets and LiveText works. A basic understanding of regular expressions would be beneficial as well.

This post will set the stage for the next post on how to add Java actions that use LiveText recognizers that contain capture groups. No Java code or Eclipse extension point stuff in this post.

Let me start by explaining what capture groups are. As you probably know you use regular expressions to search for text occurrences when using LiveText. In short a regular expression is a text pattern to search for in a block of text. Regular expressions can be hard to grasp at first but once you "have it" they will become an invaluable tool in your arsenal.

A regular expression can range from the simple to the extremely complex. A simple regular expression to find a product number like OTGC-5431 could look like this one:

[A-Z]{4}-\d{4}
This regular expression tells the regular expression engine to search for 4 consecutive, uppercase, letters ([A-Z]{4}) followed by a hyphen (-) followed by 4 digits (\d{4}).

Now that's great but what if this isn't just a product number but it's actually a compound data format and that the product number is made up of a product family (OTGC) and a part number (5431) and I needed the two pieces of information separately? Well that's where capture groups become important.

In regular expressions there is a syntax to signal that the text that you find actually consists of multiple, separate, discrete, pieces of information. As in the example with a product number such as OTGC-5431. This product number consists of two parts - 1) the product family (OTGC) and 2) the part number (5431). If you need access to the product family and part number separately you can use capture groups to split up the product number in the regular expression itself instead of relying on parsing after recognition.

So instead of simply getting a match of "OTGC-5431" you also get information that the product family is "OTGC" and the part number is "5431".

So how does one use capture groups?

Well you start with the regular expression above and then you add capture groups by simply changing it to be

([A-Z]{4})-(\d{4})
Notice how I only added two sets of parentheses. That all. That tells the regular expression engine that the result is made of of two parts. So instead of getting just one result (OTGC-5431) I get three: OTGC-5431, OTGC, 5431 (the match in it's entirety and the two capture groups).

So how do I use these results in MyWidgets / LiveText? Well let me walk you through an example.

Lets imagine that you have a web service that allows you to search for product numbers but need the product family and part number separately. The syntax is something like http://www.example.com/prodquery?pf=<product family>&pn=<part number> (http://www.example.com/prodquery?pf=OTGC&pn=5431). Let me show you, end to end, how to do this using MyWidgets and LiveText.

  1. Start by creating a new widget. Choose to create a web widget and click Next.
  2. Now specify the URL as being "http://www.example.com/prodquery?pf=OTGC&pn=5431" (Please note: The address doesn't point to anything but it proves the point we need). Now click Next.
  3. A GET request is fine - just click Next.
  4. Now the web page is fetched. As we know the URL we specified doesn't work just click Next.
  5. In the "Configure a Widget" dialog name the widget "Demo Product Search" and choose "Wire as an action" at the bottom. Then click the "Advanced" tab at the top.
  6. Put a checkmark in both boxes in the "Configure" column as we need to map both URL parameters to our recognized LiveText. Then click Next.
  7. We need a new recognizer to recognize our product number. To do this click the "New Recognizer..." button.
  8. Name the recognizer "Demo Product Number" in the top text box. Now since our recognizer uses two capture groups we need to tell Notes how to map these to our widget (as widget properties) so we need a new Content Type. To do this click the "New Type..." button.
  9. In the "Configure a Content Type" dialog box you name the parts of the text you recognize. We have two parts so we click the "Add"-button twice and fill the text fields like specified below. We do this to indicate we have two properties called "pf" and "pn". Then click OK.
  10. Back in the "Configure a Recognizer" dialog our new Content Type ("Demo Product Number") has been chosen for us. Now we specify our regular expression with the two capture groups. Then we click the "Add"-button twice and map capture group 1 (the "product family") to content property "pf" and capture group 2 (the "part number") to content property "pn" as shown below. Then click OK.
  11. Back in the "Wire an action to configure a widget" dialog our newly created recognizer has been chosen for us. Now we need to map the widget properties (the parts of the recognizer) to the URL parameters. We do this on the "Advanced" tab so click on that near the top.
  12. On the "Advanced" tab add a second parameter box by clicking the "Add"-button and map the URL parameters to our widget properties as shown below. Then click Finish.
Now take a deeeeeeeeeeeeeeeeep breath... :-)

That's what's required to create a new widget with a new recognizer and new content type. It may seem like much, and I think it is, but remember that you may now add a second web widget that uses the same recognizer by following the same steps but ignoring step 7-10. Also when you've done it a few times it becomes second nature and you use it all the time. I do.

Now we need some text to test on. Create a new e-mail message, add a subject, some text to the body field including a couple of product numbers and e-mail the message to yourself. To make it easier you may copy/paste the below text:

Ullamcorper veniam aliquip duis, vel vero dolore in dolor 
aliquam dolore lobortis delenit vel duis, magna. Eros 
iusto, consequat iriure eu enim nulla exerci minim nulla 
facilisis, ex te ut nulla volutpat qui: OTGC-5431, 
OTMM-6615. Odio nulla amet ea quis volutpat suscipit exerci 
eros et dolore feugiat, ea dolor ad, vulputate, delenit 
enim sed autem tation enim zzril blandit iusto. Dolor 
facilisi vero feugait iriure, et consequat ut, et euismod 
ipsum praesent quis duis zzril in hendrerit, at et, dolor 
hendrerit dignissim. Ut commodo odio consequat, onsectetuer 
augue dignissim nulla dolore velit. 
Now when you open the message from your inbox you should see something like this:

As you can see the Notes client recognized two text strings as shown by the blue dotted lines. If you hover over the text and click the down arrow (will appear to the right of the text) you'll see a small menu as shown below. From that menu select "Display Demo Product Number Properties". That will show a dialog box explaining exactly what Notes found and what text goes into which capture groups and hence into which widget properties.

In the next post in the series I'll show how to use these widget properties from a Java action. Stay tuned...

How to extend Notes 8: coupling custom LiveText recognisers to a Java action

I get so many question on how to extend Notes 8 that I finally decided to create a series of blog posts on how to do it. All the posts in the series may be found under the extending_notes8 tag. In all of the examples I assume a working knowledge of Eclipse and Java programming and how to work with extension points.

For this post I'll build on the "How to extend Notes 8: coupling LiveText to a Java action"-post and show how to act on your own custom recognizer.

Most of the work is actually the same than for using the built-in recognizers but now you need to utilize your custom recognizer. So you need a recognizer - there are of cause ways to do this programmatically but that's the focus for another post. For now lets focus on using existing recognizers. Do that by adding your recognizer to Notes - either using MyWidgets or simply importing a recognizer using an extension.xml file such as this one. Remember you need both the recognizer AND the content type it produces (the file has both).

For this example I'll use the extension.xml I link to above - to install simply drag the link to your MyWidgets sidebar panel. That file gives you a new recognizer with an id of "DCR.Toddlerdemo.885487295" and a content type with an id of "DCCT.demonotes85inspirationproductno.1361861595". As in previous posts you link your Java action to the content type so make a note of the id.

Now create your Java action class - again implemening org.eclipse.ui.IObjectActionDelegate - and add the org.eclipse.ui.popupMenus extension point to your plugin.xml file using the content type id as below.

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension  point="org.eclipse.ui.popupMenus">
      <objectContribution id="com.lekkimworld.livetxt.objectContr1" 
         objectClass="com.ibm.rcp.content.IDocumentContent">
         <visibility>
            <and>
               <objectState name="content.type" 
               value="DCCT.demonotes85inspirationproductno.1361861595"/>
               <objectState name="contents" value="" />
            </and>
         </visibility>
         <action class="com.lekkimworld.livetext.MyAction"
            enablesFor="*" 
            id="com.lekkimworld.livetxt.action1" 
            label="Do stuff!" />
      </objectContribution>   
   </extension>
</plugin>

Again when it comes to grabbing the contents of the recognized LiveText it comes down to you selectionChanged-method of your Java action. If your custom recognizer doesn't use capture groups your contents will be in the "contents" property as previously. If you DO use capture groups you need to use the names you specified for the capture groups when you mapped it to the widget - we'll look at that another time. The example code below simply assumes a single group.

public void selectionChanged(IAction action, ISelection selection) {
   IDocumentContent doc = null;
   
   // cast/adapt selection
   if (selection instanceof StructuredSelection) {
      Object sel = ((StructuredSelection)selection).getFirstElement();
      if (sel instanceof IDocumentContent) {
         doc = (IDocumentContent)sel;
      }
   } else if (selection instanceof IDocumentContent) {
      doc = (IDocumentContent)selection;
   } else {
      // try and adapt
      IAdapterManager amgr = Platform.getAdapterManager();
      doc = (IDocumentContent)amgr.getAdapter(selection, 
          IDocumentContent.class);
   }
   if (null == doc) {
      this.selection = null;
      return;
   }
   
   // get number from document property
   this.selection = doc.getProperties().getProperty("contents");
}

That's all. Again the main post is knowing how but again 95% of the plugin.xml file and the Java action is the same. In a future post in this series I'll show how to act upon custom recognizers using capture groups. Stay tuned...

How to extend Notes 8: using the other built in LiveText recognisers with Java actions

I get so many question on how to extend Notes 8 that I finally decided to create a series of blog posts on how to do it. All the posts in the series may be found under the extending_notes8 tag. In all of the examples I assume a working knowledge of Eclipse and Java programming and how to work with extension points.

This second post builds upon the "How to extend Notes 8: coupling LiveText to a Java action"-post posted earlier. Most of the post is the same but you'll need to change the content type to act on. Read on.

My Notes 8.5 client comes with the follow built in recognizers:

RecognizerContent type
Phone numbercontent.phone
Addresscontent.address
Organizationcontent.org
Personcontent.person
Web sitecontent.web
The trick is to couple our definitions in plugin.xml to the right content type. So to attach to a recognized web address you need to specify content.web as the content type as shown below:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
  <extension point="org.eclipse.ui.popupMenus">
    <objectContribution
          id="com.lekkimworld.livetext.objectContribution2"
          objectClass="com.ibm.rcp.content.IDocumentContent">
       <action
             class="com.lekkimworld.livetext.Action1"
             id="com.lekkimworld.livetext.action2"
             label="Do stuff with web address!">
       </action>
       <visibility>
          <and>
             <objectState name="content.type" value="content.web" />
             <objectState name="contents" value="*" />
          </and>
       </visibility>
    </objectContribution>
  </extension>
</plugin>

Now also change your action to extract the right property from the document. All the IBM recognizers stick the recognized text in the "contents" property so simply grab that. Some of the recognizers (person and address) also have some sub-parts you could extract but I find the recognizers so flaky that I haven't invested much time in using them. I find the web and phone recognizers the only useful ones. Below is some sample code for the selectionChanged method.

public void selectionChanged(IAction action, ISelection selection) {
   IDocumentContent doc = null;
   
   // cast/adapt selection
   if (selection instanceof StructuredSelection) {
      Object sel = ((StructuredSelection)selection).getFirstElement();
      if (sel instanceof IDocumentContent) {
         doc = (IDocumentContent)sel;
      }
   } else if (selection instanceof IDocumentContent) {
      doc = (IDocumentContent)selection;
   } else {
      // try and adapt
      IAdapterManager amgr = Platform.getAdapterManager();
      doc = (IDocumentContent)amgr.getAdapter(selection, 
          IDocumentContent.class);
   }
   if (null == doc) {
      this.selection = null;
      return;
   }
   
   // get text from document property
   this.selection = doc.getProperties().getProperty("contents");
}

How to extend Notes 8: coupling LiveText to a Java action

I get so many question on how to extend Notes 8 that I finally decided to create a series of blog posts on how to do it. All the posts in the series may be found under the extending_notes8 tag. In all of the examples I assume a working knowledge of Eclipse and Java programming and how to work with extension points.

For this second post I'll touch on one of my favorite features of Notes 8 that is MyWidgets and LiveText. From the user interface you may create a number of widget types (web, Notes etc.) that act on text which is automatically recognized and highlighted by Lotus Notes using the LiveText feature. But what if you wanted to perform an action that didn't lend itself to one of these widget types? What if you wanted to couple the text recognized by LiveText to a Java action? Well look no further. In this post I'll show you how to combine the org.eclipse.ui.popupMenus extension point with a com.ibm.rcp.content.IDocumentContent object contribution to do what is transparently done using MyWidgets.

Let me preface this by saying that it's still far easier to do this using MyWidgets but still this isn't rocket science.

To accomplish this task you'll need two pieces. First of you need the code to execute. This is done using an action class that implements org.eclipse.ui.IObjectActionDelegate which means that you need to implement three methods:

  • public void setActivePart(IAction action, IWorkbenchPart part)
    Called when what's called the part is changed in Eclipse. You can leave this method blank.
  • public void selectionChanged(IAction action, ISelection selection)
    Called when you run an action on some text that the client highlighted using LiveText. The purpose of this method is to extract the text and make it available to the run method (see below).
  • public void run(IAction action)
    This is the workhorse of the class and it's called whenever the action is selected from the context menu. The action will act on the text you extracted in the selectionChanged method.

The run-method isn't as interesting as it just performs the action. The method is called in the UI thread. The selectionChanged-method is more fun as this is where you extract the highlighted text. The example here acts on a recognized phone number but it could just as well have been another of the built in recognizers. Below is a snippet of code on how to get the highlighted text.

public void selectionChanged(IAction action, ISelection selection) {
   IDocumentContent doc = null;
   
   // cast/adapt selection
   if (selection instanceof StructuredSelection) {
      Object sel = ((StructuredSelection)selection).getFirstElement();
      if (sel instanceof IDocumentContent) {
         doc = (IDocumentContent)sel;
      }
   } else if (selection instanceof IDocumentContent) {
      doc = (IDocumentContent)selection;
   } else {
      // try and adapt
      IAdapterManager amgr = Platform.getAdapterManager();
      doc = (IDocumentContent)amgr.getAdapter(selection, 
          IDocumentContent.class);
   }
   if (null == doc) {
      this.selection = null;
      return;
   }
   
   // get number from document property
   this.selection = doc.getProperties().getProperty("phone");
}

The second piece to the puzzle is the plugin.xml snippet that couples our action to the LiveText feature of Lotus Notes. It's again a org.eclipse.ui.popupMenus extension point coupled to an object contribution but this time also a visibility modifier to only show the action when text matching a recognizer is shown. You will want to pay attention to the italic text. Again you will need to change the class name for the action as well.

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
  <extension point="org.eclipse.ui.popupMenus">
    <objectContribution
          id="com.lekkimworld.livetext.objectContribution2"
          objectClass="com.ibm.rcp.content.IDocumentContent">
       <action
             class="com.lekkimworld.livetext.Action1"
             id="com.lekkimworld.livetext.action2"
             label="Call it!">
       </action>
       <visibility>
          <and>
             <objectState name="content.type" value="content.phone" />
             <objectState name="contents" value="*" />
          </and>
       </visibility>
    </objectContribution>
  </extension>
</plugin>

Easy isn't it??

In a future post in this series I'll show how to act upon the other built in recognizers and how to act on your own. Stay tuned...

How to extend Notes 8: coupling text selection to Java action

I get so many question on how to extend Notes 8 that I finally decided to create a series of blog posts on how to do it. All the posts in the series may be found under the extending_notes8 tag. In all of the examples I assume a working knowledge of Eclipse and Java programming and how to work with extension points.

For this first post I'll touch on one of my favorite features of Notes 8 that is MyWidgets and LiveText. From the user interface you may create a number of widget types (web, Notes etc.) that act on selected text but what if you wanted to perform an action that didn't lend itself to one of these widget types? What if you wanted to couple text selection to a Java action? Well look no further. In this post I'll show you how to combine the org.eclipse.ui.popupMenus extension point with a org.eclipse.jface.text.ITextSelection object contribution to do what is transparently done using MyWidgets.

Let me preface this by saying that it's still far easier to do this using MyWidgets but still this isn't rocket science.

To accomplish this task you'll need two pieces. First of you need the code to execute. This is done using an action class that implements org.eclipse.ui.IObjectActionDelegate. This means you need to implement three methods:

  • public void setActivePart(IAction action, IWorkbenchPart part)
    Called when what's called the part is changed in Eclipse. You can leave this method blank.
  • public void selectionChanged(IAction action, ISelection selection)
    Called when you select some text in the Notes client and select your action. The purpose of this method is to extract the selected text and make it available to the run method (see below).
  • public void run(IAction action)
    This is the workhorse of the class and it's called whenever the action is selected from the context menu. The action will act on the selected text you extracted in the selectionChanged method.

The run-method isn't as interesting as it just performs the action. The method is called in the UI thread. The selectionChanged-method is more fun as this is where you extract the selected text. Below is a snippet of code on how to do it.

public void selectionChanged(IAction action, ISelection selection) {
   StructuredSelection sel = (StructuredSelection)selection;
   try {
      IAdapterManager amgr = Platform.getAdapterManager(); 
      Object obj1 = sel.getFirstElement();
      Object obj2 = amgr.getAdapter(obj1, ITextSelection.class);
      if (obj2 instanceof org.eclipse.jface.text.ITextSelection) {
         ITextSelection txtSelection = (ITextSelection)obj2;
         this.selection = txtSelection.getText();
      }
   } catch (Throwable t) {
      this.selection = null;
   }
}

The second piece to the puzzle is to tell the platform when you would like your action to be listed ie. when select is selected. This is done in the plugin.xml using the org.eclipse.ui.popupMenus extension point and by doing an object contribution as shown below. The italic text (the id's and the action label) may be changed to your liking. The bold/italic text is the class name of your action which should be changed to match your action class.

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension point="org.eclipse.ui.popupMenus">
      <objectContribution
            id="com.lekkimworld.textsel.objectContribution1"
            objectClass="org.eclipse.jface.text.ITextSelection">
         <action
               class="com.lekkimworld.textsel.SelectionAction"
               enablesFor="*"
               id="com.lekkimworld.textsel.action1"
               label="Perform action from selected text">
         </action>
      </objectContribution>
   </extension>
</plugin>

The next post (which will be published tomorrow) will show you how to act upon LiveText that is couple your Java action to text that the Notes client recognizes and highlights for you. Stay tuned...

Websphere Terminology for newcomers

Found this very good document describing the terminology from Websphere Application Server for people new to the platform. So if you're unsure of the exact difference between a cell, node, profile and a cluster I suggest you peruse this document. I also recommend printing the graphics on page 4 and keeping it nearby.

Overview of IBM WebSphere Application Terminology for IBM Lotus Connections Administrators

IBM makes Firefox the default company browser? When will IBM Lotus Notes stop depending on Internet Explorer?

In recent news IBM officially proclaimed Mozilla Firefox as the corporate browser of choice. The news was picked up by major news outlets such as CNet, readwriteweb.com and ars technica ("IBM embraces Firefox, adopts it internally"). The news even made it to small Denmark as a news item on Version 2 ("IBM gør Firefox til standardbrowser for 400.000 ansatte"; English: IBM makes Firefox the default browser for 400.000 employees).

While I really like the choice being a multi-year-long Firefox user myself it raises a question. If Microsoft Internet Explorer isn't a good choice for a web browser and not something that IBM wants to bet their money on for internal web browser usage how come it's still good enough as a core component in Lotus Notes 8? As you might know most (if not all) e-mail rendering in Lotus Notes is done using Internet Explorer. Also Internet Explorer is the browser of choice for web-based Composite Application components (on Windows anyway). Despite the hate for Internet Explorer that some may carry around it works and works well.

It does however raise an interesting question...

What's to stop Microsoft from introducing a special "feature" in Internet Explorer that makes it crash when used inside Lotus Notes? Customers would blame Lotus Notes while the "feature" would in effect cripple all Lotus Notes 8 e-mail rendering on the Windows platform. The only thing that I can see stopping them from a move like this is behaving nicely - but how long will that continue?

If only there was a way to solve that problem... Well there is. Create a SWT Browser component that uses Webkit or another open source rendering engine that IBM can control and can continue to control. That would put IBM Lotus back in control of a core component of their own product. Maybe this egg is too precious to put in another vendors basket.

Comments?

Solving a Lotus Connections 2.5 login performance issue

During the last week I have been diagnosing a login performance issue at a Lotus Connections 2.5 customer. The issue manifested itself by it taking around a minute for some users to login. It was only an issue for the initial login hence it was caused by something that the Websphere server cached on subsequent login attempts.

After diagnosing and making sure the install was at the latest fixpack and fixlevel from Fix Central, I finally found out what was going on. By using the Websphere Application Server trace functionality it became apparent that it was the Waltz / Directory Service Extension (DSX) component of Lotus Connections that was causing the problem. The issue was that Waltz took a very long time to resolve the groups the user belonged to and hence login took forever.

Waltz is using the federated repository LDAP setup from Websphere so for starters I found a workaround. The workaround was to disable group support in the Integrated Solutions Console (ISC) by setting a custom group search filter (e.g. objectClass=dummy). This works but also means you're turning of group support completely.

A better solution which also works is to modify the Waltz setup in the directory.services.xml file in the LotusConnections-config directory. By default the top section looked like this:

<!-- *************************** -->
<!--   Waltz Profile Provider    -->
<!-- *************************** -->
<profileProvider 
   class="com.ibm.connections.directory.
      services.provider.WaltzServiceProvider" />
Reading through the file and using the schema as a guideline I could add an option to disable the group expansion i Waltz by embedding a property-tag beneath the profileProvider-tag as shown below.
<!-- *************************** -->
<!--   Waltz Profile Provider    -->
<!-- *************************** -->
<profileProvider 
   class="com.ibm.connections.directory.
      services.provider.WaltzServiceProvider">
   <property name="com.ibm.connections.directory.
      services.ldap.group.membership.service.enabled">false</property>
</profileProvider>

Lotus Connections seems to be working just fine despite this option being set though I'm not completely sure of all side effects. I'll post more if/when I learn more.

Eclipse Helios (3.6) and why it's important to Notes administrators

Notes 8 is based on Eclipse and Eclipse use OSGi for bundle lifecycle and dependency management. Part of OSGi is the OSGi console that is a console into the inner working of OSGi. The console is very useful and may be used to diagnose Eclipse and Notes 8 issues. I've previously blogged about the OSGi console and how to access it in Notes in my "SWT@Notes 8: -console" post back in 2008. One of the cool things about the OSGi console is that you can write administrative commands for the console that you may invoke using the text based interface.

One major shortcoming of the OSGi console was that one could only access it once the platform was invoked that is it couldn't be accessed once Notes was started. This is a real bummer as it could be very useful in certain troubleshooting scenarios. This is about to change.

In the upcoming Eclipse 3.6 (Helios) release we'll get even easier access to the OSGi console as you may attach to OSGi console after launching the platform. Yeah!!

On his blog Chris Aniszczyk of Redhat has a post called "Easier access to the OSGi console":


In Eclipse 3.6 M7, it will be easier to access the OSGi 
Console within the running Eclipse. The Equinox team 
added a org.eclipse.osgi.framework.console.ConsoleSession 
service that you can use to get the input and output to a 
console session. The PDE team took advantage of this 
recently by extending the org.eclipse.ui.console.consoleFactories  
extension point and allowing you to bring up the OSGi 
console easily...

Detecting if a sideshelf view is detached

Found this great tip on how to detect if a view was detached from the parent windows that is if a sidebar plugin was opened standalone. I'm thinking that this could be very useful and used in a variery of ways to allow further functionality in a sidebar plugin if opened standalone. What could this be? Well a sidebar plugin could provide a richer UI and/or more resource intensive operations when the user opens the view standalone as this probably means this is an important application to the user.

Tip: How to detect that a View was Detached

Tags : ,

Java 4-Ever Trailer - funny as hell

A must see. Nerdy as hell but man it's funny!! Java 4-Ever Trailer

Tags :