Creating a stock quote bot using the IBM Lotus Sametime Java toolkit

Let us show you how to create a bot that retrieves stock information for IBM Lotus Sametime Connect, using the IBM Lotus Sametime Java toolkit. StockBot uses a Web service to retrieve stock quote information from the Yahoo! Finance Web site.

Mark Talbot (talbotm@us.ibm.com), Developer, Industry Solutions, IBM, Software Group

Mark Talbot works for IBM as a developer for Industry Solutions. You can reach Mark at talbotm@us.ibm.com.



Kulvir Singh Bhogal (kbhogal@us.ibm.com), Consultant, Software Services for WebSphere, IBM, Software Group

Kulvir Singh Bhogal works as an IBM Software Services for WebSphere consultant, devising and implementing J2EE-centric solutions at customer sites across the nation. You can reach Kulvir at kbhogal@us.ibm.com.



05 October 2007 (First published 06 February 2007)

Also available in Chinese Russian

The developerWorks Lotus article, "Building your own Sametime bots, Part 1," explains how to create IBM Lotus Sametime bots, using the example of a Magic Eightball to facilitate the discussion. Since the publication of that article and with the advent of IBM Lotus Sametime V7.5, the Lotus Sametime toolkits have undergone significant repackaging. This article addresses those packaging changes and rekindles the bot discussion with the creation of a bot that provides stock quote information. This stock quote information is obtained through a Web service that you create using IBM Rational Application Developer V6.0.

Though we recap some information about bots, we do not do so exhaustively. Rather, we suggest that you familiarize yourself with the bot topic by reading the articles in the Resources section. Also, if you are not familiar with Web services, you can review the material on the developerWorks New to SOA and Web Services page.

Sametime bots and IBM Lotus Sametime Java toolkit

The term bot has its origins from the word robot and is used to describe a software application that takes instructions from a user and provides a response. Sametime bots are a breed of bots that taps into the presence awareness and instant messaging capabilities of Lotus Sametime.

A Sametime bot appears to IBM Lotus Sametime Connect users as an online person in the Contacts list. Figure 1 shows a preview of Lotus Sametime Connect interacting with the StockBot, which is the bot you build in this article.

Figure 1. StockBot preview
StockBot preview

A bot can be trained to do such things as provide information on demand to users, but how do you train a bot? You do it programmatically, using the IBM Lotus Sametime Java toolkit.

The Lotus Sametime Java toolkit is used for desktop and server development. It lets you add Lotus Sametime features to Java applications. The toolkit guide that comes with the IBM Lotus Sametime Software Development Kit (SDK) describes the Lotus Sametime Java Toolkit as a: "collection of building blocks or components that developers use to build applications that leverage the functionality and services provided by Lotus Sametime."

Beginning with Lotus Sametime V7.5, all Lotus Sametime client and server toolkits are bundled into a consolidated package named the Lotus Sametime SDK. You can download the SDK from the developerworks Lotus Toolkits page.

Using IBM Rational Application Developer for development

You can use the Lotus Sametime toolkit components in any Java development environment that supports Java Development Kit 1.4.2 or 1.5. For our bot development, we use IBM Rational Application Developer V6. Rational Application Developer is a powerful integrated development environment (IDE) based on the Eclipse platform that can catalyze development efforts.

Because this article is not a tutorial about Rational Application Developer, we assume that you are familiar with how to use the development environment. If not, we suggest you check out the developerWorks Rational Application Developer for WebSphere Software page. Rational Application Developer ships with a built-in IBM WebSphere Application Server V6 test environment, which you can use to power your enterprise applications during development.


Using the IBM Lotus Sametime 7.5 Demonstration Site as a sandbox

To create a bot, you need to reserve a Sametime ID for it. For our testing and development, we use the IBM Lotus Sametime 7.5 Demonstration Site, where you must create two Sametime IDs, one for your bot and one for a user who can access the bot. Configure Lotus Sametime Connect to connect to the stdemo3.dfw.ibm.com host server by choosing File - Preferences, by selecting Communities in the left navigation pane of the Preferences dialog box, and by clicking the Add New Community button.

In the subsequent Log In tab, enter the log-in information (Sametime Demonstration Site user name and password) for your Sametime user. Click the Server tab as shown in figure 2, enter stdemo3.dfw.ibm.com in the Host server field and 1533 in the Community port field, and then click OK.

Figure 2. Adding the Sametime community for testing and development
Adding the Sametime community for testing and development

Building and understanding the StockBot

