Bedework and Liferay

Rethinking the portlet?

After some discussion with other groups we are gradually coming round to th eview that it is a mistake to try to put as large an application as bedework into a portlet.

We have been coinstrained for a long time by a desire not to do anything whicnh would make jsr168 complinace difficult to achieve. This has led to what we regard as deficiencies in the user interface but hasn't in the long run made it much easier to implement portlets.

Liferay for example, seems to change significantly between releases. The problems below appear to be caused by liferay serializing the entire request object along with all page/session/request scode beans.

This is causing some real problems with hibernate.

The approach we are considering is that the main bedework application should just be front-ended by the portal whic acts as a proxy, either through the use of proxy channels or just through the use of iframes.

There is still room for portlets but these will probably be much more restricted in behavior - perhaps intended for navigation or task lists and will direct the user to the main calendar application.

Liferay version 5

These are currently just notes on attempting to get this to build with version 5.

The version of liferay is 5.1.2 packaged with tomcat 5.5.x

Many of the properties for liferay 4 appear to work.

Got ucal to appear as an application - but was able to add it to the home page - perhaps because I'm acting as admin?

It appeared in guest mode - this broke the client which expects to be authenticated. User client should not be visible in guest mode.

During deployment (maybe a tomcat issue?) the context.xml file in the webapp (ucal/META-INF/context.xml) does not get copied into conf/Catalina/localhost - not sure this matters.

Tried to add hsql jdbc jars to common/lib

Liferay now uses hibernate and hsql so we're getting version skew. Drivers for liferay conflict with the common/lib drivers.

Removed hsql driver from common/lib/ext Replaced with bedework hsql driver.

In conf/Catalina/localhost/ROOT.xml had

	<Resource
		name="jdbc/LiferayPool"
		auth="Container"
		type="javax.sql.DataSource"
		driverClassName="org.hsqldb.jdbcDriver"
		url="jdbc:hsqldb:lportal"
		username="sa"
		password=""
		maxActive="20"
	/>

changed

		url="jdbc:hsqldb:lportal"

to

           url="jdbc:hsqldb:hsql://localhost:9887"

Added a liferaydb task to bedework ant scripts to start a localhost copy of hsql for liferay.

Restarted and liferay populated the new db.

Logged in, agreed to stuff then added ucal to a new page.

Hibernate initialized OK for bedework but we ran into xml transform errors.

http://localhost:8080/web/guest/home;jsessionid=AD942B9EBD2872C1B4FC2DB1BD3D5382; Line #2; Column #67; stylesheet requires attribute: version
[Fatal Error] home;jsessionid=AD942B9EBD2872C1B4FC2DB1BD3D5382:11:5: The content of elements must consist of well-formed character data or markup.
http://localhost:8080/web/guest/home;jsessionid=AD942B9EBD2872C1B4FC2DB1BD3D5382; Line #11; Column #5; org.xml.sax.SAXParseException: The content of elements must consist of well-formed character data or markup.
22:54:58,281 ERROR [ConfiguredXSLTFilter:436] Unable to transform document
java.lang.NullPointerException
	at org.apache.xalan.transformer.TransformerImpl.createSerializationHandler(TransformerImpl.java:1178)

followed by some hibernate errors - possibly due to followuop request.

Liferay is packaged with xalan etc in common/endorsed. These are older or newer than those bedework uses.

NOTE: it would be useful if the liferay delivered jars had the version name included.

Tried removing xml jars from common/enorsed and restarted. Different error this time

23:35:26,001 ERROR [ConfiguredXSLTFilter:469] Unable to transform document
javax.xml.transform.TransformerConfigurationException: javax.xml.transform.TransformerConfigurationException: javax.xml.transform.TransformerException: org.xml.sax.SAXException: Missing or incorrect XSLT Namespace. 

Removed serializer.jar (another xml jar) and now get

23:54:18,763 INFO  [SessionListener:152] SESSION-START:D727EE9E5E6568D29EDE5AA0C59756DA:DemoUserCal:1:1:147M:520M
23:54:18,767 INFO  [[/ucal]:647] ========= New session(DemoUserCal): 1 active, 1 total. vm(used, max)=(146M, 520M)
23:54:18,801 ERROR [UploadServletRequestImpl:111] the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is application/x-www-form-urlencoded; charset=UTF-8
23:54:18,819 ERROR [UploadServletRequestImpl:111] the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is null
23:54:18,867 INFO  [RenderAction:674] REQUEST:D727EE9E5E6568D29EDE5AA0C59756DA:unknown:null:/ucal/main/initialise.rdo?
23:54:18,867 INFO  [RenderAction:674] REQUEST:D727EE9E5E6568D29EDE5AA0C59756DA:unknown:null:/ucal/main/initialise.rdo?
23:54:18,868 INFO  [RenderAction:674] REFERRER:D727EE9E5E6568D29EDE5AA0C59756DA:unknown:http://localhost:8080/web/guest/2
23:54:18,869 INFO  [RenderAction:674] REFERRER:D727EE9E5E6568D29EDE5AA0C59756DA:unknown:http://localhost:8080/web/guest/2
... messages as hibernate configures...
23:54:22,539 ERROR [RenderAction:256] <No-message>
java.lang.NullPointerException
	at org.bedework.webcommon.BwAbstractAction.performAction(BwAbstractAction.java:262)

