Guidelines for Writing JSR-168 Portletsby Drew Varner AbstractJSR-168 is a collection of Java APIs for portlet developers. There are a number of reasons to design JSR-168 portlets that adhere to the specification. Portability is an obvious benefit. Code written according to the specification will be easier to move to among portal servers. The majority of Java-based portal servers support JSR-168 portlets. Another benefit is easier federation. Exposing JSR-168 Portlets via Web Services for Remote Portlets (WSRP) producers is easier when portlets adhere to the JSR-168 specification. WSRP provides a standard to federate portlet content via Web services. JSR-168 and WSRP 1.0 portlet capabilities are tightly coupled. JSR-168 to WSRP portlet bridges utilize JSR-168's URL rewriting APIs. This article illustrates best practices for developing JSR-168 portlets for portability. 1. Always Utilize the URL Rewriting APIs for Content in Your PortletJava developers often write the URL to an image from a JSP like this: <img src="/<%= request.getContextPath()%>/images/logo.gif"/> This is incorrect in a JSR-168 portlet. The correct method is: <img src="<%= renderResponse.encodeURL(renderRequest.getContextPath()+
"/images/logo.gif") %>"/>
The 2. Do Not Append Paths to a Rewritten URLThe URL passed into The following call demonstrates the correct way to encode a URL to an image: <@= renderResponse.encodeURL(renderRequest.getContextPath()+
"/images/logo.gif")@>
It generates the following HTML fragment in BEA WebLogic Portal 9.2 using a <img src="http://localhost:7001/PortalWebApp/images/logo.gif;PORTAL_TAU=W3f6FbmLLcgZq9Fpv1JHLs5rrJG8Lgj2nnDVJqdfShhRGFnsqCKZ!-545815275"/> The following call is incorrect. The URL will not point to the intended resource. <@= renderResponse.encodeURL(renderRequest.getContextPath()+
"/images/")+"logo.gif"@>
It generates the following HTML fragment in WebLogic Portal 9.2 using a <img src="http://localhost:7001/PortalWebApp/images/;PORTAL_TAU=W3f6FbmLLcgZq9Fpv1JHLs5rrJG8Lgj2nnDVJqdfShhRGFnsqCKZ!-545815275logo.gif"/> 3. Qualify Client-side Script Variables and Methods with NamespacesLet's say you want to validate user input using JavaScript in your portlet. The following JavaScript function could be useful:
<script>
function validate(foo) {
if (foo.bar.value=="") {
return false;
}
return true;
}
</script>
It is possible that another portlet in the same page will also
have a JavaScript method named <%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%> The <script>
function validate<portlet:namespace/>(foo) {
if (foo.bar.value=="") {
return false;
}
return true;
}
</script>
Here is how you call the namespaced JavaScript method: <form action="http://www.somesite.org/servlet" method="GET" onsubmit="return validate<portlet:namespace/>(this);"> <label for="bar">Text(required): </label> <input type="text" name="bar" id="bar"> </form> 4. Ensure Inline Client-side Scripts that Refer to Portlet Resources Follow the SpecClient-side scripts often reference external resources (images, movies, external pages) to enhance the user interface. A common example is JavaScript that preloads images to make swapping images efficient. Here is an example:
<script>
function preloadImages(){
var menuImage =
new Image();
menuImage.src = "images/icon.gif";
var menuImageDark=new Image();
menuImageDark.src = "images/icon.gif";
}
</script>
URLs in these client-side scripts must be rewritten according to the JSR-168 specification. These scripts have to be in a JSP or JSR-168 portlet class to call the URL rewriting APIs. They cannot be in a standalone JavaScript (.js) file. Here is what a properly namespaced script with URL rewriting looks like in a JSR-168 portlet: <script>
function <portlet:namespace/>preloadImages(){
var menuImage = new Image();
menuImage.src = "<%=renderResponse.encodeURL(renderRequest.getContextPath()+ "images/icon.gif")%>";
var menuImageDark= new Image();
menuImageDark.src = "<%=renderResponse.encodeURL(renderRequest.getContextPath()+ "images/icon_dark.gif") %>";
}
</script>
5. Always Declare a Content Type for Portlet ResponsesAccording to the JSR-168 specification, "A portlet must set the
content type of the response using the This example demonstrates a portlet correctly setting its content type: public class MyPortlet extends GenericPortlet {
public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("<p>I set my content type!</p>");
}
}
This example is incorrect but will still compile: public class MyPortlet extends GenericPortlet {
public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
// no content type set!
PrintWriter writer = response.getWriter();
writer.println("<p>I did NOT set my content type!</p>");
}
}
6. Do Not Send Cookies from PortletsAccording to the JSR-168 portlet specification, calling If you'd like to persist information on a per-user basis while they are using the portal, you can persist the information as an attribute in the portlet's session. If you'd like to persist information after the user logs out, you can persist it in a data store (file system, database, LDAP, for example). 7. Separate Business Logic from PresentationExperienced developers know that model viewer controller frameworks like Struts or Beehive make development of rich Web applications easier. The same holds true for portlets. JSR-168 is not the only deal in town for platform-independent portlets. WSRP portlets are portable among portals that implement the standard including non-Java portals. WebLogic Portal can expose Beehive and Struts portlets via WSRP. If you are required to deploy portlets as JSR-168 WARs you still have options.
The simplest technique to separate business logic from presentation logic in a JSR-168
portlet is to dispatch to a JavaServer Page (JSP). The portlet handles business logic
in the rendering methods( public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
response.setContentType("text/html");
request.setAttribute("foo","bar");
String jsp = "/pages/portal.jsp";
PortletContext ctx = getPortletContext();
PortletRequestDispatcher dispatcher = ctx.getRequestDispatcher(jsp);
dispatcher.include(request, response);
}
The value of the path to the JSP ( JSR-168's dispatching methods allow separation of business logic and presentation. However, they lack the sophistication of mature MVC frameworks. Frameworks for JSR-168 development include: Struts Action 2 is a combination of Struts and WebWork, so the portlet codebases are nearly identical for now. These frameworks simplify the development and maintenance of complicated portlets. SummarySticking to these guidelines will keep your portlets in line with the JSR-168 specification. Adhering to the specification makes it easier to move your portlets among Java portal servers. It also makes it easier to federate your portal's content using WSRP. Resources
Drew Varner is a senior principal consultant in BEA's Federal Professional Services practice. He has spent the past two years working with defense and intelligence agencies on implementations, including JSR-168 and WSRP portal technologies. Return to dev2dev. Showing messages 1 through 10 of 10.
|
Article Tools Related Products Check out the products mentioned in this article:Bookmark Article
|