6.4 Portlet deployment examples

 < Day Day Up > 



6.4 Portlet deployment examples

In this section we show two examples of deploying portlets on z/OS as follows:

  1. Using WPACONF job via TSO to deploy a portlet from the Portlet Catalog. Section 6.4.3, "Installing portlets obtained from the Portlet Catalog" on page 215 provides more information about portlets from the Portlet Catalog.

  2. Using the WPAConfig script via USS to deploy an out of the box portlet installed during portal server installation but not deployed.

6.4.1 Example of installing a portlet using WPACONF job

As our first example of deploying a portlet, we used the Health Care click-to-action (C2A) sample portlet available for download from the Portlet Catalog (NAVCODE 1WP10003L).

Install the portlet via WebSphere Portal administration GUI

There are a number of different paths that an administrator can take to deploy portlets and make them available for users on a page. In fact, the only steps an administrator has to do is deploy the portlets and assign user rights so that users can add them to a page for themselves. In this example, we performed the following steps as an administrator to install the portlet:

  1. Download the sample from the Portlet Catalog Web site to a Windows system and unzip the file. Follow the instructions in the supplied documentation in the form of file readme.html.

    Tip 

    Because of the installation differences between distributed platforms and z/OS we used the following directories on z/OS instead of the ones referred to in the portlet installation instructions:

    • Step 3: Used directory <WPS_PATH>/PortalServer/libbapp instead of <was_root>\lib\app.

    • Step 4: Used directory <WPS_PATH>/PortalServer/libbapp/nls instead of <was_root>\lib\app\nls.

    • Step 5: Created directory c2a in directory <WS_CONFIG_PATH>/apps/WSPORT/WPS Enterprise Application\wps.war instead of <wp_root>\app\wps.ear\wps.war.

    • Step 6: Used directory <WPS_PATH>/libapp/WEB-INF/tld instead of <was_root>\lib\app|WEB-INF\tld.

    Tip 

    We recommend that changes are made, if required, to properties and xml files before deploying portlets on z/OS. This is because some of these files are in ASCII format, and some are stored inside the runtime of the expanded WAR file on the application server, making it difficult to change them after deployment.

  2. Stop the Portal Server from a TSO session and then restart it.

    Note 

    The following steps will fail for the C2A portlets, if the Portal server is not stopped and restarted after following the portlet installation Steps 3-8 in the Readme.

  3. Ensure that WebSphere Portal server on z/OS is running, and from a Web browser go to the following URL: http://<HOST_NAME>/wps/portal.

  4. Login as the portal administrator with the default userid and password of wpsadmin as shown in Figure 6-17 on page 208.

  5. Go to the Portal Administration place and select Install Portlets.

  6. Browse the directory on the distributed system that corresponds to <WPS_PATH>/PortalServer/app/DeployablePortlets directory and select healthcarec2a.war. Click Next.

  7. On the Install Portlet Application screen, the portlet(s) contained in the WAR and to be deployed are shown as in Figure 6-13 on page 203.

    click to expand
    Figure 6-13: Installing C2A portlets from the Portal Administration place

  8. Click Install to install all the C2A Health Care sample portlets and ensure you receive the message Portlets successfully installed.

Run the WPACONF job

Logon to TSO and using the TSO ISH environment you can optionally verify that the portlet deployment job(s) have been added to directory <WPS_PATH>/temp/jobs as shown in Figure 6-14 on page 204.

click to expand
Figure 6-14: C2A deploy work ready to run job WPACONF

Submit job WPACONF, after reviewing the JCL job card. Note that if the Portal Server is running it will be stopped and re-started for the deployment of each portlet it deploys from the WAR files in the work directory. Therefore, we recommend stopping Portal Server before submitting the job and re-starting it manually on completion. Check the job completes without errors.

Add the portlet to a page

Start Portal Server and login using the administrative user ID via http://<yourhost>/wps/portal. Navigate to the page you want to add the newly deployed portlets via Work with pages -> Edit layout and content -> Place+Page -> Get Portlets. We chose a filtered search on C2A and selected the Health Care sample portlets to be added to our page as shown in Figure 6-15 on page 205.

click to expand
Figure 6-15: Adding the C2A portlets to a page

The next portal administration screen allows you to select the row and column containers to show the portlets on the selected page. Finally, ensure that page is activated.

Verify that the portlet works

Navigate to the page and the deployed portlets should be available and working, as shown for example in Figure 6-16 on page 206.

click to expand
Figure 6-16: C2A example portlets

6.4.2 Example of installing a portlet using WPAConfig

In this section we take you through the steps of installing a portlet supplied with WebSphere Portal but not installed as part of the post installation process. All portlets that come with WebSphere Portal can be found as WAR files in <WPS_PATH>/PortalServer/app/DeployablePortlets directory. We will install the Document Viewer portlet and place it on a page we created called Redbook that exists in the ITSO place that we also created. The following steps are enumerated:

Tip 

Since the HFS on z/OS cannot be accessed directly from a browser or as a mapped drive, copy the portlet WAR file(s) to a distributed system where you are running the Web browser.

Install the portlet via WebSphere Portal administration GUI

  1. Assuming that WebSphere Portal server on z/OS is running, bring up a Web browser and go to the default URL: <HOST_NAME>/wps/myportal.

  2. Login as the portal administrator with the default userid and password of wpsadmin as shown in Figure 6-17 on page 208.

    click to expand
    Figure 6-17: WebSphere Portal login window

  3. Go to Portal Administration Pages and make sure the Install Portlets page is selected.

  4. Browse to the directory on the workstation where you transferred docviewer.war from the z/OS HFS directory <WPS_PATH>/PortalServer/app/DeployablePortlets and select docviewer.war. See Figure Figure 6-18 on page 209. Click Next.

    click to expand
    Figure 6-18: Initial window on portlet installation

  5. On the Install Portlet Application page, you will the portlet(s) contained in the WAR file. Notice that the document viewer portlet is a portlet application that contains 5 separate portlets.

  6. Click Install to install all the Document Viewer Portlets. This will take a few moments.

  7. Wait until you receive the message - Portlets successfully installed.

  8. If you go to the Manage Portlet Applications tab, and look for the docviewer.war in the list of Web modules, you will see that the Portlet application belonging to it are Active as seen in Figure Figure 6-19 on page 210.

    click to expand
    Figure 6-19: Manage Portlet Applications window

Place the portlet on a portal page

  1. Select Work with Pages place and click on Edit Layout and Content.

  2. Select ITSO in the Place drop down and select Redbook in the Page drop down list.

  3. Click Get portlets.

  4. On the following screen entitled Get portlet for: ITSO, click the radio button to Show all portlets. Click Go.

  5. You should see a list of all the available portlets. We will install 2 of the 5 portlets that were contained in the docviewer WAR file. Click the plus icon on the left of Name field to add PDF Document Viewer and Word Document Viewer. Those portlets will be added to the Portlet list. Click OK in the portlet menu bar.

  6. You will be back at the Edit layout and Content window for the Redbook page. Highlight PDF Document Viewer Portlet, move your cursor to the left side of one of the columns on the page and click the Add icon.

    Then click to select the WORD Document Viewer Portlet and click the Add portlet icon in the right-side column. The resulting screen is shown Figure 6-20 on page 211.

    click to expand
    Figure 6-20: Laying out the portlets in portlet containers on a page

  7. Remember to click the Activate label so that the page is activated and can be viewed.

  8. From the place drop down list, select ITSO, navigate to the Redbook page and you should see the portlet outlines with a Error 404: File not found message as seen in Figure 6-21 on page 212.

    click to expand
    Figure 6-21: Screen showing the newly installed portlets with the error message

