The AMSeT Project Blog

Saturday Sep 26, 2009

Pathy News

Or... Status Symbols for the Java Developer.

This might save someone 10 minutes or so.

Here's the problem. You have nested arrays that you want to loop over to display in a jasper and bind these to form elements using Spring.

Specifically, the SWORD bean hierarchy in AMSeT contains a branch consisting of

serviceDocumentContext.serviceDocument.service.workflowList.collections.

The workflowList and collections objects are lists and each have a number of simple datatype fields that need to be bound to a form input element using Spring.

Using JSTL the basic construct is nested <c:forEach/> elements. Normally you would write something like

<c:forEach items="${serviceDocumentContext.serviceDocument.service.workflowList}" var="workflow">

and then loop using $workflow as the representative indexed item.

Now, each workflow has a title. The title of the first workflow would be accessed using the following variable:

${serviceDocumentContext.serviceDocument.service.workflowList[0].title}

Each collection has a title, which for the first worklow and first collection would be found at

${serviceDocumentContext.serviceDocument.service.workflowList[0].collections[0].title}

Both workflow and collections have several fields and you want to output them all. Some index variable is needed to label the iterations. This is where the varStatus attribute of the <c:forEach/> comes into play.

Forget about var for a while - this justs confuses the issue when it comes to Spring which doesn't recognise the usage.

The varStatus attribute represents a LoopTagStatus object, one of whose fields is index which is a
zero-start counter for the iteration.

So the forEach becomes:

<c:forEach items="${../../...workflowList}" varStatus="wloop" ></c:forEach>

For the inner collections loop we have:

<c:forEach items="${../../...collections}" varStatus="cloop"></forEach>

The general title field of collections then becomes:

${serviceDocumentContext.serviceDocument.service.workflowList[wloop.index].collections[cloop.index].title}

Note no dollars on the index.

In order to bind a form element to Spring the following construct is required:

<spring:bind path="serviceDocumentContext.serviceDocument.service.workspaceList[${wloop.index}].collections[${cloop.index}].title">

<input type="hidden" name="<c:out value='${status.expression}'/>" value="<c:out value='${status.value}'/>" />

</spring:bind>

Note the dollar variable notation for the index in the Spring path.

The ${status.expression} and ${status.value} variables apply to the object pointed to in the Spring path. The expression is the precise path expression of the object bound to the form element and the value is its value, a string or integer.

Cock-a-doodle-do.

Friday Sep 25, 2009

Bean Soup and Spring Bananas

I've been driving a NetBeans Hacker automatic for too long now to go back to a manual shift. At the click of a mouse I can write 20 getters and setters at a time. And these little getters and setters let me use yet more tools to pull apps together. Spring is one such. Alfresco's AMP extension modules require Spring to wire into the main application.

Databinding in the view layer in SpringMVC requires that Java objects have the Bean getter/setter structure. There is a nested class structure running down the SWORD "common core" spine ServiceDocument.Service.Workspace.Collection... Spring can see Java fields OK until it burrows down to Workspaces and Collections where it goes bananas (eh?) when the Bean structure is broken. For example, the Workspaces getter returns an Iterator and the setter uses a List.

This means that Spring and other tools can't be used directly to bind to display fields in the view layer. This might be something to consider if SWORD is to be developed further.

There's always another way. One obvious solution is to write <%...%> Java code in the jaspers and talk to the objects directly. But, old-fashioned as I am, I'm not that old-fashioned. Another way would be to write a tag library, but in a stocking-filler workpackage, I thought better of that. What I have done is create mini AmsetWorkspace and AmsetCollection objects in which The Canonical Bean is restored. I should get away with that.

Tuesday Sep 15, 2009

Alfresco SWORD

As we approach the last few furlongs of AMSeT, the SWORD workpackage has been unsheathed from its scabbard.

There is a server and client component to the task. An implementation of the Java SWORD server will be added to the Alfresco Web application and a Building Block extension to the Blackboard VLE will be created that will house a SWORD client. It will then be possible to publish Blackboard documents to a SWORD-fronted repository.