Note that liferay didn't seem to want to re-render after a restart. Had to remove ucal and re-add to get new errors.

Note the UploadServletRequestImpl? message - what's that about?

The null pointer exception is probably a bedework bug I need to track down. Sometimes a new user causes a null-pointer.

Tried a restart adn this time no null pointer but all the other exceptions that followed it were still there....

javax.xml.transform.TransformerConfigurationException: javax.xml.transform.TransformerConfigurationException: javax.xml.transform.TransformerException: org.xml.sax.SAXException: Missing or incorrect XSLT Namespace. 

reappeared followed by a load of hibernate errors - possibly caused by an odd request sequence?

Replaced xalan-2.6.0.jar with the liferay version which appears to be 2.7.0 Added serializer-2.7.0.jar also aas it's required by the above.

Now I get

23:25:14,180 INFO  [ConfiguredXSLTFilter:606] PRETRANSFORM:6B106C144621EC184811AFDFDE7775D4:4477
(Location of error unknown)java.net.ConnectException: Connection refused
(Location of error unknown)java.net.ConnectException: Connection refused
23:25:15,368 INFO  [ConfiguredXSLTFilter:606] POSTTRANSFORM:6B106C144621EC184811AFDFDE7775D4:5665
23:25:15,379 ERROR [LazyInitializationException:19] failed to lazily initialize a collection of role: org.bedework.calfacade.BwCalendar.categories, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.bedework.calfacade.BwCalendar.categories, no session or session was closed
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)

Not sure what the connection refused is (dtd?)

The hibernate problems are something to do with liferay poking around in the session -

23:25:15,379 ERROR [LazyInitializationException:19] failed to lazily initialize a collection of role: org.bedework.calfacade.BwCalendar.categories, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.bedework.calfacade.BwCalendar.categories, no session or session was closed
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
	at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:97)
	at org.hibernate.collection.PersistentSet.size(PersistentSet.java:139)
	at org.bedework.calfacade.BwCalendar.getNumCategories(BwCalendar.java:572)
	at org.bedework.calfacade.BwCalendar.toString(BwCalendar.java:1271)
	at org.bedework.calfacade.wrappers.CalendarWrapper.toString(CalendarWrapper.java:644)
	at java.lang.String.valueOf(String.java:2615)
	at com.liferay.util.portlet.PortletRequestUtil._isValidAttributeValue(PortletRequestUtil.java:329)
	at com.liferay.util.portlet.PortletRequestUtil.toXML(PortletRequestUtil.java:192)

The toString method is being called


Liferay version 4

The bedework web client is intended to work as a jsr168 client. There seems to be a little more work needed but here's how it was done for liferay4.

Jboss version

Some of the notes in Building bedework for jboss are relevant for the jboss deployment of liferay.

Liferay version installed

I downloaded and installed the jobss + tomcat version of liferay which unpacked into the directory

liferay-portal-jboss-tomcat-4.2.1

We can refer to this as JBOSS-HOME

After some PermGen space errors I tried running it under Java6. This seemed to work OK and the errors went away without any extra configuration. (Later on they came back. It appears that Java6 performs better but not well enough without some explicit configuration)

Properties file

Most of the properties are the same. The liferay changes are mostly in the global settings. I had problems running using the hsqldb database which may have been driver version errors. Jboss uses hsql for persistance of objects so I switched to mysql.

I commented ot the standalone section

# These for standalone and for j2ee
#org.bedework.global.servlet.class=org.apache.struts.action.ActionServlet
#org.bedework.global.ignoreContentType=false
#org.bedework.global.portlet.mapping=
#org.bedework.global.genurl.taglib.tld=struts-html.tld

and uncommented the liferay4 section