As mentioned previously, we are building a bot that provides stock quote information, hence the name StockBot. The question is how do you obtain this stock quote information? To do this, you tap into the stock quote information provided by the Yahoo! Finance Web site . Specifically, we use a Yahoo facility that returns stock quotes in a comma-separated value (CSV) format.

The following is the CSV return value for the request of the IBM stock symbol:

"IBM",93.86,"N/A"

In particular, we are interested in the second token (93.86 in our example), which is the last traded value (commonly referred to as a stock quote). To get a quote like that one, you need to contact the URL:

http://finance.yahoo.com/d/quotes.csv?f=sl1e1&e=.csv&s=

concatenated with the stock symbol you are looking for. For example, if you are looking for a quote of IBM, your URL is

http://finance.yahoo.com/d/quotes.csv?f=sl1e1&e=.csv&s=IBM

Use the f=sl1e1 in the URL to specify that you want Yahoo to return the symbol (represented by the s), the last trade price (l1), and an error indication (e1) if you provide the service with an invalid symbol. Later, you also leverage Java’s built-in networking facilities given through the java.net package to contact the Yahoo! Finance Web site and to get the requested stock quote information.

Creating the StockQuoter Class

This is the code for the com.devworks.example.StockQuoter class. This and the other code associated with this article can be downloaded from the Download section.

Listing 1. com.devworks.example.StockQuoter class
public class StockQuoter {
	private static String YAHOO_URL = 
		"http://finance.yahoo.com/d/quotes.csv?f=sl1e1&e=.csv&s=";
	Pattern p = Pattern.compile("N/A");
	private static final float 
		INVALID_SYMBOL_RETURN_VALUE = -999.999F;
	
