« Torna a Development (Legacy)

Access Liferay API from Portlet

The problem #

Starting from Liferay 4, a new separate classloader architecture is used. This brings lots of improvements such as the possibility of the portlet using its own version of the libraries such as hibernate, spring, etc. that are also used by the core Liferay code.

On the other hand, it might also have negative side effects to portlets using the API offered by Liferay from a portlet application packaged in a WAR. If that's your case the recommended solution is to change your code to use the portal-service.jar API.

But sometimes that solution is not applicable such as when:

  • You need a very quick solution until you change your code
  • You are accesing internal APIs that are not being exposed through liferay-client

In those cases you can use the following solution.

The solution #

The solution is to make all of Liferay's classes accessible through the global classpath. There are three ways to achieve this:

1. Make the portlet application use the portal webapps classloader. In tomcat you achieve this by creating a file called context.xml in the META-INF folder of your portlet webapp with the following content:

<Context>
	<Loader 
		loaderClass="com.liferay.support.tomcat.loader.PortalClassLoader"
	/>
</Context>

2. Configure the application server to use a single classloader for all application.

3. Copy all of Liferay's libraries and it's dependent libraries to a path in the global classpath.

The next sections offer detailed instructions for alternative 3 for the most common application servers.

Note: This solution has an important drawback: as we are putting all the libraries that are used by Liferay in the global classpath it might collide with other versions of the same libraries in independent portlet applications. If you run into this problem use the recommended solution of invoking only the public Liferay API offered through liferay-service.jar.

Tomcat #

In tomcat the best solution is to copy the necessary libraries to the global classpath. Here are the recommended steps to do this:

0) Stop Tomcat

1) Check that the directory common/lib/ext exists. If it does not exist create it and add it to the list of global classpath paths editing $TOMCAT_HOME/conf/catalina.properties and adding it to the values of common.loader:

 common.loader=
    ${catalina.home}/common/classes,\
    ...\
    ${catalina.home}/common/lib/ext/*.jar

2) Move all files from ROOT/WEB-INF/lib to the common/lib/ext. Be sure to not leave any library in the original location

3) Start Tomcat

JBoss-Tomcat #

For JBoss it's possible to configure a single classloaders:

1) Open $JBOSS_HOME/server/default/deploy/jbossweb-tomcat55.sar/META-INF/jboss-service.xml and set UseJBossWebLoader to true:

 <attribute name="UseJBossWebLoader">true</attribute>

With this setting we use Jboss' unified classloader instead of tomcat's classloader.

2) Open $JBOSS_HOME/server/default/conf/jboss-service.xml and set the deployment sorter to PrefixDeplomentSorter instead of the default org.jboss.deployment.DeploymentSorter:

 <attribute name="URLComparator">org.jboss.deployment.scanner.PrefixDeploymentSorter</attribute>

This way we'll be able to control the order in which the web applications are loaded by changing the WAR file names. Our purpose will be to make sure that the portal loads first that the portlet applications.

3) Rename the file names of all portlet applications to make them start with the number '1'. For example:

 sample-struts-portlet.war   -> 1sample-struts-portlet.war
 sample-jsp-portlet.war -> 1sample-jsp-portlet.war

Drawbacks and alternatives #

The main drawback of this solution is that it will not be possible to have different versions of the same library in two different portlet applications. Also those libraries already included in Liferay such as Spring, Struts, Apache Commons, etc must be used by the portlet applications which won't be able to provide their own.

The only alternative to this solution is to use the liferay-client.jar API.

0 Allegati
60266 Visualizzazioni
Media (2 Voti)
La media del punteggio è 3.5 stelle su 5.
Commenti
Commenti Autore Data
Would alternative 3 for Glassfish be the same... Diane Lowe 12 marzo 2009 16.24
Hello! Hoy could you do this for Oracle... Manuel de la Peña 4 dicembre 2009 0.08
Hello, how we can use apis in Liferay 5.2.3?... Carlos Sanchez Ruiz 24 febbraio 2010 8.23
And what about glassfish? Krzysztof Makowski 23 marzo 2010 9.05
Thanks for this wiki! It helped me a lot. It... Krzysztof Makowski 26 aprile 2010 6.33
This approach does not work on Liferay 6.0 When... Matvey Kazakov 6 luglio 2010 6.23
i have same problem, now can work in Liferay 6.0? kan kan 5 settembre 2010 23.25
There is a workaround:... Igor Popik 29 settembre 2010 8.34
We are developing struts-portlet on glassfish,... Dat Thien Ngo 21 luglio 2010 18.55
We are working with liferay 5.2.3 on glassfish. Dat Thien Ngo 21 luglio 2010 18.55
I had tried to write a classloader, insert it... Dat Thien Ngo 21 luglio 2010 18.56
Has anybody done it using Jboss 5.x??? mikel basabe 22 luglio 2011 5.46

Would alternative 3 for Glassfish be the same or similar to the how-to for Tomcat?
Inviato il 12/03/09 16.24.
Hello! Hoy could you do this for Oracle Application Server??

Many thanks!
Inviato il 04/12/09 0.08.
Hello, how we can use apis in Liferay 5.2.3?
Thanks!!
Inviato il 24/02/10 8.23.
And what about glassfish?
Inviato il 23/03/10 9.05.
Thanks for this wiki! It helped me a lot. It would be great if someone could add info how to access full liferay api in jboss 5.x this version of Jboss handle class loading configuration in different way.
Inviato il 26/04/10 6.33.
This approach does not work on Liferay 6.0
When we hot-deploy portlet everything works just fine.
But as soon as Liferay is restarted Catalina starts loading portlet WARs in alphabetical order and portlets with names lower than ROOT could not start with the message:

INFO: Deploying configuration descriptor bar-portlet.xml
Jul 6, 2010 12:55:42 PM com.liferay.portal.kernel.log.Jdk14LogImpl error
SEVERE: Portal class loader is not available to override the default Catalina web class loader
Jul 6, 2010 12:55:42 PM org.apache.catalina.core.StandardContext start
SEVERE: Error listenerStart
Jul 6, 2010 12:55:42 PM org.apache.catalina.core.StandardContext start
SEVERE: Context [/bar-portlet] startup failed due to previous errors

So portlet is not available after restart.
Inviato il 06/07/10 6.23.
We are developing struts-portlet on glassfish, and it's painly difficult with the class-loader. There's no any well-documented document for developing struts-portlet on Liferay 5.2.3
Inviato il 21/07/10 18.55.
We are working with liferay 5.2.3 on glassfish.
Inviato il 21/07/10 18.55 in risposta a Dat Thien Ngo.
I had tried to write a classloader, insert it into the listener tag of web.xml within Liferay\WEB-INF. But not work.
Inviato il 21/07/10 18.56 in risposta a Dat Thien Ngo.
i have same problem, now can work in Liferay 6.0?
Inviato il 05/09/10 23.25 in risposta a Matvey Kazakov.
There is a workaround: http://www.liferay.com/community/forums/-/message_boards/message/4824410#_19_mes­sage_6014564
Inviato il 29/09/10 8.34 in risposta a Matvey Kazakov.
Has anybody done it using Jboss 5.x???
Inviato il 22/07/11 5.46.