An image of some Dominos

Domino & BlackBerry Java Applications - Part 1

Print Friendly and PDF

Posted: September 7, 2009 | | Categories: IBM Lotus Domino

Introduction

When I worked at Research In Motion and after, I've presented at Lotusphere and the View Domino Developer Conference on how to access Domino applications from BlackBerry devices.

Of course, the lead approach was to use the browser to access mobile friendly Domino applications. It's not a very exciting demo though – you take a domino database and scrunch it down so it fits the smaller screen and uses rich media sparingly.

The other option I discussed was to create Web Services in a Domino application then use Research In Motion's MDS Runtime technology to access the operations exposed by these services. It was a truly amazing demonstration to illustrate the web service then build a rich (non-browser) BlackBerry application that talked to it in minutes. With Research In Motion's recent announcement of the end of life of MDS Runtime and associated development tools – developers need another option for building a (non-browser) rich client application that talks to web services. I'm sure there's a way to do it from a BlackBerry Widget but I still haven't had a chance to play with that technology yet.  The only other option is to consume the Web Service from a Java application and for my presentation this year at the View Domino Developer conference I built a Java version of the application I'd been demonstration for years using MDS Runtime.

A few weeks ago I posted here that I was going to write some articles about how to build that application. From the responses I received, it seems that there are a lot of you who are interested in the information, so here we go…

I'm going to split this topic into three parts:

  • Part 1: (this article) How to build the Domino Web Service used in the sample application
  • Part 2: How to create the Web Service Stub called by the Java application
  • Part 3: How to build the Java application (for BlackBerry of course) that talks to the service

Before we begin, it's important to highlight that Research In Motion has published a lot of information about connecting to a Domino application from a BlackBerry device – be sure to check out na.blackberry.com/eng/developers/started/develop/ibm.jsp for additional information on the topic.

Learning How to Build a Domino Web Service

