Working with plug-ins in IBM Lotus Sametime V7.5.1: Developing the BuddyNote plug-in

Building IBM Lotus Sametime on top of Lotus Expeditor lets you use Eclipse as a Plug-in Development Environment (PDE) to extend Lotus Sametime's functionality in many ways. This article, part 2 of a four-part series, shows how to develop the BuddyNote plug-in from scratch.

Dan Kehn, Senior Software Engineer, IBM, Software Group

Dan Kehn is a senior software engineer at IBM in Research Triangle Park, N.C. He has a broad range of software experience, having worked on development tools, such as IBM Rational Application Developer, and on operating system performance, memory analysis, and UI design. He is also co-author of the award-winning book The Java Developer's Guide to Eclipse. Currently, he is a technical enablement specialist helping business partners integrate their products into IBM Lotus Sametime Connect.



Lawrence Wright, Co-Op student, IBM

Lawrence Wright is a Co-Op student from North Carolina State University with a BS degree in Electrical Engineering. He is currently pursuing a BS degree in Computer Science.



17 July 2007 (First published 03 July 2007)

Also available in

This article is part 2 of a four-part series on working with plug-ins in IBM Lotus Sametime V7.5.1. In Part 1, "Working with plug-ins in IBM Lotus Sametime V7.5.1: Configuring the Eclipse environment," you learned that Lotus Sametime V7.5.1 is based on the rich client platform, IBM Lotus Expeditor, which in turn is based on the open source, plug-in model of Eclipse, which can be configured as a Plug-in Development Environment (PDE) for Lotus Sametime. Part 1 walked you through the configuration steps. In this, the second installment of the series, you use the Eclipse workspace you configured in part 1 to develop the custom plug-in, BuddyNote, from scratch. If you skipped part 1, you can download and use the BuddyNote workspace from the "Downloads" section of this article to complete this installment.

NOTE: To use the BuddyNote workspace you need to complete the "Install J9 Plug-In" section of the first part of this series. You also need to have IBM Lotus Sametime Connect V7.5.1 and the IBM Lotus Sametime V7.5.1 SDK installed to the default locations (C:\Program Files\IBM\Sametime Connect and C:\st751sdk, respectively).

This article series is intended for those with an interest in extending the capabilities of Lotus Sametime by developing plug-ins. You should be familiar with Lotus Sametime and its use.

About this series

This four-part article series provides an introduction to Lotus Sametime V7.5.1 plug-in development using the Eclipse platform:

  • Part 1 guides you through the configuration of Eclipse for Lotus Sametime V7.5.1 plug-in development.
  • In this installment, part 2, you use Eclipse to extend the Lotus Sametime user interface to create the custom plug-in, BuddyNote.
  • Part 3 demonstrates how to debug your plug-in using the tools that Eclipse provides.
  • Part 4 shows you how to deploy a custom plug-in, allowing you to share your creations, by setting up a Feature and Update Site project.

About this article

The purpose of this article is to introduce you to Lotus Sametime V7.5.1 plug-in development using the Eclipse platform by guiding you through the development of the BuddyNote plug-in step by step. The BuddyNote plug-in extends the Lotus Sametime user interface to add an area, called a view part, that displays the business card information for someone in the Contacts list and allows the user to add text notes. These notes are stored locally and are recalled anytime the user selects that contact. When Lotus Sametime first connects, the BuddyNote view part displays information about the user by default until the user selects a contact as shown in figure 1.

Figure 1. Completed BuddyNote plug-in
Completed BuddyNote plug-in

In this article, you follow these steps to create the BuddyNote plug-in and allow it to extend the Lotus Sametime user interface:

  • Declare the required dependencies
  • Extend the extension points needed for the desired functionality
  • Create the Java classes that make it all work

The final code is included in the "Downloads" section if you want to fill in the classes all at once. Parts 3 and 4 of this series demonstrate how you can troubleshoot and deploy your custom plug-in creations.


Prerequisites

This article is designed for those with Java Development experience, but not necessarily experience in Eclipse or plug-in development. You should have Lotus Sametime V7.5.1 installed and be familiar with its use. You also need to have Eclipse installed and a clean workspace that is configured for Lotus Sametime V7.5.1 plug-in development. See part 1 of this series, "Configuring the Eclipse environment," for configuration instructions and system requirements, or download and use the BuddyNote workspace provided in the "Downloads" section of this article.


Introduction

We recommend that you exit all running instances of Lotus Sametime before you work through the steps outlined in this article.

Because Lotus Sametime V7.5.1 is based on the Eclipse platform, the application is essentially a number of plug-in components tied together. You can think of each component as a package of Java classes that controls a specific functionality. Some of these packages are extensible, allowing the development of additional plug-ins that extend the base functionality. You have to determine the functionality a plug-in extends, and you must declare the appropriate plug-ins as dependencies. This provides access to their extension points and a foundation on which you can build.

