Creating Remote Services with Service Builder

Creating Remote Services
Step 1 of 1

Earlier, you used Service Builder to generate the Guestbook’s model, persistence, and service layers. Services generated by Service Builder can come in two flavors: local and remote. The local services you already used can only be invoked locally from the same OSGi container. Remote services can be invoked by any application with permission to access your server via the web. Remote services are published as JSON or SOAP.

For more information, click here to see the Service Builder Web Services section of tutorials.

Creating web services for the Guestbook application takes two steps:

  1. Generate the web services with Service Builder.

  2. Expose the services you want and wrap them in permission checks.

There’s a level of security in the assumption that local services can only be called by other services in the container. For example, the web app does permission and validation checks before calling services. To access these services, developers must be able to deploy their modules on the server. You don’t have these assurances when you expose services to the web, so you must check for permission before calling a service.

But first you must tell Service Builder to generate web services. Follow these steps:

  1. Open service.xml from the guestbook-service module. Find the tags for the Guestbook and Entry entities:

    <entity name="Guestbook" local-service="true" uuid="true">
    
    <entity name="Entry" local-service="true" uuid="true">
    
  2. As described in the service.xml DTD, local-service defaults to false and remote-service defaults to true. It helps other developers who read your code to specify what services are generated. Therefore, 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">
    
  3. In the Gradle Tasks window on the right-hand side of Liferay Developer Studio, expand the service module’s build folder. Run Service Builder by double-clicking buildService. When Service Builder finishes, refresh the guestbook-api and guestbook-service modules in the Project Explorer.

You may be interested to know that Service Builder did absolutely nothing. Since remote services are generated by default, you’ve always had their stubs in your project. All you did was make it explicit in the code.

By implementing local services, you separated concerns. Local services can assume things like permission checks have already been done before they’re called. This separates the business logic from the permissions logic. If instead you implemented everything in the remote services, this separation wouldn’t exist.

You may see code from other developers, however, who didn’t implement the local service, and instead elected to place all their business and permission logic in the remote service. This works, but makes the code less readable. With the concerns separated, a business logic bug is contained in the local service, and a permissions bug is contained in the remote service.

To expose remote services, you’ll implement methods in the -ServiceImpl classes instead of the -LocalServiceImpl classes. Since the primary concern is permissions, however, first create a helper class to hold the permissions:

  1. In the src/main/java folder, create the new package com.liferay.docs.guestbook.util. In this new package, create this ActionKeys class:

    package com.liferay.docs.guestbook.util;
    
    public class ActionKeys extends
                    com.liferay.portal.kernel.security.permission.ActionKeys {
    
            public static final String ADD_ENTRY = "ADD_ENTRY";
            public static final String ADD_GUESTBOOK = "ADD_GUESTBOOK";
    }
    

    The ADD_ENTRY and ADD_GUESTBOOK strings reference the permissions defined in the guestbook-service module’s docroot/WEB-INF/src/resource-actions/default.xml file earlier in this Learning Path. It’s a best practice to create strings to refer to permissions in a class called ActionKeys that extends com.liferay.portal.kernel.security.permission.ActionKeys. The parent ActionKeys contains strings that are used to refer to portal permissions. These include strings for common permissions such as VIEW, UPDATE, DELETE, and so on.

  2. Add the following methods to the GuestbookServiceImpl class; then organize the imports by selecting SourceOrganize Imports:

    public Guestbook addGuestbook(long userId, String name,
        ServiceContext serviceContext) throws SystemException,
        PortalException {
    
        return guestbookLocalService.addGuestbook(userId, name, serviceContext);
    }
    
    public Guestbook deleteGuestbook(long guestbookId,
        ServiceContext serviceContext) throws PortalException,
        SystemException {
    
        return guestbookLocalService.deleteGuestbook(guestbookId, serviceContext);
    }
    
    public List<Guestbook> getGuestbooks(long groupId) throws SystemException {
            return guestbookLocalService.getGuestbooks(groupId);
    }
    
    public List<Guestbook> getGuestbooks(long groupId, int start, int end)
                    throws SystemException {
            return guestbookLocalService.getGuestbooks(groupId, start, end);
    }
    
    public int getGuestbooksCount(long groupId) throws SystemException {
            return guestbookLocalService.getGuestbooksCount();
    }
    
    public Guestbook updateGuestbook(long userId, long guestbookId,
        String name, ServiceContext serviceContext) throws PortalException,
        SystemException {
    
        return guestbookLocalService.updateGuestbook(userId, guestbookId,
            name, serviceContext);
    }
    

    These are stub remote service methods that expose each guestbook local service method. For now, the remote service method implementations call the local service implementations. Later, you’ll add permission checks to these methods, to wrap them in the same permissions you created in the UI. Service calls have no UI, so you must check for permission to access them. For now, you’re exposing the services to confirm they work and are accessible.

  3. Add the following methods to the EntryServiceImpl class, then organize the imports as you did in step 2:

    public Entry addEntry(long userId, long guestbookId, String name,
            String email, String message, ServiceContext serviceContext)
            throws PortalException, SystemException {
    
        return entryLocalService.addEntry(userId, guestbookId, name, email,
                     message, serviceContext);
    }
    
    public Entry deleteEntry(long entryId, ServiceContext serviceContext)
                    throws PortalException, SystemException {
    
        return entryLocalService.deleteEntry(entryId, serviceContext);
    }
    
    public List<Entry> getEntries(long groupId, long guestbookId)
                    throws SystemException {
    
        return entryLocalService.getEntries(groupId, guestbookId);
    }
    
    public List<Entry> getEntries(long groupId, long guestbookId, int start,
                    int end) throws SystemException {
    
        return entryLocalService.getEntries(groupId, guestbookId, start, end);
    }
    
    public int getEntriesCount(long groupId, long guestbookId)
                    throws SystemException {
    
        return entryLocalService.getEntriesCount(groupId, guestbookId);
    }
    
    public Entry updateEntry(long userId, long guestbookId, long entryId,
                    String name, String email, String message,
                    ServiceContext serviceContext) throws PortalException,
                    SystemException {
    
        return entryLocalService.updateEntry(userId, guestbookId, entryId,
                            name, email, message, serviceContext);
    }
    

    Like you did for guestbooks, you’ve now created method stubs for guestbook entries. Each method implemented here exposes a service to the web. You’ll add permission checks in the next section.

  4. Run Service Builder and refresh the API and service modules. Then redeploy the guestbook-* modules.

