Introduction
This
article is divided into two main parts: The first part covers all the
perspectives developers need to consider, including resource
preparation, programming, and exception handling; the second part
discusses how to integrate Lotus Connections into other applications
through the APIs.We also include information on how to handle some
common issues during integration.
NOTE: All the examples in this article are written in JavaTM, and the Java Document Object Model (JDOM) is used when parsing or creating XML document.
Prerequisites
This
article assumes that you are familiar with Lotus Connections and its
APIs, and have knowledge of Atom and XML. Since we use Java as the
programming language to demonstrate all the examples, having Java
development skills is also a must.
Working with Lotus Connections APIs
The
Connections APIs enable developers to retrieve/post information from/to
Lotus Connections features in programs. Basically, all the work you can
do in the browser can also be accomplished through the APIs. Version
2.5 of the Connections APIs adds support to the newly imported features
of Files and Wikis, as well as some enrichment to the original features.
For more detailed information, refer to the Lotus Connections 2.5 APIs section in the Lotus Connections 2.5 Information Center.
Finding the correct URL for a specific API
Generally you can find all the API information you need from the Lotus Connections Information Center. However, if that's not helpful in your case, there are two other ways to find the correct URL for the API you want to access:
Finding the URL directly from a Web page
In
most Web pages, Lotus Connections provides the link to the API for the
same function represented by the Web page. For example, at the bottom
of the Web page displaying public blogs, you can find the following
link:
In
this way, if we want to find the URL retrieving all the public blogs,
we can first access the Web page and then find the link to get the
right URL.
Inferring the API URL from the current Web page URL
Besides
finding the URL directly from an API link in a Web page, this is
another quick way. For example, suppose we want to find the API for
retrieving all the bookmarks posted by the person whose email address
is john.doe@company.com. To do this, follow the steps below:
Navigate to the Bookmarks Web page displaying bookmarks for john.doe@company.com in a browser.
Find the URL of the Web page from the address field; it should look like this: http://connections.company.com/dogear/html?email=arennie@us.ibm.com
Modify the URL by changing “html” to “atom”; it should look like this: http://connections.company.com/dogear/atom?email=arennie@us.ibm.com
This method can be applied to most of the Connections APIs.
Understanding the parameters
All
the Lotus Connections APIs accept the same parameters for similar
functions. By understanding the parameters from a functional
perspective, you can save a lot of time when working with Connections
APIs.
Retrieving/searching content by person
As an example, let's retrieve a person’s information from Connections Profiles:
NOTE: You cannot use the email parameter if Lotus Connections is configured to prevent email address from being displayed. The userid
parameter is always available, so if you are considering leveraging a
parameter as the user unique ID in your application, choose userid.
Listing/searching a collection of entries
As an example, let's list the second 50 public posted bookmarks:
ps
– the number of entries to return per page. Each Lotus Connections
Feature has a maximum value for ps, except Bookmarks. If you specify a
value greater than the maximum value, the maximum value is used instead
of the value you specified. Bookmarks will print an exception message
instead.
Analyzing the results
Lotus
Connections APIs are implemented by use of the Atom Syndication format.
Since XML is used as the data format for Atom, you can leverage any
programming language that can handle an XML document. Listing 1 shows
an XML document as a typical Atom document:
Listing 1. XML document as an Atom document<feed xmlns="http://www.w3.org/2005/Atom">
<id>http://www.example.org/myfeed</id>
<title>My Simple Feed</title>
<updated>2005-07-15T12:00:00Z</updated>
<link href="/blog" />
<link rel="self" href="/myfeed" />
<entry>
<id>http://www.example.org/entries/1</id>
<title>A simple blog entry</title>
<link href="/blog/2005/07/1" />
<updated>2005-07-15T12:00:00Z</updated>
<summary>This is a simple blog entry</summary>
</entry>
<entry>
<id>http://www.example.org/entries/2</id>
<title />
<link href="/blog/2005/07/2" />
<updated>2005-07-15T12:00:00Z</updated>
<summary>This is simple blog entry without a title</summary>
</entry>
</feed>
Most
of the content returned by Lotus Connections APIs complies with the
format above, with some additional extended elements, except for the
documents displaying categories (or tags). The
entry
element represents different entities in Lotus Connections features,
such as a user’s profile in Profiles, a blog entry or comment in Blogs,
a community in Communities, or an activity in Activities.
For more information on the Atom Syndication format, refer to the RFC document here: ftp://ftp.rfc-editor.org/in-notes/rfc4287.txt.
Retrieving content using the subscription API
The subscription API is used to retrieve information from Lotus Connections. Here we retrieve information about the latest 10 publicly shared files from Connections Files, including title, author, update time, and download link.
When parsing the XML document, you should always keep namespace in mind. If the element tag is not named with a prefix explicitly, the default namespace of atom is used.
You can parse the element as follows:
Namespace ns = Namespace.getNamespace("atom", "http://www.w3.org/2005/Atom");
String title = entry.getChildText("title", ns);
If the element tag is named with a prefix explicitly, other namespaces should be used accordingly. For example, the userid element is under the namespace of snx:
<snx:userid xmlns:snx="http://www.ibm.com/xmlns/prod/sn"></snx:userid>
You can parse the userid element as follows:
Namespace atom = Namespace.getNamespace("atom", "http://www.w3.org/2005/Atom");
Namespace snx = Namespace.getNamespace("snx", " http://www.ibm.com/xmlns/prod/sn ");
String userid = entry.getChild("author", atom).getChildText("userid", snx);
There are several link elements in each entry, which are differentiated by the rel attribute. In Connections Files, each file entry contains the following link elements:
<link href="http://connections.tap.ibm.com/files/href1" rel="self" />
<link href="http://connections.tap.ibm.com/files/href2" rel="edit" />
<link href="http://connections.tap.ibm.com/files/href3" rel="enclosure" />
<link href="http://connections.tap.ibm.com/files/href4" rel="replies" />
The
line above containing the rel attribute value of
enclosure is what we want as the download link. To get
the value of its href attribute, we could traverse all
the link elements and test whether its rel
attribute value is equal to enclosure.
But here we have a quicker and more elegant way to handle this. The following code snippet leverages XPath in JDOM to get the download link directly in the Files entry:
Namespace ns = Namespace.getNamespace("atom", "http://www.w3.org/2005/Atom");
XPath xpath = XPath.newInstance("atom:link[@rel='enclosure']");
xpath.addNamespace(ns);
String link = ((Element) xpath.selectSingleNode(entry)).getAttributeValue("href");
For detailed information regarding XPath, refer to the w3Schools' XPath
Tutorial.
Listing 2 shows the process to retrieve all the latest shared files from Connections Files.
Listing 2. Code for retrieving shared files from Connections Files
String url = "http://connections.tap.ibm.com/files/basic/anonymous/api/documents/feed?visibility=public";
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(url);
Namespace ns = Namespace.getNamespace("atom", "http://www.w3.org/2005/Atom");
List<Element> entries = doc.getRootElement().getChildren("entry", ns);
XPath xpath = XPath.newInstance("atom:link[@rel='enclosure']");
xpath.addNamespace(ns);
for (Element entry : entries) {
String title = entry.getChildText("title", ns);
String author = entry.getChild("author", ns).getChildText("name", ns);
String update = entry.getChildText("published", ns);
String link = ((Element)xpath.selectSingleNode(entry)).getAttributeValue("href");
}
Posting conent using the publishing API
The publishing API is used to interact with the Lotus Connections features programmatically, including posting, updating, and deleting; and it requires authentication. Here we create a community in Connections Communities with a specified title, description, and type.
To publish content to Lotus Connections, we can leverage the
Apache
HttpClient. The HttpClient can help communicate with Lotus Connections through the HTTP protocol, including request posting and authentication.
The code snippet in listing 3 shows how to leverage the HttpClient to connect to Lotus Connections and pass authentication.
Listing 3. Using HttpClient to connect and authenticateHttpClient client = new HttpClient();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("username", "password");
AuthScope authscope = new AuthScope("connections.compay.com", AuthScope.ANY_PORT, AuthScope.ANY_REALM);
client.getState().setCredentials(authscope, credentials);
String url = "https://connections.company.com/communities/service/atom/communities/my";
PostMethod postMethod = new PostMethod(url);
Before posting the community creation request, we must know the data format that the Lotus Connections API accepts. From the
Lotus
Connections Information Center, we determine that it accepts content in community entry format.
Listing 4 shows an XML document that is a valid community entry.
Listing 4. Valid community entry<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns:snx="http://www.ibm.com/xmlns/prod/sn" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2005/Atom">
<title type="text">#TITLE#</title>
<content type="html">#DESCRIPTION#</content>
<category term="community" scheme="http://www.ibm.com/xmlns/prod/sn/type"></category>
<snx:communityType xmlns:snx="http://www.ibm.com/xmlns/prod/sn">#TYPE#</snx:communityType>
</entry>
For detailed information on the parameters used for creating communities, refer to the
Community
entry content section of the Connections 2.5 information center.
We can either create the community entry with JDOM or make a template and fill in the required parameters. The code in listing 5 shows how to use a community entry template to compose the community creation request.
Listing 5. Using the community entry templateInputStream is = Communities.class.getResourceAsStream("CommunityTemplate.xml");
BufferedReader in = new BufferedReader(new InputStreamReader(is));
StringBuffer sf = new StringBuffer();
String line = "";
while ((line = in.readLine()) != null){
sf.append(line);
}
String content = sf.toString();
content = content.replaceAll("#TITLE#", "title");
content = content.replaceAll("#TITLE#", "description");
content = content.replaceAll("#TYPE#", "public");
is = new ByteArrayInputStream(content.getBytes());
Now we can use the HttpClient to post the request (see listing 6).
Listing 6. Using HttpClient to post requestRequestEntity requestEntity = new InputStreamRequestEntity(is, "application/atom+xml");
postMethod.setRequestEntity(requestEntity);
int statusCode = client.executeMethod(postMethod);
if (statusCode == 201) {
System.out.println("Done!");
} else {
System.out.println("Failed!");
}
Listing 7 shows the actual code to create a community to Connections Communities through the publishing API.
Listing 7. Code to create a community through publishing API HttpClient client = new HttpClient();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("username", "password");
AuthScope authscope = new AuthScope("connections.compay.com", AuthScope.ANY_PORT, AuthScope.ANY_REALM);
client.getState().setCredentials(authscope, credentials);
String url = "https://connections.company.com/communities/service/atom/communities/my";
PostMethod postMethod = new PostMethod(url);
InputStream is = Communities.class.getResourceAsStream("CommunityTemplate.xml");
BufferedReader in = new BufferedReader(new InputStreamReader(is));
StringBuffer sf = new StringBuffer();
String line = "";
while ((line = in.readLine()) != null){
sf.append(line);
}
String content = sf.toString();
content = content.replaceAll("#TITLE#", "title");
content = content.replaceAll("#TYPE#", "public");
is = new ByteArrayInputStream(content.getBytes());
RequestEntity requestEntity = new InputStreamRequestEntity(is, "application/atom+xml");
postMethod.setRequestEntity(requestEntity);
int statusCode = client.executeMethod(postMethod);
if (statusCode == 201) {
System.out.println("Done!");
} else {
System.out.println("Failed!");
}
Handling a common exception
When programming with Lotus Connections APIs, it is common for some exceptions to occur from time to time. Here we discuss one of the most common and critical ones, together with a suggested solution:
Exception: “An invalid XML character (Unicode: 0x0) was found in the element content of the document.”This occurs when building an XML document model into memory from the output of a URL, for example:
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(url); // possibly throw exception here
Obviously, this exception is due to the invalid characters contained in the XML file to be built. Actually, since Communities and Blogs allow users to input free-format text, it is possible that the Atom format content returned from the API contains some invalid characters.
To avoid the exception, you must filter the invalid characters before building the XML document model.
From the
XML
specification, we can see that an accepted character is defined as follows:
Char ::= #x9|#xA|#xD|[#x20-#xD7FF]|[#xE000-#xFFFD]|[#x10000-#x10FFFF]
So we just need to filter all those characters out of the range above. This code shows how to filter the invalid characters:
private static String filterInvalidXmlCharacter(String s) {
String symbols = "[^\\x09\\x0A\\x0D\\x20-\\xD7FF\\xE000-\\xFFFD\\x10000-x10FFFF]";
return s.replaceAll(symbols, "");
}
The code snippet in listing 8 shows how to handle this exception.
Listing 8. Code to avoid the exceptionDocument doc;
SAXBuilder builder = new SAXBuilder();
try {
doc = builder.build(url);
} catch (JDOMException e) {
InputStream is = new URL(url).openStream();
StringBuffer sb = new StringBuffer();
byte[] b = new byte[4096];
for (int n; (n = is.read(b)) != -1;) {
sb.append(new String(b, 0, n));
}
String xml = sb.toString();
xml = filterInvalidXmlCharacter(xml);
doc = builder.build(new StringReader(xml));
}
Integrating Lotus Connections into other applications
There are two common ways to integrate Lotus Connections into other applications (especially Web applications):
In
this section, we use practical examples to demonstrate the different
integrations into a Social Network Analysis (SNA) application.
Leveraging Connections data to build new applications
In
this example, we implement a chart (see figure 1) displaying a
person’s colleagues, as well as their betweenness (indicating how
close two persons are).
Figure
1. User interface