With the extension points for the required dependencies available, you have to decide where your plug-in integrates with the user interface. Each dependency can have multiple extension points based on the functions they control. For instance, the ChatWindow dependency (com.ibm.collaboration.realtime.chatwindow) provides access to one extension point for adding to the chat window and another for creating a pop-up add-on. The proper extension point has to be identified, and an extension must be defined. Eclipse makes this simple with templates.

After the extension points are identified and the extensions defined, you code the Java classes needed to perform the new functionality. Eclipse provides assistance by recommending the necessary superclasses and/or interfaces needed for some extensions.

The BuddyNote plug-in demonstrates key functionality necessary when extending the Lotus Sametime user interface, such as performing the following actions:

  • Declare an extension to add an application as a view part, which is an area of the user interface where applications that interact with Lotus Sametime can be displayed using collapsible frames.
  • Track the selection of a person.
  • Persist data locally.

Lotus Sametime can also be extended to add functionality in the form of buttons on the action bar, pop-up menus, and toolbar menus. This article does not deal with these options, but if you are interested, you can consult the links in the "Resources" section regarding the extension of Lotus Sametime.


Creating the plug-in

To let Eclipse know that you are developing a plug-in, you start by creating a plug-in project. This provides access to the Eclipse PDE and creates a package to contain all the resources the plug-in needs.

  1. Choose File - New – Project. Expand Plug-in Development, choose Plug-in Project, and click Next.
  2. Type sample.buddynote in the Project name field. Accept the rest of the default choices.
  3. Click Next.
  4. Type a descriptive name in the Plug-in Name field or keep the default, Buddynote Plug-in. Accept the remaining default values.
  5. Click Finish.

NOTE: You may get a message asking if you want to open the Plug-In Development Perspective. If you do, click Yes.

Following these steps places the sample.buddynote project in the Package Explorer and opens the Plug-In Overview in the center frame as shown in figure 2. Notice the tabs at the bottom of the Overview window, particularly the tabs labeled Dependencies and Extensions.

Figure 2. BuddyNote Plug-in - Overview
BuddyNote Plug-in - Overview

Add the plug-in dependencies

Now that you have created the sample.buddynote project, you need to declare the required dependencies. Based on its description, the BuddyNote plug-in needs to add an application frame to the user interface and to detect the selection of contacts. Table 1 lists some of the plug-in dependencies that provide access to extension points for these functions (to save space, * = com.ibm.realtime.collaboration in table 1).

Table 1. BuddyNote plug-in dependencies
Plug-inDescription
org.eclipse.core.runtime org.eclipse.core.ui Eclipse core plug-ins; ui provides the views extension points to create a visual application
com.ibm.rcp.uiProvides the shelfViews extension point to place a view part into the Lotus Sametime application
*.communityManages different IM communities using a common API
*.coreDefines core classes such as ServiceHub
*.messages Manages the message handler event
*.peopleListens for online people status
*.magiccarpetProvides implementation-only classes and interfaces

The following steps add the necessary plug-ins as dependencies for the BuddyNote plug-in.

  1. Click the Dependencies tab of sample.buddynote at the bottom of the center frame.

    The org.eclipse.ui and org.eclipse.core.runtime plug-ins should already be listed under Required Plug-ins.
  2. Click Add and add the following:
    • com.ibm.collaboration.realtime.community
    • com.ibm.collaboration.realtime.core
    • com.ibm.collaboration.realtime.magiccarpet
    • com.ibm.collaboration.realtime.messages
    • com.ibm.collaboration.realtime.people
    • com.ibm.rcp.realtime.livenames
    • com.ibm.rcp.ui
    The screen should look like the one shown in figure 3 (the plug-in order is not important).
Figure 3. BuddyNote required plug-ins
BuddyNote required plug-ins

NOTE: Adding these plug-in dependencies using the PDE wizard adds the following to the MANIFEST.MF file, which defines the plug-in. You can see the contents of this file by selecting the MANIFEST.MF tab as shown in listing 1.

Listing 1. BuddyNote plug-in – MANIFEST.MF

Require-Bundle: org.eclipse.ui,
 org.eclipse.core.runtime,
 com.ibm.collaboration.realtime.community,
 com.ibm.collaboration.realtime.core,
 com.ibm.collaboration.realtime.magiccarpet,
 com.ibm.collaboration.realtime.messages,
 com.ibm.collaboration.realtime.people,
 com.ibm.rcp.realtime.livenames,
 com.ibm.rcp.ui

NOTE: Choose File - Save All before proceeding to allow Eclipse to read in the classes and interfaces defined in the preceding plug-ins because they are needed in the next steps.


Define the extensions

The plug-ins that make up Lotus Sametime, such as those you added as dependencies, declare extension points where developers can access established classes and interfaces for use in their own development. Extension points are the means by which you can extend the functionality of Lotus Sametime.

