Creating services works the same in a JSF portlet as it would in any other standard WAR-style MVC portlet; generate custom services as separate API and Impl JARs and deploy them as individual modules to Liferay DXP. You can generate custom services for your JSF portlet using Service Builder. To learn more about how Service Builder works in Liferay DXP, visit the Service Builder tutorials.
The JSF WAR can then rely on the API module as a provided dependency. The main
benefit for packaging your services this way is to allow multiple WARs to
utilize the same custom service API without packaging it inside every WAR’s
WEB-INF/lib
folder. This practice also enforces a separation of concerns, or
modularity, between the UI layer and service layer of a system.
To call OSGi-based Service Builder services from your JSF portlet, you need a mechanism that gives you access to the OSGi service registry, because you can’t look up services published to the OSGi runtime using Declarative Services. Instead, you should open a ServiceTracker when you want to call a service that’s in the OSGi service registry.
To implement a service tracker in your JSF portlet, you can add a type-safe
wrapper class that extends org.osgi.util.tracker.ServiceTracker
. For example,
this is done in a demo JSF portlet as follows
public class UserLocalServiceTracker extends ServiceTracker<UserLocalService, UserLocalService> {
public UserLocalServiceTracker(BundleContext bundleContext) {
super(bundleContext, UserLocalService.class, null);
}
}
After extending the ServiceTracker
, just call the constructor and the service
tracker is ready to use in your managed bean.
In a managed bean, whenever you need to call a service, open the service
tracker. For example, this is done in the same demo JSF portlet to open the
service tracker, using the
@PostContruct
annotation:
@PostConstruct
public void postConstruct() {
Bundle bundle = FrameworkUtil.getBundle(this.getClass());
BundleContext bundleContext = bundle.getBundleContext();
userLocalServiceTracker = new UserLocalServiceTracker(bundleContext);
userLocalServiceTracker.open();
}
Then the service can be called:
UserLocalService userLocalService = userLocalServiceTracker.getService();
...
userLocalService.updateUser(user);
When it’s time for the managed bean to go out of scope, you must close the
service tracker using the
@PreDestroy
annotation:
@PreDestroy
public void preDestroy() {
userLocalServiceTracker.close();
}
For more information on service trackers and how to use them in WAR-style portlets, see the Service Trackers tutorial.