These features and others are discussed in this section.
- Portlet filters
- Inter-portlet, event style, communication
- Allow portlets to produce and influence markup outside of the portlet fragment
web.xml configuration file, and can be mapped to individual servlets or particular URL patterns covering many servlets and/or other files. It is then the servlet container's responsibility to manage and apply the filters to any incoming request. Multiple filters can be applied to a single request - for example, a request might first be passed through a filter which replaced special markup in the response with HTML, and then a second filter which compressed the response before transmission.
Servlet filters deployed in a portlet application are not applied to portlets in that application. Filters are only applied to resources in that webapp which are served by the servlet container to a client; this never happens with portlets. Instead, the portlet classes are used directly by the Portal to generate their display.
JSR168 mentions portlet filters as a feature which will be defined in the next specification. The functionality provided by filters can currently be duplicated by other methods, such as having portlets inherit from a parent class with the required common features, or the workaround below.
Workaround A generic, JSR168-compliant, Filter Portlet has been implemented by Bridges project (currently part of Apache Jetspeed 2.0), which can provide similar functionality to servlet filters. This is done by registering the Filter portlet in the portlet.xml, and parameterising it with the name of the 'real' portlet class. The Filter portlet then acts as a wrapper around the real portlet.
Another option is to use aspect-oriented programming to intercept portlet methods and wrap them, which would be very similar to filters but differ in the method of configuration.
Portlet applications using either 'filter' replacement should be relatively easy to modify to support real portlet filters when it is time to upgrade to the next standard.
PortletSession.getAttributeNames(APPLICATION_SCOPE)
HttpServletRequest.getCookies(). There is no direct equivalent for this in the PortletRequest, however on some Portals the cookie Header value can be accessed using PortletRequest.getProperty("cookie"). This approach is not guaranteed to work reliably on all portals. According to PLT.11.1.4, this is due to differences in portals and servlet containers which may make the headers unavailable to portlets. JSR168 makes provision for this for some headers (such as content-length and content-type) by adding specific access methods in the PortletRequest interface, but unfortunately this was not done for cookies.
Hopefully the retrieval of cookies will be addressed in a later specification.
Workaround Some portals will allow the cookie to be retrieved using PortletRequest.getProperty("cookie"), but this cannot be relied upon.
Setting Cookies
Servlets can set cookies on the HttpServletResponse using either addCookie or setHeader. Neither is available to portlets on the PortletResponse or its subclasses.
A portlet cannot be expected to be able to set response headers during the render phase, as it can only affect its rendered page fragment. However, it should be theoretically possible for a portlet to set a cookie on an ActionResponse in the action phase (which occurs before any rendering takes place), as it is already possible to send a redirect header during this phase.
Hopefully a later specification will permit cookies to be set on an ActionResponse.
Workaround Without support in JSR168 for setting cookies as part of the response, it is necessary to resort to approaches which are more clumsy and fragile. One option is to set a cookie using JavaScript, which can be done by having the portlet generate the JavaScript as part of its rendered display - however this relies on JavaScript being enabled on the client. Another option is to add a servlet to the portlet application which sets a cookie when it is accessed. This servlet must be accessed directly by the client, not dispatched to through the portal, and so it must be loaded through an IFRAME or a popup window generated as part of the portlet display. Both approaches (JavaScript & servlet) have the disadvantage that the cookie is set only as a result of the client viewing an already-rendered portal page, so the cookie will only be available to portlets on subsequent requests.
ServletRequest.getRemoteAddr() or getRemoteHost(). This can be useful for limiting access by IP address or logging IPs associated with actions for admin or security purposes.
However, the PortletRequest classes do not provide an equivalent of these methods, and it is therefore not possible for a portlet to directly retrieve the client's IP address from the request as a servlet can. Nor can this be worked around by causing the portlet to dispatch to a servlet - JSR168 specifically prohibits the ServletRequest methods concerned from working in this context (PLT.16.3.3).
Workaround We have not found a good workaround for this issue. One possibility is to use a combination of servlets and cookies as described earlier, which would require support for reading cookies in portlets, an additional servlet in the portlet application, and at least one page render before the portlets would have access to the client IP.
portlet.xml deployment descriptor. PLT.5.1 specifies that only one actual instance of each portlet so defined will be created by the portlet container (or one per VM in the case of a distributed application). This single instance will be used to service any Action or Render requests targeted to that portlet.
However, the same portlet - with only one definition in the portlet.xml - can be placed in more than one place on a site, and often it is necessary for these different portlet entities to operate independently. For example, a 'Stocks' portlet might be configured to show a report for different stocks depending on the page; a portlet which could be pointed at any WSDL file to generate an interface to a web service might be present on different pages, providing access to web services appropriate to the page.
JSR168 defines a 'Portlet Window' as the combination of a portlet and its preferences on a portal page. It also states, "A portal page may contain more than one portlet window that references the same portlet and preferences-object." (PLT.5.2.3). The details of creating and managing portlet windows are left to the Portal and Portlet Container.
This leaves several aspects of the concept of a 'Portlet Window' undefined or ambiguous, including:
portlet.xml) to portlet window: adding a second portlet window for the same portlet will merely result in a mirroring of content from the first. In this case, multiple definitions in the portlet.xml for the 'same' portlet (merely differing in portlet name) must be added if multiple independent portlet windows are required.
The most flexible approach is to treat every portlet window on a page as an independent entity, with its own set of preferences, PORTLET_SCOPE session, and render state. This allows for an unlimited number of portlet windows associated with a single portlet definition, and is particularly well-suited to sites which give users the freedom to add portlets to their pages. This is the approach taken by Apache Jetspeed and Oracle Portal.
Intermediate approaches are also possible. For example, a portal might allow portlet windows from the same portlet definition to exist independently on different pages, but not on the same page.
Differences in portal behaviour on this subject do not significantly affect the process of developing portlets. They do affect the way the portlet deployment descriptor is written, and the way site designers and users add portlets to pages. For dynamic sites which allow users to create pages, the strict intepretation may not be sufficiently flexible, depending on the expected level of portlet reuse.
"TheThis behaviour is also described in PLT.3.1: Bridging from Portlets to Servlets/JSPs. This clearly allows for portlets and servlets in the same portlet application to easily work together, communicating through the shared session. The session may be used to send data (for example if the portlet wishes to delegate to a servlet to generate a binary file), or details of the logged-in user (which the servlet may use to confirm that the request has been suitably authenticated). However, there are implementation issues which mean that this behaviour is not found in some servlet container/portal setups. In such cases, a servlet which is accessed directly (e.g. one displayed in an IFRAME in a portlet, or in a new window) will not see the contents of the PortletSession, but instead its own separate HttpSession. This HttpSession is in fact the session associated with the portlet's (and the servlet's) webapp, whereas the PortletSession is associated with the Portal webapp, and these are kept separate following the Servlet 2.3 specification (SRV.7.3). Then, the only way the portlet can send information to the servlet is by appending URL query parameters, which may not be appropriate or possible for large amounts of data. If on the other hand the servlet is included in a portlet's output through the portal, using (in a portlet render method)PortletSessionmust store all attributes in theHttpSessionof the portlet application. A direct consequence of this is that data stored in theHttpSessionby servlets or JSPs is accessible to portlets through thePortletSessionin the portlet application scope. Conversely, data stored by portlets in thePortletSessionin the portlet application scope is accessible to servlets and JSPs through theHttpSession."
getPortletContext().getRequestDispatcher(jspPath).include(request, response), or (in a JSP included by the portlet) jsp:include, the session behaviour is correct as described in JSR168.
From testing with Jetspeed/Pluto on Tomcat 5.0 and the default configuration of 5.5, servlets accessed directly do not share the portlet session. In Tomcat 5.5 configured with emptySessionPath="true", behaviour is correct as described in the portlet specification.
HttpSession.getAttribute(name) v.s. PortletSession.getAttribute(name)). In addition, the problem may arise when using common libraries which do not (yet) provide a portlet version.
If this issue does not appear in many places, and the code can be modified, it may be acceptable to add a few duplicate functions that simply take different parameter types - however this is bad coding practice. Portal-specific solutions are sometimes suggested to obtain an object of the required class, using special knowledge of how to retrieve a particular object from a request, or by knowing which objects are safe to cast (e.g. Apache Pluto's portlet RenderRequest can be safely cast to a HttpServletRequest).
Our generic, JSR168-compliant solution was to write a number of simple wrappers or adapters, so that a Portlet object can masquerade as an HTTP Servlet object (or vice versa). For our requirements - mostly session access - this was sufficient, although this approach will clearly fail if an attempt is made to call a function which is not available on the underlying object. The only significant consideration when developing and using these wrappers was that the different scopes available in a PortletSession must be accounted for: when wrapping Portlet and Http sessions, it is necessary to specify whether the underlying session should be treated as a PORTLET_SCOPE or APPLICATION_SCOPE session.
----- Revision r1.6 - 07 Dec 2005 - 18:04 GMT - Main.MichelleOsmond
|