You contribute to three of these extension points to create the BuddyNote plug-in:

  • views. Lets you define a visual application that displays in Lotus Sametime.
  • shelfViews. Allows you to add a view as a frame to the Lotus Sametime user interface.
  • MessageHandlerListener. Notifies you of Lotus Sametime events, such as the user disconnecting, receiving a message, or in the case of BuddyNote, selecting a person from the Contacts list.

You can define extension points in the unique plug-ins you create to allow other developers to build on functionality that you provide, but that feature is not covered in this article.

The views extension

As mentioned, the views extension point allows you to define an application that displays in the Lotus Sametime user interface; it is the first extension point you define for the BuddyNote application.

  1. Click the Extensions tab. You should see the heading All Extensions on the left and nothing underneath it.
  2. Click Add, and then select the org.eclipse.ui.views extension from the list.
  3. Click Finish. On the resulting panel you now see a heading, "Extension Details," with data fields such as ID, Name, and Point. There is no need to change the values in these fields.
  4. Right-click the added extension and choose New - view.
  5. Select the newly added <view> element, and note that the Extension Element Details are updated to show the possible attributes. Modify the fields as follows:

    id*: sample.buddynote.buddynoteview
    name*: BuddyNote
    class*: sample.buddynote.BuddyNoteView

    Leave the remaining fields blank.

    The asterisk (*) indicates a required attribute. Of particular importance is the class attribute, which indicates the Java class that implements the view’s behavior (that is, this class defines what the view part area contains, how it responds to user events, and so on).

    The id field is used to identify this view when you set up the shelfViews extension point next, and the name field is what is displayed in the title bar of the view.
  6. Click the class*: attribute link to open the New Java Class dialog box.
  7. Confirm the following entries:

    Source folder: sample.buddynote/src
    Package: sample.buddynote
    Name: BuddyNoteView
    Superclass: org.eclipse.ui.part.ViewPart.

    NOTE: If org.eclipse.ui.part.ViewPart is not listed as the superclass, click Browse and type ViewPart in the text box for Choose a type. ViewPart – org.eclipse.ui.part should appear under Matching Types. Select this, and then click OK.
  8. Verify that your New Java Class dialog box matches the one shown in figure 4.
Figure 4. New Java Class dialog box - BuddyNoteView
New Java Class dialog box - BuddyNoteView
  1. Click Finish to create the BuddyNoteView class. The Java class editor opens in the center frame displaying BuddyNoteView.java. See listing 2.
Listing 2. BuddyNoteView class
package sample.buddynote;

import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

public class BuddyNoteView extends ViewPart {

	public BuddyNoteView() {
		// TODO Auto-generated constructor stub
	}

	public void createPartControl(Composite arg0) {
		// TODO Auto-generated method stub

	}

	public void setFocus() {
		// TODO Auto-generated method stub

	}
}
  1. Select the sample.buddynote tab at the top of the frame to display the Extensions tab of the plug-in manifest editor you were working with earlier. Select the plugin.xml tab at the bottom of the frame, and then verify that its contents appear as shown in listing 3.
Listing 3. BuddyNote plug-in – plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
   <extension
         point="org.eclipse.ui.views">
      <view
            class="sample.buddynote.BuddyNoteView"
            id="sample.buddynote.buddynoteview"
            name="BuddyNote"/>
   </extension>

</plugin>

As you can see, the plug-in editor guides you through the steps of creating your plug-in definition and plug-in extension definitions, automatically updating the plugin.xml file. You can enter the specifications directly into the plugin.xml file, though, if you prefer.

Now that you have defined the BuddyNote view, you need to define a shelfView to hold and display it.

The shelfView extension

Follow these steps to define a shelfView extension:

  1. Return to the Extensions tab and click the Add button.
  2. Select the com.ibm.rcp.ui.shelfViews extension from the list.
  3. Click Finish, and the extension appears under the views extension beneath All Extensions. On the right, you see Extension Details with the data fields ID, Name, and Point. You do not need to change these values.
  4. Right-click the shelfViews extension, and choose New - shelfView to create a shelfView element.
  5. The Extension Element Details dialog box appears. Modify the entries for these fields as follows:

    id*: sample.buddynote.shelfView
    view*: sample.buddynote.buddynoteview
    region: BOTTOM
    page: leave blank
    showTitle: true

    Notice that the view field contains the ID of the view extension you previously defined, indicating the view you want to display in the newly defined shelf. If these are not identical, your BuddyNote view does not display in Lotus Sametime.

    Also, region is selected as BOTTOM to place your application below the Contacts list. You can play with this attribute if you like, and you can see the BuddyNote view change location from bottom to top.
  6. You have now defined a shelfView to display your view part. Select the plugin.xml tab and verify the contents shown in listing 4.