	public float getQuote(String symbol) throws Exception
	{
		String compositeURL = YAHOO_URL + symbol;
		URL url = new URL(compositeURL);
		InputStream is = url.openStream();
		Reader reader = 
			new BufferedReader(new InputStreamReader(is));
		StreamTokenizer st = new StreamTokenizer(reader);
		// grab the first token - should be the symbol
		st.nextToken();
		String returnedSymbol = st.sval;
		if (!returnedSymbol.equals(symbol)) 
			throw 
			new Exception("A problem occurred with the stock service");
		else  
		{
			st.nextToken(); // skip the comma
			st.nextToken(); // get the quote
			float quote = (float)st.nval;
			st.nextToken(); // skip comma
			st.nextToken(); // get error
			String sError = (String)st.sval;
			Matcher myMatcher = p.matcher(sError);
			boolean found = myMatcher.find();
			if (found) return quote;
			else return INVALID_SYMBOL_RETURN_VALUE;
		}

As you can see in the class, a java.io.InputStream object is used to open the designated finance.yahoo.com URL for the symbol being requested. As described earlier, the URL is a concatenation of the finance.yahoo.com URL with the symbol for which you want a quote. You use the StreamTokenizer class to parse the output returned by visiting the URL. Next, you find the token that corresponds to your stock quote and return it as a float.

If a user happens to send an invalid stock symbol to the getQuote method, the Yahoo stock service returns a string saying that an error has occurred. If all is well, the return string is N/A. Note that a regular expression is used to analyze the Yahoo output for the presence of an N/A. If one is not seen, the dummy value of -999.99F is sent back to the method consumer, which interprets the dummy value as a call for an invalid stock symbol.

In addition to the getQuote method, the class contains a main method that can be used for unit testing the getQuote method.

The previous code must reside in the Java Source folder of a Dynamic Web Project you create in Rational Application Developer. For our Dynamic Web Project, we used the name StockQuoteWebProject. In turn, StockQuoteWebProject must be housed in an Enterprise Application Project. We named our Enterprise Project StockQuoteEARProject. The project structure appears in Rational Application Developer’s Project Explorer as shown in figure 3.

Figure 3. Project structure in the Project Explorer
Project structure in the Project Explorer

Creating the StockQuote Web service

At this point, you can have your Sametime bot interact directly with your StockQuoter class. However, to showcase the Web service creation facilities of Rational Application Developer and to show how easy it is to use the wizards of the IDE to create a client proxy, we want to show you how to create a bot that uses a Web service.

To expose the com.devworks.example.StockQuoter class as a Web service in Rational Application Developer, choose File - New - Other. From the subsequent dialog box, make sure the Show All Wizards option is selected, expand the Web Services directory, select Web Service, and click Next (see figure 4).

Figure 4. Choosing the Web Service wizard
Choosing the Web Service wizard

In the subsequent Web Service panel, make sure a Web service type of "Java bean Web Service" is selected and that the Generate a proxy option is deselected (we will generate a proxy later), and then click Next.

In the Object Selection Page panel, make sure com.devworks.example.StockQuoter is listed in the Bean field, and then click Next. In the Service Deployment Configuration panel, make sure that the Service project is defined as StockQuoteWebProject and that the EAR project is defined as StockQuoteEARProject (see figure 5).

Figure 5. Specifying the projects to use for the Web service
Specifying the projects to use for the Web service

Next, verify that the Service Endpoint Interface Selection panel shows com.devworks.example.StockQuoter as the bean and com.devworks.example.StockQuoter_SEI as the service endpoint interface. The option "Use an existing service endpoint interface" should not be selected. Click Next.

In the Web Service Java Bean Identity panel, select only the getQuote method because you don’t want to expose your main method through your Web service, and then click Next. Finally, in the Web Service Publication panel, make sure both the "Launch the Web Services Explorer to publish this Web service to the Unit Test UDDI Registry" and "Launch the Web Services Explorer to publish this Web service to a UDDI Registry" options are not selected because you do not want to publish to a UDDI registry.

After a short while, Rational Application Developer creates your Web service for you. You can use various facilities within Rational Application Developer to unit test that your Web service works. We do not discuss that process here; instead, you can refer to the Resources section if you are not familiar with how to do this.

Notice that the Rational Application Developer wizard has created a number of code artifacts, including a Web Services Description Language (WSDL) file named StockQuoter.wsdl. You should see this file when you select the Dynamic Web Project and expand the StockQuoteWebProject, WebContent, wsdl, com, devworks, and example folders.

Creating the StockQuote Web Service Client proxy

Now that you have a Web service, you are ready to consume it. Rational Application Developer allows you to avoid the intricacies of how to consume a Web service by letting you create a proxy Java class that handles the heavy lifting for you. This proxy class resides with the client, which in your case is the bot. For simplicity, let's assume that your client and server are located on the same machine.

In Rational Application Developer, choose File - New - Other (first making sure the Show All Wizards option is selected in the Select a wizard window). Expand Web Services, select Web Service Client, and click Next. In the subsequent Web Services panel, choose a Client proxy type of Java proxy, and then click Next.

Next, you need to tell Rational Application Developer the location of the WSDL file that was created when you created your Web service. Click the Browse button and from the Resource browser window that appears, expand the StockQuoteWebProject, WebContent, wsdl, com, devworks, and example folders, and select StockQuoter.wsdl (see figure 6). Then click OK.

Figure 6. Choosing the StockQuoter.wsdl file
Choosing the StockQuoter.wsdl file

In the Client Environment Configuration panel, choose a Client type of Java, and specify a Client project name of StockBotProject. As you’ll see later, we also use this project to house our bot. In the final Web Service Client wizard panel, click Finish to complete the creation of the Java proxy (see figure 7).

Figure 7. Finishing the Web Service Client wizard
Finishing the Web Service Client wizard

At this point, if you switch to the Java perspective, you should see a new project named StockBotProject, in which there are a number of classes that were auto-generated by Rational Application Developer (see figure 8). The proxy class is named StockQuoterProxy.java.

Figure 8. Proxy class auto-generated by Rational Application Developer
Proxy class auto-generated by Application Developer

Analyzing the StockQuoterProxy class, you should see a method named getQuote. Later, we show you how StockBot leverages this method to hit your stock quote Web service.


Creating the StockBot

To develop the StockBot, you use the Lotus Sametime Java toolkit. With the Lotus Sametime V7.5 Java toolkit, you can do such things as incorporate Sametime chat on your company’s Web site to instantaneously connect site visitors with your sales staff, custom-tailor Lotus Sametime to fit your business needs, or create your own Sametime-enabled Java application.

First, you must do some housekeeping to get your Java project ready to create a Sametime bot. Specifically, you need to add the STComm.jar, stcommsrvrtk.jar, and stjavatk.jar files from the Lotus Sametime Java toolkit to the Java Build Path of your StockBotProject. To do this, follow these steps:

  1. In Rational Application Developer, right-click the StockBotProject from the Package Explorer view and choose Properties.
  2. From the Properties dialog box, select Java Build Path in the left navigation pane to edit the Java Build Path properties.
  3. Select the Libraries tab (see figure 9).
  4. Click the Add External JARs button to add the Sametime Java Client JAR files. The three JAR files specified earlier are included in the Lotus Sametime Java Toolkit.
Figure 9. Editing the Java Build Path to include the necessary JAR files
Editing the Java Build Path to include the necessary JAR files

The StockService class

Your Sametime bot consists of two classes that you create, namely, StockService and StockQuoteBot. The bulk of your bot logic is in the StockService class, which implements the following Sametime interfaces:

Listing 2. Sametime interfaces
com.lotus.sametime.community.LoginListener
com.lotus.sametime.community.ServiceListener
com.lotus.sametime.im.ImServiceListener
com.lotus.sametime.community.ImListener

Create a class named StockService in a package named com.devworks.example.bot under the StockBotProject Java project. You can import the code for this class from the download associated with this article.

Now let's analyze the StockService class contents. The constructor creates a new STSession object using a string representing a session name that is unique to the Java Virtual Machine on which the bot is running. The STSession object holds the set of components associated with the Sametime session. After creating the STSession object, you load the components the bot uses and start the Sametime session.

Listing 3. StockService class
private STSession session;

public StockService(String sessionName) throws DuplicateObjectException {
		session= new STSession(sessionName);            
		session.loadSemanticComponents();
		session.start();
}

After the Sametime session is created, you can join the Sametime community. The CommunityService class allows the StockService class to log into a Lotus Sametime server. For the bot to receive responses to its requests (such as a login request), it must have the appropriate listeners associated with it. The first listener that you associate with the StockService class is the com.lotus.sametime.community.ServiceListener. The ServiceListener provides updates on the availability of server-side components in response to requests made on the CommunityService object. After you add a ServiceListener, you call your private login method as shown in listing 4.

Listing 4. CommunityService class
private CommunityService service;  

  public void start(String server, String username, String password)
  {
      service = (CommunityService)session.getCompApi(CommunityService.COMP_NAME);
      service.addServiceListener(this);
      login(server, username, password);
  }

In the following login method, you associate a com.lotus.sametime.community.LoginListener to your CommunityService object. Because your StockService class also implements the LoginListener interface, you can use this as an argument. After associating the LoginListener, you can log into the Lotus Sametime server using your server name, user name, and password:

Listing 5. login method
private void login(String server, String username, String password)
  {
    service.addLoginListener(this); 
    service.loginByPassword(server,username,password);
  }

The com.lotus.sametime.community.LoginListener interface has two callback methods that must be implemented. The loggedIn method is called upon a successful login, and the loggedOut method is called upon logging out. The loggedOut method is invoked after unsuccessful logins as well as successful logouts. When you implement your loggedOut method, you check the reason for logging out and display it to the system console:

Listing 6. loggedOut method
public void loggedOut(LoginEvent event)
  {
    int reason = event.getReason();
    if (reason == 0)
    	System.out.println("Successfully logged out.");
    else 
    	System.out.println("Failed to login.  Return Code =" + reason);
    session.stop();
    session.unloadSession();
  }

In the following loggedIn method, we set up an InstantMessagingService object. The InstantMessagingService object works similarly to the CommunityService object in that it has a series of methods and listeners. The IMServiceListener interface allows you to listen for messages that the bot receives from users:

Listing 7. loggedIn method
InstantMessagingService imService;

  public void loggedIn(LoginEvent event)
  {
	imService = (InstantMessagingService) 
	_session.getCompApi(InstantMessagingService.COMP_NAME);
	imService.registerImType(ImTypes.IM_TYPE_CHAT);
	imService.addImServiceListener(this);
    System.out.println("Logged In");
  }

The IMServiceListener interface has one callback method, imReceived, which is called each time a user opens a new instant messaging window to initiate contact with the bot. To listen for messages and data that the user sends from that instant messaging window, an ImListener implementation must be created. Also, because our bot is friendly, it sends a welcome message each time a user initiates contact with it:

Listing 8. imReceived method
String welcomeMessage = "Welcome to the StockBot. 
Enter a stock symbol.";

public void imReceived(ImEvent arg0) {
	System.out.println("im received");
	arg0.getIm().sendText(false, welcomeMessage);
	arg0.getIm().addImListener(this);
}

The StockImListener callback methods include dataReceived, textReceived, imClosed, openImFailed, and imOpened. Our bot responds only to the textReceived and imClosed methods. When the user closes his instant messaging window, the listener is removed, preventing the bot from using system resources on users who are no longer using the bot:

Listing 9. imClosed method
public void imClosed(ImEvent arg0) {
	System.out.println("Im Closed");
	arg0.getIm().removeImListener(this);
}

The StockBot’s response to the textReceived callback is what earns the StockBot its nickname. In our implementation of textReceived, we get the stock symbol requested. Then, getQuoteString, a convenient method for contacting the stock quote Web service, is called to invoke the Web service you created earlier. If the user types help, a message is sent by the bot containing instructions for interacting with the bot:

Listing 10. textReceived method
String helpMessage = "Enter a stock symbol and I will return a price.";

public void textReceived(ImEvent arg0) {
	String stockSymbol = arg0.getText();
	String stringPriceMessage;
	if (stockSymbol.equals("help"))
		stringPriceMessage = helpMessage;
	else
		stringPriceMessage = getQuoteString(stockSymbol);
	arg0.getIm().sendText(true, stringPriceMessage);
}

The following getQuoteString method contains the logic for looking up the stock symbol using the StockQuoterProxy class you generated earlier. The getQuoteString method returns either a stock price or a message stating that it had a problem with the user’s request:

Listing 11. getQuoteString method
private String getQuoteString(String stockSymbol) {
	String stringPriceMessage;
	try {
		float stockPrice = 0.0f;
		StockQuoterProxy proxy = new StockQuoterProxy();
		proxy.getQuote(stockSymbol);
  stockPrice = stockLookup.getQuote(stockSymbol.trim());
		if (stockPrice != -999.99f)
	  stringPriceMessage = 
	  String.valueOf(stockPrice);
		else
		  stringPriceMessage = 
  "I'm sorry I had trouble with your request.";	
	} catch (RemoteException e) {
		stringPriceMessage = 
"I'm sorry I had trouble with your request.";
	} catch (Exception e) {
		stringPriceMessage = 
"I'm sorry I had trouble with your request.";
	}
	return stringPriceMessage;
}

Driving the bot with the StockQuoteBot class

The StockQuoteBot class provides the command line functionality for the bot. The class retrieves the Lotus Sametime server information to which it must connect as well as the user credentials for the bot as command line arguments. The class logs in using an instance of the StockService class described earlier. When you press a key on the keyboard, the StockBot is terminated:

Listing 12. StockQuoteBot class
public class StockQuoteBot {
	public static void main(String[] args) {
		StockService service = new StockService();
		String server = args[0];
		String userID = args[1];
		String password = args[2];
		service.start(server, userID, password);
		System.out.println("Stock Quote Bot is Running.  Press any key to terminate.");
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	try {
			br.readLine();
	} catch (IOException e) {
			System.out.println("error");
	}
		service.stop();
		System.out.println("Stock Quote Bot has terminated");
	}
}

Using the StockBot

Now that you have completed your bot development, you can easily run the bot in your Rational Application Developer test environment. To do this, right-click the StockQuoteBot.java file and choose Run - Run.

At this point, a Run dialog box as shown in figure 10 displays, so you have the opportunity to pass in command line arguments to the StockBot. In the Configurations pane, select Java Application, and then click the New button. A new Java Application configuration appears for the StockQuoteBot class. After that configuration appears, select the Arguments tab. For our program, the arguments entered are 192.168.19.128 "Stock Quote Bot" ibm, which are the values for our Lotus Sametime server address, user ID, and password, respectively.

Figure 10. Configuring the StockBot for work inside Rational Application Developer
Configuring the StockBot for work inside Rational Application Developer

After running the bot class, you receive confirmation in the console that the Sametime bot logged in successfully (see figure 11).

Figure 11. Rational Application Developer console view displays the StockBot’s output
Rational Application Developer console view displays the StockBot’s output

Now that the bot is running, you can log into your Lotus Sametime server with Lotus Sametime Connect and communicate with your StockBot as shown in figure 12. To do this, you need to add the Sametime partner ID that you reserved for your StockBot.

Figure 12. Interacting with the StockBot
Interacting with the StockBot

Conclusion

In this article, we demonstrated how to create a Sametime bot that subserviently listens for and responds to requests. Specifically, you built a stock quote Web service whose implementation accesses the Yahoo! Finance Web site to obtain quote information. You then created a bot to access the Web service; in turn, clients can talk to the bot and obtain stock quotes on demand.

In a related developerWorks Lotus article, "Building a Lotus Sametime bot for language translation," we showed you how to create a Sametime bot that works in conjunction with IBM WebSphere Translation Server to provide machine translation services. The kind of bot you can build is limited only by your imagination. We hope this article has made you more comfortable with the APIs you must use to build your own bots. Happy bot building!


Download

DescriptionNameSize
Code samplestockBotSampleCleintCode.zip10KB

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=193590
ArticleTitle=Creating a stock quote bot using the IBM Lotus Sametime Java toolkit
publish-date=10052007