« 返回到 Development (Legacy)

Access Liferay API from Portlet

标签: development

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 附件
105314 查看
平均 (2 票)
满分为 5,平均得分为 3.5。
评论
讨论主题回复 作者 日期
Would alternative 3 for Glassfish be the same... Diane Lowe 2009年3月12日 下午4:24
Hello! Hoy could you do this for Oracle... Manuel de la Peña 2009年12月4日 上午12:08
Hello, how we can use apis in Liferay 5.2.3?... Carlos Sanchez Ruiz 2010年2月24日 上午8:23
And what about glassfish? Krzysztof Makowski 2010年3月23日 上午9:05
Thanks for this wiki! It helped me a lot. It... Krzysztof Makowski 2010年4月26日 上午6:33
This approach does not work on Liferay 6.0 When... Matvey Kazakov 2010年7月6日 上午6:23
i have same problem, now can work in Liferay 6.0? kan kan 2010年9月5日 下午11:25
There is a workaround:... Igor Popik 2010年9月29日 上午8:34
We are developing struts-portlet on glassfish,... Dat Thien Ngo 2010年7月21日 下午6:55
We are working with liferay 5.2.3 on glassfish. Dat Thien Ngo 2010年7月21日 下午6:55
I had tried to write a classloader, insert it... Dat Thien Ngo 2010年7月21日 下午6:56
Has anybody done it using Jboss 5.x??? mikel basabe 2011年7月22日 上午5:46

Would alternative 3 for Glassfish be the same or similar to the how-to for Tomcat?
在 09-3-12 下午4:24 发帖。
Hello! Hoy could you do this for Oracle Application Server??

Many thanks!
在 09-12-4 上午12:08 发帖。
Hello, how we can use apis in Liferay 5.2.3?
Thanks!!
在 10-2-24 上午8:23 发帖。
在 10-3-23 上午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.
在 10-4-26 上午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.
在 10-7-6 上午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
在 10-7-21 下午6:55 发帖。
We are working with liferay 5.2.3 on glassfish.
在 10-7-21 下午6:55 发帖以回复 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.
在 10-7-21 下午6:56 发帖以回复 Dat Thien Ngo
i have same problem, now can work in Liferay 6.0?
在 10-9-5 下午11:25 发帖以回复 Matvey Kazakov
There is a workaround: http://www.liferay.com/community/forums/-/message_boards/message/4824410#_19_mes­sage_6014564
在 10-9-29 上午8:34 发帖以回复 Matvey Kazakov
Has anybody done it using Jboss 5.x???
在 11-7-22 上午5:46 发帖。