NEW!! FREE MOCK EXAM SIMULATORS FOR IBM PORTAL TEST 399 & IBM PORTLET CERTIFICATION EXAM TEST 829!!!
Everything You Ever Wanted To Know About JSR-168 Portlet Development . . . PORTAL + TUTORIAL = www.portorials.com
Google

How do traversal permissions work with WebSphere Portal?

Please link to our site, support our site, and remember: Happy WebSphere!

Please support our site, link to us, buy some books, and remember: Happy Java!

Any preliminary look at the portlet API will demonstrate a major similarity between portlets and servlets. Both portlets and servlets handle the request-response cycle, both are Java centric components, and both have access to the J2EE runtime environment. But there are some major differences between portlets and servlets as well. One of the most significant ways portlets are different from regular servlets is their support for various modes, namely view, edit and help. When it comes to portlet modes, there is no applicable analogy to typical servlet and JSP programming. This chapter will look at the various modes available to the portlets you create, and how a developer can programmatically take advantage of these modes. Breaking Away from a Portlet as a Servlet Mentality Handling a request-response cycle is the most fundamental aspect of portlet programming, but inspecting a request and sending out a response to the client through a portlet is by no means revolutionary. After all, request-response programming is exactly what we do in a Java servlet. Let?s compare a Portlet to a Servlet: instead of a doView method, a Java Servlet has a doPost or a doGet method. Instead of being passed a PortletRequest or a PortletResponse object, a Java servlet is given an HttpServletRequest and HttpServletResponse object. In many ways, handling the request-response cycle of a portlet is very similar to handling the request-response cycle of a Servlet. In fact, one of the great things about portlets is the fact that they leverage our existing knowledge of the Servlet and JSP APIs. But what makes a portlet so incredibly sexy is all of the features and services the Portlet API affords us, over and above that of the Servlet API. The most fundamental difference between a Portlet and a Servlet is the various modes in which a Portlet can participate. A portlet has three standard, and any number of custom, implementable modes, namely: F The View Mode F The Edit Mode F The Help Mode The most common, and only required mode of a Portlet, is the view mode. When a Portlet is displayed on a page, it is typically displaying its view mode. In fact, the specification requires every portlet to have a doView method so that the portlet can render itself on a portal page. Optionally, a portlet can provide an implementation of any of the other standard modes, with perhaps the most useful mode being edit, and the most helpful, being help. J Figure 7-1The wrench, pencil, and question mark represent the config, edit and help modes of a portlet.Note that config is a custom mode. Basic Portlet Mode Implementation At the most basic level, to support the standard portlet modes, a portlet must implement a doEdit, doHelp, and doView method. Figure 7-2 ----------------------------------------------- package com.examscam.portlet; import java.io.*;import javax.portlet.*; public class MultiModePortlet extends GenericPortlet { protected void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { response.setContentType("text/html"); response.getWriter().print("This is the View mode."); } protected void doEdit(RenderRequest request, RenderResponse response) throws PortletException, IOException { response.setContentType("text/html"); response.getWriter().print("This is the Edit mode."); } protected void doHelp(RenderRequest request, RenderResponse response) throws PortletException, IOException { response.setContentType("text/html"); response.getWriter().print("This is the help mode."); } } Along with an implementation of the appropriate do <Mode> method, the deployment descriptor of the portlet must also indicate all of the modes the portlet supports. """ <portlet> <portlet-name>MultiModePortlet</portlet-name> <display-name>MultiModePortlet</display-name> <portlet-class> com.examscam.portlet.MultiModePortlet </portlet-class> <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> <portlet-mode>edit</portlet-mode> <portlet-mode>help</portlet-mode> </supports> <portlet-info> <title>MultiModePortlet</title></portlet-info> </portlet> """ Portlet Mode Visualization When the MultiModePortlet from Figure 7-2 is rendered by the portal, the skin of the view mode displays edit, help, minimize and maximize icons. Clicking on the question mark generates a pop-up window that displays the contents of the doView method. Clicking on the pencil takes a user into the edit mode of the portlet. The edit mode conveniently contains a caret icon that can return a user to the view mode. Help Mode and the doHelp Method The easiest portlet mode to implement has got to be the help mode. The help mode is designed to simply display to the user information about how to use the portlet. The help mode for the NumberGuesserPortlet will simply inform the user that they need to keep guessing a number until they get it right. Implementing the help mode simply requires the implementation of a doHelp method in your code and an update to the portlet.xml file to inform the portlet container that your Portlet supports the help mode. User Customization and the Edit Mode One of the main benefits of a portlet is the fact that it can be customized by a user. If you have gone to any of the mega portals like yahoo.com or excite.com, or have even installed the WebSphere Portal Server and played around with some of the Pinnacore portlets, you have inevitably run into a number of portlets you can customize by providing the portlet any number of personalized parameters. The ubiquitous weather portlet, the one that tells you the weather for three or four major international cities the first time you see it, but also gives you the ability to customize the portlet by telling it your ZIP code or the city in which you live, is a prime example of a customizable portlet. The weather portlet provides an edit mode that asks the user their zip code or city of interest. The portlet stores that information permanently, and then the next time the user views the weather portlet, it will additionally display the weather for the specified city or zip code of interest. The edit mode provides the user an opportunity to provide personal preferences to a portlet. That information is then used in the view mode to provide customized content delivery to the user. An edit mode provides a user the opportunity to customize a portlet. To handle these user requests for customizations, the portlet API matches the edit mode of a portlet, to the doEdit method of a developer?s portlet code. Figure 7-3 To implement the help and edit modes, a portlet needs a doHelp and doEdit method. """protected void doHelp(RenderRequest request, RenderResponse response) throws PortletException, IOException { response.setContentType("text/html"); response.getWriter().print("Just guess a number! "); }"""protected void doEdit(RenderRequest request, RenderResponse response) throws PortletException, IOException { String url = "/numberguesseredit.jsp" ; getPortletContext().getRequestDispatcher(url).include(request, response);}""" Edit Mode and PortletPreferences Any personal preferences provided to a portlet through the edit mode are stored permanently. The next time the user visits that portal page, this personalized information is retrieved for that user, and that user specific information can be utilized to provide a customized view for the user. As you could imagine, storing all of these user preferences persistently, and tying that data to a specific user and a specific portlet on a certain portal page is quite a bit of work. Fortunately, implementing this functionality is not shouldered by the portlet developer. Instead, the portlet API provides a very special component called the PortletPreferences object. While in the action processing phase of the edit mode of a portlet, a developer is allowed to stuff any number of Strings into the PortletPreferences object, using the very straightforward setValue(name, value) method. PortletPreferences prefs = request.getPreferences(); if (request.getParameter("guessedit") != null) { String newLimit = request.getParameter("newlimit"); prefs.setValue("upperlimit", newLimit); prefs.store(); } Any mode can access data stored in the PortletPreferences object, but only during the action processing phase of the edit mode can you actually change, add or update information stored as PortletPreferences. Store, Store, Store! When a developer stuffs a Java object into a portlet?s PortletData object, and subsequently calls the preferences.store() method, the data that was stuffed into the preferences object is stored persistently. A real rookie mistake is forgetting to call the store() method after shoving Strings into the PortletPreferences object. There is no design time type-checking to ensure the store method is called after working with the PortletPreferences object, so you really have to be diligent to ensure your preferences are stored permanently. Initialization of PortletPreferences: portlet.xml One of the challenges in working with the edit mode is initializing default values for PortletPreferences, or as it was known in the Jetspeed API, PortletData. With JSR-168, each portlet can configure any number of initial values by specifying them in the portlet-preferences section of the deployment descriptor. Furthermore, preferences can be multivalued, and stored as an array of Strings, as opposed to just single value Strings. Finally, PortletPreferences can be set as read-only. This essentially ensures that a given PortletPrefernce will be common to all users of the portlet. <portlet-preferences> <preference> <name>upperlimit</name><value>10</value> <read-only>false</read-only> </preference> </portlet-preferences> It should also be noted that in order for a portlet to support the edit mode, the portlet.xml file must have the appropriate entry for the portlet. Manipulating PortletPreferences is pretty much a moot endeavor if you haven?t specified in the deployment descriptor that the portlet supports the edit mode. <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> <portlet-mode>edit</portlet-mode> <portlet-mode>help</portlet-mode> </supports> PortletPreferences and the NumberGuesser So, how can we take our simple, NumberGuesserPortlet and complicate it to the n?th degree by adding user customization through PortletPreferences? Well, by default, the user guesses a number between 1 and 10. But perhaps we want the user to customize the experience by choosing a number between 1 and 100, or 1 and 1000? We could easily make the range customizable through a PortletPreference. Figure 7-6xxx Without preferences, our number guessing game always uses 10 as the upper limit. We could store a String value named upperlimit in the PortletPreferences object, and use the portlet.xml file to give this value a default of 10. <portlet-preferences> <preference> <name>upperlimit</name><value>10</value> <read-only>false</read-only> </preference> </portlet-preferences> When the user starts the number guessing game, we could use the upperlimit value, stored in the PortletPreferences, to generate the magic number. /*obtain the PortlePreferences object from the request*/ PortletPreferences prefs = request.getPreferences(); /*pull the upperlimit String from the preference*/ String upperLimit = prefs.getValue("upperlimit", null); /*use the upperLimit to generate the new random number to be guessed*/ long number =(System.currentTimeMillis()%Integer.parseInt(upperLimit))+1; /*put the new number in the session*/ session.setAttribute("magicnumber", new Long(number)); Figure 7-5 Updating the processAction method. public void processAction (ActionRequest request, ActionResponse response) throws PortletException, java.io.IOException {/* get the preferences and session from the request object */ PortletPreferences prefs = request.getPreferences();PortletSession session = request.getPortletSession();/* if we are in the edit mode, get the new range limit */ if (request.getParameter("guessedit") != null) { String newLimit = request.getParameter("newlimit"); prefs.setValue("upperlimit", newLimit); prefs.store();}/* Obtain application data from the session. */Long magicNumber = (Long) session.getAttribute("magicnumber");Long guess = new Long(request.getParameter("number"));String guesses = (String) session.getAttribute("guesses");String message = "Guess Higher!!!";/* If a number was guessed, see if it is correct */if (request.getParameter("guesssubmit") != null) { /* if the magicNumber is null, this is their first guess. */ if (magicNumber == null) { String upperLimit = prefs.getValue("upperlimit", null); /* use the range limit from preferences to calc the number */ long number = (System.currentTimeMillis()%Integer.parseInt(upperLimit)) + 1; session.setAttribute("magicnumber", new Long(number)); guesses = "1"; }else { guesses = "" + (Integer.parseInt(guesses) + 1); } if (guess.intValue() > magicNumber.intValue()) { message = "Guess Lower."; } if (guess.intValue() == magicNumber.intValue()) { message = magicNumber + " is correct. # of guesses: " + guesses; session.setAttribute("guesses","0"); session.removeAttribute("magicnumber"); }}/* appropriately set the message and guess number in the session */session.setAttribute("message", message);session.setAttribute("guesses", guesses);} Customization Through the Edit Mode Figure 7-7 The user sets an custom upper limit through the edit mode. While default values will be provided through the portlet.xml file, the user can change the range by using the edit mode of the portlet. The edit mode could be used to update the preference, allowing the user to set a range larger than 1 to 10. /*if the user clicked the button named guessedit from the edit page */ if (request.getParameter("guessedit") != null) { String newLimit = request.getParameter("newlimit"); prefs.setValue("upperlimit", newLimit); prefs.store(); } After updating their preferences through the edit mode, when the user returns to the view mode, all numbers will be generated based upon the new range, as set in PortletPreferences. An additional code snippet in the jsp allows the new upper range limit to be displayed to the user: <%=renderRequest.getPreferences() .getValue("upperlimit", null) %> Figure 7-8 Notice how the user has set the upper limit to 999, as opposed to the default of 10. Figure 7-9 Code used for the View JSP in this example. Notice how the message is coming from the PortletSession. <%@ page contentType="text/html"%><%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%><portlet:defineObjects /><%=renderRequest.getPortletSession().getAttribute("message")%><FORM action="<portlet:actionURL />">Pick a number between 1 and <%=renderRequest.getPreferences().getValue("upperlimit", null) %> <INPUT name="number" size="10" type="text" /> <INPUT name="guesssubmit" value="Guess!!" type="submit" /></FORM>Number of guesses:<%=renderRequest.getPortletSession().getAttribute("guesses")%> Fig 7-10 The JSP used for the Edit mode, numberguesseredit.jsp <%@ page contentType="text/html"%><%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%><portlet:defineObjects /> <FORM action="<portlet:actionURL />">Choose the range.<BR>The number will be between 1 and...<INPUT name="newlimit" size="10" type="text" /> <INPUT name="guessedit" value="Submit" type="submit" /></FORM> Figure 7-11 Full portlet.xml file. Notice the support for multiple modes, and the default value given for the upperlimit preference. <portlet> <portlet-name>NumberGuesser</portlet-name> <display-name>NumberGuesser portlet</display-name> <portlet-class> com.examscam.portlet.NumberGuesserPortlet </portlet-class> <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> <portlet-mode>edit</portlet-mode> <portlet-mode>help</portlet-mode> </supports> <portlet-info> <title>NumberGuesser portlet</title> </portlet-info> <portlet-preferences> <preference> <name>upperlimit</name> <value>10</value> <read-only>false</read-only> </preference> </portlet-preferences></portlet> Fig. 7-12 The doEdit method simply points to the edit.jsp. protected void doEdit (RenderRequest request, RenderResponse response) throws PortletException, IOException { String url = "/numberguesseredit.jsp" ; this.getPortletContext().getRequestDispatcher(url) .include(request, response);} Figure 7-11 NumberGuesser (Sorry it is so small, but I wanted it on one page) package com.examscam.portlet;import java.io.*;import javax.portlet.*;public class NumberGuesserPortlet extends GenericPortlet { protected void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { PortletContext context = this.getPortletContext(); PortletSession session = request.getPortletSession(); if (session.getAttribute("message") == null) { session.setAttribute("guesses", "0"); session.setAttribute("message", "Guess the number!"); } String url = "/numberguesser.jsp"; context.getRequestDispatcher(url).include(request, response); } protected void doHelp(RenderRequest request, RenderResponse response)throws PortletException, IOException { response.setContentType("text/html"); response.getWriter().print("You should be able to figure this out!!!"); } protected void doEdit(RenderRequest request, RenderResponse response) throws PortletException, IOException { String url = "/numberguesseredit.jsp"; getPortletContext().getRequestDispatcher(url).include(request,response); } public void processAction(ActionRequest request, ActionResponse response) throws PortletException, java.io.IOException { PortletSession session = request.getPortletSession(); /* obtain the PortlePreferences object from the request */ PortletPreferences prefs = request.getPreferences(); if (request.getParameter("guessedit") != null) { String newLimit = request.getParameter("newlimit"); prefs.setValue("upperlimit", newLimit); prefs.store(); } if (request.getParameter("guesssubmit") != null) { if (session.getAttribute("magicnumber") == null) { /* pull the upperlimit String from the preference */ String upperLimit = prefs.getValue("upperlimit", "3"); /* use the upperLimit to generate the new random number to be guessed */ int magicNumber = (int)((System.currentTimeMillis() % Integer.parseInt(upperLimit)) + 1); /* put the new number in the session */ session.setAttribute("magicnumber", new Integer(magicNumber)); session.setAttribute("guesses", "0"); } Integer magicNumber = (Integer)session.getAttribute("magicnumber"); String guesses = (String) session.getAttribute("guesses"); guesses = "" + (Integer.parseInt(guesses) + 1); session.setAttribute("guesses", guesses); session.setAttribute("message", "Guess higher!"); Integer guess = new Integer(request.getParameter("number")); if (guess.intValue() > magicNumber.intValue()) { session.setAttribute("message", "Guess lower!"); } if (guess.intValue() == magicNumber.intValue()) { String message = magicNumber + " is correct. Play again!"; session.setAttribute("message", message); session.removeAttribute("magicnumber"); } } }} Figure 7-9 The JSP used for the View mode, numberguesser.jsp <%@ page contentType="text/html"%><%@ taglib uri="http://java.sun.com/portlet" prefix="portlet"%><portlet:defineObjects /><%=renderRequest.getPortletSession().getAttribute("message")%><FORM action="<portlet:actionURL />">I'm thinking of a number between 1 and <%=renderRequest.getPreferences() .getValue("upperlimit", null) %><INPUT name="number" size="10" type="text" /> <INPUT name="guesssubmit" value="Guess!!" type="submit" /></FORM>Number of guesses:<%=renderRequest.getPortletSession().getAttribute("guesses")%> Fig 7-10 The JSP used for the Edit mode, numberguesseredit.jsp <%@ page contentType="text/html"%><%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%><portlet:defineObjects /> <FORM action="<portlet:actionURL />">Choose the range.<BR>The number will be between 1 and...<INPUT name="newlimit" size="10" type="text" /> <INPUT name="guessedit" value="Submit" type="submit" /></FORM>Upper Limit:<%=renderRequest.getPreferences().getValue("upperlimit", null)%> PortletPreferences and the PreferencesValidator Part of the JSR-168 API is a convenient interface called the PreferencesValidator. PortetPreferences provide the end user the ability to customize their user experience, but as with any type of input taken from a user, there is the possibility that data provided to the server won?t be valid for a particular scenario. To provide some level of control over how users configure a particular preference, a PreferencesValidator can be coded, and subsequently configured in the portlet.xml file. The PreferencesValidator has only one method that needs to be overridden: the validate(PortletPreferences prefs) method. The job of the developer is to code a custom class that implements this interface, and then configure the portlet.xml file, thus making the portal server aware of the validator. The contract between the portlet.xml file and the portal server ensures that before any data is saved into PortletPreferences, the validate method of the PreferencesValidator will be invoked. If validation fails, the validate method must throw the special ValidatorException, which is part of the JSR-168 Portlet API. To ensure that only numeric data is stored as an upper limit of the number guessing game, a class that implements the PreferencesValidator was coded, and configured in the portlet.xml file. PreferencesValidator and ValidatorException NumberGuesserValidator As you can see, the NumberGuesserValidator is relatively straight forward. The preference of interest, the upperlimit, is pulled from the preferences object passed into the validate method, and if the upperlimit field does not pass muster, then a ValidatorException is thrown. package com.examscam.portlet; import javax.portlet.*; public class NumberGuesserValidator implements PreferencesValidator { public void validate(PortletPreferences preferences) throws ValidatorException { try { String upperLimit = preferences.getValue("upperlimit", null); if (upperLimit != null) { Integer.parseInt(upperLimit); } } catch (NumberFormatException nfe) { throw new ValidatorException("upperlimit", nfe, null); } } } Catching PortletPreference Exceptions If you code a PreferencesValidator, it makes sense that you would then catch the corresponding ValidatorException in your portlet code; specifically, when you add new data to your PortletPreferences. Notice that there are actually three exceptions being handled in the following code snippet: """ if (request.getParameter("guessedit") != null) { String newLimit = request.getParameter("newlimit"); try { prefs.setValue("upperlimit", newLimit); prefs.store(); } catch (ValidatorException e) {e.printStackTrace(); } catch (ReadOnlyException e) {e.printStackTrace(); } catch (IOException e) {e.printStackTrace(); } } """ PortletPreference Related Exceptions PortletPreferences are typically stored in a centralized database, where the portal server can easily retrieve user customizations. Because the act of storing data to a database, or even just sending data across a network, can be problematic, the store method of the PortletPreferences object can potentially throw the java.io.IOException. More curiously though, the store method can throw the javax.portlet.ReadOnlyException. In the portlet.xml file, PortletPreferences can be configured, and default values can be assigned to them. These default values will be used unless a user goes to the edit mode and further customizes their preferences. However, in the portlet.xml file, a preference can be marked as read-only. If a preference is marked as read-only in the portlet.xml file, and an attempt is made to edit that preference at runtime, a ReadOnlyException is thrown. Finally, we should mention again that the PortletPreferences object can potentially call the ValidatorException. If a PreferencesValidator is configured in the portlet.xml file, and that validator throws an exception when a particular field is placed into the PortletPreferences, a ValidatorException will be triggered. Class Diagram of the ReadOnlyException PreferencesValidator and the portlet.xml File <?xml version="1.0" encoding="UTF-8"?> <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" id="com.examscam.portlet.NumberGuesserPortlet.420453eee0"> <portlet> <portlet-name>NumberGuesser</portlet-name> <display-name>NumberGuesser portlet</display-name> <portlet-class> com.examscam.portlet.NumberGuesserPortlet </portlet-class> <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> <portlet-mode>edit</portlet-mode> <portlet-mode>help</portlet-mode> </supports> <supported-locale>en</supported-locale> <portlet-info> <title>NumberGuesser portlet</title> </portlet-info> <portlet-preferences> <preference> <name>upperlimit</name> <value>10</value> <!--Setting read-only to true will trigger a ReadOnlyException if the preference is updated at runtime.--> <read-only>false</read-only> </preference> <!-- If validation fails, a preferences-validator will throw a ValidatorException.--> <preferences-validator> com.examscam.portlet.NumberGuesserValidator </preferences-validator> </portlet-preferences> </portlet> </portlet-app> Question xxx-1 The decision as to which of the various do methods to invoke, such as doEdit or doHelp, occurs in which method? ˇ a) initˇ b) destroyˇ c) actionProcessˇ d) doDispatch Question xxx-2 PortletPrefernces are not being saved. What are two possibilities as to why this might be happening ¨ a) the store() method is not being invoked¨ b) the save() method is not being invoked¨ c) the PortletPreferences are being configured in the doView method¨ d) the PortletPreferences are being manipulated in the processAction method Answer xxx-3 What are the standard, JSR-168, portlet modes? ¨ a) edit¨ b) view¨ c) help ¨ d) config Question xxx-4 To ensure a PortletPreference has a default value, even if the user hasn?t customized their portlet, the best plan of action is to: ¨ a) code a default value in the web.xml file¨ b) code a default value in the portlet.xml file¨ c) provide a default value as the second parameter of the PortletPreferences getValue() method¨ d) accept a null value as a valid PortletPreference Question 6-5 Which of the following checked exceptions could be thrown by a call to the PortletPreferences store method? ¨ a) ReadOnlyException¨ b) PortletException¨ c) ValidatorException¨ d) IOException Answer xxx-9 Minimize, Maximize and Normal are all valid: ˇ a) window statesˇ b) window modesˇ c) Portlet statesˇ d) Portlet modes Answer 7xxx-7 Where is a PortletPreference defined as being read only. ˇ a) programmatically through the PortletPreferences objectˇ b) by adding a read-only parameter to the portlet.xml fileˇ c) by adding a read-only parameter to the web.xml fileˇ d) PortletPreferences are always editable Answer xxx-1 The decision as to which of the various do methods to invoke, such as doEdit or doHelp, occurs in which method? ˇ a) initˇ b) destroyˇ c) actionProcessˇ d) doDispatch Option d) is correct.The init method is called when a portlet is first loaded, and destroy is called when the portlet is unloaded, but neither of those lifecycle methods have anything to do with the render phase of a portlet. Similarly, the actionProcess can help decide which mode or state in which a portlet will appear, but it does not directly call doEdit or doView. It is the doDispatch method that is responsible for figuring out which of the do<mode> methods should be invoked for portlet rendering. Answer xxx-2 PortletPrefernces are not being saved. What are two possibilities as to why this might be happening ¨ a) the store() method is not being invoked¨ b) the save() method is not being invoked¨ c) the PortletPreferences are being configured in the doView method¨ d) the PortletPreferences are being manipulated in the processAction method Options a) and c) are correct.There are two common reasons why PortletPreferences don?t get saved. First of all, developers forget to call the store method, and secondly, developers try to manipulate PortletPreferences in the wrong mode. Answer xxx-3 What are the standard, JSR-168, portlet modes? ¨ a) edit¨ b) view¨ c) help ¨ d) config Options a) b) and c) are correct.All JSR-168 compliant portal servers must support view, edit and help modes. However, portal servers are free to support any custom modes. The WebSphere Portal Server has built in features for supporting a configure mode. Answer xxx-4 To ensure a PortletPreference has a default value, even if the user hasn?t customized their portlet, the best plan of action is to: ¨ a) code a default value in the web.xml file¨ b) code a default value in the portlet.xml file¨ c) provide a default value as the second parameter of the PortletPreferences getValue() method¨ d) accept a null value as a valid PortletPreference Options b) and c) are correct.Making sure there?s a default value for a user configurable property is always a challenge. With the PortletPreferences, we can code a default value in two ways. First, we can put a preference value in the portlet.xml file. Secondly, the getValue() method takes two parameters, the first being the name of the property you wish to extract, and the second parameter being a default value, just in case the property you are looking for doesn?t exist. Answer 6-5 Which of the following checked exceptions could be thrown by a call to the PortletPreferences store method? ¨ a) ReadOnlyException¨ b) PortletException¨ c) ValidatorException¨ d) IOException Options a) c) and d) are correct.PortletPreferences are stored persistently, typically in a centralized database, and that database write can throw an IOException. Furthermore, PortletPreferences can be associated with a PreferencesValidator, which throws a ValidatorException if a preference doesn?t pass a validation test. Finally, PortletPreferences can be configured as being read-only, and if someone tries to overwrite a read-only preference, a ReadOnlyException is thrown. Answer xxx-6 Minimize, Maximize and Normal are all valid: ˇ a) window statesˇ b) window modesˇ c) Portlet statesˇ d) Portlet modes Answer a) is correct. Minimize, maximize and normal are the three standard window states. Sometimes the terms state and modes are easily confused. View and edit are modes, minimize and maximize are states. Answer 7-7 Where is a PortletPreference defined as being read only. ˇ a) programmatically through the PortletPreferences objectˇ b) by adding a read-only parameter to the portlet.xml fileˇ c) by adding a read-only parameter to the web.xml fileˇ d) PortletPreferences are always editable Answer b) is correct. There is no programmatic way to set a PortletPreference to be read-on; this can only be done by setting the preference through the portlet.xml file, and subsequently adding a tag indicating that the preference is read only. l Chapter 8Custom Portlet Modes The JSR-168 portlet specification requires all portal servers to provide services for the three standard portlet modes: view, edit and help. However, portal administrators are allowed to provide support for any number of extra portlet modes they think would be helpful. For example, it is envisioned that many portlets would benefit from a print mode that would make it possible to print out a portlet with the simple click of a button. IBM always provided support for a configure mode with their legacy portlet API, so it?s no surprise that the WebSphere Portal Server comes with built in support for a configure mode. Portal Support for Custom Modes First of all, I want to make it clear that you can follow all of the programming steps required to create a portlet that has a custom mode, but if the portal server you are deploying to doesn?t support that custom mode, that custom mode just ain?t going to work. If you want your portlets to render a custom portlet mode, that custom portlet mode must be enabled on the portal server to which you are deploying. Now, the WebSphere Portal Server supports the configure mode, so I will demonstrate how to write a portlet that supports the configure mode. The assumption is that we will be deploying to WebSphere. Implementing Custom Portlet Modes The first step in coding a custom portlet mode it overriding the inherited doDispatch method of the GenericPortlet. The doDispatch method is always invoked before the doView or doEdit modes, so, if we override this method and inspect to see if our custom portlet mode is being invoked, we can capture the request, and send it to our own custom do method, which in this case, will be doCustomConfig(). And what do we do in our doCustomConfig () method? Well, anything we want. This method will be responsible for rendering the config mode of the portlet. This method can do anything you want it to do, but in all likelihood, the method will forward to a jsp file. Figure xxx WebSphere Portal Server 6.x has inherent support for the custom config mode. Even if custom modes are coded properly, if a portal server is not configured to support that custom mode, the custom mode simply will not be available to the end user. The Custom do<mode> Method When the custom configure mode is being requested, we call to our custom do<mode> method named doCustomConfig(). In our example, the config mode simply prints a message about its own self-actualization to the console. However, this method will never be called, unless we override the doDispatch method. protected void doCustomConfig( RenderRequest request, RenderResponse response) throws PortletException, IOException { response.setContentType(?text/html?); response.getWriter().print("I have a custom config mode!!!"); } Overriding the doDispatch Method When overriding the doDispacth method, we first check to see if the portlet is minimized. The mode being requested really doesn?t matter if the portlet is minimized, so if it is, we just skip the whole render phase processing. If the portlet isn?t minimized, then we check to see if the portlet mode being requested is the config portlet mode. If it is, then we call our doCustomConfig method. If our custom portlet mode is not being invoked, we simply call super.doDispatch(), which essentially allows the portlet to run as though our custom, overridden doDispatch method was never called. protected void doDispatch( RenderRequest request, RenderResponse response) throws PortletException, IOException{ /* don?t do anything if the window is minimized */ if (!WindowState.MINIMIZED.equals(request.getWindowState())) { /* find out which portlet mode is being requested */ PortletMode requestedMode = request.getPortletMode(); PortletMode customPortletMode = new PortletMode("config"); /* if our custom mode is requested, call our custom do method */ if (requestedMode.equals(customPortletMode)) { /* this is the call to our custom do <mode> method */ doCustomConfigure(request, response); return; } /*if our custom portlet wasn?t called, allow the regular portlet mode processing happen*/ super.doDispatch(request, response); } } Editing the Portlet Deployment Descriptor Along with the overridden doDispatch method, and the custom do<mode> method, the deployment descriptor of the portlet application must be updated to indicate that a new portlet mode is being supported. <?xml version="1.0" encoding="UTF-8"?> <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd id="com.examscam.portlet.CustomModePortlet.051cf00ef0"> <portlet> <portlet-name>CustomModePortlet</portlet-name> <display-name>CustomModePortlet</display-name> <display-name xml:lang="en"> CustomModePortlet </display-name> <portlet-class> com.examscam.portlet.CustomModePortlet </portlet-class> <expiration-cache>0</expiration-cache> <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> <!-- This entry indicates the portlet supports the config mode --> <portlet-mode>config</portlet-mode> </supports> <supported-locale>en</supported-locale> <portlet-info> <title>CustomModePortlet</title> </portlet-info> </portlet> <!-- This entry indicates the portlet application supports config--> <custom-portlet-mode> <portlet-mode>config</portlet-mode> </custom-portlet-mode> </portlet-app> The Full CustomModePortlet package com.examscam.portlet; import java.io.*;import javax.portlet.*; public class CustomModePortlet extends GenericPortlet { protected void doView (RenderRequest request, RenderResponse response) throws PortletException, IOException { response.setContentType(?text/html?); response.getWriter().println("Custom Portlet View Mode"); } protected void doCustomConfigure (RenderRequest request, RenderResponse response) throws PortletException, IOException { response.setContentType(?text/html?); response.getWriter().println("Custom Config Mode!!!?); } protected void doDispatch (RenderRequest request, RenderResponse response) throws PortletException, IOException{ /* don?t do anything if the window is minimized */ if (!WindowState.MINIMIZED.equals(request.getWindowState())) { /* find out which portlet mode is being requested */ PortletMode requestedMode = request.getPortletMode(); PortletMode customPortletMode = new PortletMode("config"); /* if our custom mode is requested, call our custom do method */ if (requestedMode.equals(customPortletMode)) { /* this is the call to our custom do <mode> method */ doCustomConfigure(request, response); return; } /*if our custom portlet wasn?t called, allow the regular portlet mode processing happen*/ super.doDispatch(request, response); } } } Answer 6-6 Special icons associated with a particular custom portlet mode are defined: ˇ a) in the web.xml fileˇ b) in the portlet.xml fileˇ c) in the render phase of the portletˇ d) in a portal skin Option d) is correct.The cute little icons, such as the pencil for the edit mode, or the wrench for the custom config mode, are part of a portal skin, and defined outside of the actualy portlet application. The fact that icons for custom modes is defined at the portal server level, not the portlet level, is part of the reasons why portlets cannot simply define custom portal modes on their own. The PortletSession If the user is going to be good enough to provide information to us through html forms and http headers, the least we could do is keep track of that information, if only for the duration of the user's visit to our site. To provide a stateful experience for portal users, portlet developers rely upon the services of the PortletSession, which, by the way, is remarkably similar to the HttpSession object from the Servlet API. The PortletSession is easy to use, and helps maintain a stateful experience for the user, overcoming the stateless nature of the HTTP protocol. This chapter will look at the PortletSession, how the PortletSession works, and will even discuss some of the drawbacks and alternatives to using a PortletSession object. Canada and the http protocol have one thing in common: they are both stateless. Canada has ten provinces and three relatively empty territories, but no states. Of course, they have been eyeing Michigan for a while. Managing State with the PortletSession Object When a user visits our site, we often need to keep track of information the user has provided. Information stored in the PortletRequest or PortletResponse objects are purged as soon as a response is sent back to the client, which creates a problem if we want to keep track of information that a user has provided on previous request-response cycles. To store user specific information for the duration of the user's interaction with the server, the Portal API provides a special object called the PortletSession. Any useful piece of information, in the form of Java objects, can be stuffed inside of a user's session object. That information is then available to our portlet on all subsequent request-response cycles. The PortletSession is effectively tied to the user for which it is created. The Transient Nature of the PortletSession One thing to note about the PortletSession is that it is transient ? it's the hobo of the Portlet API. If the user leaves our site, doesn't interact with the site for a predetermined amount of time (usually thirty minutes), or even if the user closes their browser, information stored in the PortletSession is lost, or at least, the session containing the information will not longer be tied to the user. Information stored in the PortletSession is not stored persistently. The job of the PortletSession is to simply create a stateful experience for users while interacting with our site. Taking Advantage of the PortletSession Object Figure 5-1 shows a simple portlet that keeps track of the number of times the doView method of a portlet is called. The view count variable is stored in the PortletSession, under the key named timesvisited. Every time the doView method of the portlet is called, the view count increases by one. The view count is then displayed back to the user. Notice how the SimpleSessionPortlet requires some session-data management. When the portlet is first viewed, there will be no data stored in the session regarding the view count. On the first iteration, a timesvisited key, with an assigned value of 1, is placed into the PortletSession. On subsequent iterations, when the timesvisited key is present in the session, the associated value is extracted, incremented, and then stored back in the PortletSession. Figure 5-1 Taking Advantage of the PortletSession package com.examscam.portlet;import java.io.*;import javax.portlet.*;public class SimpleSessionPortlet extends GenericPortlet { protected void doView(RenderRequest request, RenderResponse response)throws PortletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); /*grab the PortletSession out of the PortletRequest*/ PortletSession session = request.getPortletSession(); /*pull the visitCount out of the session. On the first visit, this will be null*/ String visitCount = (String)session.getAttribute("timesvisited"); if (visitCount == null) { /*if this is the first time viewing the portlet, set the timevisited value to 1*/ session.setAttribute("timesvisited", "" + 1); out.print("Welcome to our little portlet!"); out.print("Click refresh, minimize or maximize!!!"); } else { /*if this portlet has been visited before, increase the count*/ int newCount = Integer.parseInt(visitCount) + 1; session.setAttribute("timesvisited", "" + newCount); out.print("Number of times visiting this portlet: "); out.print(newCount); } }} PortletSessions and User Portlets An interesting aspect of the PortletSession is the fact that data stored in the PortletSession, by default, is local and accessible only to the portlet that created it. By default, data stored in the PortletSession by one portlet cannot be shared by any other portlets on the same portal page. If there are four portlets on a portal page, if they all use a PortletSession object, then each one will have a separate, unshared, PortletSession namespace. Even if two instances of the same portlet appear on a portal page, each one will have its own, unshared, PortletSession namespace. PortletSession and the PORTLET_SCOPE This default behavior is known as PORTLET_SCOPE, and has been the way the PortletSession object has behaved for years. However, developers have done nothing but moan and groan about the fact that it is incredibly difficult to share information between portlets that exist within the same portlet application (think war file), so, with the JSR-168 portlet specification, the Java Gods introduced the concept of a shared, APPLICATION_SCOPE, for the PortletSession. When a portlet shoves an object into the PortletSession, and specifies APPLICATION_SCOPE as the visibility of the data, any portlet that is part of that same portlet application, can obtain that data by providing the appropriate key when making a call to the PortletSession's getAttribute method. PortletSession Constants The JSR-168 API introduces two new constants, or should I say, final static variables, in the PortletSession class. These two new contains are called APPLICATION_SCOPE and PORTLET_SCOPE, and represent the numbers 0x01 and 0x02 respectively. /* constants representing the PortletSession scopes*/ PortletSession.APPLICATION_SCOPE //0x01 PortletSession.PORTLET_SCOPE //0x02 Newly Overloaded PortletSession Methods In a typical Servlet and JSP based application, along with legacy JetSpeed and proprietary Portlet APIs, the setAttribute method is used to save data to the PortletSession. The setAttribute method takes a name/value-object pair as arguments. Data is pulled out of the session with a call to getAttribute, with the name provided as a parameter; the associated value-object is then returned to the calling program. However, in the JSR-168 Portlet API, the setAttribute and getAttribute methods have been overloaded, with an extra parameter added, that allows for one of the two new portlet scopes to be specified. /* default mechanism for adding to a PortletSession */ session.setAttribute(?key?, ?value?); /* overloaded mechanism for adding to a PortletSession*/ session.setAttribute(?key?, ?value?, PortletSession.PORTLET_SCOPE); /*placing data into the APPLICATION_SCOPE of a PortletSession*/ session.setAttribute(?key?, ?value?, PortletSession.APPLICATION_SCOPE); /* default mechanism for pulling from a PortletSession */ session.getAttribute(?key?); /* overloaded mechanism for pulling from a PortletSession*/ session.setAttribute(?key?, PortletSession.PORTLET_SCOPE); /*pulling data from the APPLICATION_SCOPE*/ session.setAttribute(?key?, PortletSession.APPLICATION_SCOPE); PortletSession and the APPLICATION_SCOPE When data placed into the PortletSession is given APPLICATION_SCOPE, the data is visible to all other portlets that are packaged as part of the same portlet application. Portlets are part of the same portlet application when they are defined in a common portlet.xml file, and packaged in a common war file. Many developers believe that data stored in the APPLICATION_SCOPE of the PortletSession is available to all of the portlets a users might access on the portal. This is simply not the case. While APPLICATION_SCOPE allows a degree of sharing of data, the data is not shared with portlets that are defined in separate war files. All portlets sharing APPLICATION_SCOPE data must be defined in a common portlet.xml file. Class Diagram of the PortletSession ?The PortletSession interface provides a way to identify a user across more than one request and to store transient information about that user. A PortletSession is created per user client per portlet application. A portlet can bind an object attribute into a PortletSession by name. The PortletSession interface defines two scopes for storing objects: APPLICATION_SCOPE PORTLET_SCOPE All objects stored in the session using the APPLICATION_SCOPE must be available to all the portlets, servlets and JSPs that belongs to the same portlet application and that handles a request identified as being a part of the same session. Objects stored in the session using the PORTLET_SCOPE must be available to the portlet during requests for the same portlet window that the objects where stored from. Attributes stored in the PORTLET_SCOPE are not protected from other web components of the portlet application. They are just conveniently namespaced. The portlet session is based on the HttpSession. Therefore all HttpSession listeners do apply to the portlet session and attributes set in the portlet session are visible in the HttpSession and vice versa.? -Description of the PortletSession from the IBM/Sun Portal API JavaDocs Reading from the APPLICATION_SCOPE Our SimpleSessionPortlet defined in Fig. 5-1, places a hitcount into the session using the key timesvisited. To allow another portlet to access this hitcount, we could change the scope of the timesvisited key to APPLICATION_SCOPE, and have a second Portlet, which we will name SessionViewerPortlet, pull the key out of the APPLICATION_SCOPE. package com.examscam.portlet; import java.io.*;import javax.portlet.*; public class SessionViewerPortlet extends GenericPortlet { protected void doView (RenderRequest request, RenderResponse response) throws PortletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); PortletSession session = request.getPortletSession(); Object count = session.getAttribute("timesvisited", PortletSession.APPLICATION_SCOPE); if (count != null) { out.print("I found the count in the session: "); out.print(count.toString()); } else { out.print("Couldn't find the count in the session."); } } } While the SessionViewerPortlet looks for the timesvisited key in the APPLICATION_SCOPE, the lookup will be unsuccessful until the SimpleSessionPortlet explicitly places the timesvisited key in the appropriate scope. Figure 5-2 Taking Advantage of the PortletSession package com.examscam.portlet;import java.io.*;import javax.portlet.*;public class SimpleSessionPortlet extends GenericPortlet { protected void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); PortletSession session = request.getPortletSession(); String visitCount = (String)session.getAttribute( "timesvisited", PortletSession.APPLICATION_SCOPE); if (visitCount == null) { /*if this is the first time viewing the portlet, set the timevisited value to 1*/ session.setAttribute("timesvisited", "" + 1, PortletSession.APPLICATION_SCOPE); out.print("Welcome to our little portlet!"); out.print("Click refresh, minimize or maximize!!!"); } else { int newCount = Integer.parseInt(visitCount) + 1; session.setAttribute("timesvisited", "" + newCount, PortletSession.APPLICATION_SCOPE); out.print("Number of times visiting this portlet: "); out.print(newCount); } }} Now that the key timesvisited is stored in the scope of the application, both the Session ViewerPortlet, and the SimpleSessionPortlet, can share information through the PortletSession. But notice how the two portlets are out of sync, with one showing a count of 2, and the other showing a count of 3? This very issue will lead us into the next chapter on the action processing phase of a portlet. Portlet.xml File for PortletSession Examples <?xml version="1.0" encoding="UTF-8"?> <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" id="PortletSessions.8a76e53fe0"> <portlet> <portlet-name>SessionViewerPortlet</portlet-name> <display-name>SessionViewerPortlet</display-name> <portlet-class> com.examscam.portlet.SessionViewerPortlet </portlet-class> <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> </supports> <portlet-info> <title>SessionViewerPortlet</title> </portlet-info> </portlet> <portlet> <portlet-name>SimpleSessionPortlet</portlet-name> <display-name>SimpleSessionPortlet</display-name> <portlet-class> com.examscam.portlet.SimpleSessionPortlet </portlet-class> <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> </supports> <portlet-info> <title>SimpleSessionPortlet</title> </portlet-info> </portlet> </portlet-app> The NumberGuesser and the PortletSession Our NumberGuesserPortlet could really use a good dose of the PortletSession object. Currently, our NumberGuesserPortlet thinks up a number, and asks the user to guess it, but it doesn't give the user a chance to keep trying until they guess the magic number correctly. By incorporating the PortletSession object into the NumberGuesserPortlet, we could store both the magic number and the number of guessing attempts. We could even give the user a hint as to whether they should guess higher or lower. When the user guesses successfully, we can then provide a message that indicates their success, and subsequently displays the number of attempts it took. Our improved NumberGuesserPortlet appears in Figure xxx-2 Be aware that changes will be required in the corresponding JSP in order for the portlet to function properly. The JSP changes are listed in Figure 6xxx-5. Tips for Manipulating the PortletSession Information is pulled out of the PortletSession using the getAttribute(String) method. Objects are put into the PortletSession using the setAttribute(String, Object) method. The name used to put an object into the session must exactly match the name used to pull the object out. Spellling mistakes, or even a different caSinG of letters will cause the return of a null object. Always try to avoid NullPointerExceptions. J The PortletSession also includes a method called removeAttribute(String). If you no longer have use for an object you have stored in the PortletSession, that object should be removed from the session. The misuse of session data is one of the most significant performance bottlenecks a portal server, or any J2EE application server for that matter, will encounter. Eliminating unnecessary objects from your PortletSession, and avoiding what is known as ?session bloat,' will help you avoid performance problems at runtime. Figure 5-3 The New and Improved NumberGuesserPortlet package com.examscam.portlet;import java.io.*;import javax.portlet.*;public class NumberGuesserPortlet extends GenericPortlet {protected void doView (RenderRequest request, RenderResponse response) throws PortletException, IOException {PortletContext context = this.getPortletContext();PortletSession session = request.getPortletSession();if (session.getAttribute("magicnumber") == null) { /* generate a magic number to start the game*/ int magicNumber = (int) (System.currentTimeMillis() % 9) + 1; /* populate the session with pertinent Java objects*/ session.setAttribute("magicnumber", new Integer(magicNumber)); session.setAttribute("guesses", "0"); /* place the message in the session*/ session.setAttribute("message", "Guess the number!");} else { /* get the magicNumber and number of guesses out of the session*/ /* NOTE: what will happen if the user didn't type anything in? */ Integer magicNumber = (Integer) session.getAttribute("magicnumber"); String guesses = (String) session.getAttribute("guesses"); /* increment the number of guesses*/ guesses = "" + (Integer.parseInt(guesses) + 1); session.setAttribute("guesses", guesses); /* what did the user guess? */ Integer guess = new Integer(request.getParameter("number")); /* figure out a message to return to the user*/ if (guess.intValue() > magicNumber.intValue()) { session.setAttribute("message", "Guess lower!"); } else { session.setAttribute("message", "Guess higher!"); } if (guess.intValue() == magicNumber.intValue()) { String message = magicNumber + " is correct. Play again!"; session.setAttribute("message", message); /* purge the session of unneeded data*/ session.removeAttribute("magicnumber"); }}/* forward to the jsp for display */String url = "/numberguesser.jsp";context.getRequestDispatcher(url).include(request, response);}} Inspecting the Better NumberGuesserPortlet The first two lines of our improved portlet simply declares the PortletSession and PortletContext objects for easy access later on in the portlet. The next step is to see if a magic number exists in the session. If there is no magic number in the session, then we assume the user is looking at this portlet for the first time, or they are re-starting the guessing process. In that case, we create a new magic number and stuff that number into the PortletSession. We also set the number of guesses to zero, after all, the number guessing game is just starting. Once all of our objects have been initialized, and stuffed into the PortletSession, we can forward to a JSP page, but before we do that, we stuff a little message into the PortletSession. The message simply says ?Guess the number!!!? This message will be printed out by the JSP. Figure 5-4 """public class NumberGuesserPortlet extends GenericPortlet {protected void doView (RenderRequest request, RenderResponse response) throws PortletException, IOException {PortletContext context = this.getPortletContext();PortletSession session = request.getPortletSession();if (session.getAttribute("magicnumber") == null) { /*generate a magic number to start the game*/ int magicNumber=(int)(System.currentTimeMillis() % 9)+1; /*populate the session with pertinent Java objects*/ session.setAttribute("magicnumber", new Integer(magicNumber)); session.setAttribute("guesses", "0"); /*message is set in the session*/ session.setAttribute("message", "Guess the number!");}"""} When Form Data is Present If request.getParameter(?number?) does not return null, then indeed the user has just submitted a form, trying to guess the magic number. In this case, we grab the magic number from the session, then we grab the number of guesses from the session, and finally we grab the number guessed by the user, using the request.getParameter(?number?) method. ***Note that we have been lazy so far. If the use clicks submit without typing anything into the textfield, or types in non-numeric data, we are going to have a NumberFormatException. If the number is too high, we send them to the numberguesser.jsp file with a message stuffed into the session object instructing them to guess lower. session.setAttribute("message", "Guess lower!"); If the number is too low, we send them to the numberguesser.jsp file with a message stuffed into the request object instructing them to guess higher. session.setAttribute("message", "Guess higher!"); If the user guesses the magic number correctly, we stuff a friendly message in the session object, indicating that the user has successfully guessed the magic number. After updating the message, we remove the magic number from the session. After all, it is not needed now that the number has been guessed. If the user wants to play again, we'll just generate a new magic number, and set their number of guesses to zero. Figure 5-5 """if (guess.intValue() == magicNumber.intValue()) { String message= magicNumber + " is correct. Play again!"; session.setAttribute("message", message); //Purge the session of unneeded data session.removeAttribute("magicnumber");}""" Debriefing the NumberGuesser's JSP Pages A JSP is used to generate the markup needed to display the portlet on a portal page. The JSP used in this example is displayed in Figure 6xxx-5. Figure 5-6 Generating a View with a JSP <%@ page contentType="text/html"%><%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%> <portlet:defineObjects /> <%=renderRequest.getPortletSession(). getAttribute("message")%> <FORM action=""><portlet:renderURL />">I'm thinking of a number between 1 and 10. <BR /> <INPUT name="number" size="10" type="text" /><INPUT value="Guess!!" type="submit" /></FORM> Number of guesses:<%=renderRequest.getPortletSession() .getAttribute("guesses")%> The biggest change for the JSP on this iteration of the NumberGuesserPortlet is the presence of the expression: <%=renderRequest.getPortletSession().getAttribute(?message?)%> just before the input field. Inside the NumberGuesserPortlet, a message is placed in the session scope, indicating whether a user should guess higher, lower, or if the user is guessing for the first time, simply to guess randomly. This message is then printed out just above the textfield in the numberguesser.jsp page. This script allows a single JSP page to be used dynamically, and render itself slightly differently, depending upon the state of the application. Our improved form also displays to the user how many guesses they have made at the magic number, based on the guesses key placed into the PortletSession during the doView method. Number of guesses: <%=renderRequest.getPortletSession() .getAttribute("guesses")%> Question 5-1 What type of data is acceptable for the storage in the PortletSession? ˇ a) any class that inherits from java.lang.Objectˇ b) any String valueˇ c) any serializable Java objectˇ d) any serializable String value Question 5-2 Programmatically, what is the process for storing transient data in the PortletSession? ˇ a) call the setAttribute(name, value) method of the PortletSession, followed by the store() methodˇ b) call the setAttribute(name, value) method of the PortletSession, followed by the save() methodˇ c) call the setAttribute(name, value) method of the PortletSession, followed by the set() methodˇ d) call the setAttribute(name, value) method of the PortletSession Question xxx-3 Information stored in the PortletSession with the visibility of APPLICATION_SCOPE: ˇ a) will be stored persistentlyˇ b) will be stored until the portlet application it is associated is stoppedˇ c) will be destroyed when the user's session times out ˇ d) will be stored until the portal server is shut down Question 5-4 Which of the following is true about the JSR-168 PortletSession? ¨ a) Data stored in the PortletSession is also available to the HttpSession of the Servlet and JSP API¨ b) Data stored in the HttpSession is also available to Portlets through the PortletSession¨ c) The PortletSession inherits from the HttpSession of the Servlet and JSP API¨ d) The PortletSession is based on the HttpSession of the Servlet and JSP API Question 5-5 A portlet needs to share session data with another portlet defined in the same portlet.xml file. Which PortletSession scope should be used? ˇ a) PORTLET_SCOPEˇ b) SESSION_SCOPEˇ c) APPLICATION_SCOPEˇ d) This type of session sharing is not possible Answer 5-1 What type of data is acceptable for the storage in the PortletSession? ˇ a) any class that inherits from java.lang.Objectˇ b) any String valueˇ c) any serializable Java objectˇ d) any serializable String value Answer c) is correct. While non-serialized objects can safely be placed in the PortletSession on a non-distributed environment, in order to have portlet applications behave properly in a distributed environment that employs multiple JVMs, you must ensure that any object placed in the PortletSession is serializable. Answer 5-2 Programmatically, what is the process for storing transient data in the PortletSession? ˇ a) call the setAttribute(name, value) method of the PortletSession, followed by the store() methodˇ b) call the setAttribute(name, value) method of the PortletSession, followed by the save() methodˇ c) call the setAttribute(name, value) method of the PortletSession, followed by the set() methodˇ d) call the setAttribute(name, value) method of the PortletSession Answer d) is correct. In order to save data in the PortletSession, you simply call the setAttribute method, providing a name for the object being placed in the session, along with the object itself. Only the PortletPreferences object needs an explicit call to store() in order to ensure that data is saved persistently for the user. Answer 5-3 Information stored in the PortletSession with the visibility of APPLICATION_SCOPE: ˇ a) will be stored persistentlyˇ b) will be stored until the portlet application it is associated is stoppedˇ c) will be destroyed when the user's session times out ˇ d) will be stored until the portal server is shut down Answer c) is correct. PortletSession data, regardless of whether it is APPLICATION_SCOPE or PORTLET_SCOPE, will be only stored transiently. Answer 5-4 Which of the following is true about the JSR-168 PortletSession? ¨ a) Data stored in the PortletSession is also available to the HttpSession of the Servlet and JSP API¨ b) Data stored in the HttpSession is also available to Portlets through the PortletSession¨ c) The PortletSession inherits from the HttpSession of the Servlet and JSP API¨ d) The PortletSession is based on the HttpSession of the Servlet and JSP API Answers a) and d) are correct, with d) actually being lifted directly from the PortletSession JavaDoc. Since the PortletSession is essentially the HttpSession of the user, data stored in the HttpSession becomes available to the user through the PortletSession. Answer 5-5 A portlet needs to share session data with another portlet defined in the same portlet.xml file. Which PortletSession scope should be used? ˇ a) PORTLET_SCOPEˇ b) SESSION_SCOPEˇ c) APPLICATION_SCOPEˇ d) This type of session sharing is not possible Answer c) is correct. The APPLICATION_SCOPE makes it possible to share session data across portlets that are part of the same portlet application.
Google



eXTReMe Tracker

ActionRequest ActionResponse GenericPortlet PortletRequestDispatcher . Portlet ..... PortletURL
PortletContext PortletException PortletMode a PortletModeException PortletPreferences
PortalContext PortletResponse PortletSession PortletSecurityException PreferencesValidator
PortletConfig RenderRequest RenderResponse UnavailableException PortletSessionUtil
PortletRequest ValidatorException WindowState WindowStateException UnmodifiableException