The recommended method for adding functionality to Alfresco is to create an Alfresco Module Package (AMP). This is installed into the Alfresco WAR file using the Module Management Tool (MMT). The structure and contents of an AMP will be described in a future post. The SWORD server will hand the deposit process to a class that will use the Alfresco Foundation API to publish the incoming document.

There is no concept of a collection in Alfresco and so an addition to its default content model will have to be made to add a collection aspect to a folder node.

The original SWORD SourceForge repository includes a Web application client. Our Building Block expert will visit shortly to advise on the conversion. The webapp has been built as a NetBeans project and deposited in SourceForge at https://amset.svn.sourceforge.net/svnroot/amset/sword/webapp-client. (IE doesn't like the markup, fine with Firefox, Chrome and Safari.)

Wednesday Sep 02, 2009

Atomic Workflows on the Bus

Using NetBeans BPEL Designer and GlassFishESB, a set of atomic workflows for the Alfresco content management system has been created, see the amsetwiki. There are 27 at the moment and the final number will probably reach around the 40 mark.

Technical documentation is available on the wiki and the projects will be ferried across to the AMSeT SourceForge repository.

Now, workflows are not usually referred to as atomic, being conceptually rather the opposite. However, these workflows in the context of Alfresco can be looked at as simple, synchronous operations involving users, groups, folders and permissions from which more extensive workflows can be created, both synchronous and asynchronous.

Some examples of these molecular workflows will be provided.

Tuesday Jul 14, 2009

wsmonitor

When developing Web services and workflows, a tool to monitor outgoing and incoming messages is pretty much essential.

There are a few candidates here: SOAPMonitor, soapUI, TCPMon, tcpmon. I have used wsmonitor (Web Services Monitor) most of the time and find it is easy to use and works well.

It uses port-forwarding and intercepts all HTTP traffic in and out of a port specified in a config.xml file. Outgoing messages are then re-routed to the ultimate Web service endpoint.

An example config.xml file is given below:

<monitor xmlns="http://java.sun.com/xml/ns/jax-ws/ri/config/monitor"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="config.xsd">
<connection
name="5050 --> my.webservicehost.ac.uk:8080"
description="5050->8080"
listenPort="5050"
targetHost="my.webservicehost.ac.uk"
targetPort="8080"/>
</monitor>

In order for this to work the host in the service endpoint URL in the WSDL file must be changed to http://localhost:5050/myservice from http://my.webservicehost.ac.uk:8080/myservice.

Unzipping the distribution file provides an executable in the bin directory. Placing the config.xml file in the bin and executing

>wsmonitor config.xml

from the command line, wsmonitor would then look the following:

wsmonitor

Connections to multiple servers can be created simultaneously, each with a different listen port.

Tuesday Jun 16, 2009

Shibbing Alfresco

Introduction

Part of the AMSeT project is the addition of a Shibboleth Service Provider to Alfresco. Some work has already been done in this area by Kimmo Ilppola, but this has used the Internet 2 implementation of the Shibboleth SAML Profile. This requires Apache as well as Tomcat and is complicated to set up and test.

We decided to use the Guanxi implementation instead. Written entirely in Java by Alistair Young at the University of the Highlands and Islands, all Guanxi modules are fully compatible with the Internet2 implementation and also fully compatible with the UK Access Management Federation and OpenAthens. These notes describe how Alfresco was 'shibbed' using Guanxi.

Adding Guanxi to Alfresco

We used Tomcat version 5.5.27, Java 1.6.0_13 and Alfresco Labs version 3 final. Most of our work has been done using Red Hat Enterprise 5 on a 64-bit Dell server, but we have also successfully installed Guanxi on Windows and OSX computers.