Run the WPAConfig script

  1. Go to a z/OS TSO session screen and stop WebSphere Portal, in our case we issued command: /p WSPORTA.

  2. Log on to the UNIX System Services on the target system as a user with administrator authority for WebSphere Application Server. (On our system we logged in as CBADMIN.)

  3. Change directory to

     /usr/lpp/PortalServer/PortalServer/zosinst/tools/deploy. 

  4. If need be run the batch file client_env, as follows:. client_env

  5. Change directory to /usr/lpp/PortalServer/PortalServer/zosinst/scripts. Invoke the WPAConfig.sh command. This will run the job, start a conversation, and install the portlets on the WebSphere Application Server for z/OS and OS/390.

  6. Wait for the committed message (Figure 6-22 on page 213):

     Conversation WPSConversation_xxxxxxxx_hh:mm:ss was committed. 

    click to expand
    Figure 6-22: Command window output of running the WPAConfig script

  7. Make sure there are no error messages. At this stage the portlets are loaded and portal server needs to be restarted.

  8. From the z/OS console, start WebSphere Portal, in our case we issued command: /s WSPORT.WSPORTA.

Verify that the portlet works

  1. Refresh the browser that was displaying the Redbook page in the ITSO place or bring up a new browser and go to the ITSO place and down to the Redbook page. The two portlets should be displayed without any errors as shown in Figure 6-23 on page 213.

    click to expand
    Figure 6-23: Screen showing the docviewer portlets before configuration

  2. Click the Edit icon (one that looks like a pencil) in the menu bar at the top of one of the portlets. Enter the name of the PDF document you want to view. You have the choice of displaying the document in a new window or within the portlet as shown in Figure 6-24 on page 214. After all the parameters are entered, click Save.

    click to expand
    Figure 6-24: Configuring the PDF document viewer portlet with document details

  3. You will taken back to the Redbook page and the contents of the PDF will be displayed.

  4. You can similarly deploy and use the other portlets in the docview Web module.

click to expand
Figure 6-25: PDF file viewed in the portlet

6.4.3 Installing portlets obtained from the Portlet Catalog

There are hundreds of portlets in the IBM Portlet Catalog to be found at

http://www-3.ibm.com/services/cwi/portal/_pagr/105/

Many of them are available for download for free although some provided by third parties require registration and a fee.

Note 

Portlets are categorized in the IBM Portlet Catalog for different versions of WebSphere Portal and different editions. We recommend ensuring you download portlets for WebSphere Portal Enable V4.1 or V4.2.

In the following examples the installation steps are the same as we have seen in the preceding sections on portlet deployment. For each of the examples we describe any unique configuration steps that are performed.

Host on Demand (HOD) portlet

In this example we will download the WebSphere Host On Demand (HOD) portlet, install and deploy it. There are 4 HOD portlets in the catalog - HOD 3270 cached and non-cached and HOD 5250 Cached and Non-cached. We will usethe HOD 3270 Cached portlet for WebSphere Portal V4.1.4 (NavCode 1WP10006L).

Once the portlet WAR file has been downloaded the steps are same as listed in 6.4.2, "Example of installing a portlet using WPAConfig" on page 206 except for the fact that you browse the directory where the portlet WAR file was downloaded. We created a page called HOD in our portal ITSO place to place the 3270 Cached HOD portlet.

Assuming you are logged in as the portal administrator (or anyone else who has the authority to install portlets) do the following:

  • Navigate to Work with Pages->Edit Layout and Content.

  • Choose ITSO place and HOD page.

  • Get and select the HOD 3270 Download portlet.

  • Add it to a portlet container and Activate the page.

The portlet addition screen is shown in Figure 6-26 on page 217.

click to expand
Figure 6-26: Window showing the placement of HOD portlet on the HOD page

The HOD portlet has to be configured like this, before you can actually work with it:

  • Navigate to Portal Administration -> Portlets -> Manage Portlets.

  • In the list of Portlets, highlight HOD 3270 Download and select Modify parameters.

  • In the hodCodeBase parameter enter the name of the server that is running the HOD server and point to the hod directory. In our example we used http://wtsc48.itso.ibm.com:86/hod.

  • Click Save. Then click Close.

click to expand
Figure 6-27: Screen to modify the parameters for the HOD portlet

Navigate to the ITSO place and bring up the page that has the HOD portlet, you should see the HOD portlet displaying a login screen as seen in Figure 6-28 on page 218. Enter the User ID and password and click Log On.


Figure 6-28: HOD portlet login window

If there are any sessions configured, you should see icons reflecting them on the next screen. If you double-click on any icon then that session will be activated. A new floating screen will be displayed and an icon will appear in the Active Sessions pane of the HOD portlet. See Figure 6-29 on page 219. You can use this session like a normal 3270 session.

click to expand
Figure 6-29: HOD portlet showing an active 3270 session

This ends the deployment and verification of the HOD portlet.

Lotus iNotes Portlets

The Portlet Catalog provides several portlets for accessing Lotus Notes® functions available on a Lotus Domino server, for example there are portlets called iNotes, Notes and MyNotes. The iNotes portlet can be used with the WebSphere Portal Enable edition giving users a browser view of the following Lotus Notes databases: mail, calendar, to-do, contacts and notebook.

We downloaded the Lotus iNotes Mail portlet from the Portlet Catalog NavCode: 1WP10007P which is saved as file inotes.war. The WAR file contains separate portlets for portlets mail, calendar, to-do, contacts and notebook and has a single configuration parameter authMethod for user sign on kept in the portlet.xml file in the WEB-INF directory inside the WAR file.

Tip 

We recommend that changes are made if required to web.xml and portlet.xml before deploying portlets on z/OS. This is because these files are in ASCII format and stored inside the runtime of the expanded WAR file on the application server, making it difficult to change them after deployment.

After deploying the portlets, we clicked on the portlet edit icon, and then added the Notes server and user configuration properties to the iNotes portlets as shown in Notebook portlet example in Figure 6-30.

click to expand
Figure 6-30: Edit the iNotes portlet

Click Save and the portlets will try to access the server and if successful you should see the Notes database as shown in the Mail portlet example in Figure 6-31 on page 221.

click to expand
Figure 6-31: iNotes Mail portlet

Lotus Quickplace

WebSphere Portal on z/OS can also be used to integrate access to Lotus Quickplace and there are portlets for this available in the Portlet Catalog. We cheated by using the iFrame portlet that was already installed on the portal server to access our Quickplace server with quite good results as shown in "Accessing Lotus Quickplace from Portal Server" on page 222.

click to expand
Figure 6-32: Accessing Lotus Quickplace from Portal Server

6.4.4 Deploy the Hello World Portlet

In 6.1.1, "Using Application Developer to develop a portlet" on page 184 we developed a portlet called HelloWorld.

The steps for installing and deploying a custom portlet developed using Application Developer are the same as listed in 6.3.1, "Portlet deployment jobs" on page 195, except for the fact that you browse the directory where the portlet WAR file was exported and copied to.

We followed the two-step process for deploying our Hello World portlet, placed it on a page on the portal and accessed the page with the result as seen in Figure 6-33.

click to expand
Figure 6-33: Our Hello World portlet deployed in the portal

6.4.5 Accessing CICS from a portlet

In this section we take a J2EE application called Trader that accesses an application running on CICS. The solution was developed for redpaper From code to deployment: Connecting to CICS from WebSphere V4.01 for z/OS, REDP0206, and run it under WebSphere Portal Server using the following two methods:

  1. Use the iFrame portlet to access the Trader application from its browser based GUI.

  2. Convert the Web application part of the J2EE application into a portlet.

Another option would be to use the ServletInvokerPortlet, that is installed but not deployed, to access and display the Web application from a portlet. The ServletInvokerPortlet can be configured with a URL to point to the Web page of a Web application. We did explore this option but at the time of writing we were not successful in getting this portlet to render correctly on z/OS.

The Trader application is available for download from:

http://publib-b.boulder.ibm.com/Redbooks.nsf/RedpaperAbstracts/redp0206.html?Open

It comes as packaged in a single file named Connector_code.zip. We downloaded the file and unzipped it to a directory and examined its contents. The unpacked file contains several directories: Completed Trader, Trader-Cobol, VisualAge® for Java and WebSphere Studio. Redpaper From code to deployment: Connecting to CICS from WebSphere V4.01 for z/OS, REDP0206, explains that the directory contents are as follows:

  • Completed Trader: the J2EE application EAR file

  • Trader-Cobol: code and JCL for the CICS application

  • VisualAge for Java: commarea data for the J2EE EJB

  • WebSphere Studio: WAR file and classes for the Web application

