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:
- A string representing the service being invoked
- A parameters object
- 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.
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.
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 theBlogsEntry
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.