# These for liferay 4
liferay4.lib=${org.bedework.default.lib}/liferay4.2
org.bedework.build.for.liferay4=yes
org.bedework.global.portal.platform=liferay4
# servlet-class is the action servlet in web.xml
org.bedework.global.servlet.class=com.liferay.util.apache.bridges.struts.LiferayPortletServlet
# portlet-servlet.class is the servlet-class element  for the portlet servlet in web.xml
org.bedework.global.portlet-servlet.class=com.liferay.portal.kernel.servlet.PortletServlet
# portlet.class is in portlet.xml and the value for the portlet-class init par in web.xml
org.bedework.global.portlet.class=org.apache.portals.bridges.struts.StrutsPortlet
# portal-servlet.context.provider is in portlet.xml
org.bedework.global.portal-servlet.context.provider=com.liferay.util.apache.bridges.struts.LiferayServletContextProviderWrapper
org.bedework.global.portal-servlet.context.listener=com.liferay.portal.kernel.servlet.PortletContextListener
org.bedework.global.ignoreContentType=true
org.bedework.global.genurl.taglib.tld=bedework-portlet-struts-html.tld
org.bedework.global.liferay.company-id=liferay.com

It may be possible to get this working for liferay3 by changing some of those values above.

In addition you need to set the portlet name for each application:

...
org.bedework.app.CalAdmin.portlet.name=CalAdmin
...
org.bedework.app.UserCal.portlet.name=UserCal

and it seems that the web.xml display-name element is used by liferay and needs to be set to the same as the portlet-name, e.g.

...
# display.name has to be same as portlet name for liferay?
org.bedework.app.UserCal.display.name=UserCal
...

With those changes in place you should be able to build the portlet.

Libraries

For the time being I have copied 3 liferay jar files into the bedework library (bedework/lib/liferay4 and bedework/lib/liferay4.2) which are copied into the war files. The appropriate location is specified above as

...
liferay4.lib=${org.bedework.default.lib}/liferay4.2
...

Deploying

I have had problems using the auto-deploy feature of liferay and uportal. I believe the problem resides in the tool which maniupulates the web.xml file and I think this tool is in both cases a modified version of the pluto tool. (Note - with 4.2.1 this problem may have been resolved.)

It has problems with the multiple servlet-mapping elements and loses all but one of them.

The build process builds the web.xml as it would have been built by the deployer tool so it can be dropeed straight into the correct directory.

In the case of the jboss system, this directory is JBOSS-HOME/server/default/deploy

In addition, we need to copy in the xsl stylesheets and common javascript so they are available at the root context.

For this release of liferay, the directory is JBOSS-HOME/server/default/deploy/liferay-portal.ear/portal-web.war

For example, for the personal calendar portlet you will need to copy out of the quickstart tomcat webapps directory the following:

  • bedework-common
  • ucalrsrc.liferay4
  • ucalrsrc (if you want to try the standalone application as well)

If you are switching databases, build the new database as set out in the deployment manual.

Running

I ran under Java6 (eventually). set JAVA_HOME, cd to JBOSS-HOME/bin and do "./run.sh"

In your browser go to localhost:8080 and login as test@liferay.com with password test.

Click on the "add content" link, open the "Test" tab and add "UserCal".

If all went well, you'll (eventually) see the user calendar displayed as a portlet - a little cramped for space perhaps.

Problems

At the moment pop-up windows are not working correctly, which makes it difficult to add events. Currently we need to select the calendar and I believe this should be a resource url, flagged by the "gdo" suffix.

In a production environment we would probably have a different set of stylesheets for the portal version. This is why the resource name is suffixed by ".liferay4". It allows multiple sets of stylesheets for a single application. Currently I have gone back to loading the same version as the standalone application.


Further changes

These will probably need to be backported to 3.3.1

POST v GET

A number of the forms didn't have method="POST". When they were changed they started to work - to some extend. For example, we could create a new calendar in the user client.

popups

Those that use launchSizedWindow seem to work except that they launch an entire portal with that particular calendar page. e.g. Adding attendees.

gdo v do v rdo

These distinguish between the various types of url, RESOURCE, ACTION and RENDER. RESOURCE url processing seems to be a problem. A resource url allows the application to set the content type, normally disallowed.

The export link on the detailed event page was such a url. Not sure it needs to be but it generates a bad url anyway. Tried changing it to a ".do" and that generated a different bad url.

Switched back to gdo but changed from a genurl:link to a genurl:rewrite. That at least generates a url that works.

export changes

To try to get this working switched to writing directly to output stream. Requires

  1. a code change to UtilAbstractAction - not handling null action
  2. Change ExportAction
  3. Change style sheet so we don't set contentType and skinName
  4. Remove ical.xsl
  5. Remove export code from FreeBusyAction? (FreeBusyPublish? does it)
  6. Remove vcal property from form
  7. Remove showExportData action from struts-config
  8. Ensure other data export actions don't forward