
Understanding ServiceBuilder and JavaScript for Liferay
Introduction #
ServiceBuilder is a tool included with Liferay that can be used to build Java services that can be accessed in a variety of ways. That includes, local access from Java code, remote access using web services, etc. This article explores a new possibility introduced in Liferay 4.3: accessing the services from a browser using JavaScript.
The articles is targeted to developers that want to extend Liferay and thus uses the Liferay development environment in the instructions. To follow them you'll have to download Liferay's sourcecode from the downloads section of www.liferay.com or from Sourceforge's subversion repository. The article will refer the directory with the sources as {Liferay-home}
Getting Started #
Let’s start at the {Liferay-home}/portal-impl directory. As of Liferay Portal 4.3.1, it should look like this:
build.xml is the build file for Ant. Opening this file, you’ll see a section with several targets (do a search for “build-service-portlets”):
You can see that there are several entries of the variation “target=build-service-portlet-”; these are ant targets.
What Are Ant Targets? #
Ant targets are just shortcuts for ant commands. For example, if you wanted to run all of the commands in the block above, you could type:
ant build-service-portlet†
instead of doing each one individually. You can, of course, also run each of the individual ant targets.
†Make sure you’ve opened a terminal / cmd prompt and navigated to {Liferay home}/portal-impl
Running Ant #
We’re going to focus on the tags functionality for now, which will use the build-service-portlet-tags command.
Run:
ant build-service-portlet-tags
and you should get this output:
image:Build-service-output.gif
If you’re successful, you’ll know you’re in the right directory and have ant set up correctly.
Generating Files #
Next we’re going to actually make ServiceBuilder do some work.
Go to your file system and open up
{Liferay-home}/portal-impl/src/com/liferay/portlet/tags/service/impl/
I’ve done this in tree view, so it looks like this:
We’re going to edit the file TagsAssetServiceImpl.java.
For each set of classes in an impl folder, you can think of the ServiceImpl class as the one that’s accessible to the “public,” whether that public means SOAP-based web services, REST style web services, or JSON access via JavaScript. ServiceImpl classes will contain several methods, the signatures of which will form the basis for generated code, including JavaScript calls.
Now go ahead and open TagsAssetServiceImpl.java and add the following method code just below the second method and before the closing brace:
public TagsAsset editAsset(long assetId) throws PortalException, SystemException {
return new TagsAsset; }
Now, don’t be confused by the fact that I’m calling this method “editAsset”; in fact that’s probably a bad example because we generally use “update” for methods that apply edits. Just take it as an example for now.
What we’re doing here is adding a new method to the ServiceImpl class. Right now the method itself doesn’t really do anything but it will have an effect on the ServiceBuilder output.
Now go back to your terminal / cmd prompt and run the ant command again. You should see the output below:
Basically what’s going on at this point is ServiceBuilder is generating new files for various services and adding support for the new method (editAsset) that we added. Notice that JSON is one of the services supported.
What happens if you run the ant command again? Well, now that the new method has already been added, your output will look like our initial output above (without the “Writing…” statements). This is true even if you edit the method contents, because the way you access the method (the method “signature”) has not changed. Of course, if you add more input variables to the method, the files will be re-generated.
Let’s go back to the tree structure and also open up TagsAssetLocalServiceImpl.java. You’ll notice there are a lot of different methods for doing stuff to TagsAsset objects. The idea is to use these methods as much as possible in the methods you write in your publicly-exposed TagsAssetServiceImpl class. For example, you may use the updateAsset() method in TagsAssetLocalServiceImpl in the body of the editAsset() method you added to TagsAssetServiceImpl.java.
JavaScript Access #
There’s something else we can check out at this point. If you open up SmartSVN (or whatever SVN client you use) and do a refresh, you should notice that several files have been changed:
This is what it looks like in my SmartSVN after a fresh update and running the ant build-service-portlet-tags command.
Notice that one of the affected files is service.js. What happens if you open up that file?
In my version of SmartSVN I can see a diff of the modified file against the original file in source control. It shows that a new method has been generated called editAsset, which is the name of the method I added to TagsAssetServiceImpl.java.
For JavaScript, this is what you can use to call the “editAsset” method from the presentation layer.
Another useful thing to read are the comments that are generated into every ServiceJSON.java file:
This class provides a JSON utility for the com.liferay.portlet.tags.service.TagsAssetServiceUtil service utility. The static methods of this class calls the same methods of the service utility. However, the signatures are different because it is difficult for JSON to support certain types.
ServiceBuilder follows certain rules in translating the methods. For example, if the method in the service utility returns a java.util.List, that is translated to a org.json.JSONArray. If the method in the service utility returns a com.liferay.portlet.tags.model.TagsAsset, that is translated to a org.json.JSONObject. Methods that JSON cannot safely use are skipped. The logic for the translation is encapsulated in com.liferay.portlet.tags.service.http.TagsAssetJSONSerializer.
This allows you to call the the backend services directly from JavaScript. See portal-web/docroot/html/portlet/tags_admin/unpacked.js for a reference of how that portlet uses the generated JavaScript in portal-web/docroot/html/js/service.js to call the backend services directly from JavaScript.
The JSON utility is only generated for remote services.
Using This In Actual Practice #
Hopefully the existing methods in the Local class for the functional area you’re working with has enough variations that you can get away with not adding any new methods there. If you need to add a new method to access the database, you'll need to learn how to work with Hibernate queries.