Generating the Back-end
Step 2 of 3
The persistence layer saves and retrieves your model data. The service layer is a buffer between your application and persistence layers: having it lets you swap out your persistence layer for a different implementation without modifying anything but the calls in the service layer.
To model the guestbooks and entries, you’ll create guestbook and entry model classes. But you won’t do this directly in Java. Instead, you’ll define them in Service Builder, which generates your object model and maps it to all the SQL databases Liferay DXP supports.
This application’s design lets you create multiple guestbooks, each containing different sets of entries. All users with permission to access the application can add entries, but only administrative users can add guestbooks.
It’s time to get started. You’ll create the Guestbook
entity first:
-
In your
guestbook-service
project, openservice.xml
. -
When Liferay Developer Studio generated your project, it filled this file with dummy entities, which you’ll replace. First replace the file’s opening contents (below the
DOCTYPE
) with the following code:<service-builder auto-namespace-tables="true" package-path="com.liferay.docs.guestbook"> <author>liferay</author> <namespace>GB</namespace> <entity name="Guestbook" local-service="true" uuid="true">
This defines the author, namespace, and the entity name. The namespace keeps the database field names from conflicting. The last tag is the opening tag for the
Guestbook
entity definition. In this tag, you enable local services for the entity, define its name, and specify that it should have a universally unique identifier (UUID). -
Next, replace the PK fields section:
<column name="guestbookId" primary="true" type="long" />
This defines
guestbookId
as the entity’s primary key, of the typelong
. -
The group instance can be left alone.
<column name="groupId" type="long" />
This defines the ID of the site in Liferay DXP that the entity instance belongs to (more on this in a moment).
-
Leave the Audit Fields section alone. Add status fields:
<!-- Status fields --> <column name="status" type="int" /> <column name="statusByUserId" type="long" /> <column name="statusByUserName" type="String" /> <column name="statusDate" type="Date" />
The Audit section defines Liferay DXP metadata. The
companyId
is the primary key of a portal instance. TheuserId
is the primary key of a user. ThecreateDate
andmodifiedDate
store the respective dates on which the entity instance is created and modified. The Status section is used later to implement workflow. -
In the Other fields section, remove all the generated fields and put this one in their place:
<column name="name" type="String" />
-
Next, remove everything else from the Guestbook entity. Before the closing
</entity>
tag, add this finder definition:<finder name="GroupId" return-type="Collection"> <finder-column name="groupId" /> </finder>
This defines a finder that generates a
get
method you’ll use to retrieve Guestbook entities. The fields used by the finder define the scope of the data retrieved. This finder gets all Guestbooks by theirgroupId
, which corresponds to the site the application is on. This lets administrators put Guestbooks on multiple sites, and eachGuestbook
has its own data scoped to its site.
The Guestbook
entity is finished for now. Next, you’ll create the Entry
entity:
-
Add the opening entity tag:
<entity name="Entry" local-service="true" uuid="true">
As with the
Guestbook
entity, you enable local services, define the entity’s name, and specify that it should have a UUID. -
Add the tag to define the primary key and the
groupId
:<column name="entryId" primary="true" type="long" /> <column name="groupId" type="long" />
-
Add the audit fields as you did with the
Guestbook
entity:<column name="companyId" type="long" /> <column name="userId" type="long" /> <column name="userName" type="String" /> <column name="createDate" type="Date" /> <column name="modifiedDate" type="Date" />
-
Add status fields like you did for the guestbook:
<!-- Status fields --> <column name="status" type="int" /> <column name="statusByUserId" type="long" /> <column name="statusByUserName" type="String" /> <column name="statusDate" type="Date" />
-
Add the fields that define an
Entry
:<column name="name" type="String" /> <column name="email" type="String" /> <column name="message" type="String" /> <column name="guestbookId" type="long" />
The
name
,email
, andmessage
fields comprise anEntry
. These fields define the name of the person creating the entry, their email address, and the Guestbook message, respectively. TheguestbookId
is assigned automatically by code you’ll write, and is aGuestbook
foreign key. This ties theEntry
to a specificGuestbook
. -
Add your finder and closing entity tag:
<finder name="G_G" return-type="Collection"> <finder-column name="groupId" /> <finder-column name="guestbookId" /> </finder> </entity>
Here, you define a finder that gets guestbook entries by
groupId
andguestbookId
. As before, thegroupId
corresponds to the site the application is on. TheguestbookId
defines the guestbook the entries come from. This finder returns aCollection
of entries. -
Define your exception types outside the
<entity>
tags, just before the closing</service-builder>
tag:<exceptions> <exception>EntryEmail</exception> <exception>EntryMessage</exception> <exception>EntryName</exception> <exception>GuestbookName</exception> </exceptions>
These generate exception classes you’ll use later in try/catch statements.
-
Save your
service.xml
file.
Now you’re ready to run Service Builder to generate your model, service, and persistence layers!
-
In the Gradle Tasks pane on the right side of Developer Studio, open
guestbook-service
→build
. -
Run
buildService
by right-clicking it and selecting Run Gradle Tasks. Make sure you’re connected to the Internet, as Gradle downloads dependencies the first time you run it. -
In the Project Explorer, right-click the
guestbook-service
module and select Refresh. Repeat this step for theguestbook-api
module. This ensures that the new classes and interfaces generated by Service Builder show up in Developer Studio. -
In the Project Explorer, right-click the
guestbook-service
module and select Gradle → Refresh Gradle Project. Repeat this step for theguestbook-api
module. This ensures that your modules’ Gradle dependencies are up to date.
Service Builder is based on a design philosophy called loose coupling. It
generates three layers of your application: the model, the service, and the
persistence layers. Loose coupling means you can swap out the persistence layer
with little to no change in the model and service layers. The model is in the
-api
module, and the service and persistence layers are in the -service
module.
Each layer is implemented using Java Interfaces and implementations of those
interfaces. Rather than have one Entry
class that represents your model,
Service Builder generates a system of classes that include a Guestbook
interface, a GuestbookBaseImpl
abstract class that Service Builder manages,
and a GuestbookImpl
class that you can customize. This design lets you
customize your model, while Service Builder generates code that’s tedious to
write. That’s why Service Builder is a code generator for code generator haters.
Next, you’ll create the service implementations.