Listing 4. BuddyNote plug-in – plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
   <extension
         point="org.eclipse.ui.views">
      <view
            class="sample.buddynote.BuddyNoteView"
            id="sample.buddynote.buddynoteview"
            name="BuddyNote"/>
   </extension>
   <extension
         point="com.ibm.rcp.ui.shelfViews">
      <shelfView
            id="sample.buddynote.shelfView"
            region="BOTTOM"
            showTitle="true"
            view="sample.buddynote.buddynoteview"/>
   </extension>

</plugin>

The previous steps defined the extension of the views and shelfViews, which are the visual representation of BuddyNote. The next extension, *messages.MessageHandlerListener, defines the class that you want to be notified of events in Lotus Sametime, such as when a person is selected in the Contacts list.

The MessageHandlerListener extension

To define the MessageHandlerListener extension, follow these steps:

  1. Return to the Extensions tab and click the Add button.
  2. Select the following extension from the list: com.ibm.collaboration.realtime.messages.MessageHandlerListener.
  3. Click Finish, and this extension appears under the shelfViews extension beneath All Extensions. On the right, you see Extension Details with the data fields ID, Name, and Point. You do not need to change these values.
  4. Right-click the MessageHandlerListener extension, and then choose New - messageHandler to create a messageHandler element.
  5. Extension Element Details appears on the right of the window with the fields class, id, and destinedMessagesOnly. You are interested in only the class field. Type sample.buddynote.BuddyNoteMessageHandlerAdapter in the text box, and then click the class* link.
  6. A New Java Class dialog box opens. The new class is named BuddyNoteMessageHandlerAdapter. Confirm the following entries:

    Source Folder: sample.buddynote/src
    Package: sample.buddynote
    Name: BuddyNoteMessageHandlerAdapter
    Superclass: com.ibm.collaboration.realtime.messages.MessageHandlerAdapter

    NOTE: If com.ibm.collaboration.realtime.messages.MessageHandlerAdapter is not listed as the superclass click Browse and type in MessageHandlerAdapter in the text box for Choose a type. MessageHandlerAdapter – com.ibm.collaboration.realtime.messages should appear under Matching Types. Select this and click OK.
  7. Verify that your New Java Class dialog box matches the one shown in figure 5.
Figure 5. New Java Class dialog box – BuddyNoteMessageHandlerAdapter
New Java Class Dialog – BuddyNoteMessageHandlerAdapter
  1. This brings up the class BuddyNoteMessageHandlerAdapter ready for editing. Return to the plug-in manifest editor, and then select the plugin.xml tab at the bottom. Verify the contents shown in listing 5, and then choose File - Save All.
Listing 5. BuddyNote plug-in – plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
   <extension
         point="org.eclipse.ui.views">
      <view
            class="sample.buddynote.BuddyNoteView"
            id="sample.buddynote.buddynoteview"
            name="BuddyNote"/>
   </extension>
   <extension
         point="com.ibm.rcp.ui.shelfViews">
      <shelfView
            id="sample.buddynote.shelfView"
            region="BOTTOM"
            showTitle="true"
            view="sample.buddynote.buddynoteview"/>
   </extension>
   <extension
         point="com.ibm.collaboration.realtime.messages.MessageHandlerListener">
      <messageHandler class="sample.buddynote.BuddyNoteMessageHandlerAdapter"/>
   </extension>

</plugin>

Progress check

You have now set up the basic framework of your BuddyNote plug-in. You have declared the points at which it extends the Lotus Sametime application user interface and the location where you want it to appear. To verify the BuddyNote framework, run Lotus Sametime and confirm that the plug-in is working as expected. Remember to exit all other running instances of Lotus Sametime on your machine first.

On the Eclipse toolbar, click the drop-down arrow to the right of the Run button. You now see a list of the available runtime configurations for testing. There’s only one choice in this case, ST 751, as shown in figure 6.

Figure 6. Run drop-down menu
Run drop-down menu

NOTE: This is the means of running the application referred to throughout this article. You can also use the menu bar to choose Run - Run and run ST 751 from the resulting dialog box shown in figure 7.

Figure 7. Run dialog box
Run configuration dialog box

NOTE: If you are prompted to save after selecting ST 751, click OK.

You are prompted to log into Lotus Sametime. Use the same information you use for your everyday use of Lotus Sametime.

Your screen should look similar to figure 8.

Figure 8. BuddyNote frame is visible
BuddyNote frame is visible

The BuddyNote frame can be minimized at the bottom of the user interface. If so, click its title bar to maximize.

Congratulations! You have reserved space in the Lotus Sametime Contacts list for the BuddyNote application. Next, you add the Java code that provides the desired functionality, such as a business card view for the currently selected contact and a text field below for adding notes. This code is provided for you. It is recommended that you read the methods to gain insight into how some of the Lotus Sametime objects fit together. If you are interested, you can also consult the JavaDoc provided in the Lotus Sametime SDK (st751sdk\client\connect\javadoc\connect).


