Smarter collaboration for the education industry using Lotus Connections, Part 1: Integrate Lotus Connections with a RESTful web application

Track publications by person using Lotus Connections Profiles

Extend IBM® Lotus® Connections capabilities with a RESTful web application that supports XML and JSON APIs. The Connections Profiles user interface is a custom widget based on the Dojo Toolkit. The web app enables a university professor to share his publications on a social network profile page. Further customize the application to share other information from the professor's profile such as research grant awards or courses taught.

Share:

Vladislav Ponomarev, Software Engineer, IBM

Photo of Vladislav PonomarevVladislav Ponomarev is a Web technology solutions team leader at IBM Russian Software and Technology Lab. His major areas of expertise include Java EE applications, virtualization, and cloud computing.



Carl Osipov, Software Architect, IBM

Photo of Carl OsipovCarl Osipov is an experienced software architect with the Strategy and Technology organization in IBM Software Group. His skills are in the area of distributed computing, speech application development, and computational natural language understanding. He has published and presented on topics including service-oriented architecture and conversational dialog management to peers in the industry and academia. His current focus is on business analytics and optimization.



21 September 2010

Also available in Russian Japanese Portuguese Spanish

The articles in the series will describe collaboration use cases for higher education (such as colleges or universities) institutions and will provide technical guidance on extending and customizing IBM Lotus Connections as well as other IBM products to enhance education industry specific collaborative scenarios. The series will focus on using business analytics and optimization capabilities of IBM products to enable Connections users to make smarter decisions about identifying and working with potential collaborators. We expect that the material in the series will be valuable to education industry information technology (IT) leaders and strategists who are considering collaboration solutions for their organizations.

The first article in the series will describe how to integrate IBM Lotus Connections with REST-based web services to enable education industry specific extensions to the product. The follow-on articles will use extended Connections capabilities to support optimized processes to help principal investigators use skills-based collaborative group identification plus content analytics of researcher's publications to enhance collaboration profiles and other topics.

Introduction

The IBM Lotus Connections® 2.5 (Connections) Profiles application can be extended with custom widgets. This is a relatively simple process when the widget user interface (UI) and code are bundled along with Profiles. However, you may need to integrate Connections with a separate application having an external API so that a custom Profiles widget can display and manipulate data managed outside of Connections.

Frequently used acronyms

  • API: Application Programming Interface
  • HTTP: Hypertext Transfer Protocol
  • JAXB: Java Architecture for XML Binding
  • JEE: Java Platform, Enterprise Edition
  • JSON: JavaScript Object Notation
  • REST: Representational State Transfer
  • UI: User Interface
  • XML: Extensible Markup Language
  • XSS: Cross-site scripting

In the first part of the article, you get an overview of the web application capabilities and requirements. Next, we expand on the technologies used and describe the application architecture. The first part concludes with an implementation description which also covers the security mechanism used in the application.

The second part of the article is dedicated to the client-side, iWidget implementation. We explain the big picture of the widget capabilities provided to a user as well as how the widget UI is organized and built with the Dojo Toolkit.

Finally, we show how the components (Profiles, web application, and widget) are integrated with each other. We provide examples of Connections configuration files for integration.


RESTful web application

We will describe a web application which helps a Profiles user (such as a professor in an education or a research institution) maintain a list of his or her authored publications. The application will expose its functionality through an HTTP-based REST interface, making it easier to communicate with the application from the browser using JavaScript or potentially from any other third party software. The application will meet the following requirements:

  1. The REST interface must:
  • Accept request messages formatted as XML and support response rendering in JSON and XML formats.
  • Provide create, retrieve, update, and delete (CRUD ) operations on publications.
  1. The following data must be persisted for each publication:
  • Auto-generated ID
  • Publication owner
  • Title
  • Year published
  • Author(s)
  • Journal
  • Publisher
  1. Unauthenticated users must not be allowed to perform operations that modify publications.
  2. Authenticated users must be allowed to only modify publications owned by them.
  3. The application should be easily extensible to support new REST entities (in addition to publications) without re-compiling its code. For example, if the application maintained a list of grant awards for each Profiles user, the code should remain untouched, and the only development tasks should be application assembly, deployment, and database schema changes.