We'll assume that Java, Tomcat and Alfresco have been successfully installed and that the Alfresco webapp is installed at <TOMCAT_HOME>/webapps/alfresco. We downloaded and compiled the source code of all five modules of Guanxi (WAYF, IdP, security provider, SP engine and SP guard from Sourceforge. Installation of Guanxi, protecting a test webapp - <TOMCAT_HOME>/webapps/protectedapp - was done as described in Alistair's localhost tutorial, except that all references to localhost were replaced by the domain name of the server.

Having tested Guanxi and made sure that the attributes were being released by the IdP, it was time to copy the Guanxi guard to the alfresco webapp.

cd <TOMCAT_HOME>/webapps/alfresco
cp -r ../protectedapp/guanxi_sp .
cp -r ../protectedapp/protected .
cd WEB-INF
cp -r ../../protectedapp/WEB-INF/classes .
cp -r ../../protectedapp/WEB-INF/guanxi_sp_guard .

Then we compared the contents of <TOMCAT_HOME>/webapps/alfresco/WEB-INF/lib with the contents of <TOMCAT_HOME>/webapps/protectedapp/WEB-INF/lib and copied from the latter to the former any files that were only found in the latter. Any jar files that were older in the former were removed and replaced with the newer files from Guanxi.

We modified Kimmo Ilppola's authentication filter to include the creation of groups and to implement a logout from the SP. Here is the Java code. The compiled class file was placed in the directory <TOMCAT_HOME>/webapps/alfresco/WEB-INF/classes/org/alfresco/web/app/servlet.

The corresponding shibbolethAttributes.properties was placed in the directory <TOMCAT_HOME>/webapps/alfresco/WEB-INF/classes.

The web.xml files of the alfresco and Guanxi Guard webapps were then merged. Here is the merged file.

The next file to edit was <TOMCAT_HOME>/webapps/alfresco/WEB-INF/guanxi_sp_guard/config/guanxi-sp-guard.xml and here is the content of our file:

<?xml version="1.0" encoding="UTF-8"?>
<Guard xmlns="urn:guanxi:sp">
  <GuardInfo>
    <HostName>socket1.leeds.ac.uk</HostName>
    <ID>alfresco-guard</ID>
    <AttributePrefix>HTTP_</AttributePrefix>
  </GuardInfo>
  <Cookie>
    <Domain>.leeds.ac.uk</Domain>
    <Path>/</Path>
    <Age units="transient"/>
    <Prefix>GUANXI_GUARD_SERVICE_PROVIDER_</Prefix>
  </Cookie>
  <EngineInfo>
    <AuthConsumerURL>https://socket1.leeds.ac.uk:8443/samlengine/shibb/acs</AuthConsumerURL>
    <WAYFLocationService>https://socket1.leeds.ac.uk:8443/samlengine/shibb/wayf-location</WAYFLocationService>
    <Timeout>10</Timeout>
  </EngineInfo>

  <TrustStore>/opt/tomcat55/webapps/alfresco/WEB-INF/guanxi_sp_guard/truststore/guard.jks</TrustStore>
  <TrustStorePassword>xxxxxxxx</TrustStorePassword>
  <Keystore>/opt/tomcat55/webapps/protectedapp/WEB-INF/guanxi_sp_guard/keystore/guard.jks</Keystore>
  <KeystorePassword>xxxxxxxx</KeystorePassword>
  <CertificateAlias>webservices</CertificateAlias>
</Guard>

Our <TOMCAT_HOME> was /opt/tomcat55 and our server's domain name was socket1.leeds.ac.uk - you will need to substitute your own values.

At this point it was necessary to start Tomcat and register the alfresco-guard with the SP engine and the IdP as described in Alistair's tutorial. If you are using the Internet2 IdP, then you will need to supply the IdP with the guard's certificate. Again, Alistair has an excellent tutorial which will guide you through the process.

Enabling logout