Figure 6-34 shows an overview of the complete Trader application.

click to expand
Figure 6-34: Trader application

Deployment of the complete application required the following prerequisites which we will not cover further in this book:

  1. WebSphere Application Server V4

  2. CTG V4.0.2 or CTG V5

  3. CICS TS V1.3

Once installed and deployed in a separate J2EE server region on our WebSphere Application Server and CICS the GUI for the Trader application looks like the example shown in Figure 6-35.

click to expand
Figure 6-35: J2EE and CIC's Trader application GUI

We obtained the JNDI name parameter for locating the EJB from the systems management SMEUI GUI as shown in Figure 6-36 on page 226.

click to expand
Figure 6-36: SMEUI view of TraderEJB home JNDI name

Using an iFrame to access Trader application from Portal

The iFrame portlet is one of the portlets that are installed and deployed during installation of the portal on z/OS. As its name implies it renders a target Web page by showing it inside an iFrame. The iFrame, which stands for inline frame, is still a fairly recent introduction to HTML and may not yet be supported by all browsers. We configured the iFrame portlet to point to URL http://wtsc58oe.itso.ibm.com:8081/TraderWeb/ and used the logon screen shown in Figure 6-37 on page 227 to logon to the Trader application.

click to expand
Figure 6-37: Logging onto Trader using the iFrame portlet

Since the Trader Web application uses quite straightforward HTML to render its simple user interface pages, the iFrame portlet handles the application quite well. Figure 6-38 on page 228 shows another example screen from one of the application's pages.

click to expand
Figure 6-38: Using the Trader application with the iFrame portlet

Converting Trader Web application to a portlet

As we have seen in Figure 6-34 on page 224, the Trader J2EE application consists of an EJB part and a Web application part. To transform this into a portlet we decided to leave untouched the EJB and concentrate on converting the Web application, consisting of servlets and JSPs, into a portlet. Some would call this portalizing.

For this we left the Web application and EJB installation untouched, running on another J2EE server on the same application server as portal. Figure 6-39 on page 229 shows an example of what we wanted to achieve by portalizing the Web application into a portlet called TraderPortlet, in comparison to using the iFrame portlet.

click to expand
Figure 6-39: TraderPortlet and iFrame portlet compared

A view from the systems management GUI SMEUI of our J2EE servers TAMAS and WSPORT is shown in Figure 6-40 on page 230. Note that for this project we did not enable any J2EE EJBROLES based security, so that by default our portal server ID was running with read access to EJBROLE. For a further discussion on this refer to Chapter 7, "Custom User Registry" on page 285.

click to expand
Figure 6-40: SMEUI view of J2EE servers

Our example does not represent a complete set of instructions on how to portalize a Web application, but just shows the steps we performed to get the example working with WebSphere Portal.

We started by importing the Completed_Trader.ear file into Application Developer using the import wizard as seen in Figure 6-41 on page 231.

click to expand
Figure 6-41: Import J2EE EAR wizard.

After completing this, then as shown from the J2EE perspective in Figure 6-42 on page 232 we were left with 275 project problems which Application Developer calls tasks.

click to expand
Figure 6-42: Tasks outstanding after importing Completed_Trader.ear

Not to worry, at this stage there were undoubtedly missing JAR files and since we would work with only half of the project, the Web application WAR, we decided to filter them out by selecting Filter Tasks->On selected resource only as seen in Figure 6-43.

click to expand
Figure 6-43: Filter tasks option

Our next step was to create the Portlet Application project in Application Developer by switching to a Portlet perspective, then right-clicking in the Navigator frame and selecting New -> Project -> Portlet application project as seen in Figure 6-44 on page 234.

click to expand
Figure 6-44: Creating a Portlet application project

Figure 6-45 on page 235 shows the settings we provided to define our Portlet project which we decided to call TraderPortlet. After entering the project's settings we clicked on Finish since we did not want Application Developer to add portlets for us, because we will use the TraderWeb.war Web application as our base for a portlet.

click to expand
Figure 6-45: Define the Portlet project

After clicking on Finish, Application Developer creates and populates the project for us as shown in Figure 6-46 on page 236.

click to expand
Figure 6-46: TraderPortlet project

Next we added TraderWeb.war to the project by clicking on the TraderPortlet project name and selecting File -> Import -> WAR file, as shown in Figure 6-47 on page 237.

click to expand
Figure 6-47: Import WAR

Figure 6-48 on page 238 shows the location of the WAR file and the options we set for the import.

click to expand
Figure 6-48: Import options for the WAR file

Finally we set the Module dependencies, which will update Application Developer's build and runtime classpaths, by clicking the checkbox for TraderEJB.jar as seen in Figure 6-49 on page 239.

click to expand
Figure 6-49: Set the module dependencies

We then clicked on Finish and also clicked on Yes to the dialog window shown in Figure 6-50.

click to expand
Figure 6-50: Resource dialog

Application Developer completes the import of the TraderWeb Web application WAR file into our portlet project as shown in Figure 6-51.

click to expand
Figure 6-51: Portlet application project with imported code from TraderWeb.war

Modifying the imported servlet to create a portlet

We now need to make changes to the imported servlet files to convert them into a portlet. The main items we needed to consider, examine and possibly change are the following.

  1. portlet.xml: Assign a servlet to be used for the portlet.

  2. HTML pages: Convert to JSPs.

  3. JSP source: Ensure only page fragments are in the JSP, use the Portal tag library as desired, parameterize the ACTION field of any FORMS, and ensure the INPUT field of any forms is unique in the portal namespace.

  4. Java source: Use Portlet API instead of Servlet API.

  5. web.xml: Update references.

  6. Miscellaneous considerations for changing a servlet to a portlet.

Note that as we have already said, this list is not meant to represent all the items that need to be considered when portalizing a Web application, but it was enough for our project, and we explain each of the things we did in more detail in the following steps.

1. Changing Portlet.xml

Servlets provide descriptor file web.xml in directory WEB-INF. In addition to this file portlets need to provide their own descriptor file portlet.xml. Parameters in portlet.xml typically include the servlet ID, concrete portlet ID, mark-up languages supported, title, and configuration options.

Using Application Developer we clicked on file portlet.xml in the WEB-INF directory, and noted that there were two tasks listed, complaining about the lack of a servlet reference. We expanded the Portlet application in the right hand Portlets view frame, and selected Portlet_1 as shown in Figure 6-52 on page 242.

click to expand
Figure 6-52: Select Portlet_1 to assign a servlet to the portlet

Next we clicked on the Browse button next to the grayed out Servlet list box, and in the pop-up dialog window selected TraderServlet which was the only servlet listed, as shown in Figure 6-52 on page 242.

click to expand
Figure 6-53: Select servlet to assign to the portlet

Click on OK, then File->Save portlet.xml and Application Developer updates the project and the Tasks listed for portlet.xml should have cleared.

2. Changing the HTML pages

Because WebSphere Portal aggregates multiple portlet JSPs into a single Web page, any existing HTML pages need to be converted to JSPs containing only page fragments that are rendered from the Portlet Java code. The Trader Web application servlet had a single HTML page Logon.html that we converted, bit in general this would need to be done for all HTML pages making up a Web application. Figure 6-54 on page 244 shows the top page level tags in Logon.html ready for deletion.

click to expand
Figure 6-54: Deleting page level tags from the HTML

Figure 6-55 on page 245 shows the bottom page level tags in Logon.html ready for deletion.

click to expand
Figure 6-55: Deleting page level tags from the HTML

The next to last step was to rename the HTML file from Logon.html to Logon.jsp as seen in Figure 6-56 on page 246.

click to expand
Figure 6-56: The newly renamed Logon.jsp

3. Changing JSPs