Technologies used

Since an IBM Lotus Connections 2.5 installation includes an instance of IBM WebSphere® Application Server (WebSphere) 6.1, we will use the latter for running our application. WebSphere 6.1 implements a set of J2EE specifications, including Java™ Servlet 2.4 (JSR 154) and Enterprise JavaBeans™ (EJB) 2.1 (JSR 153).

The application uses a JSR 154-compliant servlet as a service end-point. As noted in the requirements, we must implement doGet(), doPost(), doPut(), and doDelete() methods to accept XML messages in the servlet.

Since annotation-enabled JAXB (standard for XML serialization and deserialization) is not available in the WebSphere 6.1 JRE, we used the Java 6 JAXB libraries to enable XML support in the servlet. As for JSON support, our implementation relies on the JSON4J library, shipped as a part of the WebSphere Feature Pack for Web 2.0. To support persistence, we use JSR 153 entity beans which enable an object-relational database mapping programming model (see Appendix B: EJB pros and cons for details).

Application architecture overview

The diagram in Figure 1 illustrates the application architecture.

Figure 1. Application architecture
Diagram of the application architecture

The UI shown on the left hand side of the figure provides a user with HTML graphical controls for performing CRUD operations on publications. Whenever an operation is triggered by a user action in the web browser, the application JavaScript passes an HTTP request to the server-side (middle of the figure) part of the application through a REST interface. To ensure that the UI can be rendered on a Profiles page, the HTML markup and the JavaScript are packaged in a Connections-compatible iWidget format.

The central part of the figure represents the JEE container hosting the servlet, entity bean (EJB), and auxiliary components. When an HTTP request is received from the browser, it passes through the Security Filter, to the appropriate method in the REST servlet (such as the doPost()method). Next, the servlet invokes the appropriate CRUD operation through a façade object on the entity bean component. The façade hides the client code from the fine-grained interface provided by entity beans, allowing the client to work with lightweight Plain Old Java Objects (POJOs). Finally, the servlet renders the response into the appropriate format which concludes the request processing.

The right-most part of Figure 1 depicts the database table deployed to the database server. The JEE container and the database are shown as logically separate; however, in practice, the two may be co-located. Now look at the database structure in Figure 2.

Figure 2. Database structure
Diagram of the database structure

The PUBLICATION database table, detailed in Figure 2, is created as part of the Connections PEOPLEDB database. One advantage of having a common database for Profiles and the application is the ability to impose a foreign key constraint (see Figure 2) on the OWNERID column of the PUBLICATION table so that it references the primary key column of the EMPLOYEE table.

Now look at the POJO and EJB relationship, beginning with the hierarchy of POJO objects (see Figure 3).

Figure 3. Domain objects hierarchy
Diagram of the hierarchy for the domain objects

The root class, DomainObject, describes a domain object having an ID and respective accessor methods. The descendant class, OwnedDomainObject (lower left in the figure), adds an owner ID field. The Publication object inherits OwnedDomainObject and adds publication-specific fields. The classes are JAXB-annotated, enabling object serialization and deserialization to and from XML.

Look at the entity beans in Figure 4.

Figure 4. Entity bean hierarchy
Diagram of the Entity bean hierarchy