Filling in the code

You have set up the BuddyNote framework by defining the proper extension points; now you need to provide the Java code to make it work. The first class you define is BuddyNoteView, created when you defined the views extension point.

You start by filling out the instance variables, constructor, and some helper methods that are not specific to Lotus Sametime. After that is done, go to the code that is specific to extending Lotus Sametime. Copy and paste the code provided into the appropriate classes in the center frame of Eclipse. Listing 6 provides the instance and class variables for BuddyNoteView.

Listing 6. BuddyNoteView - instance and class variables
	static public BuddyNoteView INSTANCE;
	private final String DEFAULT_NOTE = "<Click to enter notes>";
	private Person person = null;
	MyBusinessCard bizCard;
	StyledText textControl;
	String currentNote = null;

The BuddyNoteView constructor was automatically generated when the class was created. In the change that follows, it stores a reference to the view part instance in a class variable. Note that this assumes there is only one instance of the BuddyNote view part. Replace or modify the existing constructor to match the one shown here:

public BuddyNoteView () {
INSTANCE = this;
}

NOTE: In Eclipse, you can use the menu choice Source - Organize Imports to add the needed import statements after pasting a code snippet. It is recommended that you use this each time after pasting the provided code.

When Organize Imports is used, you may be asked which Person class to use. Be sure to select com.ibm.collaboration.realtime.people.Person and not com.ibm.collaboration.realtime.imhub.SametimeConnectListParser.Person.

Here are brief descriptions of some support methods in the class. Paste them below the createPartControl method.

The method getLocalFilespec shown in listing 7 maps between a Lotus Sametime user's login ID and a file name used to store any notes associated with it. A more sophisticated implementation stores the notes elsewhere, for example, in a backend database.

Listing 7. BuddyNoteView - getLocalFilespec
private String getLocalFilespec(Person p) {
	// Store the BuddyNote in the plug-in metadata area
	// named by person ID. Replace invalid filespec characters like
	// the colon.
	StringBuffer sb = new StringBuffer();
	String id = p.getId();
	sb.append(Activator.getDefault().getStateLocation());
	sb.append(File.separator);
	for (int i=0; i < id.length(); i++) {
		if (Character.isLetterOrDigit(id.charAt(i))) 
			sb.append(id.charAt(i));
		else
			sb.append('_');
	}
	sb.append(".txt");
	return sb.toString();
}

The storeBuddyNote method shown in listing 8 stores a note (String s) associated with a Person object. To simplify the implementation, the file name for the stored text is the same as the user's Lotus Sametime login ID with any invalid file name characters removed. This file is stored in an area reserved for plug-ins called the plug-in data area (specifically the Eclipse runtime's .metadata/.plugins/sample.buddynote directory).

Listing 8. BuddyNoteView - storeBuddyNote
private void storeBuddyNote(Person p, String s) {
	try {
		String spec = getLocalFilespec(p);
		File f = new File(spec);
		// Delete the file if the new note is empty
		if (s == null || s.trim().length() == 0) {
			f.delete();
			return;				
		}
		if (!f.exists())
			f.createNewFile();
		BufferedWriter out = new BufferedWriter(new FileWriter(f));
		out.write(s);
		out.close();
	} catch (IOException e) {
		e.printStackTrace();
	}
}

The retrieveBuddyNote method shown in listing 9 reads the text file associated with the provided person where any notes about him are stored. As with storeBuddyNote, it uses the user's Lotus Sametime login ID to construct the name of the file and reads it from the plug-in data area (specifically the Eclipse runtime's .metadata/.plugins/sample.buddynote directory).

Listing 9. BuddyNoteView - retrieveBuddyNote
private String retrieveBuddyNote(Person p) {
	String s = null;
	if (person != null) {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		String spec = getLocalFilespec(p);
		File f = new File(spec);
		if (f.exists()) {
			try {
				BufferedReader in = new BufferedReader
					(new FileReader(f));
				String str;
				while ((str = in.readLine()) != null) {
					pw.println(str);
				}
				in.close();
				s = sw.toString();					
			} catch (IOException e) {
			}
		}
	}
		
	return s;
}

Completing the createPartControl method

That takes care of the non-Sametime-specific code. Let's now take a look at the code that extends Lotus Sametime to create the BuddyNote area in the user interface and allows it to interact with the program.

BuddyNote is a view part. View parts contribute viewable areas to Lotus Sametime. This area is defined in the createPartControl method using Eclipse's standard widgets, called SWT (Standard Widget Toolkit).

