By Bill Bodine
Introduction
With GroupWise 7, Novell has introduced a new SDK for accessing the server that provides cross platform capabilities not previously available. In previous versions most applications used the GroupWise Object API. While this served its designed purpose it had the drawback of only being available in the MS Windows environment, since it uses the COM technology.
The difference with the new SDK is that it is implemented as a Web Service using industry standard protocols and languages like SOAP, XML, WSDL and HTTP. Because of this, an application may be written on virtually any platform and, depending on the development language (Java, PHP, etc.), it can be run on various platforms as well.
The purpose of this article is to give a brief overview to the GroupWise Web Service and then, and most importantly, to provide some steps that can be followed to build a simple mail client that reads a users email from their mailbox. At this point I anticipate writing a few articles. This one will build the client using Java, whereas a future article will build the client using PHP (both very cross platform capable languages) and the future articles will delve a bit deeper into the Web Service. Additionally, a Web tutorial will be built that will serve as a visual representation of how to build the client discussed in this article.
In this article I will not really spend much time giving an overview of SOAP or the other relevant Web Service protocols, since there is ample information available on the Web to illustrate their use. It should be sufficient enough to say that their use is wide spread and that, since they use standard networking protocols (TCP/IP), they can fit nicely into nearly every IT organization (by default the server uses port 7191 rather than the default HTTP port of 80, so IT organizations may need to open their firewall up to all access to that port).
Getting Started
The components needed to build a GroupWise client using the SOAP API are: 1)GroupWise 7.0 SP1 or later and 2) the GroupWise Web Service components..
For clients to access the GroupWise server with the SOAP API's, the Post Office Agent (POA) must have the “Soap-enabled” option set. This is done fairly easily. It can be set by one any of the following means:
ConsoleOne
Command Line
POA Configuration File
The Web Service components are still evolving a bit. So while they are can downloaded from the Novell Developer web site (http://developer.novell.com), it is probably best, for the time being, to access them at: http://forge.novell.com/modules/xfmod/project/?gwsoap. From there you can select the appropriate download for your platform. I will not go into how to install each of the respective downloads here. If you are not sure how to use an .EXE or an .RPM file for installing then the documentation on the web should be adequate for getting past that point. Assuming a Linux installation, the GroupWise Web Service will be installed into a directory similar to the following:
/opt/novell/ndk/novell-gwsoap-devel-2006.06.14-1.cross_platform
From there you will see that there are a few of the customary 'readme' files and the following directories:
doc
Contains .pdf files used as documentation for the GroupWise Web Service.
Java
Contains a -netbeans- folder that has a few sample GroupWise client projects built with the NetBeans IDE. These can be valuable resources for learning how to use certain features of the SDK.
It also has a -wsdl- folder that contains java classes built in accordance with the API's wsdl document. (NOTE: if you have not heard of a wsdl document before, it might be helpful to read up on it. Essentially it is an XML document that describes all the possible methods that can be invoked in a Web Service call).
MS.NET
A folder containing nearly the same information as the Java directory except that it is obviously geared toward .NET developers.
schemas
This folder contains the 'groupwise.wsdl' file and a few schema files that define syntax for various events, methods and types that are defined by the GroupWise Web Service.
Once the GroupWise Web Service is installed on your system you are about ready to begin development of your new GroupWise client. Since we are using Java for this article, you will want to notice that there is a .jar file located at:
<install directory>/Java/wsdl/java/dist/lib/gwws.jar
This .jar file will need to be referenced in your system classpath. It contains all the methods and types needed to call the GroupWise Web Service. Since the Web Service includes the groupwise.wsdl file in the 'schemas' folder referenced earlier, it is possible to build an equivalent file to the gwws.jar file yourself. However, unless you have some very specific needs, the already generated .jar file should work for most situations.
Building the Application
The first thing your application will need to do is authenticate to the GroupWise server. If we look at the wsdl and schema files we will see the following:
groupwise.wsdl
xmlns:tns="http://schemas.novell.com/2005/01/GroupWise/groupwise.wsdl"
xmlns:methods="http://schemas.novell.com/2005/01/GroupWise/methods"
...
<message name="loginRequestMessage">
<part name="loginReq" element="methods:loginRequest"/>
</message>
...
<message name="loginResponseMessage">
<part name="loginRes" element="methods:loginResponse"/>
</message>
...
<operation name="loginRequest">
<input message="tns:loginRequestMessage"/>
<output message="tns:loginResponseMessage"/>
</operation>
...
<operation name="loginRequest">
<soap:operation soapAction="loginRequest" style="document" />
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
methods.xsd
<xs:element name="loginRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="auth" type="types:Authentication" />
<xs:element name="language" type="xs:language" />
<xs:element name="version" type="xs:decimal" />
<xs:element name="application" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="loginResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="session" type="xs:string" minOccurs="0" />
<xs:element name="userinfo" type="types:UserInfo" minOccurs="0" />
<xs:element name="entry" type="types:AccessRightEntry" minOccurs="0" />
<xs:element name="gwVersion" type="xs:string" minOccurs="0" />
<xs:element name="redirectToHost" type="types:Host" minOccurs="0" maxOccurs="1"
/>
<xs:element name="serverUTCTime" type="xs:dateTime" minOccurs="0" />
<xs:element name="status" type="types:Status" />
</xs:sequence>
</xs:complexType>
</xs:element>
types.xsd
<xs:complexType name="PlainText">
<xs:complexContent>
<xs:extension base="tns:Authentication">
<xs:sequence>
<xs:element name="username" type="xs:string" />
<xs:element name="password" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="Proxy">
<xs:complexContent>
<xs:extension base="tns:Authentication">
<xs:sequence>
<xs:element name="username" type="xs:string" />
<xs:element name="password" type="xs:string" minOccurs="0" />
<xs:element name="proxy" type="xs:string" />
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
You have heard programmers say that they don't write separate documentation for their code. “My code is the documentation” they say. While the GroupWise SOAP API does have documentation it is possible to look at the wsdl and schema files and get a good feel for what needs to be called for the various requests and what the output will be. By looking at the XML code above we learn that the wsdl document describes an operation called “loginRequest”. This operation has an input and an output message called “loginRequestMessage” and “loginResponseMessage” respectively. These messages intern make reference to the “methods” namespace that defines the specific types expected from these messages. Specifically, the loginRequestMessage takes as parameters: 1) a complex type referenced by the 'types' namespace and the Authentication name, 2) a language identification, 3) a version assignment, and 4) an application string. You can see from the types.xsd document that there are two possible Authentication types we may use for this call, either PlainText or a Proxy.
Now lets look at how we make this call in our Java code.
//First setup access to GroupWise server
Stub clientStub = (Stub)(new GroupwiseService_Impl().getGroupwiseSOAPPort();
// Default port is 7191
clientStub._setProperty( javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,
“http://somegwserver.com:7191/soap” ); GroupWisePortType gwService = (GroupWisePortType)clientStub;
// Now setup the login credentials
PlainText ptLogin = new PlainText();
ptLogin.setUsername(“demouser”);
ptLogin.setPassword(“demouserpassword”);
// Make the call to the loginRequest
LoginResponse loginRes = gwService.loginRequest(( Authentication)ptLogin,
“us”,
new BigDecimal(1.0),
“Our GW Client”,
false );
if ( loginRes.getStatus().getCode() == 0 ) {
// Within here we can pull out the various response values like the following
loginRes.getUserInfo().getName();
}
As you would expect, everything starts by using the Web Service's service class (GroupwiseService as defined in the groupwise.wsdl document). JAXRPC automatically creates a class with 'getter' methods that are used to access its port types. In the case of the GroupWise Web Service we have two port types defined: GroupwiseSOAPPort and GroupwiseEventsSOAPPort. Since we are interested in accessing the mailbox folder for our application, we declared an instance variable, gwService, that will be used by our application to invoke the rpc calls to the GroupWise server. The same way it is used here to login to the server with the loginRequest method, it will be used to invoke the subsequent rpc methods.
Once the client has authenticated to the server, the steps to follow for this simple application is to:
1.Find the users “Mailbox” folder by querying all the folders and identifying the one that has a name of “Mailbox”. Mailbox is one of the selectable folder types identified in the types.xsd file
String[] sView = new String[1];
GetFolderListResponse folderListResponse;
folderListResponse = new GetFolderListResponse();
folderListResponse = gwService.getFolderListRequest( “folders”, sView, true,
false, false, loginRes.getSession(), false );
if ( folderListReponse.getStatus().getCode() == 0 ) {
for ( int i=0;i<folderListResponse.getFolders.getFolder().length;i++ ) {
if ( folderListResponse.getFolders.getFolder()[i].getName.equalsIgnoreCase(“Mailbox”))
return (folderListResponse.getFolders().getFolder()[i].getId();
}
}
2.Listing the items (emails) contained within the Mailbox. By specifying the “default” option as one of the views, we are telling the server to respond with the basic information about each mail message (ie. subject, distribution list, delivery date and time, etc.). We additionally specify the “message” option so that we can view the message body of the email messages (see the 'Mail' entry in the types.xsd document). To specify that we only want to see received messages we have set the 'source' (see 'tns:ContainerItem' in types.xsd) to be only 'received' items (see 'ItemSource' in types.xsd).
String[] sView = {“default”, “message”};
FilterEntry gwFilterEntry = new FilterEntry();
Filter gwFilter = new Filter();
ItemRefList itemRefList = new ItemRefList();
//Ensure that filter only gets 'received' items
gwFilterEntry.setField(“source”);
gwFilterEntry.setValue(“received”);
gwFilterEntry.setOp(FilterOp.eq);
gwFilter.setElement(gwFilterEntry);
GetItemsResponse itemsResponse = gwService.getItemsRequest(
mailBoxFolderId, //returned from step one above
sView,
gwFilter,
itemRefList,
100, //we'll just return the 100 most recent items here
loginRes.getSession(),
false );
3.Allowing the client to select a specific email to view. Since we have already received the message body when we invoked the getItemsRequest call, all we need to do here is call the appropriate method to output the message.
Mail gwMail = new Mail();
gwMail = (Mail)itemsResponse.getItems().getItem()[selectedRow]; // selectedRow was picked by user in UI
if ( gwMail != null && gwMail.getMessage() != null ) {
MessageBody mb = gwMail.getMessage();
if ( mb != null && mb.getPart() != null ) {
byte[] b = mb.getPart()[0].getValue();
if ( b != null && b.length != 0 ) {
try {
String messageBodyString = new String(b, “UTF-8”);
} catch ( Exception ex ) ex.printStackTrace();
}
}
}
Conclusion
In the article I have tried to show how to write a simple mail client that reads mail message from a GroupWise server. While I have only include code snippets here, there is a complete project built using the NetBeans IDE that can be used to fill in any of the missing pieces not seen in this article. Since reading a mail message's text is only one of the many functions needed by a mail client, I will follow this article up with some tutorials and other articles that explore other features of the SDK.
© 2009 Novell, Inc. All Rights Reserved.