Each POJO has a corresponding entity bean (see the left side of Figure 4). Moreover, the bean interfaces inheritance tree is similar to the one for POJOs (that is, DomainObject has corresponding DomainLocal and DomainLocalHome interfaces, and the same for OwnedDomainObject (see the right side of Figure 4). The bean interfaces are built using Java 5 Generics capability to:

  • Provide client code with a toPojo() factory method used to convert the bean into a POJO.
  • Define update() and create() methods which accept the POJO as an argument.

A dedicated façade object hides entity beans from the client code and performs CRUD operations on them. The façade (see Figure 1) can support arbitrary entities, if they are constructed similarly to the Publication entity (that is, adhere to the same inheritance rules), by registering them through the registerDomainObject() method.

On application startup, the REST servlet, using configuration parameters taken from web.xml file, creates and configures the adapter objects. This allows an Application Assembler (a JEE role defined by the EJB 2.1 specification, chapter 3.1.2) to enable the application to work with new entities without recompiling the code. The REST service object is responsible for mapping HTTP requests to particular entity types.

Data access layer

The Publication POJO is implemented according to Figure 3 from the previous section. Note that class fields are annotated with @XmlElement to make the object serializable to and deserializable from XML using JAXB.

The entity beans expose only the local interface to prevent access to the beans over the network. In Listing 1, look at the definition of an entity local interface:

Listing 1. Local interfaces
public interface DomainLocal<D extends DomainObject>
{
 String getId();
 void setId(String newId);
 
 void update(D domainObject);
 D toPojo();
}

public interface OwnedDomainLocal<D extends OwnedDomainObject> extends DomainLocal<D>
{
 String getOwnerId();
 void setOwnerId(String ownerId);
}

public interface PublicationLocal extends OwnedDomainLocal<Publication>, EJBLocalObject
{
 public java.lang.String getTitle();
 public void setTitle(java.lang.String newTitle);

 public java.lang.String getJournal();
 public void setJournal(java.lang.String newJournal);

 public java.lang.String getPublisher();
 public void setPublisher(java.lang.String newPublisher);

 public java.lang.Integer getYearPublished();
 public void setYearPublished(java.lang.Integer newYear);

 public java.lang.String getInternetLink();
 public void setInternetLink(java.lang.String newLink);

 public void setAuthors(String authors);
 public String getAuthors();
}

Note that the root of the hierarchy, the DomainLocal interface, prescribes that the entity must have a factory method to convert itself into a POJO. Also, the update() method, which accepts a POJO instance, acts as a façade to the fine-grained mutators (the setXXX() methods). You are advised to change entity state using this method so that all fields are set in one operation.

Local home interfaces mirror the same hierarchy. They define methods to create and look up entities.

Listing 2. Local home interfaces
public interface DomainLocalHome<D extends DomainObject, L extends DomainLocal<D>>
{
 Collection<L> findAll()
 throws FinderException;
}

public interface OwnedDomainLocalHome
 <D extends OwnedDomainObject, L extends OwnedDomainLocal<D>>
 extends DomainLocalHome<D, L>
{
 Collection<L> findByOwner(String ownerId)
 throws FinderException;
}

public interface PublicationLocalHome
 extends OwnedDomainLocalHome<Publication, PublicationLocal>, EJBLocalHome
{
 public PublicationLocal create(Publication pub) // Return type is local interface!
 throws CreateException; 

 public PublicationLocal findByPrimaryKey(String primaryKey)
 throws FinderException;
}

Used extensively throughout the code, the Generics feature of the Java language minimizes the need for class casts in the client. However, using Generics raises some issues:

The EJB specification restricts the return type of the create() and findByPrimaryKey() methods to the entity interface (see the commented line in the code snippet in Listing 2). Since implementation objects are generated by the JEE container at runtime, when no generic information is available, you cannot move the create() method upwards in the hierarchy and make it generic as you did with findByOwner().

The erasure feature of Java Generics hides the type of information of the concrete POJO classes. Therefore the implementation of update() and toPojo() methods of local interface must depend on the common ancestor (that is, DomainObject).

Listing 3 shows the implementation of the methods.

Listing 3. Implementation of generic methods in the Publication bean
public abstract class PublicationBean implements javax.ejb.EntityBean
{
 public String ejbCreate(Publication pub)
 throws javax.ejb.CreateException
 {
 setId(pub.getId());
 setAuthors(pub.getAuthors());
 setInternetLink(pub.getInternetLink());
 setJournal(pub.getJournal());
 setOwnerId(pub.getOwnerId());
 setPublisher(pub.getPublisher());
 setTitle(pub.getTitle());
 setYearPublished(pub.getYearPublished());
 
 return null;
 }

 public void ejbPostCreate(Publication pub)
 throws javax.ejb.CreateException {
 }

 public void update(DomainObject domainObject)
 {
 Publication pub = (Publication) domainObject;
 
 setAuthors(pub.getAuthors());
 setInternetLink(pub.getInternetLink());
 setJournal(pub.getJournal());
 setOwnerId(pub.getOwnerId());
 setPublisher(pub.getPublisher());
 setTitle(pub.getTitle());
 setYearPublished(pub.getYearPublished());
 }
 
 public DomainObject toPojo()
 {
 Publication pub = new Publication();
 pub.setId(getId());
 pub.setAuthors(getAuthors());
 pub.setInternetLink(getInternetLink());
 pub.setJournal(getJournal());
 pub.setOwnerId(getOwnerId());
 pub.setPublisher(getPublisher());
 pub.setTitle(getTitle());
 pub.setYearPublished(getYearPublished());
 
 return pub;
 }
...
}

Now that you have implemented the EJB, you need a façade object which first hides the Java Naming and Directory Interface (JNDI) lookup code, and second, allows clients to work with REST entities (such as a Publication) in terms of the respective POJO classes. The façade must have CRUD methods in its interface, as in Listing 4.

Listing 4. Façade interface methods
public <D extends DomainObject> Collection<D> find(Class<D> domainClass)
public <D extends DomainObject> D find(Class<D> domainClass, String id)
public <D extends DomainObject> void create(D domainObject)
public <D extends DomainObject> void remove(Class<D> domainClass, String id)
public <D extends DomainObject> void update(D domainObject)
public <LH extends DomainLocalHome<D, ?>, D extends DomainObject>
void registerDomainObject(
 Class<LH> localHomeClass,
 Class<D> domainClass,
 String jndiName,
    LocalInterfaceCaller<?, LH, D> caller)

The purpose of the last method in the list is to make the façade object aware of new REST entities.

Entity registration example

Here is how the Publication REST entity is registered within the façade:

service.registerDomainObject(
PublicationLocalHome.class, Publication.class, "ejb/Publication", new PublicationCaller());

The façade object allows the client code to work both with concrete POJO classes (like Publication) and with base classes (DomainObject or OwnedDomainObject). However, there is one more obstacle: The façade needs to call create() and findByPrimaryKey() methods that belong to the concrete home interface (such as PublicationLocalHome), not to the base ones. To work around this, when you register a new REST entity through the registerDomainObject() method, the client code must pass an additional object which encapsulates the aforementioned calls to the home interfaces, as in Listing 5.

Listing 5. Sample caller implementation
public class PublicationCaller implements 
    CrudService.LocalInterfaceCaller<PublicationLocal, PublicationLocalHome, Publication>
{ 
    public void callCreate(PublicationLocalHome localHome, 
        Publication domainObject) throws CreateException { 
        localHome.create(domainObject); 
    } 

public PublicationLocal callFindByPrimaryKey( PublicationLocalHome localHome, String id) 
    throws FinderException { 
        return localHome.findByPrimaryKey(id); 
    }
}

The Generic type parameters of LocalInterfaceCaller are replaced with concrete local and local home interfaces which provide the create() and findByPrimaryKey() methods.

Besides hiding EJB-related code, the façade object (in conjunction with the hierarchy of domain objects) has another advantage: It can simplify migration to EJB 3. POJO will become JPA-annotated (Java Persistence API), turning into entity beans, and façade implementation will be changed to reflect the next version of the EJB specification. Note that the client code is not affected.

Figure 5. Façade object class diagram
Diagram of the facade object class

For the implementation of the façade object, please refer to the sample source code. You can find the link in Downloads.

Security mechanism

To understand the security implementation, let’s recap against which threats you want to protect the application.

  1. Modification operations (expressed by POST, PUT, and DELETE HTTP verbs) should only be allowed for authenticated users.
  2. Authenticated users should only be allowed to modify publications that they own.

The authentication mechanism used in Lotus Connections relies on a Lightweight Third-Party Authentication (LTPA) token carried along with cookies with each HTTP request. Since the application UI is integrated into Profiles, you can expect the same token to be present in a request coming to your REST servlet. WebSphere Application Server detects user identity based on the token, so the application checks authentication by calling the getRemoteUser() method defined in the HttpServletRequest class. If the user is authenticated, this method returns the login name of the user. Otherwise, this call returns null.

To implement the security mechanism, we use a filter in front of the servlet to intercept each request (see Figure 6). The filter determines whether a user is authenticated, as described above. If not, and the HTTP method is other than GET, the request processing is terminated and HTTP status 401 (unauthorized) is returned. If the HTTP method is GET, the control flow is transferred to the servlet. Finally, if an authenticated user is about to perform a modification operation, the filter retrieves the user login name, queries the database to get a Connections identifier of the user, and caches it in the session object. Once a user is authenticated, the filter does nothing upon each subsequent call, so the identifier is retrieved only once.

Figure 6. Authentication filtering
Diagram of the authentication filter

When an HTTP request for a modification operation reaches the servlet, the user identifier is cached in the session object, so you can compare that identifier with the owner ID of the target REST entity (in this case, a Publication). To encapsulate this authorization check, we developed an adapter on top of the façade object described above. The adapter holds a reference to the façade. The latter is declared with public methods mirroring CRUD methods defined on the adapter but with a user identifier as an additional argument. The identifier of the REST entity owner is compared to the user identifier, and if they don’t match, an authorization exception is thrown.

XML and JSON support

XML support is enabled in the application out of the box, as long as the JAXB libraries are on the class path and the POJO objects are annotated. The process is as easy as registering domain classes within a JAXBContext object and using its factory methods, createMarshaller() and createUnmarshaller(), to obtain domain objects capable of XML serialization and deserialization.

To enable JSON support, we used the JSON4J library shipped as part of WebSphere Feature Pack for Web 2.0. The output in JSON format is adjusted to comply with the requirements of the dojo.data.ItemFileReadStore component: The returned object specifies identifier, label, and items attributes.

The servlet accepts XML messages and renders a response either in XML or JSON format, depending on the Accept header of the HTTP request or on the as request parameter. The latter takes precedence over the header. This logic is encapsulated in a dedicated factory method of the servlet which constructs either an XML or a JSON renderer responsible for object serialization. See Figure 7 below.

Figure 7. Renderers class diagram
Class diagram of the renderer

REST servlet implementation

The REST servlet lifecycle begins with the init() method which handles servlet initialization based upon parameters defined in web.xml.

The CrudConfigurators initialization parameter contains a comma-separated list of classes which implement the CrudServiceConfigurator interface. These objects are required to have a no-arguments constructor. After instantiation, the configure() method for each object, which accepts a CRUD façade instance, is called. Each configurator registers a set of REST entities within the façade.

Similarly, the restConfigurators parameter stores a comma-separated list of RestServiceConfiguration implementations. The processing is the same as for crudConfigurators. The RestService object is essentially responsible for establishing a correspondence between a request path and a particular domain class. For example, the DELETE /rest/publication/123 request must be executed against a Publication entity. Each configurator registers its own set of REST entities within the RestService object.

This configuration mechanism and the façade object we covered earlier make it easy to add support for arbitrary entities that follow the design approach of Publication without recompiling the code. For each new entity, an Application Assembler just has to add new configurator objects to servlet initialization parameters in the deployment descriptor and bundle them along with domain classes into the web application.

Once the web.xml is configured, the servlet is ready to handle HTTP requests. Table 1 below summarizes the REST API provided by the servlet. For brevity, the <host>:<port> part of the URL is omitted.

Table 1. Servlet REST API
HTTP MethodURIParameters
GET/tonkawaWeb/rest/publication
[?ownerId=<ownerId>]
[&as={xml|json}]
POST/tonkawaWeb/rest/publication[?as={xml|json}]
DELETE, PUT/tonkawaWeb/rest/publication/<id>[?as={xml|json}]

Upon successful processing, the response body for a GET request will contain a list of publications, the response for a POST contains a single publication (the one stored to the database), and the response for a PUT or DELETE contains only a confirmation message. If an exception occurs, the response body will contain an HTTP status code and an optional error message in an appropriate rendering format.

Listing 6 shows an example of an HTTP request.

Listing 6. Sample HTTP POST request
POST /tonkawaWeb/rest/publication
Accept: application/json

<?xml version="1.0" encoding="UTF-8"?>
<publication>
 <id></id>
 <title>Publication title</title>
 <internetLink>http://mysite.com</internetLink>
 <authors>John Doe</authors>
 <journal>My Journal</journal>
 <publisher>Publisher and Co</publisher>
 <yearPublished>2010</yearPublished>
 <ownerId>6d14080a-e26e-40d3-8588-9b7b4011e65d</ownerId>
</publication>

The sequence diagram in Figure 8 illustrates request processing, where the components are wired together. (View a larger version of Figure 8.)

Figure 8. HTTP POST processing
Sequence diagram of HTTP POST processing

iWidget

The user interface of the application is implemented by an iWidget 1.0 component included in the Profiles UI. The user interface depends on the Dojo Toolkit JavaScript library version 1.2.3 which is shipped along with Lotus Connections 2.5. The publications widget provides the following capabilities:

  • View the publication list on an open profile page for a Connections user.
  • Create or update a publication, while enforcing client side validation rules.
  • Remove a publication.

iWidget editing buttons are available only when a user views their own profile.

UI Structure

The iWidget UI is comprised of a Dojo stack container with 3 panes. The first pane presents the user with a read-only formatted list of publications (see Figure 9a or a larger version of Figure 9a).

Figure 9a. List of publications
Screen capture of the list of publications

If a user views his or her profile, then it’s possible to switch to the next pane where an individual publication can be selected for editing (see Figure 9b or a larger version of Figure 9b).

Figure 9b. Publication details
Screen capture of details for a selected publication

The pane includes Add, Edit and Remove buttons. Click on the Add or Edit buttons to show the editing form pane with Title, Link, Author(s), Journal, Publisher, Year, and Selected publication fields (see Figure 9c or a larger version of Figure 9c.).

Figure 9c. Edit the publication
Screen capture of publication in the edit form

The form’s input controls apply basic validation rules (see the Input validation section above for details).

Implementation

According to the specification, an iWidget consists of a JavaScript class (in this case, the DwPublication class) with a definition of callback handlers, and an XML file containing HTML markup.

Figure 10 shows how the UI components interact with each other and with the server. (View a larger version of Figure 10.)

Figure 10. Interaction of the iWidget components
Diagram of interactions for the UI componenets and the server

Upon the first loading of the publications iWidget, its onLoad() callback handlers are executed (Step 1, Figure 10) and then its HTML markup is parsed by Dojo, so that the widget is rendered in the browser. Next, the DwPublication class fetches a publication list by instantiating a Dojo data store object (dojo.data.ItemFileWriteStore) and instructs it to query for a list of publications from the server (2). The data store is passed a callback function that builds respective DOM nodes to display a read-only list (2.1). When a user clicks on the Edit publications link, the DwPublication class constructs a new DataGrid object and shows the edit panel where to display the grid (3). The grid is populated by content from the data store created in step (2).

The edit panel has Create, Edit and Remove buttons. If either of the first two are clicked, a user is shown an edit form to fill in the data. When the form is submitted, control flow is transferred back to DwPublication which sends an HTTP POST or PUT request to create or update the publication.

Alternatively, if the Remove button is clicked, DwPublication sends an HTTP DELETE request to delete a publication from the database.

Our iWidget implementation ensures the correct behavior of the refresh and maximize features enabled by Lotus Connections. When the entire Profiles web page is loaded or reloaded and an iWidget is in a maximized state, the HTML body’s onLoad() event handler added by Dojo automatically parses the HTML markup on the page in order to construct the Dojo widgets. In contrast, when an iWidget is refreshed through its context menu (or maximized after the page was loaded with a minimized iWidget), then the iWidget’s DOM tree is destroyed and re-built based on the XML file given as a part of iWidget definition. Parsing does not occur in this case and should be called manually. Also, Dojo widgets created prior to refresh or maximize events must be destroyed to prevent memory leaks.

Figure 11 shows the difference in these flows. onLoad() and onUnload() callback handlers in the DwPublication class are invoked when the old widgets should be cleaned up and the HTML markup should be parsed again.

Figure 11. iWidget (re)load behavior
Diagram of the iWidget load and reload behavior

Localization support

To enable full localization of the UI, we implemented a number of custom Dojo widgets designed to set the innerHTML property of a particular node to a localized string taken from a resource bundle. First, you develop a mix-in that supports a label property (see Listing 7).

Listing 7. Mix-in with a 'label' property
dojo.provide("com.ibm.tonkawa.i18nInnerHtmlMixin");

dojo.declare(
 "com.ibm.tonkawa.i18nInnerHtmlMixin",
 null,
 {
 label: {},
 _defaultLabel: "$unset$",

 buildRendering: function()
 {
 this.inherited(arguments);
 this.containerNode.innerHTML = this.label ? this.label : this._defaultLabel;
 }
 }
);

With the mix-in in place, you can add the label property to a newly declared Dojo widget by specifying i18nInnerHtmlMixin in the list of ancestors (see code snippet in Listing 8 ). The default implementation of the buildRendering() method may be overridden to put a label property value in whatever DOM node is required.

Listing 8. LocalizedLabel widget
dojo.provide("com.ibm.tonkawa.LocalizedLabel");

dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("com.ibm.tonkawa.i18nInnerHtmlMixin");

dojo.declare(
 "com.ibm.tonkawa.LocalizedLabel",
 [dijit._Widget, dijit._Templated, com.ibm.tonkawa.i18nInnerHtmlMixin],
 {
 templateString: "<label for=\"${forLabel}\" dojoAttachPoint=\"containerNode\"></label>",
 forLabel: ""
 }
);

Finally, in the HTML markup, the localized Dojo widget is used as in Listing 9:

Listing 9. Localized widget declaration in HTML markup
<script>
dojo.requireLocalization("com.ibm.tonkawa", "Publication", null, "en,ru,ROOT"); myBundle = dojo.i18n.getLocalization("com.ibm.tonkawa", "Publication"); </script> ... <div forLabel="publicationYearPublished" dojoType="com.ibm.tonkawa.LocalizedLabel" label="myBundle.labelYearPublished"/>

In this case, the labelYearPublished resource string is taken from resource bundle and set as a value of the label property of the custom widget.

Profiles and Dojo

We use some implementation tricks to make certain Dojo controls work with Profiles. First, we must place containers inside a <div> block with an id attribute defined. Second, to make dojox.grid.DataGrid display correctly, we must load a collection of CSS files before the markup is parsed. This is accomplished with JavaScript code which builds and appends <link type=”text/css”> nodes to the page header.

Input validation

Almost all of the application’s Dojo widgets (except diji.form.SimpleTextarea) accept user input support validation capabilities and consequently, we chose them to implement the Publication editing form. To fill the gap with text area, we developed an additional widget, com.ibm.tonkawa.ValidationTextarea, to enhance the HTML textarea element with validation support. In a nutshell, it’s a mixture of dijit.form.ValidationTextBox and dijit.form.SimpleTextarea widgets with onBlur() and onFocus() callback handlers overridden to perform validation.

When constructing an XML message to send to the server, certain characters like less than (<) or greater than (>) are escaped to prevent XSS injections. Similarly, these characters are also escaped when rendering them on the HTML page.


Appendix A: Integration with Profiles

The process of adding custom iWidget into Profiles application is thoroughly covered in the IBM Lotus Connections Infocenter. It involves stopping Profiles, checking out the widget configuration file, augmenting it with the iWidget definition and placement instructions, and checking it in. Listing 10 shows an example of the widgets-config.xml file.

Listing 10. Profiles widget definition and placement configuration
<widgetDef
 defId="dwPublication"
 bundleRefId="tonkawaBundle"
 url="{contextRoot}/../tonkawaWeb/widget/dwPublication.xml?version={version}"/>
…
<widgetInstance uiLocation="col2" defIdRef="dwPublication"/>

Optionally, you may register a custom resource bundle to provide localization strings for the iWidget title and menu items. A bundle is a zipped directory with properties files whose definition is added to the Lotus Connections configuration file (LotusConnections-config.xml). For an example, see Listing 11.

Listing 11. Resource bundle definition
<resources>
 <!-- Bundle is located in the ext-i18n-resources/tonkawa.zip file -->
 <localZipFile file="tonkawa.zip">
 <bundle bid="tonkawaBundle" name="tonkawa.widgets.resources"/>
 </localZipFile>
…
</resources>

Finally, the Profiles application starts.


Appendix B: EJB pros and cons

In case of the application in this article, the use of EJBs offers the following advantages:

  • Independence from the deployment environment. The EJB programming model insulates developers from the underlying middleware.
  • Reusability of EJB components. The programming model specification prescribes the required API for JEE-compliant containers, allowing one to choose the most suitable middleware given requirements while minimizing component code changes.
  • Integration with the JEE platform. Related mature technologies, such as Java Database Connectivity (JDBC), Java Message Service (JMS), J2EE Connector architecture (JCA), and so on, provide services EJB code can leverage in a well-defined manner described by the specifications;
  • Distributed transaction support.
  • Transparent scalability.

The complexity of EJB 2.1 is well known. For example, it burdens a developer with multiple interfaces (local, remote, and home), JNDI lookup code, and XML deployment descriptors which depend on JEE container specific parameters. For the application in this article, the merits highlighted above outweigh the shortcomings due to complexity. Also, the next generation of the EJB specification, EJB 3.0, addresses many of the complexity issues. Support for the new specification can be enabled by installing the EJB 3.0 Feature Pack on top of WebSphere 6.1. Since it may not be acceptable to install the feature pack in every Connections deployment environment, this article describes EJB 2.1 for the persistence layer implementation. However, by using certain techniques covered in the Data access layer section, migration to EJB 3 can be simplified.


Conclusion

In this article, we showed an approach for creating a custom REST web application and integrating it into IBM Lotus Connections Profiles. The application extends Profiles with the ability to maintain a list of publications that belong to a particular user. It provides a user-friendly UI aligned with the Lotus Connections look-and-feel and is built upon Dojo Toolkit components. Security constraints are enforced to keep data consistent and prevent it from corruption. Moreover, the application is extensible to support new entities without recompiling the code.


Download

DescriptionNameSize
Sample implementation codesource.zip840KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into IBM collaboration and social software on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Lotus, Java technology, XML
ArticleID=524518
ArticleTitle=Smarter collaboration for the education industry using Lotus Connections, Part 1: Integrate Lotus Connections with a RESTful web application
publish-date=09212010