The ServiceContext class is a parameter class used for passing contextual information for a service. Using a parameter class lets you consolidate many different methods with different sets of optional parameters into a single, easier-to-use method. The class also aggregates information necessary for features used throughout Liferay’s core portlets, such as permissions, tagging, categorization, and more.

In this section, you’ll examine the Service Context fields, learn how to create and populate a Service Context, and learn to access Service Context data. First, let’s look at the fields of the ServiceContext class.

Service Context Fields

The ServiceContext class has many fields. The best field descriptions are found in the Javadoc:

http://docs.liferay.com/portal/6.2/javadocs/com/liferay/portal/service/ServiceContext.html.

Here, you can review a categorical listing of the fields:

  • Actions:
    • _command
    • _workflowAction
  • Attributes:
    • _attributes
    • _expandoBridgeAttributes
  • Classification:
    • _assetCategoryIds
    • _assetTagNames
  • IDs and Scope:
    • _companyId
    • _portletPreferencesIds
    • _plid
    • _scopeGroupId
    • _userId
    • _uuid
  • Language:
    • _languageId
  • Miscellaneous:
    • _headers
    • _signedIn
  • Permissions:
    • _addGroupPermissions
    • _addGuestPermissions
    • _deriveDefaultPermissions
    • _groupPermissions
    • _guestPermissions
  • Resources:
    • _assetEntryVisible
    • _assetLinkEntryIds
    • _createDate
    • _indexingEnabled
    • _modifiedDate
  • URLs, paths and addresses:
    • _currentURL
    • _layoutFullURL
    • _layoutURL
    • _pathMain
    • _portalURL
    • _remoteAddr
    • _remoteHost
    • _userDisplayURL

Are you wondering how the ServiceContext fields get populated? Good! We’ll show you that next.

Creating and Populating a Service Context

Although all the ServiceContext class fields are optional, services that store any kind of scopeable data need to at least specify the scope group ID. Here’s a simple example of creating a ServiceContext instance and passing it as a parameter to a Liferay service API using Java:

ServiceContext serviceContext = new ServiceContext();
serviceContext.setScopeGroupId(myGroupId);

...

BlogsEntryServiceUtil.addEntry(..., serviceContext);

If you invoke the service from a servlet, a Struts action, or any other front-end end class which has access to the PortletRequest, use one of the ServiceContextFactory.getInstance(...) methods. These methods create a ServiceContext object from the request and automatically populate its fields with all the values specified in the request. The above example looks different if you invoke the service from a servlet:

ServiceContext serviceContext =
    ServiceContextFactory.getInstance(BlogsEntry.class.getName(), portletRequest);

...

BlogsEntryServiceUtil.addEntry(..., serviceContext);

You can see an example of populating a ServiceContext with information from a request object in the code of the ServiceContextFactory.getInstance(...) methods. The methods demonstrate how to set parameters like scope group ID, company ID, language ID, and more. They also demonstrate how to access and populate more complex context parameters like tags, categories, asset links, headers, and the attributes parameter. By calling ServiceContextFactory.getInstance(String className, PortletRequest portletRequest), you can assure that your Expando bridge attributes are set on the ServiceContext. Expandos are the back-end implementation of custom fields for entities in Liferay.

Creating and Populating a Service Context in JavaScript

Liferay’s API can be invoked in languages other than Java, such as Beanshell, Groovy, JavaScript, Python, and Ruby. Some methods of Liferay’s API require or allow a ServiceContext parameter. If you’re invoking such a method via Liferay’s JSON web services, you might want to create and populate a ServiceContext object in JavaScript. Creating a ServiceContext object in JavaScript is no different from creating any other object in JavaScript.

Before examining a JSON web service invocation that uses a ServiceContext object, it helps to see a simple JSON web service example in JavaScript:

Liferay.Service(
    '/user/get-user-by-email-address`,
    {
        companyId: Liferay.ThemeDisplay.getCompanyId(),
        emailAddress: 'test@liferay.com`
    },
    function(obj) {
        console.log(obj);
    }
);

If you run this code, the test@liferay.com user (JSON object) is logged to the JavaScript console.

The Liferay.Service(...) function takes three arguments:

  1. A string representing the service being invoked
  2. A parameters object
  3. A callback function

The callback function takes the result of the service invocation as an argument.

The Liferay JSON web services page (its URL is localhost:8080/api/jsonws if you’re running Liferay locally on port 8080) generates example code for invoking web services. To see the generated code for a particular service, click on the name of the service, enter the required parameters, and click Invoke. The JSON result of your service invocation appears. There are multiple ways to invoke Liferay’s JSON web services: click on JavaScript Example to see how to invoke the web service via JavaScript, click on curl Example to see how to invoke the web service via curl, or click on URL example to see how to invoke the web service via a URL.

jsonws-simple-example.png

Figure 1: When you invoke a service from Liferay’s JSON web services page, you can view the result of your service invocation as well as example code for invoking the service via JavaScript, curl, or URL.

To learn more about Liferay’s JSON web services, please see the JSON Web Services tutorial.

For an example of how to create and populate a ServiceContext object in JavaScript and how to pass it as a parameter to a Liferay JSON web service invocation, please see the Sample JSONWS Portlet. All the Sample JSONWS portlet’s functionality is provided in its view.jsp file. The portlet displays a button that, when clicked, creates a new user by invoking Liferay’s JSON web services. Let’s examine the JSON web service invocation:

Liferay.Service(
    '/user/add-user',
    {
        companyId: Liferay.ThemeDisplay.getCompanyId(),
        autoPassword: false,
        password1: 'test',
        password2: 'test',
        autoScreenName: false,
        screenName: 'joe.bloggs',
        emailAddress: 'joe.bloggs@liferay.com',
        facebookId: 0,
        openId: '',
        locale: 'en_US',
        firstName: 'Joe',
        middleName: 'B',
        lastName: 'Bloggs',
        prefixId: 0,
        suffixId: 0,
        male: true,
        birthdayMonth: 1,
        birthdayDay: 1,
        birthdayYear: 1970,
        jobTitle: 'Tester',
        groupIds: null,
        organizationIds: null,
        roleIds: null,
        userGroupIds: null,
        sendEmail: false,
        serviceContext: {assetTagNames: ['test']}
    },
    function(obj) {
        console.log(obj);
    }
);

The Add User service requires a lot of parameters. The serviceContext parameter is optional. You can use it with the Add User service to specify tags to be applied to the user that’s being created. See the Javadoc of the service method for details: https://docs.liferay.com/portal/6.2/javadocs/com/liferay/portal/service/UserServiceUtil.html. In the example above, the serviceContext parameter specifies that the tag test should be applied to the user that’s being created.

To test the service invocation with the serviceContext parameter, deploy the Sample JSONWS Portlet, add it to a page, and click on the Create User button. Then navigate to the Control Panel, click on Users and Organizations, edit the newly created user, click on Categorization, and confirm that the specified tag has been applied.

jsonws-simple-example.png

Figure 2: To test invoking a Liferay JSON web service, deploy the Sample JSONWS Portlet, add it to a page, click on Create User, and confirm that the tag test has been applied to the newly created user.

Important: To invoke Liferay web services via JavaScript, your JavaScript context must include AlloyUI. In the Sample JSONWS Portlet, the JavaScript code in view.jsp was wrapped in the <aui:script use="node, event"> and </aui:script> tags. The node and event modules were required to implement the button. Only the base AUI is required to invoke a Liferay JSON web service. The <aui:script> tag was made available to the view.jsp page by this taglib import:

<%@ taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui" %>

If you’re not working in a JSP, you won’t have access to taglibs. In this case, you can create an Alloy context manually. For example,

AUI().use('aui-base', function(A){
    // Liferay service invocation here
});

Next, you’ll learn how to access information from a ServiceContext object.

Accessing Service Context Data

In this section, you’ll find code snippets from BlogsEntryLocalServiceImpl.addEntry(..., ServiceContext). This code demonstrates how to access information from a ServiceContext and provides an example of how the context information can be used.

As mentioned above, services for scopeable entities need to get a scope group ID from the ServiceContext object. This is true for the Blogs entry service because the scope group ID provides the scope of the Blogs entry (the entity being persisted). For the Blogs entry, the scope group ID is used in the following way:

  • It’s used as the groupId for the BlogsEntry entity.
  • It’s used to generate a unique URL for the blog entry.
  • It’s used to set the scope for comments on the blog entry.

Here are the corresponding code snippets:

long groupId = serviceContext.getScopeGroupId();

...

entry.setGroupId(groupId);

...

entry.setUrlTitle(getUniqueUrlTitle(entryId, groupId, title));

...

// Message boards

if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
    mbMessageLocalService.addDiscussionMessage(
        userId, entry.getUserName(), groupId,
        BlogsEntry.class.getName(), entryId,
        WorkflowConstants.ACTION_PUBLISH);
}

Can ServiceContext be used to access the UUID of the blog entry? Absolutely! Can you use ServiceContext to set the time the blog entry was added? You sure can. See here:

entry.setUuid(serviceContext.getUuid());
...
entry.setCreateDate(serviceContext.getCreateDate(now));

Can ServiceContext be used in setting permissions on resources? You bet! When adding a blog entry, you can add new permissions or apply existing permissions for the entry, like this:

// Resources

if (serviceContext.isAddGroupPermissions() ||
    serviceContext.isAddGuestPermissions()) {

    addEntryResources(
        entry, serviceContext.isAddGroupPermissions(),
        serviceContext.isAddGuestPermissions());
}
else {
    addEntryResources(
        entry, serviceContext.getGroupPermissions(),
        serviceContext.getGuestPermissions());
}

ServiceContext helps apply categories, tag names, and the link entry IDs to asset entries too. Asset links are the back-end term for related assets in Liferay.

// Asset

updateAsset(
    userId, entry, serviceContext.getAssetCategoryIds(),
    serviceContext.getAssetTagNames(),
    serviceContext.getAssetLinkEntryIds());

Does ServiceContext also play a role in starting a workflow instance for the blogs entry? Must you ask?

// Workflow

if ((trackbacks != null) && (trackbacks.length > 0)) {
    serviceContext.setAttribute("trackbacks", trackbacks);
}
else {
    serviceContext.setAttribute("trackbacks", null);
}

WorkflowHandlerRegistryUtil.startWorkflowInstance(
    user.getCompanyId(), groupId, userId, BlogsEntry.class.getName(),
    entry.getEntryId(), entry, serviceContext);

The snippet above also demonstrates the trackbacks attribute, a standard attribute for the blogs entry service. There may be cases where you need to pass in custom attributes to your blogs entry service. Use Expando attributes to carry custom attributes along in your ServiceContext. Expando attributes are set on the added blogs entry like this:

entry.setExpandoBridgeAttributes(serviceContext);

You can see that the ServiceContext can be used to transfer lots of useful information for your services. Understanding how ServiceContext is used in Liferay helps you determine when and how to use ServiceContext in your own Liferay application development.

Related Topics

Creating Local Service Classes

Invoking Local Services

Security and Permissions

0 (0 Votes)
Running Service Builder and Understanding the Generated Code Previous