The SWT API is similar in many ways to the Java AWT (Abstract Window Toolkit) API. SWT widgets are portable, and the toolkit includes custom widgets beyond the minimum defined on all platforms (for example, SWT's table widget is entirely implemented in Java and runs on all Eclipse-supported platforms).

The createPartControl method signature should have been added into the BuddyNoteView class automatically by Eclipse. Confirm that the createPartControl method signature in your code matches the following:

public void createPartControl (Composite parent) {

The method code begins by creating the form that contains the business card and text area:

Composite comp = new Composite(parent, SWT.BORDER);
comp.setLayout(new FormLayout());

Next, the code adds a business card as shown in listing 10. This is the Lotus Sametime Connect widget used to display information about people in the Contacts list. You may recognize the business card from Lotus Sametime’s chat window.

Listing 10. BuddyNoteView – createPartControl Business Card
	// Business card is "person aware", i.e., will update 
	// as the person's status updates.
	bizCard = new MyBusinessCard(comp, SWT.NONE);
	FormData fd = new FormData();		
	fd.top = new FormAttachment(0, 0);
	fd.left = new FormAttachment(0, 0);
	fd.right = new FormAttachment(100, 0);
	bizCard.setLayoutData(fd);

Next you define a divider line to separate the business card and the text area, and then you initialize the text area as shown in listing 11.

Listing 11. BuddyNoteView – createPartControl text area
	// Dark line separator between business card and text area.
	Label divider = new Label(comp, SWT.NONE);
	divider.setBackground(divider.getDisplay().getSystemColor(
			SWT.COLOR_DARK_GRAY));
	fd = new FormData();
	fd.top = new FormAttachment(bizCard, 0);
	fd.left = new FormAttachment(0, 0);
	fd.right = new FormAttachment(100, 0);
	fd.height = 1;
	divider.setLayoutData(fd);

	// Text input area; it displays an indication that it's empty
	// as defined by DEFAULT_NOTE
	textControl = new StyledText(comp, SWT.MULTI | 
		SWT.V_SCROLL | SWT.WRAP);
	fd = new FormData();
	fd.top = new FormAttachment(divider, 0);
	fd.bottom = new FormAttachment(100, 0);
	fd.left = new FormAttachment(0, 0);
	fd.right = new FormAttachment(100, 0);
	textControl.setLayoutData(fd);
	textControl.setText(DEFAULT_NOTE);

To complete this method, you need to add a focus listener for the text area that automatically saves the entered text associated with the current contact into a file, indexed by the contact’s Lotus Sametime login ID, or that retrieves the text from the file depending upon whether the BuddyNote frame has gained or lost the focus. See listing 12.

Listing 12. BuddyNoteView – createPartControl focus listener
	// Save and restore the BuddyNote on gain/lose focus.
	// (remember not to store the "default" note!)
	textControl.addFocusListener(new FocusAdapter() {
		public void focusLost(FocusEvent e) {
			if (person != null && !textControl.getText().
					equals(currentNote)) {
				currentNote = textControl.getText();					
				storeBuddyNote(person, currentNote);
			}
		}

		public void focusGained(FocusEvent arg0) {
			if (person != null && textControl.getText().
					equals(DEFAULT_NOTE)) 
				textControl.setText("");
			}
		});

The last bit of code asks the form (composite) to position the widgets you created.

comp.layout();

Choose File - Save All, and then run the sample to confirm the createPartControl method executes as expected. The business card is blank because the code doesn't set the "person" it should display. That's the next step. The text field "<Click to enter notes>" shows default text as a reminder to the user as shown in figure 9.

Figure 9. Progress Check – BuddyNote Frame Layout
Progress Check – BuddyNote Frame Layout

Define the message event handling

Lotus Sametime components communicate key events through a common messaging bus. The components that use the messaging framework are called participants. A sender interacts only with the messaging bus and does not need to know anything about the component that processes a message.

Message classes are defined to make the creation and processing of the messages simple, fast, and type safe. There is a subclass of the base Message class specific to each type of message. For example, the class ImTextReceivedMessage represents the message that is broadcast when the user receives an incoming text message.

The MessageHandler interface and DefaultMessageHandler class provide separate methods for each type of Message subclass. You can subclass DefaultMessageHandler and override the handleMessage (a Message subclass) methods for the messages that you want to process. Methods that are not explicitly overridden get passed to the subclass's handleDefaultMessage method. This DefaultMessageHandler subclass is typically used in conjunction with a MessageHandlerAdapter.

Here are some of the message events that can be intercepted from the message bus and acted upon:

  • handleMessage(ImChatWindowAdditionMessage)
  • handleMessage(ImChatWindowCloseWarningMessage)
  • handleMessage(ImChatWindowFlashWindowMessage)
  • handleMessage(ImChatWindowForceFocusMessage)
  • handleMessage(ImChatWindowToolbarRedrawMessage)
  • handleMessage(ImConnectedMessage)
  • handleMessage(ImConnectionStatusChangeMessage)
  • handleMessage(ImDisconnectedMessage)
  • handleMessage(ImTextConnectionClosedMessage)
  • handleMessage(ImTextConnectionOpenMessage)
  • handleMessage(ImTextReceivedMessage)
  • handleMessage(ImTextSendMessage)

You created a MessageHandlerAdapter class called BuddyNoteMessageHandlerAdapter when you set up the MessageHandlerListener extension. You next complete this class by including a call to a MessageHandler class called BuddyNoteMessageHandler that you then create.

BuddyNoteMessageHandler overrides the methods handleMessage(BuddySelectedMessage) and handleMessage(ImConnectedMessage). These methods allow the BuddyNote application to start up with your information by default and update based on any contacts you subsequently select.

BuddyNoteMessageHandlerAdapter

A message handler adapter is specified in the extension manifest as the class associated with the *messages.MessageHandlerListener extension point. You added this extension point as a dependency of the BuddyNote plug-in at the beginning of the article, and you defined the associated class as BuddyNoteMessageHandlerAdapter.

If you click the sample.buddynote tab in the center Eclipse frame, and then select the plugin.xml tab at the bottom, you see the code shown in listing 13.

Listing 13. MessageHandlerListener extension point
<extension
         point="com.ibm.collaboration.realtime.messages.MessageHandlerListener">
      <messageHandler class="sample.buddynote.BuddyNoteMessageHandlerAdapter"/>
   </extension>

Listing 14 is all there is to the BuddyNoteMessageHandlerAdapter code. The two constructor signatures have already been constructed by Eclipse, and you do not add any methods.

Listing 14. BuddyNoteMessageHandlerAdapter class
public class BuddyNoteMessageHandlerAdapter extends MessageHandlerAdapter {

	public BuddyNoteMessageHandlerAdapter(MessageHandler handler) {
		super(handler);
	}

	public BuddyNoteMessageHandlerAdapter() {
		super (new BuddyNoteMessageHandler());
	}
}

The adapter code simply decides the appropriate message handler to be used. In a more complex case, the adapter is a good place for initialization code that its handler(s) require.

As you can see, the default constructor uses a BuddyNoteMessageHandler object. This is the class that does the actual work of processing incoming events; it is a subclass of DefaultMessageHandler. You create and define this class next.

BuddyNoteMessageHandler

BuddyNoteMessageHandler contains the necessary code to detect the user's selection of a contact, to call a method to populate the business card with the selected contact’s information, to detect the user’s connection state, and to call a method to fill the business card with the user’s information at startup.

To create this class, perform these steps:

  1. Select the package sample.buddynote in the Package Explorer.
  2. Choose New - Class and enter this information in the fields:

    Source Folder: sample.buddynote/src
    Package: sample.buddynote
    Name: BuddyNoteMessageHandler
    Superclass: com.ibm.collaboration.realtime.messages.DefaultMessageHandler

    NOTE: Choose Browse and type DefaultMessageHandler in the text box for Choose a type. DefaultMessageHandler – com.ibm.collaboration.realtime.messages appears under Matching Types. Select this and click OK.
  3. Verify that your New Java Class dialog box matches the one shown in figure 10.
Figure 10. New Java Class dialog box – BuddyNoteMessageHandler
New Java Class Dialog – BuddyNoteMessageHandler
  1. Click Finish to create the class.

BuddyNoteMessageHandler has one overridden method, handleMessage. These use methods from the BuddyNoteView class, handleBuddySelected and handleConnected, which you deal with next. Therefore, disregard compiler errors in Eclipse regarding undefined methods because they are cleared up in the next section.

The handleMessage(BuddySelectedMessage message) event notifies the singleton BuddyNote using its handleBuddySelected method. It responds by setting the information of the selected user into the business card you initialized earlier in the createPartControl method of BuddyNoteView.

The code in listing 15 uses Lotus Sametime's ServiceHub to retrieve the registered people service; this service handles mapping IDs (a string consisting of the user's login and community ID) into person instances.

Listing 15. BuddyNoteMessageHandler - handleMessage(BuddySelectedMessage message)
public void handleMessage(BuddySelectedMessage message) {
	try {
		PeopleService peopleSvc = (PeopleService) ServiceHub.
			getService(PeopleService.SERVICE_TYPE);
		Person person = peopleSvc.getPersonById(
			message.getPersonId());
		BuddyNoteView.INSTANCE.handleBuddySelected(person);		} 
	catch (ServiceException e) {
		e.printStackTrace();
	}		
}

The handleMessage(ImConnectedMessage) event notifies the singleton BuddyNote view part using its handleConnected method. It responds by setting the information of the logged-in user in the business card at startup. In other words, the business card in the BuddyNote frame displays your business card until you select one from the Contacts list.

public void handleMessage(ImConnectedMessage message) {
BuddyNoteView.INSTANCE.handleConnected();
}

Reminder: Use the menu choice Source - Organize Imports to add the needed import statements after pasting a code snippey. Be sure to select com.ibm.collaboration.realtime.people.Person and not com.ibm.collaboration.realtime.imhub.SametimeConnectListParser.Person when asked.

Ignore any errors regarding undefined methods because these errors clean up once the remainder of the code is added.


Finishing BuddyNoteView

Now that the message handler and adapter are finished, you add the methods to BuddyNoteView that respond to these events in the view part. These methods rely on two others, getLocalPerson and refreshPersonInfo, which are discussed next.

The handleConnected method is called from BuddyNoteMessageHandler if it detects that Lotus Sametime has connected. If so, it sets the business card to the logged-in user’s information by default until the user selects a contact. See listing 16.

Listing 16. BuddyNoteView - handleConnected
void handleConnected() {
	// initialize to current user if none already selected
	if (person == null) {
		person = getLocalPerson();
		refreshPersonInfo(person);				
	}
}

The handleBuddySelected method is called from BuddyNoteMessageHandler when it detects that you have selected someone from the Contacts list. The business card is then updated to that of the currently selected contact. See listing 17.

Listing 17. BuddyNoteView - handleBuddySelected
void handleBuddySelected(Person person) {
	this.person = person;
	refreshPersonInfo(person);
}

The refreshPersonInfo method updates the business card to the currently selected contact or to your own information if Lotus Sametime has just connected. The notes section is updated to the note stored for this contact or, if no contact is selected, to the default note ("<Click to enter notes>"). See listing 18.

Listing 18. BuddyNoteView - refreshPersonInfo
private void refreshPersonInfo(final Person person) {
	// Notifications in Sametime Connect often come from
	// non-UI threads. Queue a request to the UI thread.
		
	bizCard.getDisplay().asyncExec(new Runnable() {
		public void run() {
			if (textControl.isDisposed())
				return;
				
			bizCard.setPerson(person);				
			currentNote = retrieveBuddyNote(person);
			if (currentNote != null)
				textControl.setText(currentNote);
			else
				textControl.setText(DEFAULT_NOTE);			
		}
	});		
}

The getLocalPerson method is the final method needed to allow your BuddyNote plug-in to work as intended. Your own information is retrieved to place in the business card section when Lotus Sametime first connects using Community and PeopleService. Community maintains the list of known communities (Lotus Sametime, external IM networks, and so on), and PeopleService handles mapping between person IDs and the person instances at runtime. See listing 19.

Listing 19. BuddyNoteView - getLocalPerson
private Person getLocalPerson() {
	// Return the local person (for the initial display)
	Person p = null;
	try {
		CommunityService communityMgr = (CommunityService)
			ServiceHub.getService
			(CommunityService.SERVICE_TYPE);
		Community community = communityMgr.getDefaultCommunity();
		if (null != community) {
			String localUserId = community.getUserId();
			if (localUserId != null) {
				PeopleService peopleSvc = (PeopleService)
					ServiceHub.
					getService(PeopleService.SERVICE_TYPE);
				p = peopleSvc.getPerson(
					localUserId, community.getId());
			}
		}
	} catch (ServiceException e) {
		e.printStackTrace();
	}
	
	return p;
}

Running the BuddyNote plug-In

Now that you have added all the code necessary, all that is left is to test your plug-in and to debug, if necessary. First choose File - Save All, and then confirm that there are no errors by looking in the Problems view as shown in figure 11.

Figure 11. Console View – Problems tab
Console View – Problems tab

If any problems are listed, double-click them. Eclipse takes you to their location in the code. A red x appears to the left of the line in question; clicking the red x shows you recommendations for correcting the problem. See figure 12.

Figure 12. Problem example
Problem example

Before trying to fix any of the problems, though, try using Source - Organize Imports because a missing import statement is the most likely source of the error. If the problem persists, attempt the recommended action.

If there are no errors, run the application using ST 751 from the Run drop-down menu as you have been doing throughout this article. Wait a few moments for Lotus Sametime to launch. Log in using your ID and password, and you see something similar to figure 1.

Congratulations, you have created your first Lotus Sametime plug-in!


Conclusion

This article guided you through the creation of a Lotus Sametime view part extension. You learned how to create a plug-in, plug-in extensions, and the classes that define the behavior of these new extensions. Finally, you tested your new code in Eclipse’s PDE.

The next installment in this series, part 3, demonstrates how to use the debug tools built into Eclipse to troubleshoot any errors you encounter when developing a plug-in. Part 4, the final installment, shows you how to deploy a plug-in using an update site.


Downloads

DescriptionNameSize
Code sampleBuddyNote_Workspace.zip1428KB
Code sampleBuddyNoteCode.txt8KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into IBM collaboration and social software on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Lotus
ArticleID=237517
ArticleTitle=Working with plug-ins in IBM Lotus Sametime V7.5.1: Developing the BuddyNote plug-in
publish-date=07172007