Chapter 9. Using the Lotus Connections API

Lotus Connections 2.0 has various out-of-the-box integration capabilities (as described in Chapter 8, “Extending Lotus Connections to Other Applications”) but it also supplies an application programming interface (API) that allows you to create your own integration points or even entirely new custom applications that work with the Lotus Connections data. This chapter details the API that works with Lotus Connections and provides sample code to demonstrate how to work with the API.

An entire book could be written on working with the Lotus Connections API. This chapter intends to introduce you to the basic concepts. Consequently, the sample code in this chapter is designed to help developers new to REST APIs and XPath develop their understanding of both technologies as well as the Lotus Connections API. Additionally, the examples are designed simplistically to more clearly demonstrate the concept and how all the pieces fit together—not necessarily the way it would be done in a production environment (although it would work in production).

Overview of Lotus Connections API

The Lotus Connections API utilizes the Representational State Transfer, or REST, architecture, which relies on HTTP. This allows developers to use any language capable of sending and receiving HTTP requests. There are six services within Lotus Connections (Home Page, Profiles, Communities, Blogs, Dogear, and Activities), each with its own API. These have a common format, which makes working with each service easy after you’ve mastered working with one of them.

Each API returns data in an XML feed that conforms to the Atom Syndication Format, requiring developers to use programming tools that allow them to work with XML-formatted data. There are free open-source solutions that can make programming easier, such as Apache Xerces and Apache Abdera, but for this chapter we will use XPath (which is included with Java) for the following reasons:

  • Using XPath avoids the use of external and/or open-source libraries. Many companies have restrictions on these offerings that might prevent their use.

  • Using XPath forces developers to confront the format of the documents that are returned at a lower level without any abstraction layers. This will help you better understand the pieces and ultimately improve troubleshooting.

For a good introduction to XPath syntax and use, see the XPath tutorial at w3.schools.com.

Representational State Transfer (REST) APIs

Representational State Transfer, or REST, is an application architecture that relies on a number of web standards, including HTTP, XML, and URIs. It is designed to be a simple way to transfer data over the Web without the overhead associated of other web-based standards like SOAP and web services. It also avoids the complexity of session tracking and cookie management.

Additional advantages of the REST architecture are improved performance and scalability due to caching, as well as its reliance on web standards that are unlikely to change dramatically over time. This relieves developers from the concerns over vendor lock-in.

Through the use of the HTTP protocol, REST-based services can perform all the standard database application methods, such as Create, Read, Update, and Delete, using the POST, GET, PUT, and DELETE HTTP commands.

Atom Syndication

The Lotus Connections API relies on the Atom Publishing Protocol to create, update, or delete information over HTTP. Originally developed as an alternative to RSS, Atom documents are well-formed XML documents that provide a very structured methodology for describing documents. Lotus Connections relies on the use of Atom entry documents to represent the various pieces of content within Lotus Connections (blog entries, member lists, profiles, and so on).

Authentication

The default setup requires authentication only for the Lotus Connections Home Page and Activities. The remaining services do not force authentication so that anonymous browsing can be accomplished. However, authentication can be set for all Lotus Connections services by administrators. When accessing services that require authentication, developers must provide a username and password. Any API calls that update or delete data require authentication.

To prevent login credentials from being passed “in the clear,” administrators can configure Lotus Connections to send all HTTP traffic through SSL, forcing all HTTP requests to be redirected to HTTPS. The API uses standard authorization headers for basic authorization as documented in the HTTP specification and requires base64 encoding for the user id and password.

There are many ways to implement authentication; in this chapter, we will use the following method:

URL url = new
URL("https://connections.example.com/homepage/atom/mysearch/
facets/people?query=%22API%22");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
String encoded = new String(Base64.encodeBase64(("user" + ":" +
 "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);

The preceding code creates the URI we intend to connect to (with a search for the term “API”) and generates the base64-encoded username and password required for authentication.

Accessing Lotus Connections

The Lotus Connections API relies on Atom and requires developers to parse an XML document. To accomplish this task in Java, developers can use the XPath classes introduced in Java 5 with the javax.xml.xpath package.

Developers are also encouraged to review the Apache Abdera effort at http://abdera.apache.org/. Initially developed by IBM, Abdera has since been given to the Apache Software Foundation and is now an open-source implementation of Atom syndication and publishing. Abdera provides developers with a set of classes that make it much easier to work with Atom feeds and Lotus Connections.

For XPath to process the Atom feeds created by Lotus Connections, various namespaces (including Atom) must be handled. To facilitate that task, this class can be used:

public class NameSpace  implements NamespaceContext {
    public String getNamespaceURI(String prefix) {
        if (prefix == null) throw new NullPointerException("Null
prefix");
        else if ("atom".equals(prefix)) return
"http://www.w3.org/2005/Atom";
        else if ("xml".equals(prefix)) return
XMLConstants.XML_NS_URI;
        return XMLConstants.NULL_NS_URI;
    }
    // Method stub, not required
    public String getPrefix(String uri) {
        throw new UnsupportedOperationException();
    }
    // Method stub, not required
    public Iterator getPrefixes(String uri) {
        throw new UnsupportedOperationException();
    }
}

This code will help us in the first few examples we review, but as we move forward into creating and updating, some elements will require additional namespaces to be handled.

Home Page API

The Home Page is the initial landing page for Lotus Connections and generates an aggregated view of all the installed Lotus Connections features. Accessing the API through the Home Page allows developers to search content, people, and tags from all the installed features and retrieve the URI of that content.

The advantage of working at the Home Page level is that we can determine exactly which Lotus Connections features are installed and available for us to work with, and we can search all those features or use URI parameters to limit searches to specific features or public and private information.

Installed Features

Determining the installed features of any Lotus Connections environment is relatively simple. In this example, we will access the Lotus Connections Home Page and generate a list of the returned services that are available (Lotus Connections does not require that all five services be implemented). The XML returned by this REST call is detailed in the InfoCenter, so we’ll concern ourselves just with the specifics of getting the information and printing it:

public class InstalledFeatures {
    public static void main(String[] args){
DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
        domFactory.setNamespaceAware(true);
// required to handle the w3 Atom namespace
        String URL =
"http://connections.example.com/homepage/serviceconfigs";
        DocumentBuilder builder = domFactory.newDocumentBuilder();
        Document doc = builder.parse(URL);
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        xpath.setNamespaceContext(new NameSpace());
        XPathExpression expr =
 xpath.compile("/atom:feed/atom:entry/atom:title/text()");
        Object result = expr.evaluate(doc,
XPathConstants.NODESET);
        NodeList nodes = (NodeList) result;
        for (int i = 0; i < nodes.getLength(); i++) {
            System.out.println(nodes.item(i).getNodeValue());
        }
}

Note: In the XPath expression, we must specifically name the Atom namespace.

Searching for Information

Beginning with Lotus Connections 2.0, the Home Page API also allows for searching of all installed Lotus Connections features for content related to specified search terms. Developers can specify the scope of the search to include only public information or aggregate the public information with private information to which the login id used has access. For example, to search for all users who are associated with “API,” developers would use this URL:

https://connections.example.com/homepage/atom/mysearch/facets/people?query=%22API%22

Note: The encoding used for quotes is %22.

The following code uses the preceding URI to find all people within the Connections environment that are associated with “API.”

public class Search {
    public static void main(String[] args) {
        DocumentBuilderFactory domFactory =
 DocumentBuilderFactory.newInstance();
        domFactory.setNamespaceAware(true);
URL url = new
URL("https://connections.example.com/homepage/atom/mysearch/facets/
people?query=%22API%22");
        HttpURLConnection connection = (HttpURLConnection)
 url.openConnection();
        String encoded = new
String(Base64.encodeBase64(("userid" + ":" +
"password").getBytes()));
        connection.setRequestProperty("Authorization", "Basic " +
encoded);
        DocumentBuilder builder = domFactory.newDocumentBuilder();
        Document doc = builder.parse(connection.getInputStream());
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        xpath.setNamespaceContext(new NameSpace());
        XPathExpression XPexpr =
xpath.compile("/atom:feed/atom:entry/atom:title/text()");
        Object result = XPexpr.evaluate(doc,
XPathConstants.NODESET);
        NodeList entries = (NodeList) result;
        for (int i = 0; i < entries.getLength(); i++) {
            System.out.println(entries.item(i).getNodeValue());
}

Note: The preceding example authenticates with the server since it is accessing public and private data through a secure connection as indicated by the “/mysearch” subpath in the URI.

The same algorithm is used with modifications to the URI being requested to search for general information, tags, and people. The query parameter supports the standard Boolean operators AND, OR, and NOT, as well as common search qualifiers like “+” to force a term to be included in the results, “-” to prohibit a specific term from the results, and “?” as a wildcard for individual letters.

A search at the Home Page level searches all installed Lotus Connections features. Through the use of the component parameter, developers can limit the search to a specific feature or features. At the Home Page level, the search also includes all users but can be limited to specific users through the email parameter.

For example, to find all blog posts that relate to API programming, we would use the URI http://connection.example.com/homepage/atom/search/results?component=blogs&query=“api&programming”.

Blogs API

There are three basic entries in a blog: posts, comments, and media entries. Blog posts are simply the post that a user (or, in our case, a program running under the credential of the authenticated user) creates on his or her blog. Comments are the comments made relating to a specific post, and media entries are uploaded resources such as images that are embedded into a post.

Accessing Blog Entries

To read from a blog, the InfoCenter specifies that each blog has a “handle” that is generated when a blog is first created. What this means is there is a unique identifier associated with blogs—typically the email address of the blog owner. For example, https://connections.example.com/weblogs/[email protected] would be the “handle” of the blog for the user “John Doe” within IBM.

To access the Atom feed of John Doe’s blog, we would use the handle and then append the request for the resource as specified in the InfoCenter. To request all of John Doe’s blog entries, the format of the URI would be https://connections.example.com/weblogs/[email protected]/feed/entries/atom, and accessing the comments to posts on the blog would be https://connections.example.com/weblogs/[email protected]/feed/comments/atom.

In code, we would try something like this:

DocumentBuilderFactory domFactory
=DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
URL url = new
URL("https://connections.example.com/weblogs/[email protected]/feed/
entries/atom");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
String encoded = new String(Base64.encodeBase64(("userid" + ":" +
 "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr =
 xpath.compile("/atom:feed/atom:entry/atom:title/text()");
Object result = XPexpr.evaluate(doc, XPathConstants.NODESET);
NodeList entries = (NodeList) result;
for (int i = 0; i < entries.getLength(); i++) {
    System.out.println(entries.item(i).getNodeValue());
}

Note: Developers might try to specify a URI pointing directly to a blog post. This will result in a parsing error since the returned text will be formatted as HTML rather than an XML-formatted Atom document.

Creating Blog Entries

Developers who have attempted to post entries to Lotus Connections are likely familiar with the published format of the entry:

POST /weblogs/services/atom/userid/entries HTTP/1.1
Host: connections.example.com
Content-Type: application/atom+xml
Content-Length: 246
Authorization: Basic BDuFF132MnXuiu98cGHnK76L
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
<author><name>John Doe</name></author>
<title type="text">API Post</title>
<content type="text">Example of a post using the API.</content>
</entry>

If you’re not familiar with this format used to describe HTTP posting, this requires some explanation. Host and POST combined is the URI to which you will send the content to be posted. For Lotus Connections blog entries, the content-type is application/atom+xml (some entry types will be different). Content-Length is the total length of the post and is generally not required since the HTTP client implementation should use “chunked encoding” (part of the HTTP 1.1 specification) to transfer the data to the web server. Authorization is the same basic authentication we’ve been using in other examples.

Blogs require only the information shown in Table 9.1 to be successfully posted.

Table 9.1. Required Blogs Elements

Element

Description

<?xml version="1.0" encoding="utf-8">

XML declaration.

<entry xmlns="http://www.w3.org/2005/atoms"

Atom namespace declaration.

<title type="text">

The actual title of the blog post. The type attribute is optional since type="text" is the default and only format allowed.

<content type="html">

The content of this blog entry.

Table 9.2 lists other elements that are optional when a blog post is created.

Table 9.2. Optional Blogs Elements

Element

Description

<category term=" tag_word"/>

Used to tag the post with a keyword. Repeat this element for each blog entry tag that will be associated with the post. Tags should not use spaces.

<app:control>

Indicates whether comments are allowed on this entry. This element will contain the snx:comments element.

<snx:comments enabled="xxx" days="nnn" />

Specifies whether comments are enabled for this blog entry. The default value is yes but it can be set to no. The days attribute specifies the number of days after post creation that comments will be allowed. The default is 0, indicating that there is no limit.

The following code will generate a blog posting. There are cleaner ways to do this, but for someone new to this type of development, this is clearer:

DocumentBuilderFactory domFactory
= DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
URL url = new
URL("https://connections.com:443/weblogs/services/atom/userid/
entries");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-type",
"application/atom+xml");
String encoded = new String(Base64.encodeBase64(("userid" + ":" +
 "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
connection.connect();
OutputStream ops = connection.getOutputStream();
PrintWriter pw = new PrintWriter(ops);
pw.println("<?xml version="1.0" encoding="utf-8"?>");
pw.println("<entry xmlns="http://www.w3.org/2005/Atom">");
pw.println("<title type="text">API Test Entry</title>");
pw.println("<content type="text">Test from the Connections
 API</content></entry>");
pw.flush();
pw.close();
int responseCode = connection.getResponseCode();
connection.disconnect();

Note: Developers should ensure that the response code is 201 for a successful post.

Of particular interest to developers is the URI used. That is found in the href attribute of the <collection title="Weblog Entries"> element in User’s Service Document, which can be accessed at http://connections.example.com/weblogs/services/atom (your exact server and path structure will vary, but “services/atom” is required). Developers can use the examples in the previous sections to access and read the service document.

Deleting Blog Entries

Blog entries are relatively easy to delete after you determine the appropriate URI to use. The URI to get a handle on the blog post you want to delete can be found in the services document returned from the URI https://connections.example.com/weblogs/services/atom/userid/entries, where userid is typically the email address of the user you’re working with.

The value of the href attribute of the <link rel="edit"> element of the entry you want to delete is what we need use with the DELETE command to have the post deleted and will be in a format similar to https://connections.example.com:443/weblogs/services/atom/userid/entries/468G092D7C36DF64FECCE1D9269402001000. Using that URI, developers would use code as shown here to delete the post:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
URL url = new
URL("https://connections.example.com:443/weblogs/services/atom/user
id/entries/468G092D7C36DF64FECCE1D9269402001000");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("DELETE");
String encoded = new String(Base64.encodeBase64(("userid" + ":" +
 "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
connection.connect();
int rc = connection.getResponseCode();
connection.disconnect();

Note: Developers should ensure that the response code is 204 or 200 for a successful delete.

Editing Blog Entries

Blog entries are not truly edited, they are overwritten. To avoid losing the content in the existing post, you must retrieve any data you want to keep and include it in the updated Atom entry document. The following code will first get a blog entry and the data in the content tag and then append new content before posting:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
String urlString =
"https://w3.tap.ibm.com:443/weblogs/services/atom/[email protected]/
entries/B19G092D7C36DF64FECCE1D92694020013BD";
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
String encoded = new
String(Base64.encodeBase64(("[email protected]" +
 ":" + "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr =
xpath.compile("/atom:entry/atom:content/text()");
Object result = XPexpr.evaluate(doc, XPathConstants.NODESET);
NodeList entries = (NodeList) result;
String previousContent = entries.item(0).getNodeValue();
System.out.println(previousContent);
connection.disconnect();
url = new URL(urlString);
connection.setRequestProperty("Authorization", "Basic " +
encoded);
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
connection.setRequestProperty("Content-type",
"application/atom+xml");
connection.connect();
OutputStream ops = connection.getOutputStream();
PrintWriter pw = new PrintWriter(ops);
pw.println("<?xml version="1.0" encoding="utf-8"?>");
pw.println("<entry xmlns="http://www.w3.org/2005/Atom">");
pw.println("<author><name>John Doe</name></author>");
pw.println("<title type="text">API Test Update Entry</title>");
pw.println("<content type="text">" + previousContent + " new
 text.</content></entry>");
pw.flush();
pw.close();
int rc = connection.getResponseCode();

Dogear API

Just getting a Dogear feed is a straightforward HTTP call with any parameters the developer wants to use to filter the results to get the bookmarks you need. Various parameters are listed in the Lotus Connections InfoCenter; some of the most notable are listed in Table 9.3.

Table 9.3. Dogear Parameters

Parameter

Description

Access

Filters the bookmarks based on whether they are private or public. Options are the following: all (the default setting; this returns all bookmarks), private (returns private bookmarks; that is, bookmarks that can be accessed only by their owner after authentication), and public (returns only public bookmarks on your intranet).

Email

Returns bookmarks created by the user specified by the Internet email address. Note: You must format the HTTP request using the proper URL encoding. For example, the encoded form of the @ symbol is %40 as in: username%40example.com.

network

Filters the bookmarks based on the network at which the bookmark points. Options are the following: all (the default setting; this returns all bookmarks), internet (returns only the bookmarks that link to Internet resources, which are visible outside the intranet firewall), and intranet (returns only the bookmarks that link to resources available on the corporate intranet; that is, resources that are not externally visible).

Search

Well-formed full-text search query. Performs a text search on the title, description, and tags of all bookmarks.

searchOperator

Default operator between search terms in the search parameter. Options are the following: and or. Note: The default value is set by your system administrator.

Sort

Specifies how the results should be sorted. Options are the following: date (the default setting; bookmark entries are sorted by the date they were created) and popularity (bookmarks are sorted by popularity).

sortOrder

Specifies the order the results should be sorted in. Options are the following: asc (bookmarks are sorted in ascending order—oldest to newest, or least to most popular) and desc (the default setting; bookmarks are sorted in descending order—newest to oldest, or most to least popular).

url

A well-formed web address. Returns bookmarks for the given web address. When you use this parameter, all other search parameters are ignored.

userid

Unique ID that represents a specific person.

For example, to find the most recent bookmarks on your intranet relating to Lotus Connections, the URI would be http://dogear.example.com/atom?tag=connections&network=intranet&sort=date&sortOrder=desc.

We can access this URI programmatically in the following code:

DocumentBuilderFactory domFactory
=DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
URL url = new
URL("http://dogear.example.com/atom?tag=connections&network=
intranet&sort=date&sortOrder=desc&lang=en");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr =
 xpath.compile("/atom:feed/atom:entry/atom:title/text()");
Object result = XPexpr.evaluate(doc, XPathConstants.NODESET);
NodeList entries = (NodeList) result;
for (int i = 0; i < entries.getLength(); i++) {
    System.out.println(entries.item(i).getNodeValue());}

Note: Authentication is not required since we are merely browsing the Dogear entries and administrators have not forced secure connections.

Creating a Dogear Bookmark

Creating bookmarks is similarly straightforward after you have the Dogear service document, which can be found at http://dogear.example.com/dogear/api/app. The URI in the href attribute of the collection element specifies the URI required to create a bookmark for a specific user and will look similar to this: https://dogear.connections.com/api/app?email=userid%40connections.com or https://dogear.connections.com/api/[email protected].

From there, we can create a class that will generate the bookmark for that person:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
URL url = new
URL("https://dogear.example.com/api/app?email=userid%40us.ibm.com");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-type",
"application/atom+xml");
String encoded = new
String(Base64.encodeBase64(("[email protected]" +
":" + "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
connection.connect();
OutputStream ops = connection.getOutputStream();
PrintWriter pw = new PrintWriter(ops);
pw.println("<?xml version="1.0" encoding="utf-8"?>");
pw.println("<entry xmlns="http://www.w3.org/2005/Atom">");
pw.println("<author><name>John Doe</name></author>");
pw.println("<title>API Test Dogear Entry 4</title>");
pw.println("<content type="html"><![CDATA[<b>John Doe</b>
creates book mark with the API.]]></content>");
pw.println("<category
scheme=http://www.ibm.com/xmlns/prod/sn/type
 term="bookmark"/>");
pw.println("<category term="Connections"/>");
pw.println("<category term="API"/>");
pw.println("<link href="http://www.ibm.com"/></entry>");
pw.flush();
pw.close();
int rc = connection.getResponseCode();

Note: The content type is html and we used CDATA to pass actual HTML code to the entry.

Profiles API

Retrieving the profile entry for a person is a relatively straightforward procedure. We make a call like all the other HTTP requests we’ve been making and can parse the results in a node list or simply have elements of the entry returned as a string. To further our understanding of XPath as well as the Lotus Connections API, let’s look at some code that retrieves only one item from a user’s profile, the email address:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
URL url = newURL("http://profiles.example.com/profiles/atom/
[email protected]");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr =
xpath.compile("//xhtml:a[@class='email']/text()");
System.out.println("Email: " + XPexpr.evaluate(doc,
XPathConstants.STRING));

Since we are browsing profiles without requiring authentication, we no longer need the base64 encoding and authentication setup.

The Atom feed returned by Lotus Connections relies on the Atom namespace, but as it moves into the content area of the profile document, it will switch to a different namespace at the first div tag. The new namespace is xhtml and is defined here: http://www.w3.org/1999/xhtml. Consequently, we must specify a new namespace in our NameSpace class (detailed previously) so that the class has the new line in the else if clause:

else if ("xhtml".equals(prefix)) return
"http://www.w3.org/1999/xhtml";

Of particular note for developers is the new XPath expression and the different evaluation call that specifies STRING. The XPath expression is significantly different from the full path version we’ve been using. In this expression, we’re telling XPath to give us all the XML tags that are an a (an anchor link) with the attribute class that equals email (there is only one), and that we want the text contained in that element. This is a much cleaner and easier-to-use format than the full path used in the previous examples. The other change is that we are no longer asking the XPath expression to evaluate to a NodeList but instead to a string that we can print out or work with however we please.

Retrieving Profile Tags

By now you’re getting familiar with the basic buildup of making a Lotus Connections API call: Create the document factory, set up the namespace, authenticate when necessary, set up XPath, and parse the results. Retrieving profile tags is no different, and rather than continuing to produce the same code over and over, we’ll start looking at the differences in XPath expressions.

In the case of profile tags, we’re going to go back to using a NodeList since we can return multiple tags. Our URI is https://profiles.example.com/profiles/atom/[email protected].

This will return an Atom feed similar to this:

<app:categories fixed="false"
snx:targetEmail="[email protected]"  snx:tagOthersEnabled="true"
  xmlns:snx="http://www.ibm.com/xmlns/prod/sn"
xmlns:atom=http://www.w3.org/2005/Atom
  xmlns:app="http://www.w3.org/2007/app" >
<atom:generator version="2.0.1" >Lotus Connections –
 Profiles</atom:generator>
<atom:category term="Connections"  snx:frequency="1"
 snx:intensityBin="1"   snx:visibilityBin="1" ></atom:category>
<atom:category term="API"  snx:frequency="1"
snx:intensityBin="1"  snx:visibilityBin="1" >
</atom:category>
<atom:category term="Lotus" snx:frequency="1"
snx:intensityBin="1"  snx:visibilityBin="1" ></atom:category>
</app:categories>

Notice that the difference here is that all the category elements do not contain text. The information we’re interested in is instead stored in the element attribute term. The XPath expression is //@term and will result in a NodeList with three entries: Connections, API, and Lotus. The code to accomplish this task is shown here:

URL url = new URL("http://connection.example.com/profiles/atom/
[email protected]");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr = xpath.compile("//@term");
Object result = XPexpr.evaluate(doc, XPathConstants.NODESET);
NodeList entries = (NodeList) result;
for (int i = 0; i < entries.getLength(); i++) {
    System.out.println(entries.item(i).getNodeValue());
}

Updating Profile Tags

An HTTP PUT request can be used to update the tags that have been assigned to a user’s profile. There are two major points to be aware of when updating these tags:

  • All the existing tags will be erased when you send the tags entry document to the server. Consequently, you will need to retrieve the old tags you want to save and include them in your new tags entry.

  • You can replace only tags created by the user you authenticate as. You can’t overwrite someone else’s tags.

To accomplish the PUT, you rely on the parameters shown in Table 9.4 in the URI.

Table 9.4. Profile Parameters

Parameter

Description

targetEmail

The email address of the person whose profile you want to update. You must provide one target parameter, either this one or targetKey.

targetKey

Specifies the unique ID of the person whose profile you want to update. You must provide one target parameter, either this one or targetEmail.

sourceEmail

The email address of the creator of the tags. You must provide one source parameter, either this one or the sourceKey.

sourceKey

The unique ID of the creator of the tags. You must provide one source parameter, either this option or sourceEmail.

For example, to update the tags for John Doe’s profile that were created by John Doe himself, use the following URI:

https://connections.example.com/profiles/atom/profileTags.do?targetEmail=jdoe%40example.com&sourceEmail=jdoe%40example.com or https://connections.example.com/profiles/atom/[email protected]&[email protected].

Note: We replaced the “@” symbol with the appropriate XLM encoding, “%40.”

The code to update the profile tags for John Doe would be this:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
String urlString = "http://connections.example.com/profiles/atom/
[email protected]";
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr = xpath.compile("//@term");
Object result = XPexpr.evaluate(doc, XPathConstants.NODESET);
NodeList entries = (NodeList) result;
String oldTags = "";
for (int i = 0; i < entries.getLength(); i++) {
oldTags = oldTags += "<atom:category term="" +
 entries.item(i).getNodeValue() + "" snx:frequency="1"/>"
    }
connection.disconnect();
urlString = "https://connections.example.com/profiles/atom/
profileTags.do?targetEmail=jdoe%40us.ibm.com&sourceEmail=jdoe%40us.ibm.com";
url = new URL(urlString);
String encoded = new
String(Base64.encodeBase64(("[email protected]" +
 ":" + "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
connection.setRequestProperty("Content-type",
"application/atomcat+xml");
connection.connect();
OutputStream ops = connection.getOutputStream();
PrintWriter pw = new PrintWriter(ops);
pw.println("<?xml version="1.0" encoding="UTF-
8"?><app:categories
 fixed="false" snx:targetEmail="[email protected]"
snx:tagOthersEnabled="true"
  xmlns:snx="http://www.ibm.com/xmlns/prod/sn"
xmlns:atom=http://www.w3.org/2005/Atom
  xmlns:app="http://www.w3.org/2007/app" >");
pw.println(oldTags);
pw.println("<atom:category term="connections"
snx:frequency="1"/>");
pw.println("</app:categories>");
pw.flush();
pw.close();
int rc = connection.getResponseCode();

Activities API

Activities saw a major change in Lotus Connections 2.0. All activities node types were changed to just be entry types, the type of entry based on the field type. This greatly reduced the effort for developers since we now have to work with only one node type.

The simplest way to jump into activities is to read the list of current activities that can be found at the URI https://activities.example.com/activities/service/atom/activities. With the returned document from that REST API call, we can review all of a user’s activities. The following code will accomplish that task:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
URL url = new
URL("https://activities.example.com/activities/service/atom/
activities?public=no");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
String encoded = new String(Base64.encodeBase64(
("[email protected]" + ":" + "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr =
 xpath.compile("/atom:feed/atom:entry/atom:title/text()");
Object result = XPexpr.evaluate(doc, XPathConstants.NODESET);
NodeList entries = (NodeList) result;
for (int i = 0; i < entries.getLength(); i++) {
    System.out.println(entries.item(i).getNodeValue());}

Note: The public=no parameter is not required but makes it clear what is expected.

Creating an Activity

Activity creation is similar to document creation in all the other features we’ve seen—part of the value in using the Atom Syndication Format. All we need to do to create an activity for someone is POST the Atom activity document to the person’s activities feed. The URI for that is the value of the href attribute of <collection> element that contains a <title> element, which has a value of Overview in the user’s service document and will be similar to https://activities.example.com/activities/service/atom2/activities.

The required elements to create an activity are listed in Table 9.5.

Table 9.5. Required Activity Creation Elements

Element

Description

<title type="text">

Descriptive title of the activity specified in text format. The type attribute is optional.

<category scheme="http://www.ibm.com/xmlns/prod/sn/type" term="activity" label="Activity" />

Identifies this particular entry document as an activity.

<content type="html">

The formatted content of an activity, although this can be empty.

There are also several optional elements you can include in the activity document, shown in Table 9.6.

Table 9.6. Optional Activity Creation Elements

Element

Description

<category scheme="http://www.ibm.com/xmlns/prod/sn/priority" term="3000" label="High" />

The priority of the activity. Options are High, Medium, or Normal.

<snx:duedate>

The activity’s due date.

<category term="{tag}"/>

Specifies a tag associated with the activity. Use this tag multiple times to associate multiple tags.

<category scheme="http://www.ibm.com/xmlns/prod/sn/flags" term="completed"/>

Identifies a completed activity. To mark an activity complete, use this element. Without it, the activity is considered not complete.

With these elements, we can use code similar to the following to create an activity assigned to the authenticated user:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
URL url = new
URL("https://activities.example.com/activities/service/atom
/activities");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-type",
"application/atom+xml");
String encoded = new String(Base64.encodeBase64(
("[email protected]" + ":" + "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
connection.connect();
OutputStream ops = connection.getOutputStream();
PrintWriter pw = new PrintWriter(ops);
pw.println("<?xml version="1.0" encoding="utf-8"?>");
pw.println("<entry xmlns=http://www.w3.org/2005/Atom
 xmlns:snx="http://www.ibm.com/xmlns/prod/sn">");
pw.println("<author><name>John Doe</name></author>");
pw.println("<title type="text">API Test Activity</title>");
pw.println("<category term="api"/>");
pw.println("<category term="programming"/>");
pw.println("<snx:duedate>2009-12-15T05:00:00Z</snx:duedate>");
pw.println("<category
scheme=http://www.ibm.com/xmlns/prod/sn/type
 term="activity" label="Activity" />");
pw.println("<content type="text">Test activity creation with
the API.</content></entry>");
pw.flush();
pw.close();
connection.disconnect();

Note: The preceding code creates an activity assigned to John Doe (with John Doe listed as its author as well), and tags the activity with the tags api and programming and gives it a due date of December 15, 2009.

Creating a To-Do Item

Very often, we will want to drill down into one specific activity and work with the elements within that activity (for example, members, to-dos, email). To accomplish this task, we will need the URI of the activity we’re working with. This can be returned to us during the activity’s creation along with the result code. Alternatively, we could parse the Atom document of the activities feed to find the value of the href attribute inside the <link> element identified with the rel="edit" attribute for the activity we want to work with. For example, the Atom document of an activity feed contains the following link element that identifies the activity’s URI:

<link rel="self" type="application/atom+xml"
href="http://example.com/activities/service/atom/
acl?activityUuid=D9CG092D5BA530432F0C2D21CC724E003E95"/>

With that URI, we will have a handle on the activity and can begin working with the elements such as the to-dos within that particular activity.

To-do entries have the required elements displayed in Table 9.7.

Table 9.7. Required To-Do Creation Elements

Element

Description

<title type="text">

Title of the to-do item. The type attribute is optional.

<category scheme="http://www.ibm.com/xmlns/prod/sn/type" term="todo" label="To Do" />

Identifies this Atom entry document as a to-do item.

<content type="html">

HTML-formatted contents of the to-do item, although it can be empty.

The elements shown in Table 9.8 are optional.

Table 9.8. Optional To-Do Creation Elements

Element

Description

<snx:duedate>

The due date of the to-do item.

<snx:icon>

The icon that shows whether a to-do item has been checked complete.

<snx:assignedto>

Email address of the person assigned to the to-do item.

The following code creates a to-do item in an activity:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
String urlString =
"https://activities.example.com/activities/service/atom/
activities?public=no";
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
String encoded = new String(Base64.encodeBase64(
("[email protected]" + ":" + "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr = xpath.compile("//atom:title[text()="API
Test Activity"]/following-sibling::app:collection/@href");
String todoURL = (String) XPexpr.evaluate(doc,
XPathConstants.STRING);connection.disconnect();
url = new URL(todoURL);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic " +
encoded);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-type",
"application/atom+xml");
connection.connect();
OutputStream ops = connection.getOutputStream();
PrintWriter pw = new PrintWriter(ops);
pw.println("<?xml version="1.0" encoding="UTF-8"?><entry
 xmlns=http://www.w3.org/2005/Atom
 xmlns:snx="http://www.ibm.com/xmlns/prod/sn">");
pw.println("<title type="text">Do Something</title>");
pw.println("<content type="html">Write a connections api
 application</content>");
pw.println("<published>2009-01-28T20:12:00.000Z</published>");
pw.println("<snx:assignedto>[email protected] </snx:assignedto>");
pw.println("<snx:duedate>2009-06-15 05:00:00:CDT-
0500</snx:duedate>");
pw.println("<category scheme=http://www.ibm.com/xmlns/prod/sn/type
 term="todo" label="To Do"  /></entry>");
pw.flush();
pw.close();
int rc = connection.getResponseCode();
connection.disconnect();

Note: The preceding code gets all the activities for the authenticated user, parses it with the XPath expression that looks for the previously created activity, and then POSTs the to-do into the activity. It is assigned to John Doe and has a due date of June 15, 2009.

Creating an Email

We will look at one more example of adding elements to an activity. All the other elements are the same, with just the entry type (the term attribute in the category tag) changing, as well as some of the required elements. To create an email entry requires the elements given in Table 9.9.

Table 9.9. Required Email Creation Elements

Element

Description

<title type="text">

Title of the email item. The type attribute is optional. Typically this will be taken from the email’s subject.

<category scheme="http://www.ibm.com/xmlns/prod/sn/type" term="email"/>

Identifies this Atom entry document as an email item.

<content type="html">

HTML-formatted contents of the email body, although it can be empty.

The element described in Table 9.10 is optional.

Table 9.10. Optional Email Creation Element

Element

Description

<category term="tag_word"/>

Specifies a tag associated with the email. Use this tag multiple times to associate multiple tags.

The code to create an email entry in an activity is shown here:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
String urlString = "https://activities.example.com/activities/
service/atom/activities?public=no";
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
String encoded = new String(Base64.encodeBase64(
("[email protected]" + ":" + "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr = xpath.compile("//atom:title[text()="API
Test Activity"]/following-sibling::app:collection/@href");
String todoURL = (String) XPexpr.evaluate(doc,
XPathConstants.STRING);
connection.disconnect();
System.out.println(todoURL);
url = new URL(todoURL);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic " +
encoded);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-type",
"application/atom+xml");
connection.connect();
OutputStream ops = connection.getOutputStream();
PrintWriter pw = new PrintWriter(ops);
pw.println("<?xml version="1.0" encoding="UTF-8"?><entry
 xmlns=http://www.w3.org/2005/Atom
 xmlns:snx="http://www.ibm.com/xmlns/prod/sn">");
pw.println("<title type="text">An Email</title>");
pw.println("<content type="html"><![CDATA[<i>Creating an email
entry
 via the API!</i>]]></content>");
pw.println("<category scheme=http://www.ibm.com/xmlns/prod/sn/type
 term="email"  /></entry>");
pw.flush();
pw.close();
int rc = connection.getResponseCode();
connection.disconnect();

Note: The CDATA in the content tag allows us to create the content with HTML formatting.

Communities API

Various operations can be done on Communities in Lotus Connections. We’ll look closely at only a few of them since the algorithm is repeated for most of the features, utilizing a different URI depending on the feature you want to access. We’ll start off by simply getting a listing of all the communities in the Lotus Connections environment by using the URI http://communities.example.com/communities/service/atom/communities/all. This URI will return all the communities the authenticated user is allowed to see. Code providing a list of those communities would be as shown here:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
URL url = new
URL("http://communities.example.com/communities/service
/atom/communities/all");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr = xpath.compile("//atom:title/text()");
Object result = XPexpr.evaluate(doc, XPathConstants.NODESET);
NodeList entries = (NodeList) result;
for (int i = 0; i < entries.getLength(); i++) {
    System.out.println(entries.item(i).getNodeValue());
}

To access the communities that are restricted to a specific user and return only those communities, the URI changes to http://communities.example.com/communities/service/atom/communities/my. Unlike accessing the public communities, you will have to provide basic authentication as we’ve done in previous examples to see the private communities. You can use the same code example as listed previously.

Community Bookmarks

Among the many elements contained in a community are the bookmarks that users have created for the community’s use. Finding these bookmarks requires us to find a community’s location URI and locate within that where the URI to its bookmarks are located. That URI is found in the value of the href attribute of the <link> element with the rel="edit" attribute for each bookmark entry in the bookmarks feed. (By now this particular construct should be getting familiar.)

We will use the code that accesses communities and then parse that with an XPath expression to return the value of the href attribute of the <link> element with the rel="edit" attribute for each bookmark entry in the bookmarks feed:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
URL url = new
URL("https://communities.example.com/communities/service
/atom/communities/my");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
String encoded = new String(Base64.encodeBase64(
("[email protected]" + ":" + "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr = xpath
.compile("//atom:title[text()="API
 Community"]/following-
sibling::atom:link[@rel="http://www.ibm.com/xmlns
/prod/sn/bookmarks"]/@href");
String bookmarksURL = (String) XPexpr.evaluate(doc,
XPathConstants.STRING);
connection.disconnect();
url = new URL(bookmarksURL);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic " +
encoded);
doc = builder.parse(connection.getInputStream());
factory = XPathFactory.newInstance();
xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPexpr = xpath.compile("//atom:title/text()");
Object result = XPexpr.evaluate(doc, XPathConstants.NODESET);
NodeList entries = (NodeList) result;
for (int i = 0; i < entries.getLength(); i++) {
    System.out.println(entries.item(i).getNodeValue());
}

Note: This code retrieves a listing of all communities available to John Doe and then looks for the bookmarks listing within the community API Community. Notice the XPath expression where we look for the link element attribute rel that contains the bookmarks URI.

Community Feeds

The final element we will look at is community feeds. This is extremely similar to the algorithm in accessing bookmarks and relies on all the same Atom documents, except this time the rel attribute we look for to find the feeds URI contains feeds. The code to accomplish this task is shown here:

DocumentBuilderFactory domFactory =
DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
URL url = new
URL("https://communities.tap.ibm.com/communities/service
/atom/communities/my");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
String encoded = new String(Base64.encodeBase64(
("[email protected]" + ":" + "password").getBytes()));
connection.setRequestProperty("Authorization", "Basic " +
encoded);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(connection.getInputStream());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPathExpression XPexpr = xpath
.compile("//atom:title[text()="API
 Community"]/following-
sibling::atom:link[@rel="http://www.ibm.com/xmlns/
prod/sn/feeds"]/@href");
String bookmarksURL = (String) XPexpr.evaluate(doc,
XPathConstants.STRING);
connection.disconnect();
url = new URL(bookmarksURL);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic " +
encoded);
doc = builder.parse(connection.getInputStream());
factory = XPathFactory.newInstance();
xpath = factory.newXPath();
xpath.setNamespaceContext(new NameSpace());
XPexpr = xpath.compile("//atom:title/text()");
Object result = XPexpr.evaluate(doc, XPathConstants.NODESET);
NodeList entries = (NodeList) result;
for (int i = 0; i < entries.getLength(); i++) {
    System.out.println(entries.item(i).getNodeValue());
}

Note: All we needed to change was the XPath expression where we look for feeds instead of bookmarks.

Summary

By now you’ve noticed that working with the Lotus Connections API through the use of XPath is relatively simple, thanks to the formatting of the Atom Publishing Protocol and the consistent structure it places around the various components in Lotus Connections. After you’ve familiarized yourself with the basic document layout and acquired the foundational knowledge presented in this chapter, you’ll find you’re well positioned to extend your skills through the use of such great open-source projects as Abdera.

Do not feel locked into Java-based solutions. Any language that allows you to work with HTTP requests is a candidate for development that allows developers to create new and unique applications that enhance the social networking environment within their organization.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.151.126