Maven makes it fairly easy to create a MyFaces portlet to deploy into Liferay. This document assumes you will be using Maven 2.0.4+ and Liferay 4.0.0+.

Create your POM file

You can use the Maven webapp archetype to create your project. Your POM file will need to look something like this at a minimum.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>test.myfaces</groupId>
  <artifactId>myfacesportlet</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>MyFaces Portlet</name>
  <url>http://maven.apache.org</url>
  <repositories>
    <repository>
         <releases>
           <enabled>true</enabled>
         </releases>
         <snapshots>
           <enabled>false</enabled>
         </snapshots>
         <id>myfaces.staging</id>
         <name>MyFaces Staging Repository</name>
         <url>http://myfaces.zones.apache.org/dist/maven-repository</url>
    </repository>
  </repositories>
  <dependencies>
    <dependency>
      <groupId>org.apache.myfaces.core</groupId>
      <artifactId>myfaces-api</artifactId>
      <version>1.1.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.myfaces.core</groupId>
      <artifactId>myfaces-impl</artifactId>
      <version>1.1.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.myfaces.tomahawk</groupId>
      <artifactId>tomahawk</artifactId>
      <version>1.1.3</version>
    </dependency>    
     <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>myfacesportlet</finalName>
  </build>
</project>

Set up your web app.