When I first set about learning about how to build Web Services in Domino, there really wasn't much information available. The first I'd heard about it was from some old articles that Gary Devendorf (now at Microsoft, go figure) on how to do web services in ND6 (that's Notes & Domino 6 for the uninitiated). It was quite a mess; you had to build an agent that could read and write XML and had to hand craft the service's WSDL to use with some tools.

With the release of Domino 7, IBM made it much easier to build web services. Ultimately, the way I learned how to create the sample application in this article was from reading this: https://www.ibm.com/developerworks/lotus/library/nd7-webservices/. If you don't know how to do web services in Domino, that's a great place to start reading.

About the Project

When I first started looking for a good sample application for Domino developers I looked for something that would appeal to the widest audience of developer. I thought about how every Domino environment I'd ever worked with had at least one (sometimes more) additional contact databases outside of the standard Domino Directory. Since the BlackBerry already provided search capabilities against the Domino Directory, it seemed like a good idea to build a web service that would allow BlackBerry applications to lookup contacts in one of these other databases.

Assuming that most of these additional contact databases were created against a copy of the Domino Directory, I built the web service using that template as a starting point. If you use this web service against a database that wasn't built off of that template, you will have to change the view, column and field names to match the needs of the target database.

Building the Web Service

The web service is used to lookup contact information for a particular person in the database. It contains two operations: GetUserList and GetUserDetails. GetUserList takes as a parameter a portion of the last name being searched for and returns an array containing the names of all contacts who's last name begins with the specified string. GetUserDetails takes as a parameter the name of a contact and returns a UserInfo object containing several fields from the selected Contact document in the database.

Let's get started building the web service. To do this, you will need to use Domino Designer 7 or higher – the screen shots in this article were taken in Domino Designer 8.5. The database you're creating will need to reside on a Domino server with the HTTP task enabled in order to be able to be accessed by the BlackBerry Java application we'll create in Part 3.

Open Domino Designer and open the contact database in design mode (it would be best to do this in a template, but that's up to you). In designer, expand the 'Code' section of the design element hierarchy as shown in Figure 1. Right-click on 'Web Services Providers' and select 'New Web Service Provider…' as shown in the figure.

Figure 1
Figure 1

Designer will create a new Web Service and prompt for the properties for the service. In the first tab of the Web Service properties (shown in Figure 2) you will need to provide a name for your service. In this case, I am calling it 'DomDirLookup' – the class name for the Web Service must match the name you enter here.  In this example, I named the service and the Port Type Class the same.

Figure 2
Figure 2

On the security tab (shown in Figure 3) you will want to set the appropriate security properties for the Web Service. Depending on how confidential the data is in the database, you may want to force users to authenticate to the database before being granted access or you can just set the ACL default access to Reader to allow anyone in. If you need to be able to track access to the database, you will want to enable the 'Run as web user' checkbox so when the agent runs, it runs under the credentials of the person accessing the database.

Figure 3
Figure 3

In the propeller head tab on the Web Services properties (shown in Figure 4) are settings that effect your ability to access the Web Service from a Java application. As shown in Figure 3, the Web Service's 'Programming Model' must be set to 'RPC' and the 'SOAP message format' must be set to 'Doc/Literal.' I found that without these settings, the Sun Java Wireless Toolkit was not able to create the necessary stub program needed to access the service from a Java application.

Figure 4
Figure 4

Once you have all of the properties set, you must now start writing the code for the service. For this particular Web Service, I wrote all of the code in LotusScript. Because of the way I write agents and because of the way I loop through result sets in the agent, I added the following code to the 'Options' section of the Web Service.

Option Public  
Option Declare  
Option Base 1

The rest of the code goes into the 'Declarations' section of the Service. Since we're not running this code like an agent, the 'Initialize' and 'Terminate' sections of the Web Service aren't used – everything is in the 'Declarations.' I could have broken some of the code out into subroutines, but that wasn't needed for this simple service.

Figure 5
Figure 5

At this point, let's take a look at the core portion of the code:

The first thing the code does is declare objects for the NotesDatabase and NotesSession objects.:

'Some Notes objects we'll need  
Dim db As NotesDatabase  
Dim s As NotesSession

In the code that follows, the Web Service defines the UserList class which will return an array of Strings containing the list of contacts that matched the search criteria:

'The following class defines an array of strings  
'that will be returned by the function GetUserList  
Class UserList  
Public users() As String   
End Class

Domino can't return an array of string to the Web Service consumer, so I had to wrap the array into a class and return the class – the calling program will automatically convert the class to the appropriate array.

Next I define a UserInfo class that contains the different values returned from the selected contact record (person document). In this case it's just a bunch of fields I thought would be cool to use in the program – you may find that you need different fields returned for your particular application:

'the following class defines the user details  
'that we will be returning for a detailed lookup  
Class UserInfo  
Public FirstName As String  
Public LastName As String  
Public FullName As String  
Public EmailAddress As String  
Public OfficePhone As String  
Public MobilePhone As String  
End Class

Ok, that's it for the setup – now we need to actually write the code that does all of the work.  The first thing you must do is create the class defined when you gave the Web Service a name in Figure 2.  After that comes one subroutine and two functions:

Class DomDirLookup  
  
Sub New  
'Initialize our Notes session object  
Set s = New NotesSession  
'Then get a handle to the current database  
Set db = s.CurrentDatabase     
End Sub  
  
Function GetUserList(searchStr As String) As UserList  
  
End Function  
  
Function GetUserDetails(searchStr As String) As UserInfo  
  
End Function  
  
End Class

The New subroutine does some simple setup for the Web Service – gives it access to the current Session and the current database. This is code any experienced Domino developer has written hundreds of times, although not normally in a 'New' subroutine but rather in Initialize.

The GetUserList function is setup for the input parameter and returns the UserList class when it's all finished. TheGetUserDetails` works the same way, although it returns a UserInfo class as shown in the sample.

Once the framework for the service has all been defined, all you have to do is plunk in the rest of the code needed to implement the functionality required for the GetUserList and GetUserDetail functions. Now, before you take a look at the completed code – please try to remember that I wrote this code to demonstrate how to consume a Domino Web Service from a BlackBerry device. I did not make any effort to make the code as clean and efficient as possible, I just wrote the code to have something to call – realizing that the BlackBerry stuff was cooler. If you look at the code and think there's a better way to do it, then you're probably right – please don't tell me about it.

All right, that being said – here's the complete code for the Web Service. I tried to put in a bunch of comments so it will be easy to understand what I'm doing here. I'll attach a Notes database with the full source code for the service to this article when I publish it.

'Notes Objects  
Dim db As NotesDatabase  
Dim s As NotesSession  
Dim userView As NotesView  
Dim userDoc As NotesDocument  
  
'Other objects  
Dim i As Integer  
  
Const errorStr = "ERROR"  
  
'The following class defines an array of strings  
'that will be returned by the function GetUserList  
Class UserList  
Public users() As String   
End Class  
  
'the following class defines the user details  
'that we will be returning for a detailed lookup  
Class UserInfo  
Public FirstName As String  
Public LastName As String  
Public FullName As String  
Public EmailAddress As String  
Public OfficePhone As String  
Public MobilePhone As String  
End Class  
  
Class DomDirLookup  
  
Sub New  
'Initialize our Notes session object  
Set s = New NotesSession  
'Then get a handle to the current database  
Set db = s.CurrentDatabase     
End Sub  
  
Function GetUserList(searchStr As String) As UserList  
  
'Local Notes objects  
Dim tmpName As NotesName     
Dim ve As NotesViewEntry  
Dim vec As NotesViewEntryCollection  
  
'Put something out to the console so we know we're running  
Print "Starting GetUserList"  
'Make a new user list for our result set  
Set GetUserList = New UserList     
'Populate the list with a default value  
Redim GetUserList.Users(1)  
GetUserList.Users(1) = "Error retrieving user list"     
'Open the view we're going to lookup against  
Set userView = db.GetView("($VIMPeopleByLastName)")  
If Not userView Is Nothing Then           
'Do we have a search string?  
If Len(Trim(searchStr)) > 0 Then  
'See if we can find any users by the search string  
Set vec = userView.GetAllEntriesByKey(searchStr)  
Print |Searching contacts for "| & searchStr & |"|  
Else  
'Otherwise get all documents  
Set vec = userView.AllEntries  
Print |Retrieving all contacts|  
End If       
'Now, if we have any entries - put them into the array  
If vec.Count > 0 Then  
Print |Located "| & vec.Count & |" contacts|  
'Redimension the array to the size of the result set  
Redim GetUserList.Users(vec.count)  
'Process all of the entries in the View Entry Collection  
For i = 1 To vec.Count  
Set ve = vec.GetNthEntry(i)  
If Not ve Is Nothing Then  
Set userDoc = ve.Document  
If Not userDoc Is Nothing Then  
Set tmpName = New NotesName(userDoc.FullName(0))  
If Not tmpName Is Nothing Then  
Print |Adding "| & tmpName.Common & |" to the contact list|  
GetUserList.Users(i) = tmpName.Common             
Else  
Print |Unable to access contact information|  
GetUserList.Users(i) = errorStr  
End If  
Else  
Print |Unable to access contact document|  
GetUserList.Users(i) = errorStr  
End If             
Else  
Print |Unable to access view entry collection|  
GetUserList.Users(i) = errorStr             
End If  
Next  
Else  
Print |No contacts found|  
GetUserList.Users(1) = "No contacts found matching search criteria"     
End If  
End If     
Print "Leaving GetUserList"  
End Function  
  
Function GetUserDetails(searchStr As String) As UserInfo  
  
'Temporary storage as we manipulate the contact name  
Dim tmpName As NotesName     
  
'Put something out to the console so we know we're running  
Print "Starting GetUserDetails"  
'Make a new user list for our result set  
Set GetUserDetails = New UserInfo     
'Initialize our default return value  
GetUserDetails.FullName = "Unable to locate specified user"         
'Do we have a search string?  
If Len(Trim(searchStr)) > 0 Then  
'Open the view we're going to lookup against  
'this is a different view because we're searching against  
'the full name where above we're using last name  
Print |Opening $VIMPeople view|  
Set userView = db.GetView("($VIMPeople)")  
'Make sure we have the view  
If Not userView Is Nothing Then  
'Try to get the user document using abbreviated full name as a key  
'This should work because the view is sorted that way.  
Print |Searching for  "| & searchStr & |"|  
Set userDoc = userView.GetDocumentByKey(searchStr)  
If Not userDoc Is Nothing Then  
'Populate the result fields           
Set tmpName = New NotesName(userDoc.FullName(0))  
GetUserDetails.FullName = tmpName.Abbreviated  
GetUserDetails.LastName = userDoc.LastName(0)  
GetUserDetails.FirstName = userDoc.FirstName(0)  
GetUserDetails.EmailAddress = userDoc.InternetAddress(0)  
GetUserDetails.OfficePhone = userDoc.OfficePhoneNumber(0)  
GetUserDetails.MobilePhone = userDoc.CellPhoneNumber(0)   
Else  
Print |Unable to open contact document|  
End If         
Else  
Print |Unable to open $VIMPeople View|  
End If  
Else  
Print "No contact name provided, exiting"  
End If           
Print "Leaving GetUserDetails"   
End Function  
  
End Class

In the Next Installment

In the next installment in this series I'll demonstrate how to use the Sun Java Wireless Toolkit to generate the Java stub code needed to call this service from a Java application. Stay tuned!

Here are links to all of the articles in the series:


Next Post: BlackBerry Development Webinar Summary

Previous Post: RIM Announces Web Development Webinar

If this content helps you in some way, please consider buying me a coffee.

Header image: Photo by Tamara Gak on Unsplash.