Creating Liferay portlet with liferay-maven-sdk

| 17 Comments | 1 TrackBack

This post will demonstrate how liferay-maven-sdk can be employed to build a Liferay portlet using Liferay's Service Builder feature. For this purpose we will create service-builder-portlet which is capable of displaying a list of players and adding a new player to this list. The model, persistence layer and data access services will be generated by Service Builder.
But first things first. Download and install  liferay-maven-sdk if you haven't done so already (have a look at  "Download and Install" page for instructions). Once liferay-maven-sdk is installed in your local repository, you can create the portlet.

So enter the folder (or create one) where you keep your portlets and execute

mvn archetype:generate

you should see a list of available archetypes starting with

Choose archetype:
1: local -> liferay-portlet-archetype (Liferay portlet archetype)
2: local -> liferay-theme-archetype (Liferay theme archetype)
3: internal -> appfuse-basic-jsf (AppFuse archetype for creating a web application with Hibernate, Spring and JSF)
4: internal -> appfuse-basic-spring (AppFuse archetype for creating a web application with Hibernate, Spring and Spring MVC)
...
Choose a number:  (1/2/3/4/...)  :1

Type 1 and press enter to choose liferay-portlet-archetype. Then provide groupId, artifactID, package and version. For example:

Define value for groupId: : com.commsen.liferay.examples.portlet.servicebuilder
Define value for artifactId: : service-builder-portlet
Define value for version:  1.0-SNAPSHOT: : 1.0
Define value for package:  com.commsen.liferay.examples.portlet.servicebuilder: :

Additionally you may execute 

mvn eclipse:eclipse

to setup Eclipse IDE if, that is what you are using! At this time your portlet skeleton is ready and you may compile it and even create WAR, but it of course does nothig special.

Let's now add data model and services. Create file service-builder-portlet/src/main/webapp/WEB-INF/service.xml :

<?xml version="1.0"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 5.2.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_5_2_0.dtd">

<service-builder package-path="com.commsen.liferay.examples.portlet.servicebuilder">
    <namespace>SB</namespace>
    <entity name="Player" local-service="true" remote-service="true">

        <!-- PK fields -->
        <column name="playerId" type="long" primary="true" />

        <!-- Other fields -->
        <column name="name" type="String" />
        <column name="active" type="boolean" />
        <column name="score" type="int" />
        <column name="birthday" type="Date" />
        <column name="description" type="String" />

        <!-- Order -->
        <order by="asc">
            <order-column name="name" />
        </order>

        <!-- Finder methods -->
        <finder name="ActivePlayers" return-type="Collection">
            <finder-column name="active" />
        </finder>
    </entity>
</service-builder>

The portlet projects created by liferay-portlet-archetype contain maven profile with lifray-maven-plugin’s build-service goal attached to generate-sources phase. To run ServiceBuilder you need to activate the profile:

mvn -P build-service package

If you read carefully the messages you will realize that service and persistence classes were generated in service-builder-portlet/src/main/java-service-api/ folder. Also there should be a few implementation files in service-builder-portlet/src/main/java/.

Now we'll add custom methods. Open the following file service-builder-portlet/src/main/java/com/commsen/liferay/examples/portlet/servicebuilder/service/impl/PlayerLocalServiceImpl.java and paste this code:

public void addPlayer(String name, boolean active, int score, Date birthday, String desc) throws PortalException, SystemException {

        long playerId = CounterLocalServiceUtil.increment();

        Player player = PlayerUtil.create(playerId);

        player.setName(name);
        player.setActive(active);
        player.setScore(score);
        player.setBirthday(birthday);
        player.setDescription(desc);

        PlayerUtil.update(player, false);
    }


    public List<Player> getAllPlayers() throws PortalException, SystemException {
        return PlayerUtil.findAll();
    }

We added methods to the implementation class. The next time we compile the code we need to activate the build-service profile again in order for Service Builder to react on the change and regenerate the API and interfaces. If you want to try it now simply execute

mvn -P build-service compile

