My Worklist Portlet

The Vision

The vision of the My Worklist Portlet is to be able to aggregate an individuals "to-do" tasks from various unrelated and separate sources into a logical and actionable view.

Design: Retrieval of Tasks

The aggregation of content is designed around one interface: ITaskDao. Implementations are responsible for retrieving and returning a String representation of a users tasks. A return value of String was chosen for flexibility. Implementations can easily wrap other implementations for processing or retrieval of multiple sources ( for instance, consider a TaskDaoMultiSourceImpl which can be passed a collection of ITaskDao's for which it can call getXMLWorklist(...) on each object and do processing on returned data)

package edu.yale.its.portal.worklist.dao;

/**
 * @author Dustin Schultz
 * @version $Revision: 1366 $ $Date: 2008-11-10 16:17:38 -0500 (Mon, 10 Nov 2008) $
 * Task DAO Interface, implementations return an XML representation of a worklist.
 */
public interface ITaskDao {

	/**
	 * Return a String representation of XML containing a worklist
	 *
	 * @param obj Data needed to retrieve the worklist
	 * @return An XML (or not) string representing the user's worklist
	 */
	public String getXMLWorklist(Object obj);

}

Design: A Standard Way of Communication

A custom My Worklist Schema was created to facilitate a common interface on how all of a given users tasks would be represented.

An example of how this XML looks is below:

<?xml version="1.0" encoding="UTF-8"?>
<worklist xmlns="http://www.yale.edu/MyWorklist" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.yale.edu/MyWorklist MyWorklist.xsd">
   <system systemtitle="My Grant Tasks" systemuri="https://system1.yale.edu/tasks">
      <tasks>
         <task>
            <title>...</title>
            <link>...</link>
            <priority>...</priority>
            <description>...</description>
            <assigned>...</assigned>
            <due>...</due>
            <categories>
               <category>...</category>
            </categories>
         </task>
      <tasks>
   </system>
   <system systemtitle="My HR Tasks" systemuri="https://system2.yale.edu/tasks">
      ...
   </system>
</worklist>

It is understood that not all systems will be able to produce this XML. An interface for implementation is provided for task retrieval implementations that need to transform the retrieved data into the My Worklist schema.

package edu.yale.its.portal.worklist.service.document;

import org.dom4j.Document;

/**
 * @author Dustin Schultz
 * @version $Revision: 1366 $ $Date: 2008-11-10 16:17:38 -0500 (Mon, 10 Nov 2008) $
 * Document service whos purpose is to transform data into XML
 */
public interface IDocumentService {

	/**
	 * Input data and output an XML document
	 *
	 * @param params Any necessary data to create the document
	 * @return a Document of XML
	 */
	public Document createDocument(Object params);
}

Design: An Exception Hierarchy

An exception hierarchy was created to facilitate better error messages through the use of Spring's exception resolvers. Implementations should make use of these exceptions so they are translated to the appropriate view based on the mapping. Base exception classes in each package are created for extension.

edu.yale.its.portal.worklist.exception //base exception, extend for other specific exceptions
edu.yale.its.portal.worklist.exception.dao //data access exceptions
edu.yale.its.portal.worklist.exception.portlet //portlet level, controller exceptions
edu.yale.its.portal.worklist.exception.service //service level exceptions

Current My Worklist Portlet

The current My Worklist Portlet exists as a solution for displaying Business Process Management (BPM) tasks within the YaleInfo portal, a requirement of the the Capital Project Setup Integration (CPSI)

The BPM system which provides these tasks is called Lombardi Teamworks. We are using version 6.1. Teamworks provides a web service for retrieving a users tasks or as they call it, "tasks for saved search"

Documentation for connection to Lombardi Teamworks WebAPI can be found in their Developers Guide. Also, the WebAPI WSDL is pretty well documented; that can be found here

ITaskDao Lombardi Web Service Implementation: TaskDaoLombardiWsImpl

An implementation of ITaskDao exists for the purpose of calling the Teamworks webservice. Below is a pseudo version of the class. The implementation uses Axis 1.4 and uses generated code from WSDL2JAVA to make the web service calls. Axis 1.4 was chosen based on the documentation and end point implementation on Teamworks to maximize compatibility even though, technically, any web service implementation could have been chosen.

public class TaskDaoLombardiWsImpl implements ITaskDao {

	/**
	 * The IWebApiService used to retrieve the WebApi for calling the webservices
	 */
	private IWebApiService webApiService;

	/**
	 * The IDocumentService used to construct the XML document of tasks
	 */
	private IDocumentService documentService;

	/* (non-Javadoc)
	 * @see edu.yale.its.portal.worklist.dao.ITaskDao#getXMLWorklist(java.lang.Object)
	 */
	public String getXMLWorklist(Object obj) {

		//Test the connection
                webApi.testConnection();

		//Retrieve the tasks
		Task[] tasks = webApi.getTasksForSavedSearch(savedSearch.getId());

                // Return the XML as per the MyWorklist schema
		return documentService.createDocument(tasks).asXML();
	}
}

See Diagram Below

Authentication of Web Services using Proxy CAS

The portlet needs to perform proxy authentication in order to retrieve a users task list. A custom authentication module was added to the Lombardi Teamworks webservice authentication in order to be able to accept proxy tickets as a valid password for a user. Axis 1.4 supports basic authentication so this was an easy "hack" at performing proxy authentication.

username: whatever
password: proxy-ticket

See CASify Lombardi Teamworks Application via Jaas

In order for the portlet to be able get proxy tickets for a service, the portlet needs to retrieve a proxy granting ticket. An interceptor (similar to a servlet filter but in a portlet environment) was created to retrieve the proxy granting ticket. This will "pre handle" every request to see if the session contains a receipt for a request to get a proxy granting ticket. Below is a pseudo version of the class:

public class ProxyCasRequestorInterceptor extends HandlerInterceptorAdapter {

	/**
	 * An ICasService to process CAS related items.
	 */
	@Autowired
	private ICasService casService;

	@Override
	protected boolean preHandle(PortletRequest request,
			PortletResponse response, Object handler) throws Exception {
		PortletSession session = request.getPortletSession();
		casReceipt = casService.requestProxyGrantingTicket(request);
		session.setAttribute(CASKEY, casReceipt);
		return true;
	}

Integration & Unit Tests

Unit tests exist for the Lombardi WS implementation of IDocumentService, the creation and retrieval of the WebAPI object used for querying web services, and a basic XSLT transformation of worklist xml.

An integration test exists to query a given instance of the Lombardi Teamworks service using the default Lombardi Teamworks user (see the test context files) to retrieve zero or more tasks.

The tests make heavy use of the Spring Framework's testing packages. One of the advantages to doing this is that configuration that only differs in testing, only needs to be expressed in the test context files, instead of redefining all configuration. It is then dependent upon the order of loading the context files, making sure that the test configuration is defined last so that it will override any defined beans.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
		"classpath:/context/applicationContext.xml",
		"classpath:/context/lombardi/lombardiContext.xml",
		"classpath:/context/applicationContext-test.xml" })