To
implement this feature, we need to retrieve a person’s colleague
information from Lotus Connections Profiles through an API. Together
with the betweenness value provided by the other data source, we will
have enough information to build the data model as the input of the
visualization tool. Figure 2 illustrates the integration process.
Figure
2. Schematic of the integration process
The
code snippet in listing 9 shows how to retrieve a person’s
colleague information.
Listing
9. Code to retrieve colleague information
String url = http://connections.company.com/profiles/atom/connections.do?connectionType=colleague&email=john.doe@company.com;
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(url);
XPath xpath = XPath.newInstance("/atom:feed/atom:entry/snx:connection/atom:contributor[@snx:rel='http://www.ibm.com/xmlns/prod/sn/connection/target']");
Namespace atom = Namespace.getNamespace("atom", "http://www.w3.org/2005/Atom");
Namespace snx = Namespace.getNamespace("snx", " http://www.ibm.com/xmlns/prod/sn ");
List<Element> elements = xpath.selectNodes(doc);
for (Element element : elements) {
Element person = (Element) element;
String name = person.getChildText("name", atom);
String userid = person.getChildText("userid", snx);
String mail = person.getChildText("email", atom);
}
After
we retrieve a person’s colleagues, we still must calculate the
betweenness based on each colleague’s user ID, before drawing the
graph. After that, the new data model is built and can be used to
draw the expected graph.
This
method of integration usually occurs on the backend of the
application because more work is needed to process the data before
it is leveraged by the integrated application.