In an earlier learning path, you used Service Builder to generate the model, persistence, and service layers of your application. The services generated by Service Builder come in two flavors: local and remote. Local services, as their name implies, can only be invoked locally. This means that they are invoked from the JVM in which Liferay is running. Remote services can be invoked remotely. They are designed to be used by any web client that can access the services and is permitted to do so. The remote services generated by Service Builder are published as JSON web services when your application is deployed. You can also use Service Builder to generate a WSDL (Web Services Description Language) document for your remote services to make them available via SOAP (Simple Object Access Protocol). Please refer to the Service Builder tutorial for more information.
To specify whether Service Builder should generate local services, remote
services, or both, you need to add the appropriate entries to your application’s
service.xml
file. Open your guestbook-portlet project’s
docroot/WEB-INF/service.xml
file and examine the tags for the guestbook and
entry entities:
<entity name="Guestbook" local-service="true" uuid="true">
<entity name="Entry" local-service="true" uuid="true">
As described in the service.xml
DTD, local-service
defaults
to false
while remote-service
defaults to true
. However, it’s best to
specify explicitly whether Service Builder should generate local services and
remote services. Other developers who read your service.xml
file might not
know or remember the defaults. For this reason, add remote-service="true"
to
the entity tags of the guestbook and entry entities:
<entity name="Guestbook" local-service="true" remote-service="true" uuid="true">
<entity name="Entry" local-service="true" remote-service="true" uuid="true">
To examine the Liferay web services that are currently available on your portal,
navigate to [http://[host name]:[port number]/api/jsonws](http://[host name]:[port number]/api/jsonws) (http://localhost:8080/api/jsonws
if you’re running Liferay locally on port 8080). By default, the portal’s web
service methods are listed. Plugins, however, aren’t in this list, but you can
view the web services of a portlet application by changing the context path. For
example, to view the web services of the calendar portlet, change to context
path from /
to /calendar-portlet
. Notice that you can’t you change the
context path to /guestbook-portlet
. Why not? Because you haven’t added any
remote service methods to your remote service classes. After you’ve done this
and run Service Builder, your services will be available at /guestbook-portlet
on the JSONWS API page once you’ve redeployed your portlet.
In an earlier Learning Path, you learned that you expose access to the
persistence layer of your application by adding methods to the
*LocalServiceImpl
classes generated by Service Builder. In the
guestbook-portlet project, these classes are GuestbookLocalServiceImpl
and
EntryLocalServiceImpl
. Service Builder generates them initially, but after
that doesn’t touch them, because they’re designed for you to use to implement
your local service layer.
In a similar way, Service Builder generates *ServiceImpl
classes, which are
designed for you to implement your remote service layer. In the
guestbook-portlet project, these classes are GuestbookServiceImpl
and
EntryServiceImpl
. They’re already sitting there in your project, ready for you
to use. To get remote services working for the guestbook-portlet project, use
the following steps:
-
Create a new class in the
com.liferay.docs.guestbook.util
package calledActionKeys
. Add the following code to this class:package com.liferay.docs.guestbook.util; public class ActionKeys extends com.liferay.portal.security.permission.ActionKeys { public static final String ADD_ENTRY = "ADD_ENTRY"; public static final String ADD_GUESTBOOK = "ADD_GUESTBOOK"; }
The
ADD_ENTRY
andADD_GUESTBOOK
strings are used to reference the permissions that you defined in thedocroot/WEB-INF/src/resource-actions/default.xml
file in an earlier Learning Path. It’s a best practice to create strings to refer to your permissions in a class calledActionKeys
that extendscom.liferay.portal.security.permission.ActionKeys
.com.liferay.portal.security.permission.ActionKeys
contains strings that are used to refer to portal permissions. These include strings for common permissions such asVIEW
,UPDATE
,DELETE
, etc. -
Open the
GuestbookServiceImpl
class and add the following methods:public Guestbook addGuestbook(long userId, String name, ServiceContext serviceContext) throws SystemException, PortalException { return GuestbookLocalServiceUtil.addGuestbook(userId, name, serviceContext); } public Guestbook deleteGuestbook(long guestbookId, ServiceContext serviceContext) throws PortalException, SystemException { return GuestbookLocalServiceUtil.deleteGuestbook(guestbookId); } public List<Guestbook> getGuestbooks(long groupId) throws SystemException { return GuestbookLocalServiceUtil.getGuestbooks(groupId); } public List<Guestbook> getGuestbooks(long groupId, int start, int end) throws SystemException { return GuestbookLocalServiceUtil.getGuestbooks(groupId, start, end); } public int getGuestbooksCount(long groupId) throws SystemException { return GuestbookLocalServiceUtil.getGuestbooksCount(); } public Guestbook updateGuestbook(long userId, long guestbookId, String name, ServiceContext serviceContext) throws PortalException, SystemException { return GuestbookLocalServiceUtil.updateGuestbook(userId, guestbookId, name, serviceContext); }
Here, for each existing guestbook local service method, you’re adding a corresponding remote service method. For now, the remote service method implementations simply call the local service implementations. By Liferay convention, however, permission checking is added in remote service implementations, because users calling those services aren’t calling them from the app’s UI (which already has permission checks). Since they’re bypassing the UI and going directly to the services, you have to check to see if they have permission to access the data they’re trying to access before you give it to them. You’ll implement permission checking in the next section. For now, you just want to create remote services, confirm that they’re accessible, and confirm that they work.
-
Open the
EntryServiceImpl
class and add the following methods:public Entry addEntry(long userId, long guestbookId, String name, String email, String message, ServiceContext serviceContext) throws PortalException, SystemException { return EntryLocalServiceUtil.addEntry(userId, guestbookId, name, email, message, serviceContext); } public Entry deleteEntry(long entryId, ServiceContext serviceContext) throws PortalException, SystemException { return EntryLocalServiceUtil.deleteEntry(entryId, serviceContext); } public List<Entry> getEntries(long groupId, long guestbookId) throws SystemException { return EntryLocalServiceUtil.getEntries(groupId, guestbookId); } public List<Entry> getEntries(long groupId, long guestbookId, int start, int end) throws SystemException { return EntryLocalServiceUtil.getEntries(groupId, guestbookId, start, end); } public int getEntriesCount(long groupId, long guestbookId) throws SystemException { return EntryLocalServiceUtil.getEntriesCount(groupId, guestbookId); } public Entry updateEntry(long userId, long guestbookId, long entryId, String name, String email, String message, ServiceContext serviceContext) throws PortalException, SystemException { return EntryLocalServiceUtil.updateEntry(userId, guestbookId, entryId, name, email, message, serviceContext); }
Here, you’re doing the same thing for guestbook entries that you did for guestbooks in step 2. You’re simply creating skeleton remote service methods corresponding to existing local service methods. The remote service methods call the local service methods. You’ll add permission checks in the next section.
-
Run Service Builder (
ant build-service
) and redeploy the guestbook-portlet project.
Now, navigate to Liferay’s JSONWS page
([http://[host name]:[port number]/api/jsonws](http://[host name]:[port number]/api/jsonws))
and click on the Context Path selector. Notice that /guestbook-portlet
now
appears as an option. Select the /guestbook-portlet
context path and confirm
that your remote service methods appear in the list.
To test that your remote services are working, choose a method to invoke. Pick
a simple method that does not require a Service Context parameter, like
getGuestbooksCount(long groupId)
. One easy way to find the group ID of the
site to which you’ve added the Guestbook portlet is to use your browser’s
developer tools. Open your browser’s developer tools and open the JavaScript
console. Enter the following command into the JavaScript console:
Liferay.ThemeDisplay.getScopeGroupId();
Look for the scope group ID (the ID of the currently selected site) to appear in
the JavaScript console. Copy it to your system clipboard. Next, navigate to
[http://[host name]:[port name]/api/jsonws?contextPath=/guestbook-portlet](http://[host name]:[port name]/api/jsonws?contextPath=/guestbook-portlet) and click on the
get-guestbooks-count
method.
Paste the scope group ID that you copied into the group ID field and click Invoke. Confirm that the correct number of guestbooks is returned. Great! Your remote web services are working.
Next, you’ll build a WSDD (Web Service Deployment Descriptor) document for your
remote services to make them available via SOAP (Simple Object Access Protocol).
In Liferay IDE, open your guestbook-portlet project’s
docroot/WEB-INF/service.xml
file. Make sure that you’re viewing the
service.xml
file in Overview mode. Click on the Build WSDD button near the
top right corner of the Overview tab of service.xml
. Alternatively,
right-click on your guestbook-portlet project in the Package Explorer and select
Liferay → Build WSDD. When the Ant task finishes, notice that a
server-config.wsdd
file was created in your project’s WEB-INF
directory.
This deployment descriptor file describes the services and service methods that
your application is publishing.
After the Ant task has finished, re-deploy your guestbook-portlet application, then navigate to the following URL:
http://localhost:8080/guestbook-portlet/api/axis/Plugin_GB_GuestbookService?wsdl
This is a WSDL (Web Services Description Language) document that describes the details about the Guestbook service methods. Such details include, for example, the format of the data that can be sent to and received from the Guestbook web service methods. The following URL contains a similar WSDL document for the Guestbook Entry service:
http://localhost:8080/guestbook-portlet/api/axis/Plugin_GB_EntryService?wsdl
If you’d like to make your application’s services available for remote invocation, generating a WSDD and WSDL documents is an important step. The WSDL documents describe the functionality offered by your application’s web services. If you want to be able to create mobile clients that can access your application’s web services, you must generate WSDD and WSDL documents for your application.
Next, you’ll learn how to secure your web services. Unless you secure your web services by implementing permission checks, any user can add, update, or delete guestbooks or guestbook entries, and you certainly don’t want that.