Create your own portlet service
Writing a portlet service consists of four steps:
- Defining the interface
- Writing the service implementation
- Avoid using the destroy method and
PortletServiceDefaultFactory
- Writing the service's factory
- Registering the service
Defining the interface
This step is not required if you want to implement your service against an existing interface. Defining a portlet service interface requires the same careful considerations as defining any public API interface. A portlet service interface must extend the PortletService interface defined in the org.apache.jetspeed.portlet.service package. The following is an example interface for the HelloWorldService .
package my.portlet.service; import org.apache.jetspeed.portlet.service.*; public interface HelloWorldService extends PortletService { // my service's method public String sayIt(); }
Writing the service implementation
The service implementation must implement the PortletServiceProvider interface of the org.apache.jetspeed.portlet.service.spi package to be able to make use of the portlet service life cycle methods in addition to your service interface. The PortletServiceConfig parameter of the init() method allows you, for example, to access the configuration of the service (see Registering the service for more information.
package my.portlet.service.impl; import org.apache.jetspeed.portlet.service.*; import org.apache.jetspeed.portlet.service.spi.*; public class HelloWorldServiceImpl implements HelloWorldService, PortletServiceProvider { private String it = null; public void destroy() { // do nothing - no resources in use } public void init(PortletServiceConfig config) { it = config.getInitParameter("MY_MESSAGE"); if (it == null) it = "Hello world!!!"; } public String sayIt() { return it; } }
Avoid using the destroy method and
PortletServiceDefaultFactory
The destroy method allows custom portlet services to clean up resources when they are released. Portlet services should not use this method of releasing resources anymore, because it can delay the release of resources for a long time; instead, resources should be released by explicit release calls to the service.
Furthermore, those custom portlet services that do not follow a singleton pattern should not be configured to use the factory class com.ibm.wps.pe.pc.legacy.service.PortletServiceDefaultFactory, but the new class com.ibm.wps.pe.pc.legacy.service.PortletServiceSimpleFactory instead. Note that the destroy method will not be called for services loaded by this factory.
This does not apply to singleton services that use the factory class com.ibm.wps.pe.pc.legacy.service.PortletServiceCacheFactory, such as the content access service and the credential vault service provided by WebSphere Portal.
If at all possible, do not write code like this:
class FooServiceImpl implements FooService, PortletServiceProvider { Foo myFoo public void init(PortletServiceConfig cfg) { myFoo = FooResource.acquireNew(); } public void destroy() { FooResource.release(myFoo); } }Instead, rename the destroy method to release and add it to the service interface:
class FooServiceImpl implements FooService, PortletServiceProvider { Foo myFoo public void init(PortletServiceConfig cfg) { myFoo = FooResource.acquireNew(); } public void release() { FooResource.release(myFoo); } public void destroy() {} }In your portlets, always explicitly call the release method:
FooService service = null; try { service = (FooService) context.getService(FooService.class); // ... do something with the service ... } finally { if (service != null) service.release(); }
Writing the service's factory
This step is not required if you want to reuse an existing service factory. Usually you will not have to write a factory of your own as there are two generic factories being shipped with the portal server in the com.ibm.wps.pe.pc.legacy.service package. The PortletServiceDefaultFactory always returns a new instance of a given service and the PortletServiceCacheFactory always returns the same instance of a given service. Use one of these factories rather than implementing your service as a singleton. Factories have to implement the PortletServiceFactory interface of the org.apache.jetspeed.portlet.service.spi package.
The following is the factory class for HelloWorldService:
package my.portlet.service.factory; import org.apache.jetspeed.portlet.service.*; import org.apache.jetspeed.portlet.service.spi.*; public class HelloWorldServiceFactory implements PortletServiceFactory { PortletServiceProvider psp = null; public PortletService createPortletService(Class service, Properties serviceProperties, ServletConfig servletConfig) throws PortletServiceUnavailableException { if (psp != null) { return psp; } else { psp = new HelloWorldServiceImpl(); psp.init(new PortletServiceConfigImpl( service, serviceProperties, servletConfig)); return psp; } } }
Registering the service
- Put the portlet service classes into a JAR file.
- Place the JAR file in the wp_root/shared/app directory.
- Add the JAR file to the application server's WPSLib shared library. You can edit WPSLib in the Administrative Console by selecting Environment Shared Libraries WPSLib.
- Update the PortletServiceRegistryService.properties file in the wp_root/shared/app/config/services directory to register the new service:
- Register the implementation as the corresponding service type
- Register the factory for the implementation
- Provide configuration parameters for the implementation
See the following example:
org.apache.jetspeed.portlet.service.default.factory = com.ibm.wps.pe.pc.legacy.service.PortletServiceDefaultFactory ... my.portlet.service.HelloWorldService = my.portlet.service.impl.HelloWorldServiceImpl my.portlet.service.impl.HelloWorldServiceImpl.factory = my.portlet.service.factory.HelloWorldServiceFactory my.portlet.service.impl.HelloWorldServiceImpl.MY_MESSAGE = Hello World (properties)! ...
See also