In order to log out from a session, you need to log out from both the SP and the IdP. Logging out from the SP is easy, because we know where it is. Logging out from the IdP is not as straightforward because we need to call a web service at the IdP. We need to know the URL of this web service - if it exists. The easiest way to find the URL is for the IdP to send it as an attribute. Here is how to set this up using the Guanxi IdP. (We have been using the flat file authenticator/attributor which is the default for Guanxi. If you use a different authenticator, you will need to make the appropriate changes.)

We added the following entry to the file <TOMCAT_HOME>/webapps/guanxi_idp/WEB-INF/guanxi_idp/config/shared/custom-arps/arp-providers.xml

  <provider name="alfresco-guard">
    <allow>MappedFlatFileAttributesForAlfresco</allow>
  </provider>

We added the following entry to the file <TOMCAT_HOME>/webapps/guanxi_idp/WEB-INF/guanxi_idp/config/shared/custom-arps/arp-bags.xml

  <bag name="MappedFlatFileAttributesForAlfresco">
    <attribute name="alfresco_ID" value="*" />
    <attribute name="idWithDomain" value="*" />
    <attribute name="idEncrypted" value="*" />
    <attribute name="alfresco_FirstName" value="*" />
    <attribute name="alfresco_Surname" value="*" />
    <attribute name="alfresco_Email" value="*" />
    <attribute name="mail" value="*" />
    <attribute name="memberOf" value="*" />
    <attribute name="function" value="*" />
    <attribute name="urn:mace:dir:attribute-def:eduPersonScopedAffiliation" value="*" />
    <attribute name="alfresco_PersistentID" value="*" />
    <attribute name="logoutIDP" value="*" />
  </bag>

Then we edited Harry McDesperate's entry in the file <TOMCAT_HOME>/webapps/guanxi_idp/WEB-INF/guanxi_idp/config/shared/flatfile.xml to:

  <User>
    <!-- Harry McDesperate. The world's most violent programmer! -->
    <Username>harrymcd</Username>
    <Password>growl</Password>
    <UserAttribute name="id" value="harrymcd" />
    <UserAttribute name="firstName" value="Harry" />
    <UserAttribute name="surname" value="McDesperate" />
    <UserAttribute name="email" value="HarryMcD-AT-jumpingupanddown-DOT-net" />
    <UserAttribute name="role" value="CheifHeidbanger" />
    <UserAttribute name="group" value="heidbangers" />
    <UserAttribute name="logoutIDP" value="http://socket1.leeds.ac.uk:8080/guanxi_idp/shibb/logout" />
  </User>

Our modifications to Kimmo Ilppola's ShibbolethHttpRequestAuthenticationFilter include the following piece of code which picks up the logout service URL from the Shibboleth header and then stores it as a session attribute. It then redirects to the SP logout service, which in turn will chain the IdP logout.

  if (req.getMethod()=="POST")
  {
    for (Enumeration e = req.getParameterNames(); e.hasMoreElements(); )
    {
      String name = (String)e.nextElement();
      String value = req.getParameter(name);
      if (name.endsWith("act") && value.endsWith("logout"))
      {
        // get the IdP's logout URL - if it's there
        String logoutIDP = req.getHeader( logoutHeaderName );
        if ((logoutIDP==null) || (logoutIDP.length() <1 ))
          logoutIDP = "NO_IDP_LOGOUT";
        // and store it in the session -
        // the logout jsp will use this to log out from the IdP
        logger.info("IdP logout is "+logoutIDP);
        httpSess.setAttribute("LOGOUT_IDP_URL", logoutIDP);

        // log out of the sp
        logger.info("Logging out of SP");
        String logoutURL = req.getContextPath()+"/guard.guanxiGuardlogout";
        logger.info("URL is: "+logoutURL);
        resp.sendRedirect( logoutURL );
        return;
      }
    }
  }

