This website uses cookies to ensure you get the best experience. Learn More.
Accessing Services in JSPs
When developing JSP-based portlets for OSGi deployment, and even when doing JSP fragment bundle overrides, it is often necessary to get service references in the JSP pages. But OSGi @Reference won't work in the JSP files, so we need ways to expose the services so they can be accessed in the JSPs...
So we're going to work this a little backwards, we're going to cover how to get the service reference in the JSP itself.
In order to get the references, we're going to use a scriptlet to pull the reference from the request attributes, similar to :
<% TrashHelper trashHelper = (TrashHelper) request.getAttribute(TrashHelper.class.getName()); %>
The idea is that we will be pulling the reference directly out of the request attributes. We need to cast the object coming from the attributes to the right type, and we'll be following the Liferay standard of using the full class name as the attribute key.
The challenge is how to set the attribute into the request.
So when you control the portlet code, injecting the service reference is pretty easy.
In your portlet class, you're going to add your @Reference for the service you need to pass. Your portlet class would include something along the lines of:
@Reference(unbind = "-") protected void setTrashHelper(TrashHelper trashHelper) { this._trashHelper = trashHelper; } private TrashHelper _trashHelper;
With the reference available, you'll then override the render() method to set the attribute:
@Override public void render(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { renderRequest.setAttribute(TrashHelper.class.getName(), _trashHelper); super.render(renderRequest, renderResponse); }
So this sets the service as an attribute in the render request. On the JSP side, it would be able to get the service via the code shared above.
So you may need to build a JSP fragment bundle to override JSP code, and in your override you need to add a service which was not injected by the core portlet. It would be kind of overkill to override the portlet just to inject missing services.
So how can you inject the services you need? A portlet filter implementation!
Portlet filters are similar to the old servlet filters, they are used to wrap the invocation of an underlying portlet. And, like servlet filters, can make adjustments to requests/responses on the way into the portlet as well as on the way out.
So we can build a portlet filter component and inject our service reference that way...
@Component( immediate = true, property = "javax.portlet.name=com_liferay_dictionary_web_portlet_DictionaryPortlet", service = PortletFilter.class ) public class TrashHelperPortletFilter implements RenderFilter { @Override public void doFilter(RenderRequest renderRequest, RenderResponse renderResponse, FilterChain filterChain) throws IOException, PortletException { filterChain.doFilter(renderRequest, renderResponse); renderRequest.setAttribute(TrashHelper.class.getName(), _trashHelper); } @Reference(unbind = "-") protected void setTrashHelper(TrashHelper trashHelper) { this._trashHelper = trashHelper; } private TrashHelper _trashHelper; }
So this portlet filter is configured to bind to the Dictionary portlet. It will be invoked at each portlet render since it implements a RenderFilter. The implementation calls through to the filter chain to invoke the portlet, but on the way out it adds the helper service to the request attributes.
So we've seen how we can use OSGi services in the JSP files indirectly via request attribute injection. In portlets we control, we can inject the service directly. For portlets we do not control, we can use a portlet filter to inject the service too.