First, make sure you’re logged in as a user that can read guestbooks. Navigate to Liferay DXP’s JSONWS page (http://[host name]:[port number]/api/jsonws) and click the Context Name selector. The Guestbook app’s context, gb, appears as an option. Select it and confirm that your remote service methods appear in the list.

Figure 1: After youve added remote service methods to your projects *ServiceImpl classes, run Service Builder and redeploy your modules. Then check that your remote services are accessible.

Figure 1: After you've added remote service methods to your project's `*ServiceImpl` classes, run Service Builder and redeploy your modules. Then check that your remote services are accessible.

To test that your remote services work, choose a method to invoke. Pick a simple method that doesn’t require a Service Context parameter, like getGuestbooksCount(long groupId). To find the appropriate groupId (the ID of the site containing the Guestbook app), navigate to that site in your browser and select ConfigurationSite Settings from the Site Menu on the left. The site ID is listed at the top of the Site Settings page. Now return to the JSONWS page and enter the site ID into the group ID field and click Invoke. Confirm that the correct number of guestbooks is returned. Great! Your remote services work.

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).

Follow these steps to do so:

  1. In your Liferay workspace’s settings.gradle file, add imports for ServiceBuilderPlugin and WSDDBuilderPlugin before the buildscript block. Then add the gradle.beforeProject closure at the bottom of the file:

    import com.liferay.gradle.plugins.service.builder.ServiceBuilderPlugin
    import com.liferay.gradle.plugins.wsdd.builder.WSDDBuilderPlugin
    
    ...
    
    gradle.beforeProject {
        project ->
    
        project.plugins.withType(ServiceBuilderPlugin) {
            project.apply plugin: WSDDBuilderPlugin
        }
    }
    

    Refresh your workspace’s Gradle files: right click settings.gradle in the Project Explorer and select GradleRefresh Gradle Project.

  2. In the Gradle Tasks window on the right-hand side of Liferay Developer Studio, expand the service module’s build folder. Build the WSDD by double-clicking buildWSDD. If buildWSDD is missing, shut down your server and then restart Liferay Developer Studio. The buildWSDD command appears as described.

    The WSDD builder generates a WSDD JAR file in the guestbook-service module’s build/libs folder. Because this folder isn’t visible in Developer Studio, you must access it from the file system. The project’s modules are in the Eclipse workspace on the file system. Here’s the full file path to the WSDD JAR in your Eclipse workspace:

    com-liferay-docs-guestbook/modules/guestbook/guestbook-service/build/libs/com.liferay.docs.guestbook.service-wsdd-1.0.0.jar
    

    If this file is missing, run buildWSDD again to generate it.

  3. Deploy the WSDD JAR file to Liferay DXP, which is in the Liferay Workspace’s bundles folder. To do this, copy and paste the WSDD JAR file into this folder in your Eclipse workspace on your file system:

    com-liferay-docs-guestbook/bundles/deploy
    

    Return to Liferay Developer Studio and check the console to make sure deployment completes successfully.

  4. Go to http://[host name]:[port number]/o/com.liferay.docs.guestbook.service/api/axis in your browser to view the Guestbook app’s SOAP web services. If you’re running Liferay DXP locally on port 8080, this is http://localhost:8080/o/com.liferay.docs.guestbook.service/api/axis.

    This page contains links to the WSDL (Web Services Description Language) documents for the Guestbook and Entry remote service methods. WSDL files describe details about the remote service methods, including the type of data these methods require.

If you want to make your app’s services available for remote invocation via SOAP, generating WSDD and WSDL files is required. For example, the Liferay Mobile SDK relies on the WSDD and WSDL to discover your Liferay DXP app’s remote services. For the Liferay Mobile SDK to create a mobile client that can access your Liferay DXP app’s web services, you must therefore generate a WSDD and WSDL for your app.

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.

この記事は役に立ちましたか?
0人中0人がこの記事が役に立ったと言っています