Now we can start using these services in our portlet. Open service-builder-portlet/src/main/java/com/commsen/liferay/examples/portlet/servicebuilder/JSPPortlet.java and add this method

    @ProcessAction(name = Constants.ADD)
    public void addPlayer(ActionRequest actionRequest, ActionResponse actionResponse) throws PortletException, IOException {
        String name = ParamUtil.getString(actionRequest, "name");
        boolean active = ParamUtil.getBoolean(actionRequest, "active");
        int score = ParamUtil.getInteger(actionRequest, "score");
        String description = ParamUtil.getString(actionRequest, "description");
        int year = ParamUtil.getInteger(actionRequest, "birthday_year");
        int month = ParamUtil.getInteger(actionRequest, "birthday_month");
        int day = ParamUtil.getInteger(actionRequest, "birthday_day");

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.DAY_OF_MONTH, day);

        try {
            PlayerLocalServiceUtil.addPlayer(name, active, score, calendar.getTime(), description);
        } catch (Exception e) {
            throw new PortletException("Failed to add player", e);
        }
    }

This method handles adding players to database by calling the method we created earliar. To complete the portlet we only need the JSP page which displays the list and render HTML form to add users. The page source code is available here.

That's all! We can now create WAR file (mvn package) deploy it and add some players to our database!  For more details have a look at portlet's source code available in examples/service-builder-portlet folder of liferay-maven-sdk.

1 TrackBack

TrackBack URL: http://milen.commsen.com/cgi-bin/mt5/mt-tb.cgi/9

Liferay is the leading Open Source enterprise portal platform in the Java market. It's certainly an impressive piece of software. I've been following it for some time now and the product is improving a great deal in many areas, perhaps most in end user... Read More

17 Comments

I follow the steps you described and when i do 'mvn compile', here is what i get:

Building Player
[INFO] [resources:resources {execution: default-resources}]
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 8 resources
[INFO] [compiler:compile {execution: default-compile}]
[INFO] Compiling 16 source files to /Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/target/classes
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Compilation failure

/Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/src/main/java/com/commsen/liferay/examples/portlet/servicebuilder/service/impl/PlayerServiceImpl.java:[10,105] cannot find symbol
symbol : class PortalException
location: class com.commsen.liferay.examples.portlet.servicebuilder.service.impl.PlayerServiceImpl

/Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/src/main/java/com/commsen/liferay/examples/portlet/servicebuilder/service/impl/PlayerServiceImpl.java:[10,122] cannot find symbol
symbol : class SystemException
location: class com.commsen.liferay.examples.portlet.servicebuilder.service.impl.PlayerServiceImpl

/Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/src/main/java/com/commsen/liferay/examples/portlet/servicebuilder/service/impl/PlayerServiceImpl.java:[26,47] cannot find symbol
symbol : class PortalException
location: class com.commsen.liferay.examples.portlet.servicebuilder.service.impl.PlayerServiceImpl

/Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/src/main/java/com/commsen/liferay/examples/portlet/servicebuilder/service/impl/PlayerServiceImpl.java:[26,64] cannot find symbol
symbol : class SystemException
location: class com.commsen.liferay.examples.portlet.servicebuilder.service.impl.PlayerServiceImpl

/Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/src/main/java-service-api/com/commsen/liferay/examples/portlet/servicebuilder/service/PlayerService.java:[43,26] cannot find symbol
symbol : class Player
location: interface com.commsen.liferay.examples.portlet.servicebuilder.service.PlayerService

/Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/src/main/java-service-api/com/commsen/liferay/examples/portlet/servicebuilder/service/PlayerServiceUtil.java:[38,33] cannot find symbol
symbol : class Player
location: class com.commsen.liferay.examples.portlet.servicebuilder.service.PlayerServiceUtil

/Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/src/main/java-service-api/com/commsen/liferay/examples/portlet/servicebuilder/service/PlayerServiceClp.java:[65,26] cannot find symbol
symbol : class Player
location: class com.commsen.liferay.examples.portlet.servicebuilder.service.PlayerServiceClp

/Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/src/main/java/com/commsen/liferay/examples/portlet/servicebuilder/service/impl/PlayerServiceImpl.java:[14,24] cannot find symbol
symbol : variable PlayerUtil
location: class com.commsen.liferay.examples.portlet.servicebuilder.service.impl.PlayerServiceImpl

/Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/src/main/java/com/commsen/liferay/examples/portlet/servicebuilder/service/impl/PlayerServiceImpl.java:[22,8] cannot find symbol
symbol : variable PlayerUtil
location: class com.commsen.liferay.examples.portlet.servicebuilder.service.impl.PlayerServiceImpl

/Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/src/main/java/com/commsen/liferay/examples/portlet/servicebuilder/service/impl/PlayerServiceImpl.java:[27,15] cannot find symbol
symbol : variable PlayerUtil
location: class com.commsen.liferay.examples.portlet.servicebuilder.service.impl.PlayerServiceImpl

/Users/sulman/Documents/workspace-portlets/portlet1/service-builder-portlet/src/main/java-service-api/com/commsen/liferay/examples/portlet/servicebuilder/service/PlayerServiceClp.java:[89,31] cannot find symbol
symbol : class Player
location: class com.commsen.liferay.examples.portlet.servicebuilder.service.PlayerServiceClp


[INFO] ------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 15 seconds
[INFO] Finished at: Wed Oct 28 13:07:49 GMT 2009
[INFO] Final Memory: 20M/36M
[INFO] ------------------------------------------------------------------------

Any idea whats going on? Am i missing something here?

Sulman.

When using your archetype I get alot of lines like those below even though I have the artifacts in my local .m2/repository/. Is there a way to make that stop?

Downloading: http://repo1.maven.org/maven2/com/commsen/liferay/sdk/libraries/mail/5.2.3/mail-5.2.3.pom
[INFO] Unable to find resource 'com.commsen.liferay.sdk.libraries:mail:pom:5.2.3' in repository central (http://repo1.maven.org/maven2)


It's because the artifacts have no poms that the dependency checking keeps happening.

Looks like you need generatePom=true in all the install file goals

<execution>
<id>install ant</id>
<configuration>
<file>lib/ant.jar</file>
<groupId>com.commsen.liferay.portal.libraries</groupId>
<artifactId>ant</artifactId>
<version>5.2.3</version>
<packaging>jar</packaging>
<generatePom>true</generatePom>
</configuration>
<phase>install</phase>
<goals>
<goal>install-file</goal>
</goals>
</execution>

Hi there,

I tried the steps aove for my own portlet, but when I perform mvn package after I create the service.xml with my own stuff theres nothing create in my project, no java-service-api or anything else. What goes wrong?

greetz

When you call

mvn package
set the profile to "build-service". Inside pom.xml a default profile is set which is active by default. Set the profile "build-service" to default profile or call
mvn package -P build-service
After calling, there should be somenew classes inside your project.

Hi Milen

I did made conversion of your liferay-maven-sdk to Liferay 5.2 EE sp2, just by replacing from pom.mx 5.2.3 to 5.2-ee-sp2

update the libraries and liferay xml files.

It seems to work well. You made good design approach by making build and everyone can install those archetypes to their local repository. At LR-EE this is evenmore important.

Thanks for making my life easier.

- Sampsa

Hey, I'm using the maven-SDK coming from liferay 6.0 trunk, and I have the same issue as Christian does. The profile is activated, but it doesn't generate the classes all so that there is nothing to compile...no sources at all. I was trying to figure out what's going on from maven debug output but didn't help.

So there is an official maven-sdk for Liferay 6 and your un-official maven-sdk for Liferay 5.2.

Is there any links between the 2 ?
- Are they compatible ? (We will be able to upgrade without trouble ?)
- It is some kind of back-port or are they each starting from scratch ?

How could I decide if it is better to go for the official beta or the un-official release ??

Thanks

Hello Milen,

Thanks for a great sdk, great job! :)
However, I was wondering if it's possible to install sdk to internal repository, instead of the local repository? I have Sontaype Nexus repository configured and I'd like to put liferay-maven-sdk there the same way it's installed to my local repository.

mvn deploy
doesn't seem to do the trick, even though I do get some of the liferay-maven-sdk jars deployed. I'm still missing all the libraries (i.e. jars in portal/libraries and sdk/libraries folders). Am I missing something here? Or should I use
mvn install
with different kind of configuration to be able to install stuff to my internal repo (instead of the local repository)?

Thanks a million! ;)

Milen,
I tried what you suggested and voilĂ , it worked! ;) I simply copy-pasted the declaration of maven-install-plugin for each library pom files, changed install phase to deploy phase and ran mvn deploy. Now all the dependencies (including library jars) are sitting nicely in my nexus repo and my life just got a little easier :)

Leave a comment