Next we need to modify the JSPs that were imported from the servlet. WebSphere Portal aggregates multiple portlet JSPs into a single Web page, so the portlet JSPs must consist only of page fragments. This means we need to remove all page level HTML tags from the JSPs, for example:

  • <!DOCTYPE HTML - ....>

  • <HTML>, </HTML>

  • <HEAD>, </HEAD>

  • <BODY>, </BODY>, including <META> and <LINK>

  • <TITLE>, </TITLE>

Application Developer will automatically generate the DOCTYPE mark up for Web pages and JSPs and we needed to turn this off. Select Window->Preferences, expand Web Tools and select Files, as shown in Figure 6-57 on page 247.

click to expand
Figure 6-57: Remove insert DOCTYPE preference

Uncheck Insert this DOCTYPE, also Include GENERATOR in HTML source, and click Apply followed by OK.

Next we modified JSPs Buy.jsp, CompanySelection.jsp, Quotes.jsp, Sell.jsp and TraderError.jsp to remove the page level tags. Using Buy.jsp as an example of how to do this we opened the source frame for the JSP and highlighted for deletion the tags above the <jsp:useBean...> tags as shown in Figure 6-58 on page 248.

click to expand
Figure 6-58: deleting page level tags from the JSP, part 1

We left alone the <jsp:useBean...> tag and also other tags that form the data of the body of the JSP, and highlighted the remaining page level tag for deletion at the bottom of the JSP as seen in Figure 6-59 on page 249.

click to expand
Figure 6-59: deleting page level tags from the JSP, part 2

We next need to change the ACTION field in any FORM's in the JSPs. The action field in an HTML form is used to tell the browser which service, for example a Web page, servlet, CGI, and so on, needs to be used to perform the action associated with the form. The JSPs from the Trader Web application servlet had a hard coded relative URI value of TraderServlet that is used to by the browser to call the servlet. In the case of a portlet running under Portal Server we do not know until runtime the value of the service that will be allocated by portlet container, so the JSP needs to obtain the ACTION field value when it executes.

There are different ways that the ACTION field value can be obtained at runtime. We chose to set a parameter for this value inside the portlet code; see "5) Changing the servlet Java code to portlet code" on page 255, and extract it from the PortletRequest object using the following code in the JSP: <FORM action='<%=request.getAttribute("actionVal")%>' method="POST">. We made this change as appropriate to all of our JSPs:

The next recommended step uses the Portal Server API from the portal tag library. This is done by adding statement <%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI" %> to the top of the JSPs, as shown in Figure 6-60 on page 250.

click to expand
Figure 6-60: Portal Tag library reference in Buy.jsp

Next add file portlet.tld to directory /WEB-INF in the project as shown in Figure 6-61 on page 251.

click to expand
Figure 6-61: Adding portlet.tld to the project directory

The portal tag library contains many useful functions that can be used by JSPs and we recommend that JSP and portlet developers become familiar with these functions. In our case we considered using the portal tag library to ensure that the INPUT fields on the FORMS inside are JSPs were assigned a unique value in the portal container namespace. This is necessary because the Portal Server reserves keyword values for its own use. An example of encoding an ACTION field in a form is to use a value such as: '<%= portletResponse.encodeNamespace("DisplayMode_attr")%>'.

In the end we did not bother to do this as we were working with a small number of portlets, and the existing values from the servlet JSPs did not clash with any of those reserved by the Portal Server, but it is the recommended practice for developing portlet JSPs.

The final change we made to the JSPs with our TraderPortlet project was to move the JSPs into project directory /WEB-INF, and additionally create another directory named /WEB-INF/html and copy the JSPs there as well as shown in Chapter 6, "JSPs in WEB-INF directory" on page 252.

click to expand
Figure 6-62: JSPs in WEB-INF directory

Although not strictly necessary for our small project, you should be aware that to support different mark-up languages and NLS language translations, the portlet container assumes there is a specific directory structure for them in directory WEB-INF, and searches them starting from the bottom of the directory tree.

Example 6-2 shows the original CompanySelection.jsp taken from the servlet where we have highlighted lines that are subject to modification or change based on the preceding comments.

Example 6-2: Original CompanySelection.jsp

start example
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"><!-- Sample JSP file --> <HTML> <HEAD> <META name="GENERATOR" content="IBM WebSphere Page Designer V3.0.2 for Windows"> <META http-equiv="Content-Style-Type" content="text/css"> <TITLE> Company Selection </TITLE> </HEAD> <BODY BGCOLOR="#FFFFFF"> <jsp:useBean   scope="request" /> <H1 align="center">Company Selection</H1> <CENTER> <TABLE width="500" border="1">   <TBODY>     <TR>       <TD width="59" align="center" valign="middle"><B>Company</B></TD>       <TD width="70" align="center" valign="middle"><B>Quotes</B></TD>       <TD width="70" align="center" valign="middle"><B>Buy</B></TD>       <TD width="68" align="center" valign="middle"><B>Sell</B></TD>     </TR>     <% for(int i=0; i<companiesBean.numOfCompanies();i++) {          String compName = companiesBean.getCompany(i); %>     <TR valign="top" align="center">       <TD width="300" align="center" valign="top" height="27"><%= compName %></TD>       <TD width="60" align="center" valign="middle" height="25">       <FORM action="TraderServlet" method="POST"><INPUT type="submit" name="doShowQuotes" value="Quotes">                  <INPUT type="hidden" name="company" value="<%= compName%>">                </FORM>       </TD>       <TD width="60" align="center" valign="middle">       <FORM action="TraderServlet" method="POST"><INPUT type="submit" name="doShowBuy" value="Buy">                  <INPUT type="hidden" name="company" value="<%= compName%>">                </FORM>       </TD>       <TD width="60" align="center" valign="middle">       <FORM action="TraderServlet" method="POST"><INPUT type="submit" name="doShowSell" value="Sell">                  <INPUT type="hidden" name="company" value="<%= compName%>">                </FORM>       </TD>     </TR>     <% } %>   </TBODY> </TABLE> </CENTER> <FORM action="TraderServlet" method="POST"> <CENTER><INPUT type="submit" name="doShowLogoff" value="Logoff"></CENTER> </FORM> </BODY> </HTML> 
end example

Example 6-3 shows CompanySelection.jsp from our new TraderPortlet portlet where we have highlighted the lines that we actually added or modified. Note that we added a System.out.println statement at one stage to help us with debug as noted in Chapter 4, "Log Files" on page 136.

Example 6-3: Modified CompanySelection.jsp

start example
 <%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI" %> <jsp:useBean   scope="request" /> <H1 align="center">Company Selection</H1> <CENTER> <TABLE width="500" border="1">   <TBODY>     <TR>       <TD width="59" align="center" valign="middle"><B>Company</B></TD>       <TD width="70" align="center" valign="middle"><B>Quotes</B></TD>       <TD width="70" align="center" valign="middle"><B>Buy</B></TD>       <TD width="68" align="center" valign="middle"><B>Sell</B></TD>     </TR>     <% System.out.println("C= Henry Company JSP getAttribute = " + (String)request.getAttribute("actionVal")); %>     <% for(int i=0; i<companiesBean.numOfCompanies();i++) {          String compName = companiesBean.getCompany(i); %>     <TR valign="top" align="center">       <TD width="300" align="center" valign="top" height="27"><%= compName %></TD>       <TD width="60" align="center" valign="middle" height="25">       <% // Form action parameter obtained from portlet %>       <FORM action='<%=request.getAttribute("actionVal")%>' method="POST"><INPUT type="submit" name="doShowQuotes" value="Quotes">                  <INPUT type="hidden" name="company" value="<%= compName%>">                </FORM>       </TD>       <TD width="60" align="center" valign="middle">       <% // Form action parameter obtained from portlet %>       <FORM action='<%=request.getAttribute("actionVal")%>' method="POST"><INPUT type="submit" name="doShowBuy" value="Buy">                  <INPUT type="hidden" name="company" value="<%= compName%>">                </FORM>       </TD>       <TD width="60" align="center" valign="middle">       <% // Form action parameter obtained from portlet %>       <FORM action='<%=request.getAttribute("actionVal")%>' method="POST"><INPUT type="submit" name="doShowSell" value="Sell">                  <INPUT type="hidden" name="company" value="<%= compName%>">                </FORM>       </TD>     </TR>     <% } %>   </TBODY> </TABLE> </CENTER> <% // Form action parameter obtained from portlet %> <FORM action='<%=request.getAttribute("actionVal")%>' method="POST"> <CENTER><INPUT type="submit" name="doShowLogoff" value="Logoff"></CENTER> </FORM> 