In src/main/webapp/WEB-INF/web.xml you'll need to set up all your MyFaces stuff the way you normally would. It seems easier to use prefix mapping for the FacesServlet:

        <servlet-mapping>
                <servlet-name>FacesServlet</servlet-name>
                <url-pattern>/faces/*</url-pattern>
        </servlet-mapping>

After creating your web application it's a good idea to test it in a standalone, non-portal container to make sure everything works.

Set up Logging

If you skip this step you will see the following in your Liferay Log when you try to deploy or access the portlet.

19:49:04,765 ERROR [org.apache.catalina.startup.HostConfig] Error deploying web application directory myfacesportlet
java.lang.NoSuchMethodError: org.apache.log4j.Category.log(Ljava/lang/String;Lorg/apache/log4j/Level;Ljava/lang/Object;Ljava/lang/Throwable;)V 
        at org.apache.commons.logging.impl.Log4JCategoryLog.error(Log4JCategoryLog.java:149)
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3733)
        at org.apache.catalina.core.StandardContext.start(StandardContext.java:4187)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:759)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:739)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:524)
        at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:904)
        at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:867)
        at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:474)
        at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1190)
        at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:292)
        at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
        at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1305)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1569)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1578)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1558)
        at java.lang.Thread.run(Thread.java:613)                                                                                    

To get rid of this exception create a commons-logging.properties file in src/main/resources and add the following to it:

org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger

Create Portlet and Liferay-specific Deployment Artifacts

Also, in src/main/webapp/WEB-INF you'll need to create 3 portal deployment files: portlet.xml, liferay-portlet.xml, and liferay-display.xml. They will be described below.

portlet.xml

This file is the standard Portlet deployment descriptor. The most important distinction is to set the MyFacesGenericPortlet as your portlet-class and make sure you set a default view.

<?xml version="1.0"?>

<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" 
    version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">
    
    <portlet>
        <portlet-name>myfaces_sample_portlet</portlet-name>
        <display-name>Myfaces Test</display-name>
        <portlet-class>org.apache.myfaces.portlet.MyFacesGenericPortlet</portlet-class>
        <expiration-cache>0</expiration-cache>
        <init-param>
                <name>default-view</name>
                <value>/index.jsp</value>
        </init-param>
        <supports>
            <mime-type>text/html</mime-type>
        </supports>
        <portlet-info>
            <title>Myfaces Test</title>
            <short-title>Myfaces Test</short-title>
            <keywords>Myfaces Test</keywords>
        </portlet-info>
        <security-role-ref>
            <role-name>power-user</role-name>
        </security-role-ref>
        <security-role-ref>
            <role-name>user</role-name>
        </security-role-ref>
    </portlet>

</portlet-app>

liferay-portlet.xml

This is the Liferay-specific portlet deployment descriptor. There is nothing special about this file except that it is required for Liferay to see your portlet.

<?xml version="1.0"?>
<!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 4.0.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_4_0_0.dtd">

<liferay-portlet-app>
    <portlet>
        <portlet-name>myfaces_sample_portlet</portlet-name>
        <instanceable>true</instanceable>
    </portlet>
    
    <role-mapper>
            <role-name>administrator</role-name>
            <role-link>Administrator</role-link>
    </role-mapper>
    <role-mapper>
            <role-name>power-user</role-name>
            <role-link>Power User</role-link>
    </role-mapper>
    <role-mapper>
            <role-name>user</role-name>
            <role-link>User</role-link>
    </role-mapper>
</liferay-portlet-app>

liferay-display.xml

This file tells Liferay how to make your portlet show up in its "Add Content" section so you can add it to your pages.

<?xml version="1.0"?>
<!DOCTYPE display PUBLIC "-//Liferay//DTD Display 4.0.0//EN" "http://www.liferay.com/dtd/liferay-display_4_0_0.dtd">

<display>
    <category name="category.test">
        <portlet id="myfaces_sample_portlet" />
    </category>
</display>

Build and Test

Again, it's a good idea to develop, build, and test your MyFaces portlet in a standalone container like Tomcat. This will ensure maximum portability. It will allow you to deploy your components in a standard web application or in a portal. Make sure you note the portal-specific development notes listed elsewhere.

Add Liferay Dependencies

You will need to add Liferay's util-jsf.jar file in the WEB-INF/lib directory of your application. This file is not available on any public Maven repository. You will either need to manually place it in a local repo or manually insert it into your WAR file.

Deploy Liferay WAR

Once you have a WAR file with all the dependencies as described in the previous step you can use Liferay's deployment process to deploy the portlet into a running Liferay instance. I used the following Ant script to accomplish this task:

<project basedir="." name="target-liferay-deploy-tomcat">
    <target name="deploy">
        <!-- Tomcat -->
        <property name="liferay.portal.home" value="${user.home}/liferay-portal-tomcat-jdk5-4"/>
        <property name="app.server.dir" value="${liferay.portal.home}" />
        <property name="app.server.deploy.dir" value="${app.server.dir}/webapps" />
        <path id="project.classpath">
            <pathelement location="${env.ANT_HOME}/lib/ant.jar" />
            <fileset dir="${app.server.dir}/common/lib/ext" />
            <pathelement location="${app.server.dir}/liferay/WEB-INF/lib/portal-ejb.jar" />
            <pathelement location="${app.server.dir}/liferay/WEB-INF/lib/util-java.jar" />
            <pathelement location="${app.server.dir}/liferay/WEB-INF/lib/dom4j.jar" />
            <pathelement location="${app.server.dir}/liferay/WEB-INF/lib/concurrent.jar" />
            <pathelement location="${app.server.dir}/liferay/WEB-INF/lib/trove.jar" />
            <pathelement location="${app.server.dir}/common/lib/servlet-api.jar" />
        </path>

        <java
            classname="com.liferay.portal.tools.PortletDeployer"
            classpathref="project.classpath"
            fork="true"
            newenvironment="true">

            <!-- Required Arguments -->
            <jvmarg value="-Ddeployer.base.dir=./" />
            <jvmarg value="-Ddeployer.dest.dir=${app.server.deploy.dir}" />
            <jvmarg value="-Ddeployer.app.server.type=tomcat" />
            <jvmarg value="-Ddeployer.portlet.taglib.dtd=${app.server.dir}/liferay/WEB-INF/tld/liferay-portlet.tld" />

            <!-- Optional Arguments -->
            <jvmarg value="-Ddeployer.unpack.war=true" />
            <jvmarg value="-Ddeployer.jboss.prefix=1" />
            <jvmarg value="-Ddeployer.tomcat.lib.dir=${app.server.dir}/common/lib/ext" />

            <!-- Dependent Libraries -->
            <arg value="${app.server.dir}/liferay/WEB-INF/lib/util-java.jar" />
            <arg value="${app.server.dir}/liferay/WEB-INF/lib/util-taglib.jar" />
        </java>
    </target>
</project>

Move your .WAR file into the directory where this ant script lives and type "ant deploy".

Log onto Liferay and test.

MavenLiferayPortlet (last edited 2009-09-20 23:00:53 by localhost)