Maven Trick to Split Liferay Services and Views

>> Tuesday, April 12, 2011

The Liferay Service-builder is a pretty cool development tool that allows you to easily generate a service and persistance layer for your Liferay portlets. Combined with Maven and the Liferay Maven Plugin (see my previous post), I can use the Service-builder with my favorite Java toys. There are some caveats though as the Service-builder pretty much forces you to have your service and model code in the same Maven/Eclipse project as your presentation code (the view/controller part of the equation). Or does it? The main problem is that Service-builder (and Liferay) expect resources such as service.xml and sql files to reside in the WEB-INF folder and not in the war's classpath.

Actually, the Maven WAR plugin has some features that make it possible and relatively easy to have the service and presentation resources reside in different Maven/Eclipse projects. When you build your portlet plugin, you simply tell the WAR plugin to merge or "overlay" the service module on top of the current WAR.

Here is how it works: Create a first Maven project with a packaging of type "war" to hold the presentation layer resources and classes (JSPs, Controllers, CSS, JS etc). This we will call the "Portlet Plugin". Create a second Maven project of type "war" to hold the service layer resources (the one generated by Service-builder and the ones you create otherwise). We will call this the "Service Module".

Now, in the Portlet Plugin POM file, specify a dependency on the Service Module war and lib files as in the fragment below.

  
<dependency>
 <!-- This dependency will get "overlayed"  -->
 <groupId>com.transcontinental.medias</groupId>
 <artifactId>transco-demo-liferay-service</artifactId>
 <version>${liferay-service-version}</version>
 <type>war</type>
 <scope>runtime</scope>
</dependency>

<dependency>
 <groupId>com.transcontinental.medias</groupId>
 <artifactId>transco-demo-liferay-service</artifactId>
 <version>${liferay-service-version}</version>
 <classifier>lib</classifier>
</dependency>


In the same POM, configure the WAR plugin so that it merges the depended upon war(s) with the current one as such:

<plugin>
 <artifactId>maven-war-plugin</artifactId>
 <configuration>
  <!-- Do not overlay undesired files -->
  <dependentWarExcludes>WEB-INF/web.xml,**/**.class</dependentWarExcludes>
  <webResources>
   <resource>
    <directory>src/main/webapp/WEB-INF</directory>
    <filtering>true</filtering>
    <targetPath>WEB-INF</targetPath>
   </resource>
  </webResources>
 </configuration>
</plugin>

Since the Portlet Plugin also depends on the jar file containing the service resources, the later gets added to the WEB-INF/lib folder. The trick to generate a jar file containing the services resources is to add the following fragment to the POM file of the service module.

<plugin>
 <!-- Build a JAR artifact containing the java classes and qualified -->
 <!-- by a 'lib' classifier so it gets installed alongside the war   -->
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-jar-plugin</artifactId>
 <executions>
  <execution>
   <phase>package</phase>
   <goals>
    <goal>jar</goal>
   </goals>
   <configuration>
    <classifier>lib</classifier>
   </configuration>
  </execution>
 </executions>
</plugin>


That's pretty much all there is to it. Build the projects in the right order or group them under a common parent POM project and you should be able to produce a deployable Liferay plugin (war) that is the result of overlaying the service module on the portlet module.

Have fun in the Maven lane...

Post a Comment

  © Blogger template Webnolia by Ourblogtemplates.com 2009

Back to TOP