public class WebApiServiceSessionTest {
   ...
}

Context Files Layout & Configuration

The layout of Spring context files (bean definitions) is separated (where possible) by domain. For instance, the portletContext.xml only contains bean definitions related to portlets (like the portlet interceptor) where as the lombardiContext.xml only contains bean definitions related to lombardi. The context files may be helpful to understand how classes interact with each other and their configuration.

context
  | lombardi
     \lombardiContext.xml
  | portlet
     \worklist-portletContext.xml
  \applicationContext.xml

Context files are then loaded in the web.xml:

<param-name>contextConfigLocation</param-name>
<param-value>
	classpath:/context/applicationContext.xml
	classpath:/context/lombardi/lombardiContext.xml
</param-value>

View

The view layer is simply an XSL Transformation using JSTL transform tag.

<c:import url="http://www.yale.edu/portal/resources/WorklistPortlet/xsl/myWorklist.xsl" var="xslt"/>
<x:transform xml="${worklistXml}" xslt="${xslt}" />

Although spring provides an XSLTView for doing exactly this, JSP was chosen for flexibility as well as portlet specific tags do not exist in XSLT (portlet:actionURL, portlet:renderURL, etc). The portlet tags will be necessary to further extend the portlet to be interactive and customizable for the user.

Future My Worklist Portlet

The My Worklist Portlet has a lot of room for improvement. There were several discussions of what would be the best way to design and architect a sound solution but the time frame was not large enough to complete them in. Below is what has been discussed for improvement.

Aggregation of Tasks

As it is designed now, the portlet is responsible for aggregating and combining tasks into a common XML schema. The better way of doing this would be to involve a piece of middleware (ESB), such as web methods, that given some input, was responsible for retrieving tasks from all the various systems based on that input. The portlet then would be a light weight client which simply asks the service bus for tasks.

Retrieval of Tasks

The portlet currently retrieves tasks using a synchronous request/response model. This requires the portlet to continually ask each system for all of its tasks. The better way of doing this would be the other way around, that is for the systems to tell the portlet (by way of the ESB) that new tasks exist. This is the publish/subscribe model. The portlet would then most likely need to use some AJAX for polling its subscription, this way the other would not need to continually refresh/reload to see their tasks.

My Worklist Schema

The schema was developed based on a team discussion of what type of data a particular task producing system would have. The schema may be too well defined or perhaps not well enough. There are some common hard problems with the schema such as how do you represent a priority (do you define one and map each system to these priorities or do you use the native priorities of the system; what about systems with no priorities? how could you sort priorities?) or how do you represent categories of tasks?

Actionable Tasks

One of future objectives of the My Worklist Portlet is to have actionable tasks for a user. Throughout the various task systems, there are certain tasks which simply require a yes or no, approve or disapprove answer that would require the use to log in to that systems an perform that action. Instead, it would serve the user far better if they had the ability to take action upon that task right within the portal.

User Preferences

The ability to sort tasks, rearrange tasks, configure the number of displayed tasks, hide tasks, etc

User Interface & User Experience

This is a somewhat difficult problem that needs much room for improvement. Figuring out how to display a large set of data in a small area without loosing any important information that the user needs.

Proxy Authentication Using Basic Authentication

Proxy authentication where the password field is used to carry the proxy ticket is probably less than an ideal solution for authenticating to web services. Perhaps a better way would be to understand some of the WS-Security profiles and look to leverage that.

Portlet Preference options

Portlet Preference name
Portlet Preference Value
Descriptiopn
noTasksPageLocation https://www.yale.edu/portal/resources/WorklistPortlet/worklistNoTasks.html Location of content to display if the user no tasks are found for the logged in user.  If this parameter is not entered, a default page included with the WorklistPortlet (/WorklistPortlet/noTasksDefault.html) will be displayed.
lombardiTargetUrl https://bpm<dev,test,train>.its.yale.edu/webapi/services/WebAPIService Points to a
lombardiWebServiceHostName    

Labels

 
(None)