Liferay Portal features a convenient code generation module that allows the developer to auto generate all of the "Model" components for a portlet. The business and persistance tier classes are auto generated based on specifications outlined in a file called service.xml. Each portlet can have its own service.xml where the portlet and each entity in the portlet are defined. A portlet entity is defined as a table specifying primary keys, audit fields, and other fields used in the table as well as any finder methods that will be required. Custom portlet exceptions can also be auto generated.
Below is an example service.xml file for the Bookmarks Portlet.
<?xml version="1.0"?> <!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 4.0.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_4_0_0.dtd"> <service-builder root-dir=".." package-path="com.liferay.portlet"> <portlet name="Bookmarks" short-name="Bookmarks" /> <entity name="BookmarksEntry" local-service="true" remote-service="true"> <!-- PK fields --> <column name="entryId" type="String" primary="true" /> <!-- Audit fields --> <column name="companyId" type="String" /> <column name="userId" type="String" /> <column name="createDate" type="Date" /> <column name="modifiedDate" type="Date" /> <!-- Other fields --> <column name="folderId" type="String" /> <column name="name" type="String" /> <column name="url" type="String" /> <column name="comments" type="String" /> <column name="visits" type="int" /> <!-- Order --> <order by="asc"> <order-column name="folderId" /> <order-column name="name" case-sensitive="false" /> </order> <!-- Finder methods --> <finder name="FolderId" return-type="Collection"> <finder-column name="folderId" /> </finder> <!-- References --> <reference package-path="com.liferay.portal" entity="Resource" /> </entity> <entity name="BookmarksFolder" local-service="true" remote-service="true"> <!-- PK fields --> <column name="folderId" type="String" primary="true" /> <!-- Group instance --> <column name="groupId" type="String" /> <!-- Audit fields --> <column name="companyId" type="String" /> <column name="userId" type="String" /> <column name="createDate" type="Date" /> <column name="modifiedDate" type="Date" /> <!-- Other fields --> <column name="parentFolderId" type="String" /> <column name="name" type="String" /> <column name="description" type="String" /> <!-- Order --> <order by="asc"> <order-column name="parentFolderId" /> <order-column name="name" case-sensitive="false" /> </order> <!-- Finder methods --> <finder name="GroupId" return-type="Collection"> <finder-column name="groupId" /> </finder> <finder name="G_P" return-type="Collection"> <finder-column name="groupId" /> <finder-column name="parentFolderId" /> </finder> <!-- References --> <reference package-path="com.liferay.portal" entity="Resource" /> </entity> <exceptions> <exception>EntryURL</exception> <exception>FolderName</exception> </exceptions> </service-builder>
Upon reading service.xml found in the Bookmarks portlet, the following model classes are generated. Each model class reflects a table in the database. Never edit BookmarksEntryModel. Do edit BookmarksEntry to add hand massaged code. BookmarksEntry is generated once and extends BookmarksEntryModel. This allows the ease of generated code and flexibility of hand massaged code.
Most of the EJBs, HBMs, and Models are generated through the ant task build-service, which reads the file service.xml in /portal-ejb. Each portlet that persist data has its own service.xml (do a search in /portal-ejb and you will get a list back). Copy this file to /portal-ejb when you want to generate the persistence classes for that portlet. This is an internal tool that is built on top of the XDoclet engine.
For example, upon reading service.xml found in the Bookmarks portlet, the following model classes are generated. Each model class reflects a table in the database. Never edit BookmarksEntryModel. Do edit BookmarksEntry to add hand massaged code. BookmarksEntry is generated once and extends BookmarksEntryModel. This allows you the ease of generated code and flexibility of hand massaged code.
com.liferay.portlet.bookmarks.model.BookmarksEntry
com.liferay.portlet.bookmarks.model.BookmarksEntryModel
com.liferay.portlet.bookmarks.model.BookmarksFolder
com.liferay.portlet.bookmarks.model.BookmarksFolderModel
Hibernate classes are generated that map to the model classes. This allows for an n-tier architecture for cases where your model classes are marshalled across the wire and your Hibernate classes are not.
com.liferay.portlet.bookmarks.service.persistence.BookmarksEntryHBM
com.liferay.portlet.bookmarks.service.persistence.BookmarksFolderHBM
Persistence methods to add, update, delete, find, remove, and count the Hibernate entries are generated as the default persistence mechanism.
com.liferay.portlet.bookmarks.service.persistence.BookmarksEntryPersistence
com.liferay.portlet.bookmarks.service.persistence.BookmarksFolderPersistence
Helper classes are generated that call the persistence methods. By default, the helper classes call the Hibernate persistence methods to update the database. You can override this in portal.properties and set your own persistence class as long as it extends the default persistence class. This means you can customize where you store your data. It can be a traditional database, a LDAP server, or even something else.
com.liferay.portlet.bookmarks.service.persistence.BookmarksEntryUtil
com.liferay.portlet.bookmarks.service.persistence.BookmarksFolderUtil
Pooling classes are also created to minimize object creation. Behavior can be modified in portal.properties.
com.liferay.portlet.bookmarks.service.persistence.BookmarksEntryPool
com.liferay.portlet.bookmarks.service.persistence.BookmarksFolderPool
POJO implementations that extend PrincipalBean are generated to hold business logic that check the caller principal and can be called remotely. Calling getUserId() returns the user id of the current user. Calling getUser() returns the User model that represents the current user. The Session EJB that extends the POJO implementation implements PrincipalSessionBean.
For example, these classes allow you to delete a bookmark entry or folder only if you are the creator of that entry or folder.
These classes are only generated once if they do not already exist.
com.liferay.portlet.bookmarks.service.impl.BookmarksEntryServiceImpl
com.liferay.portlet.bookmarks.service.impl.BookmarksFolderServiceImpl
Helper classes are generated based on the POJO implementations. They help save developer time and prevent polluted code. Instead of writing many lines of code just to look up the appropriate Session EJB wrapper or POJO implementation, you simply call BookmarksEntryServiceUtil.addEntry to call the equivalent method in BookmarksEntryServiceImpl.addEntry.
BookmarksEntryServiceUtil calls BookmarksFolderServiceFactory to look up the class that implements BookmarksEntryService. BookmarksFolderServiceFactory defers to Spring and settings in portal.properties on whether to load the Session EJB wrapper or the plain POJO implementation. The Session EJB extends the POJO implementation.
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryServiceEJB
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryServiceEJBImpl
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryServiceHome
com.liferay.portlet.bookmarks.service.spring.BookmarksEntryService
com.liferay.portlet.bookmarks.service.spring.BookmarksEntryServiceFactory
com.liferay.portlet.bookmarks.service.spring.BookmarksEntryServiceUtil
com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderServiceEJB
com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderServiceEJBImpl
com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderServiceHome
com.liferay.portlet.bookmarks.seervice.spring.BookmarksFolderService
com.liferay.portlet.bookmarks.service.spring.BookmarksFolderServiceFactory
com.liferay.portlet.bookmarks.service.spring.BookmarksFolderServiceUtil
Tunneling classes are generated so that developers can call the POJO implementations over port 80. An example of this is given in section V of this document.
com.liferay.portlet.bookmarks.service.http.BookmarksEntryServiceHttp
com.liferay.portlet.bookmarks.service.http.BookmarksFolderServiceHttp
Soap classes are generated so that developers can call the POJO implementations over port 80. Soap is slower than tunneling because tunneling streams request in binary format. Soap is more flexible than tunneling because the client classes are not limited to Java.
com.liferay.portlet.bookmarks.service.http.BookmarksEntryServiceSoap
com.liferay.portlet.bookmarks.service.http.BookmarksFolderServiceSoap
POJO implementations classes that do not extend PrincipalBean are generated to hold business logic that do not check the caller principal and can be called locally. These classes exist so that business logic can be easily integrated with other projects.
These classes are only generated once if they do not already exist.
com.liferay.portlet.bookmarks.service.impl.BookmarksEntryLocalServiceImpl
com.liferay.portlet.bookmarks.service.impl.BookmarksFolderLocalServiceImpl
Helper classes are also generated.
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryLocalServiceEJB
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryLocalServiceEJBImpl
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryLocalServiceHome
com.liferay.portlet.bookmarks.service.spring.BookmarksEntryLocalService
com.liferay.portlet.bookmarks.service.spring.BookmarksEntryLocalServiceFactory
com.liferay.portlet.bookmarks.service.spring.BookmarksEntryLocalServiceUtil
com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderLocalServiceEJB
com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderLocalServiceEJBImpl
com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderLocalServiceHome
com.liferay.portlet.bookmarks.service.spring.BookmarksFolderLocalService
com.liferay.portlet.bookmarks.service.spring.BookmarksFolderLocalServiceFactory
com.liferay.portlet.bookmarks.service.spring.BookmarksFolderLocalServiceUtil
Some of our users needed to call the Local Service classes remotely, so Remote Service classes that parallel their Local counterparts are also generated.
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryRemoteServiceEJB
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryRemoteServiceEJBImpl
com.liferay.portlet.bookmarks.service.ejb.BookmarksEntryRemoteServiceHome
com.liferay.portlet.bookmarks.service.spring.BookmarksEntryRemoteService
com.liferay.portlet.bookmarks.service.spring.BookmarksEntryRemoteServiceFactory
com.liferay.portlet.bookmarks.service.spring.BookmarksEntryRemoteServiceUtil
com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderRemoteServiceEJB
com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderRemoteServiceEJBImpl
com.liferay.portlet.bookmarks.service.ejb.BookmarksFolderRemoteServiceHome
com.liferay.portlet.bookmarks.service.spring.BookmarksFolderRemoteService
com.liferay.portlet.bookmarks.service.spring.BookmarksFolderRemoteServiceFactory
com.liferay.portlet.bookmarks.service.spring.BookmarksFolderRemoteServiceUtil