To make Guanxi log out of the IdP, the following code was added to <TOMCAT_HOME>/webapps/alfresco/WEB-INF/guanxi_sp_guard/jsp/logout.jsp

  <%
    HttpSession httpSess = request.getSession();
    String logoutURL = (String)httpSess.getAttribute("LOGOUT_IDP_URL");
    if ((logoutURL==null) || (logoutURL == "NO_IDP_LOGOUT")) {
  %>
      <center>Cannot log out of the IdP.</center>
  <%
    } else {
      response.sendRedirect( logoutURL );
    }
  %>

Now when the used clicks on the logout link in Alfresco, he/she is logged out of both the SP and the IdP.

Tuesday May 26, 2009

The Prisoner of Venda

...with apologies to Rudolf Rassendyll. First rule of blogging: think of a good title. Then think of something to say.

There are not many BPEL (Business Process Execution Language) bukes on the market: a few have BPEL as the primary topic, and some others include BPEL as a subsidiary subject of SOA. The books tell an interesting story. Take, for example, "SOA Cookbook: Master SOA Process Architecture, Modeling, and Simulation in BPEL, TIBCO's Businessworks, and BEA's Weblogic Integration". Or "BPEL Cookbook: Best Practices for SOA-based Integration and Composite Applications Development": the code in this is built on Oracle's presence in the market, the BPEL Process Manager.

A pattern emerges. Vendor tie-in. In fact, the code snippets provided by the Alfresco company as an example of how to beepellify Alfresco assume the use of Oracle's Process Manager and include proprietorial extensions to the WS-BPEL standard. Little ooffles of closed-source magic.

The propulsive force leading to extensions is almost irresistible in relation to mediation of the SOAP message. There is so much useful stuff to be be done in the nukes and crannies surrounding the BPEL standard, and so, naturally, it is done.

On top of the proprietorial problem there is also another restrictive force deriving from technology and methodology. For example, if one's SOA is based on an Enterprise Service Bus (ESB) methodology implemented by Java for Business Integration (JBI), then that is going to restrict the generality of one's efforts. Also, it makes life easier if one can take advantage of an XPath function extension to call some Java in BPEL assign statements.

So there is a little issue. While it doesn't seem difficult to restrict oneself to pure BPEL and eschew extra-beepellular moves, is it worth the effort? Where this hits home in AMSeT is the Alfresco security ticket, which has to be generated in-process and placed in subsequent SOAP message headers. This is straightforward to do in BPEL. However, it consists of adding a SOAP header message to each operation in a WSDL file which might contain over a dozen of the things. Ce n'est pas élégant. Using Web service handlers can work (eg OMII-BPEL) but this does not sit well with the Alfresco security ticket model.

For reasons that will be explained elsewhere, AMSeT is using GlassFishESB, a JBI rig. It would be perverse to use an ESB and not let it do the security headers. And so, that is the plan, NetBeans/GlassFish volente. However, versions will be provided of all the Alfresco WSDLs with SOAP security header elements along with sample workflows.

Saturday Apr 11, 2009

AMSeT

This is a technical blog to accompany the JISC Alfresco Management and Security Toolkit (AMSeT) project which is funded under the Repositories: Rapid Innovation strand of the 12/08 JISC Information Environment and e-Research call.

The principal aims of the project are to produce a set of educational Web service workflows, a JISC Guanxi Shibboleth Service Provider and a JISC SWORD interface for the Alfresco content management system. A BlackBoard Building Block will also be produced for the SWORD client.

The project will run from 1 April 2009 until 30 September 2009.

The project Web site is located at http://www-DOT-agbooth-DOT-com/AMSeTWiki/amset.leeds.ac.uk_8080/amsetwiki/

The Project Team

Director

Professor Andrew G. Booth,
Institute of Molecular and Cellular Biology,
Faculty of Biological Sciences,
University of Leeds,
Leeds LS2 9JT

Email: a.g.booth-AT-leeds.ac-DOT-uk

Developer

Dr Brian P. Clark,
Institute of Molecular and Cellular Biology,
Faculty of Biological Sciences,
University of Leeds,
Leeds LS2 9JT

Email: b.p.clark-AT-leeds.ac.uk

Calendar

Search

Navigation