Portlet IPC classloading problem in Liferay

Hello,

We have developed 2 Vaadin portlets (7.0.1) that communicatie with each other using IPC (Portlet 2.0 Events).

If we put both portlets in the same war IPC works. GREAT!

But if we deploy them as seperate wars we get the following ClassCastexception:

java.lang.ClassCastException: com.vaadin.server.VaadinPortlet$RequestType cannot be cast to com.vaadin.server.VaadinPortlet$RequestType

This appears to be a classloading issue (since the exception talks about a cast of the same class) but we cannot find a solution for this problem.

The mentioned class resides in vaadin-server-7.0.1.jar and is a simple enum that represents the type of a vaadin request. This .jar exists in the Liferay lib dir (ROOT/WEB-INF/lib) because we put it there following the manual upgrade steps explained here:
Upgrade Vaadin in Liferay

We already tried with setting the scope of this dependency to provided (in both portlet projects which are Maven 2.2.1 projects) but still no succes. We also tried to remove all vaadin jars from ROOT-WEB-INF/lib and place them in tomcat/lib/ext but still no succes.

My guess is that Tomcat sees the vaadin-server.jar in both portlets as different or sees a difference between the vaadin-server.jars in the portlets and the vaadin-server.jar residing in Liferay. We also investigated if there are differences in the vaadin-server-7.0.1 jar that we downloaded as full archive from the vaadin site and the version we got from maven but also no differences here.

It can only be something small that we are overlooking but we just cant seem to find the cause of the problem!

Can anyone please explain as why this problem is occuring and how we can solve it :lol:

Regards,

Kim

I’m not sure if I can provide a solution, but maybe some hints that might help get towards one.

If I remember correctly, when the JAR is in ROOT/WEB-INF/lib, it is copied to the portlet deployment directory at deployment time by Liferay. Thus, it is loaded with the portlet classloader and so each portlet gets a separate clazz/klass instance instance of it. These cannot be cast into each other.

If you put the Vaadin JAR in tomcat/lib/ext, there will only be one copy of it on the whole server. The downsides include that the Vaadin JAR cannot find classes on the portlet classpaths when starting an Application etc. (need a custom servlet class that does not use reflection). Also, all static variables in Vaadin JAR are shared on the whole server level.

The real question is, why would the system need to cast RequestTypes - how does one get from one portlet to the other in this case? Client-side IPC does not transmit such, but sharing data somehow on the server side might - but where in your case?

Henri,

Always nice to see a big shot think along :slight_smile:

The stacktrace we get is the following:


javax.portlet.PortletException: java.lang.ClassCastException: com.vaadin.server.VaadinPortlet$RequestType cannot be cast to com.vaadin.server.VaadinPortlet$RequestType
        at com.vaadin.server.VaadinPortlet.handleServiceException(VaadinPortlet.java:674)
        at com.vaadin.server.VaadinPortlet.handleRequest(VaadinPortlet.java:505)
        at com.vaadin.server.VaadinPortlet.processEvent(VaadinPortlet.java:588)
        at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:85)

The error indicates that the publishing of the portlet event works fine but that the processing of the event causes mentioned Exception. This is verified by the fact that if we only deploy the event publishing portlet no exceptions occur.

If we dive into the vaadin source code we can see that the problem arises in the VaadinPortlet.handleRequest method (which, by the way, is marked deprecated). In my opinion this line is causing the error (for some reason I can set breakpoints but cannot step through the code using netbeans IDE 7.3 RC1, so i cannot be totally sure ):

391: RequestType requestType = getRequestType(vaadinRequest);

The mentioned RequestType enum is also marked deprecated

Sending of the event is done as follows:

VaadinPortletSession portletsession = (VaadinPortletSession) VaadinSession.getCurrent();
 portletsession.sendPortletEvent(ui, CopyProductEvent.QNAME, view.getSelectedSku());

consuming of the event goes as follows in consumer portlet:


public void handleEventRequest(EventRequest request, EventResponse response, UI root) {
        Notification.show("event  value: " +  (String)request.getEvent().getValue());
    }

Furthermore, if we deploy both portlets in 1 war everything works perfect!

Regards,

Kim