end example

4. Modifying web.xml

File web.xml from the servlet contained references to the welcome HTML page including Logon.html which we deleted. We also changed the url-pattern tag to /TraderServlet/*. Web.xml controls many of the execution and configuration parameters of the portlet -servlet, including for example security user ID's, that we did not explore here. For this project we could have left web.xml as it was, but for general conversion of a servlet to a portlet, examination and modification of this file will most likely be needed.

5. Changing the servlet Java code to portlet code

The major effort in changing the Trader Web application from a servlet to a portlet required changes to the servlet's Java code. The servlet consisted of two Java beans, ErrorInfoBean.java and UserInfoBean.java, that after examination we left unchanged.

The main servlet file TraderServlet.java needed quite significant modifications to convert it to a portlet. Some general items to be considered for this work are as follows.

  1. Add the portlet API imports to the source, for example:

     import org.apache.jetspeed.portlet.*; import org.apache.jetspeed.portlets.* 

  2. Decide which portlet class to use for the implementation. In the simple Hello World example in 6.2, "Portlet development example" on page 185 we extended the AbstractPortlet class, but the PortletAdapter class provides a default implementation of the AbstractPortlet class, and is recommended instead.

  3. Remove any doXXX() servlet methods, for example in our case doGet() and doPost(), and replace them with the doView() method instead. Consider adding other processing methods doEdit(), doHelp() and doConfig() to the portlet as appropriate.

  4. Change servlet API calls to the HTTPSession object to use the portlet API instead. For example change:

     UserInfoBean userInfo = (UserInfoBean)httpSesion.getAttribute(userInfoID); 

    to

     UserInfoBean userInfo = (UserInfoBean)request.getAttribute(userInfoID); 

  5. Change other servlet API calls to use the equivalent portlet API calls, some examples:

    1. HttpServlet to PortletAdapter

    1. HttpServletRequest to PortletRequest

    2. HttpServletResponse to PortletResponse

    3. ServletException to PortletException

    4. HttpServletSession to PortletSession

  6. Set JSPs FORM ACTION fields for runtime determination by JSPs, for example:

     PortletURI traderURI = response.createURI(); PortletAction newAction = new DefaultPortletAction("logon"); traderURI.addAction(newAction); request.setAttribute("actionVal", traderURI.toString()); 

  7. Render the JSPs to display portlet views, for example:

     getPortletConfig().getContext().include("/jsp/Logon.jsp", request, response); 

  8. Add any state handling to the portlet for user interaction, for example to handle cases where users switch portal pages away from the portlet and the return again within the same session.

Example 6-4 shows the complete source code listing of the TraderServlet before we converted it into a TraderPortlet:

Example 6-4: The servlet code before modification

start example
 package itso.cics.eci.j2ee.trader.servlet; import itso.cics.eci.j2ee.trader.*; import java.io.*; import javax.ejb.*; import javax.servlet.http.*; import javax.servlet.*; public class TraderServlet extends javax.servlet.http.HttpServlet {    // HttpSession IDs    private final static String traderID = "Trader";    private final static String companiesID = "Companies";    private final static String userInfoID = "userInfo";    // constants used in JSPs    // field names    private final static String fieldDoPerformLogon = "doPerformLogon";    private final static String fieldDoShowQuotes = "doShowQuotes";    private final static String fieldDoShowBuy = "doShowBuy";    private final static String fieldDoPerformBuy = "doPerformBuy";    private final static String fieldDoShowSell = "doShowSell";    private final static String fieldDoPerformSell = "doPerformSell";    private final static String fieldDoShowCompanies = "doShowCompanies";    private final static String fieldDoShowLogoff = "doShowLogoff";    private final static String fieldJndiName = "jndiName";    private final static String fieldNameService = "nameService";    private final static String fieldProviderURL = "providerURL";    private final static String fieldUserID = "userid";    private final static String fieldPassword = "password";    private final static String fieldCompany = "company";    private final static String fieldNumberOfShares = "numberOfShares";    // JSPs    private final static String jspLogon = "Logon.html";    private final static String jspCompanySelection = "CompanySelection.jsp";    private final static String jspQuotes = "Quotes.jsp";    private final static String jspBuy = "Buy.jsp";    private final static String jspSell = "Sell.jsp";    private final static String jspTraderError = "TraderError.jsp";    // beans    private final static String beanCompanies = "companiesBean";    private final static String beanQuotes = "quotesBean";    private final static String beanUserInfo = "userInfoBean";    private final static String beanErrorMessage = "errorMessageBean"; /**  * Process incoming HTTP GET requests  *  * @param request Object that encapsulates the request to the servlet  * @param response Object that encapsulates the response from the servlet  */ public void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException {    performTask(request, response); } /**  * Process incoming HTTP POST requests  *  * @param request Object that encapsulates the request to the servlet  * @param response Object that encapsulates the response from the servlet  */ public void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException {    performTask(request, response); } private String getCurrentCompany(HttpServletRequest request) throws Exception {    HttpSession httpSesion = request.getSession();    UserInfoBean userInfo = (UserInfoBean)httpSesion.getAttribute(userInfoID);    return userInfo.getCompany(); } public String getServletInfo() {    return super.getServletInfo(); } public String handleShowBuy(HttpServletRequest request) throws Exception {    // query company and update it    updateCompany(request);    // return user info    returnUserInfo(request);    // show buy panel    return jspBuy; } public String handleShowError(HttpServletRequest request, String errorText) throws Exception {    request.setAttribute(beanErrorMessage, new ErrorMessageBean(errorText));    return jspTraderError; } public String handleShowError(HttpServletRequest request, String errorText, String stackTrace) throws Exception {    request.setAttribute(beanErrorMessage, new ErrorMessageBean(errorText, stackTrace));    return jspTraderError; } public String handleShowSell(HttpServletRequest request) throws Exception {    // query company and update it    updateCompany(request);    // return user info    returnUserInfo(request);    // show sell panel    return jspSell; } /**  * Initializes the servlet.  */ public void init() {    // insert code to initialize the servlet here } /**  * Process incoming requests for information  *  * @param request Object that encapsulates the request to the servlet  * @param response Object that encapsulates the response from the servlet  */ public void performTask(HttpServletRequest request, HttpServletResponse response) {    try {       // declare tader       Trader trader = null;       // obtain HttpSession       HttpSession httpSesion = request.getSession();       // if logon request       if ( request.getParameter(fieldDoPerformLogon) != null) {          // create new trader session bean and keep it in session          trader = createTrader(request);          httpSesion.setAttribute(traderID, trader);       }       else {// for all other request trader must already exist          // retrieve trader from session          trader = (Trader)httpSesion.getAttribute(traderID);       }       // check which request we got and dispatch to appropriate method       String nextJsp = null;       if ( request.getParameter(fieldDoPerformLogon) != null )          nextJsp = handlePerformLogon(request, trader);       else if ( request.getParameter(fieldDoShowQuotes) != null )          nextJsp = handleShowQuotes(request, trader);       else if ( request.getParameter(fieldDoShowCompanies) != null )          nextJsp = handleShowCompanies(request, trader);       else if ( request.getParameter(fieldDoShowBuy) != null )          nextJsp = handleShowBuy(request);       else if ( request.getParameter(fieldDoPerformBuy) != null )          nextJsp = handlePerformBuy(request, trader);       else if ( request.getParameter(fieldDoShowSell) != null )          nextJsp = handleShowSell(request);       else if ( request.getParameter(fieldDoPerformSell) != null )          nextJsp = handlePerformSell(request, trader);       else if ( request.getParameter(fieldDoShowLogoff) != null )          nextJsp = handleShowLogoff(request, trader);       else          nextJsp = handleShowError(request, "Got unknown request to process, check the JSPs.");       // now process JSP       ServletContext sc = getServletContext();       RequestDispatcher rd = sc.getRequestDispatcher("/" + nextJsp);       rd.forward(request, response);    }    catch(Throwable theException) {       try {          trace( "We got an exception in TraderServlet.performTask" );          theException.printStackTrace();          ByteArrayOutputStream bas = new ByteArrayOutputStream();          PrintStream ps = new PrintStream( bas );          theException.printStackTrace(ps);          String nextJsp = handleShowError(request, "Error processing bean: " + theException.toString(), bas.toString() );          ServletContext sc = getServletContext();          RequestDispatcher rd = sc.getRequestDispatcher("/" + nextJsp);          rd.forward(request, response);       }       catch( Throwable t ) {          System.out.println( "Fatal error, exception in exception handling!" );          t.printStackTrace();       }    } } private void returnUserInfo(HttpServletRequest request) throws Exception {    // return user info    HttpSession httpSesion = request.getSession();    UserInfoBean userInfo = (UserInfoBean)httpSesion.getAttribute(userInfoID);    request.setAttribute(beanUserInfo, userInfo); } private void trace(String txt) {    System.err.println( txt ); } private void updateCompany(HttpServletRequest request) {    String company = request.getParameter(fieldCompany);    HttpSession httpSesion = request.getSession();    UserInfoBean userInfo = (UserInfoBean)httpSesion.getAttribute(userInfoID);    userInfo.setCompany(company);    request.getSession().setAttribute(userInfoID, userInfo ); } private Trader createTrader(HttpServletRequest request) throws javax.naming.NamingException, javax.ejb.CreateException, java.rmi.RemoteException {    // retrieve fields    String jndiName = request.getParameter(fieldJndiName);    String nameService = request.getParameter(fieldNameService);    String providerURL = request.getParameter(fieldProviderURL);    // create initial context    java.util.Hashtable properties = new java.util.Hashtable(2);    properties.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, nameService);    properties.put(javax.naming.Context.PROVIDER_URL, providerURL);    javax.naming.InitialContext ctx = new javax.naming.InitialContext(properties);    // lookup TraderHome    Object obj = ctx.lookup(jndiName); // Use the JNDI name from HTML page    // narrow to TraderHome and create Trader    TraderHome traderHome = (TraderHome)javax.rmi.PortableRemoteObject.narrow((org.omg.CORBA.Object)obj, TraderHome.class);    Trader trader = traderHome.create();    return trader; }public String handlePerformBuy(HttpServletRequest request, Trader trader) throws Exception {    // get the number of shares    String numberOfShares = request.getParameter(fieldNumberOfShares);    String company = getCurrentCompany(request);    // convert to integer    int shares = 0;    try {       shares = Integer.parseInt(numberOfShares);    } catch( Exception e ) {    }    // buy shares    trader.buy( company, shares );    // return user info    returnUserInfo(request);    // go back to companies selction    return handleShowCompanies(request, trader); }public String handlePerformLogon(HttpServletRequest request, Trader trader ) throws Exception {    // retrieve fields    String userID = request.getParameter(fieldUserID);    String password = request.getParameter(fieldPassword);    // check if userID and password are provided    if( userID.equals("") || password.equals("") )       return handleShowError(request, "You have to specify userID AND password" );    // now logon to the application    trader.logon( userID, password);    // store user info, we need it later    UserInfoBean userInfo = new UserInfoBean();    userInfo.setUserID(userID);    request.getSession().setAttribute(userInfoID, userInfo );    // show companies now    return handleShowCompanies(request, trader); }public String handlePerformSell(HttpServletRequest request, Trader trader) throws Exception {    // get the number of shares    String numberOfShares = request.getParameter(fieldNumberOfShares);    String company = getCurrentCompany(request);    // convert to integer    int shares = 0;    try {       shares = Integer.parseInt(numberOfShares);    } catch( Exception e ) {    }    // sell shares    trader.sell( company, shares );    // return user info    returnUserInfo(request);    // go back to companies selction    return handleShowCompanies(request,trader); }public String handleShowCompanies(HttpServletRequest request, Trader trader) throws Exception {    // check for local copy    HttpSession httpSesion = request.getSession();    CompaniesBean companies = (CompaniesBean)httpSesion.getAttribute(companiesID);    if( companies == null ) {// if not stored locally       companies = trader.getCompanies();       // to improve response time, store it locally       request.getSession().setAttribute(companiesID, companies );    }    request.setAttribute(beanCompanies, companies);    return jspCompanySelection; }public String handleShowLogoff(HttpServletRequest request, Trader trader) throws Exception {    // logoff from trader    trader.logoff();    // remove trader object in EJB server    trader.remove();    // remove session variables    request.getSession().removeAttribute(traderID);    request.getSession().removeAttribute(companiesID);    request.getSession().removeAttribute(userInfoID);    // return to logon panel    return jspLogon; }public String handleShowQuotes(HttpServletRequest request, Trader trader) throws Exception {    // query company and update it    updateCompany(request);    // get the quotes    String company = request.getParameter(fieldCompany);    QuotesBean quotes = trader.getQuotes(company);    // return quotes    request.setAttribute(beanQuotes, quotes);    // return user info    returnUserInfo(request);    // show the quotes    return jspQuotes; } } 
end example

Example 6-5 shows the complete source code listing of new TraderPortlet modified from the original servlet where we have highlighted new or modified lines. Note that we tried to leave the code logic intact but have re-ordered the methods to a more meaningful order (init, doView, performTask, and so on):

Example 6-5: The Portlet code after modification

start example
 package itso.cics.eci.j2ee.trader.servlet; import itso.cics.eci.j2ee.trader.*; import java.io.*; import javax.ejb.*; // Added for portlet import org.apache.jetspeed.portlet.*; import org.apache.jetspeed.portlets.*; /**  * TraderServlet converted to run as a portlet  */ public class TraderServlet extends org.apache.jetspeed.portlet.PortletAdapter {    // PortletSession IDs    private final static String traderID = "Trader";    private final static String companiesID = "Companies";    private final static String userInfoID = "userInfo";    // constants used in JSPs    // field names    private final static String fieldDoPerformLogon = "doPerformLogon";    private final static String fieldDoShowQuotes = "doShowQuotes";    private final static String fieldDoShowBuy = "doShowBuy";    private final static String fieldDoPerformBuy = "doPerformBuy";    private final static String fieldDoShowSell = "doShowSell";    private final static String fieldDoPerformSell = "doPerformSell";    private final static String fieldDoShowCompanies = "doShowCompanies";    private final static String fieldDoShowLogoff = "doShowLogoff";    private final static String fieldJndiName = "jndiName";    private final static String fieldNameService = "nameService";    private final static String fieldProviderURL = "providerURL";    private final static String fieldUserID = "userid";    private final static String fieldPassword = "password";    private final static String fieldCompany = "company";    private final static String fieldNumberOfShares = "numberOfShares";    private String state = null;    // JSPs    private final static String jspLogon = "Logon.jsp";    private final static String jspCompanySelection = "CompanySelection.jsp";    private final static String jspQuotes = "Quotes.jsp";    private final static String jspBuy = "Buy.jsp";    private final static String jspSell = "Sell.jsp";    private final static String jspTraderError = "TraderError.jsp";    // beans    private final static String beanCompanies = "companiesBean";    private final static String beanQuotes = "quotesBean";    private final static String beanUserInfo = "userInfoBean";    private final static String beanErrorMessage = "errorMessageBean"; /**  * Initializes the portlet.  */ public void init(PortletConfig portletConfig) throws UnavailableException {       super.init(portletConfig);       plog("TraderPortlet - init()"); } /**  * doView method added for the portlet, (instead of doGet, doPost)  */ public void doView(PortletRequest request, PortletResponse response) throws PortletException, java.io.IOException {       // Set state for processing JSP's       state = (String)request.getPortletSession().getAttribute("state");       plog("TraderPortlet - doView(), state = " + state);       // If first time through? update state, show Logon JSP       if (state == null) {          state = "logon";          request.getPortletSession().setAttribute("state", state);           // Create URI for the logon JSP FORM action attribute          PortletURI traderURI = response.createURI();          PortletAction newAction = new DefaultPortletAction("logon");        traderURI.addAction(newAction);        // save the URI so the JSP can get it          request.setAttribute("actionVal", traderURI.toString());          // Display logon JSP to render        getPortletConfig().getContext().include("/jsp/Logon.jsp", request, response);       }       // Not first time thorough, process task(s) from JSP       else {           performTask(request, response);       } } /**  * Process incoming requests for information  * (session handling changed for portlet and state tracking)  */ public void performTask(PortletRequest request, PortletResponse response) {    plog("TraderPortlet - performTask()");    try {       // declare tader       Trader trader = null;       // if logon request       if ( request.getParameter(fieldDoPerformLogon) != null) {          // create new trader session bean and keep it in session          trader = createTrader(request);          request.getPortletSession().setAttribute(traderID, trader);       }       else {       // for all other request trader must already exist          // so retrieve trader from session          trader = (Trader)request.getPortletSession().getAttribute(traderID);       }          // check which request we got and dispatch to appropriate method          String nextJsp = null;          if ( request.getParameter(fieldDoPerformLogon) != null ){             nextJsp = handlePerformLogon(request, trader);             request.getPortletSession().setAttribute("state", fieldDoPerformLogon);       }       else if ( request.getParameter(fieldDoShowQuotes) != null ){          nextJsp = handleShowQuotes(request, trader);          request.getPortletSession().setAttribute("state", fieldDoShowQuotes);       }       else if ( request.getParameter(fieldDoShowCompanies) != null ){          nextJsp = handleShowCompanies(request, trader);          request.getPortletSession().setAttribute("state", fieldDoShowCompanies);       }       else if ( request.getParameter(fieldDoShowBuy) != null ){          nextJsp = handleShowBuy(request);          request.getPortletSession().setAttribute("state", fieldDoShowBuy);       }       else if ( request.getParameter(fieldDoPerformBuy) != null ){          nextJsp = handlePerformBuy(request, trader);          request.getPortletSession().setAttribute("state", fieldDoPerformBuy);       }       else if ( request.getParameter(fieldDoShowSell) != null ){          nextJsp = handleShowSell(request);          request.getPortletSession().setAttribute("state", fieldDoShowSell);       }       else if ( request.getParameter(fieldDoPerformSell) != null ){          nextJsp = handlePerformSell(request, trader);          request.getPortletSession().setAttribute("state", fieldDoPerformSell);       }       else if (request.getParameter(fieldDoShowLogoff) != null){          nextJsp = handleShowLogoff(request, trader);          request.getPortletSession().setAttribute("state", fieldDoShowLogoff);       }       // unknown request, try to get back to where we were       else {          state = (String)request.getPortletSession().getAttribute("state");          if (state.equals(fieldDoPerformLogon)) {          nextJsp = handlePerformLogon(request, trader);          }          else if (state.equals(fieldDoShowQuotes)) {          nextJsp = handleShowQuotes(request, trader);          }          else if (state.equals(fieldDoShowCompanies)) {          nextJsp = handleShowCompanies(request, trader);          }          else if (state.equals(fieldDoShowBuy)) {          nextJsp = handleShowBuy(request);          }          else if (state.equals(fieldDoPerformBuy)) {          nextJsp = handlePerformBuy(request, trader);          }          else if (state.equals(fieldDoShowSell)) {          nextJsp = handleShowSell(request);          }          else if (state.equals(fieldDoPerformSell)) {          nextJsp = handlePerformSell(request, trader);          }          else if (state.equals(fieldDoShowLogoff)) {          nextJsp = handleShowLogoff(request, trader);          }       }       plog("TraderPortlet in PerformTask(), nextJSP = " + nextJsp);       // Changed for portlet       // Create URI for the logon JSP FORM action attribute       PortletURI traderURI = response.createURI();       PortletAction newAction = new DefaultPortletAction("company");       traderURI.addAction(newAction);       // save the URI so the JSP can get it       request.setAttribute("actionVal", traderURI.toString());       // Display next JSP to render        getPortletConfig().getContext().include("/jsp/" + nextJsp, request, response);    }    catch(Throwable theException) {       try {          trace( "WebSphere Portal : we got an exception in TraderPortlet.performTask" );          theException.printStackTrace();          ByteArrayOutputStream bas = new ByteArrayOutputStream();          PrintStream ps = new PrintStream( bas );          theException.printStackTrace(ps);          String nextJsp = handleShowError(request, "Error processing bean: " + theException.toString(), bas.toString() );          // Changed for portlet          /// Display next JSP to render        getPortletConfig().getContext().include("/jsp/" + nextJsp, request, response);       }       catch(Throwable t) {          t.printStackTrace();       }    } } /**  * Extract current Company from UserInfoBean.  */ private String getCurrentCompany(PortletRequest request) throws Exception {    plog("TraderPortlet - getCurrentCompany()");    // Session access changed for portlet    UserInfoBean userInfo = (UserInfoBean)request.getPortletSession().getAttribute(userInfoID);    return userInfo.getCompany(); } /**  * Process buy request  */ public String handleShowBuy(PortletRequest request) throws Exception {    plog("TraderPortlet - handleShowBuy()");    // query company and update it    updateCompany(request);    // return user info    returnUserInfo(request);    // show buy panel    return jspBuy; } /**  * Process an error  */ public String handleShowError(PortletRequest request, String errorText ) throws Exception {    request.setAttribute(beanErrorMessage, new ErrorMessageBean(errorText));    return jspTraderError; } /**  * Process an error with Stack  */ public String handleShowError(PortletRequest request, String errorText, String stackTrace ) throws Exception {    request.setAttribute(beanErrorMessage, new ErrorMessageBean(errorText, stackTrace));    return jspTraderError; } /**  * Process sell request  */ public String handleShowSell(PortletRequest request) throws Exception {    plog("TraderPortlet - handleShowSell()");    // query company and update it    updateCompany(request);    // return user info    returnUserInfo(request);    // show sell panel    return jspSell; } /**  * Get user info and set in UserInfoBean  */ private void returnUserInfo(PortletRequest request) throws Exception {    plog("TraderPortlet - returnUserInfo()");    // Session handling changed for portlet, get bean from session    UserInfoBean userInfo = (UserInfoBean)request.getPortletSession().getAttribute(userInfoID);    //set UserInfoBean for JSP    request.setAttribute(beanUserInfo, userInfo); } /**  * Print exceptions in error log  */ private void trace(String txt) {    System.err.println(txt); } /**  * Added for portlet, log data to Portal Log  */ private void plog(String txt) {    PortletLog log = getPortletConfig().getContext().getLog();    if (log.isDebugEnabled()) log.debug(txt);    if (log.isWarnEnabled()) log.warn(txt);    if (log.isInfoEnabled()) log.info(txt);    if (log.isErrorEnabled()) log.error(txt); } /**  * Get company selected and save in UserInfoBean  */ private void updateCompany(PortletRequest request) {    plog("TraderPortlet - updateCompany()");    // Get company selected by user    String company = request.getParameter(fieldCompany);    // Session handling changed for portlet    UserInfoBean userInfo = (UserInfoBean)request.getPortletSession().getAttribute(userInfoID);    // save in UserInfoBean    userInfo.setCompany(company);    // save in session for JSP    request.getPortletSession().setAttribute(userInfoID, userInfo ); } /**  * Lookup and accesss Trader EJB  */ private Trader createTrader(PortletRequest request) throws javax.naming.NamingException, javax.ejb.CreateException, java.rmi.RemoteException {    // Retrieve fields from logon page    String jndiName = request.getParameter(fieldJndiName);    String nameService = request.getParameter(fieldNameService);    String providerURL = request.getParameter(fieldProviderURL);    // create initial context    java.util.Hashtable properties = new java.util.Hashtable(2);    properties.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, nameService);    properties.put(javax.naming.Context.PROVIDER_URL, providerURL);    javax.naming.InitialContext ctx = new javax.naming.InitialContext(properties);    Object obj = ctx.lookup(jndiName); // Use the JNDI name from logon JSP    // narrow to TraderHome and create Trader    TraderHome traderHome = (TraderHome)javax.rmi.PortableRemoteObject.narrow((org.omg.CORBA.Object)obj, TraderHome.class);    Trader trader = traderHome.create();    return trader; } /**  * Process buy request  */ public String handlePerformBuy(PortletRequest request, Trader trader) throws Exception {    plog("TraderPortlet - handlePerformBuy()");    // get the number of shares    String numberOfShares = request.getParameter(fieldNumberOfShares);    String company = getCurrentCompany(request);    // convert to integer    int shares = 0;    try {       shares = Integer.parseInt(numberOfShares);    }    catch( Exception e ) {    }    // buy shares    trader.buy(company, shares);    // return user info    returnUserInfo(request);    // go back to companies selection    return handleShowCompanies(request, trader); } /**  * Process logon request  */ public String handlePerformLogon(PortletRequest request, Trader trader ) throws Exception {    plog("TraderPortlet - handlePerformLogon()");    // retrieve input fields user and password    String userID = request.getParameter(fieldUserID);    String password = request.getParameter(fieldPassword);    // check if userID and password are provided    if( userID.equals("") || password.equals("") )       return handleShowError(request, "You have to specify userID AND password" );    // now logon to the application    trader.logon(userID, password);    // store user info, we need it later    UserInfoBean userInfo = new UserInfoBean();    userInfo.setUserID(userID);    // session changed for portlet    request.getPortletSession().setAttribute(userInfoID, userInfo );    // show companies now    return handleShowCompanies(request, trader); } /**  * Process sell request  */ public String handlePerformSell(PortletRequest request, Trader trader) throws Exception {    plog("TraderPortlet - handlePerformSell()");    // get the number of shares    String numberOfShares = request.getParameter(fieldNumberOfShares);    String company = getCurrentCompany(request);    // convert to integer    int shares = 0;    try {       shares = Integer.parseInt(numberOfShares);    } catch( Exception e ) {    }    // sell shares    trader.sell( company, shares );    // return user info    returnUserInfo(request);    // go back to companies selection    return handleShowCompanies(request,trader); } /**  * Show companies list  */ public String handleShowCompanies(PortletRequest request, Trader trader) throws Exception {    plog("TraderPortlet - handleShowCompanies()");    // check for local copy of bean (session handling changed for portlet)    CompaniesBean companies = (CompaniesBean)request.getPortletSession().getAttribute(companiesID);    // if not stored locally in session    if( companies == null ) {       companies = trader.getCompanies();       // to improve response time, store it locally       request.getPortletSession().setAttribute(companiesID, companies );    }     // set bean for JSP    request.setAttribute(beanCompanies, companies);    return jspCompanySelection; } /**  * Handle logoff  */ public String handleShowLogoff(PortletRequest request, Trader trader) throws Exception {    plog("TraderPortlet - handleShowLogoff()");    // logoff from trader    trader.logoff();    // remove trader object in EJB server    trader.remove();    // remove session variables (session handling changed for portlet)    request.getPortletSession().removeAttribute(traderID);    request.getPortletSession().removeAttribute(companiesID);    request.getPortletSession().removeAttribute(userInfoID);    // return to logon panel    return jspLogon; } /**  * Show requested quotes  */ public String handleShowQuotes(PortletRequest request, Trader trader) throws Exception {    plog("TraderPortlet - handleShowQuotes()");    // query company and update it    updateCompany(request);    // get the company requested    String company = request.getParameter(fieldCompany);    // and get the quotes    QuotesBean quotes = trader.getQuotes(company);    // return quotes    request.setAttribute(beanQuotes, quotes);    // return user info    returnUserInfo(request);    // show the quotes    return jspQuotes; } } 
end example

6. Other things to consider when converting a servlet to a portlet

We have already covered the first four of the following items but list them here for convenience:

  1. Add the Portal API available from the WebSphere Portal tag library <%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI" %> then the JSP can use the Portal API. An example of this is shown in the next item to define a unique form namespace. If the JSP uses the Portal tag library then the library must be available in the WAR file directory /WEB-INF/tld.

  2. Ensure the HTML object namespace is unique within WebSphere Portal We did not do this, but an example applied to the INPUT field of the form in Buy.jsp is:

     <INPUT type="submit" name='<portletAPI:encodeNamespace value="Buy"/>'> 

  3. Set the action attribute of the forms in the JSPs from the doView, doPost and doGet methods in the portlet:

     PortletURI traderURI = response.createURI(); request.setAttribute("actionVal", traderURI.toString()); 

    Then in the JSP form the attribute must be evaluated, for example:

     <FORM action='<%=actionVal%>'> 

  4. In the JSPs with forms, retrieve the URI for the action attribute:

     <jsp:useBean   scope="request" /> 

  5. Add desired Portal themes and skins to the portlet We did not do this.

  6. Cleanup file names and variables to remove references to servlet We did not do this.

  7. Add additional mark-up language support to the portlet We did not do this.

  8. Import an EJB application client JAR if the portlet references EJBs For the Trader application, as we have seen in Figure 6-34 on page 224 the Web application part of the servlet, and therefore the TraderPortlet java code, performs a lookup of the JNDI namespace for the EJB home of the session bean used to wrapper the EJB that connects to CICs. At this stage this was reflected in the many cross reference errors we were seeing in the Application Developer tasks list when building the portal project.

    From the portlet perspective of the TraderEJB project in Application Developer we identified file imported_classes_EJB.jar which we found in the Application Developer directory structure file-system, and subsequently imported into the /lib directory of TraderPortlet project. This immediately resolved all of our build errors caused by missing references to the EJB.

Tip 

Additional information on portlet development is available in redbook IBM WebSphere Portal Developers Handbook, SG24-6897.

At this stage with building the portlet project, assuming there are no errors, listed by Application Developer as tasks, it is ready for either debug and testing using the development environment we described in Chapter 3, "Installing the Portal Toolkit" on page 104, or deployment directly to WebSphere Portal on z/OS for testing.

After deploying TraderServlet to WebSphere Portal, and adding it to a page we had created in out of CICS' test application place, we used the logon page rendered from our Logon.jsp and shown in Figure 6-63 on page 279 to sign on to the Trader application.

click to expand
Figure 6-63: TraderPortlet inside the Portal

As we have seen in Figure 6-36 on page 226 the EJB location parameters specified by the JNDI name are specified globally and are the same as the one we used for the original Trader Web application.

After signing on to the Trader application the Company Selection screen is received as shown in Figure 6-64 on page 280.

click to expand
Figure 6-64: Company Selection screen from the Trader Portlet

To test and exercise the portlet we chose to buy and sell some shares, first by obtaining some quotes from IBM as seen in Figure 6-65 on page 281.

click to expand
Figure 6-65: Quotes screen from the Trader Portlet

Finally the "sell shares" portlet view is shown from the portlet in Figure 6-66 on page 282.

click to expand
Figure 6-66: Sell Shares screen from the Trader Portlet

That concluded our exercise in portalizing an existing Web application to run as a portlet on WebSphere Portal. Although this was quite a simple example to work with, it demonstrated several things:

  1. The logic in the servlet being converted can remain largely intact.

  2. No deployment changes are needed at all to an existing J2EE application consisting of Web applications and EJBs.

  3. Most of the work was in handling the portlet API for the servlet/portlet/JSPs, as might be expected. For this it helps if the developer has a working knowledge of servlet/JSP programming and understands the indirection added by the portlet API.

  4. The Model-View-Controller design pattern is applicable to portlet programming, where JSPs are used for the View, portlets used for the Controller and Beans/EJBs used for the Model.



 < Day Day Up > 



Websphere Portal on Z. OS
Websphere Portal on Z/OS
ISBN: 0738499382
EAN: 2147483647
Year: 2003
Pages: 90

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net