The JSR 168 specification aims at defining porlets that can be used by any JSR168 portlet container also called portals. There are different portals out there with commercial and non-commercial licences. In this chapter we will briefly describe such portlets but for more details you should read the specifications available on the web.
As of today, JBoss portal is fully JSR168 1.0 compliant, that means that any JSR168 portlet will behave as it should inside the portal.
A portal can be seen as pages with different areas and inside areas, different windows and each window having one portlet.
A porlet can have different view modes, three modes are defined by the specification but a portal can extend those modes. The 3 modes are:
Window states are an indicator of how much page real-estate a portlet should consume on any given page. There are 3 states defined by the specification:
The tutorials contained in this chapter are targetted toward portlet developers. Although they are a good starting and reference point, we do heavily recommend that portlet developers read and understand the Portlet Specification (JSR-168) . We also recommend, using our JBoss Portal User Forums for user-to-user help, when needed.
This section will introduce the reader to deploying his first portlet in JBoss Portal. It requires you download the HelloWorldPortlet from PortletSwap.com, using this link .
Portlets are packaged in war files, just like other JEE applications. A typical portlet war file can also include servlets, resource bundles, images, html, jsps, and other static or dynamic files you would commonly include.
Included in the download bundle you should have one java source file: HelloWorldPortlet\src\main\org\jboss\portlet\hello\HelloWorldPortlet.java , and it should contain the following:
package org.jboss.portlet.hello; import javax.portlet.GenericPortlet; import javax.portlet.PortletException; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.UnavailableException; import java.io.IOException; import java.io.PrintWriter; public class HelloWorldPortlet extends GenericPortlet { protected void doView(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException { rResponse.setContentType("text/html"); PrintWriter writer = rResponse.getWriter(); writer.write("Hello World!"); writer.close(); } }
Now lets dissect our simplest of portlets:
public class HelloWorldPortlet extends GenericPortlet
All Portlets MUST implement the javax.portlet.GenericPortlet Interface.
protected void doView(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException
In this case, our doView will be called when the portlet is asked to render output in VIEW Mode.
rResponse.setContentType("text/html");
Just like in the servlet-world, you must declare what content-type the portlet will be responding in.
PrintWriter writer = rResponse.getWriter(); writer.write("Hello World!"); writer.close();
Here we output the text Hello World! in our portlet window.
JBoss Portal requires certain descriptors be included in your portlet war, for different reasons. Some of these descriptors are defined by the Portlet Specification, and some are specific to JBoss Portal.
Now lets explain what each of these does:
portlet.xml
<?xml version="1.0" encoding="UTF-8"?> <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" 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" version="1.0"> <portlet> <portlet-name>HelloWorldPortlet</portlet-name> <portlet-class>org.jboss.portlet.hello.HelloWorldPortlet</portlet-class> <supports> <mime-type>text/html</mime-type> <portlet-mode>VIEW</portlet-mode> </supports> <portlet-info> <title>HelloWorld Portlet</title> </portlet-info> </portlet> </portlet-app>
This file must adhere to its definition in the Portlet Specification. You may define more than one portlet application in this file.
<portlet-name>HelloWorldPortlet</portlet-name>
Define your portlet name. It does not have to be the Class name.
<portlet-class>org.jboss.portlet.hello.HelloWorldPortlet</portlet-class>
The FQN of your portlet class must be declared here.
<supports> <mime-type>text/html</mime-type> <portlet-mode>VIEW</portlet-mode> </supports>
The supports attributes allow you to declare extra vital information about the portlet. In this case, we are letting the portal know that it will be outputting text/html and only support a VIEW mode.
<portlet-info> <title>HelloWorld Portlet</title> </portlet-info>
The portlet's title will be displayed as the header in the portlet window, when rendered, unless it is overridden programatically.
portlet-instances.xml
<?xml version="1.0" standalone="yes"?> <!DOCTYPE deployments PUBLIC "-//JBoss Portal//DTD Portlet Instances 2.6//EN" "http://www.jboss.org/portal/dtd/portlet-instances_2_6.dtd"> <deployments> <deployment> <instance> <instance-id>HelloWorldPortletInstance</instance-id> <portlet-ref>HelloWorldPortlet</portlet-ref> </instance> </deployment> </deployments>
This is a JBoss Portal specific descriptor that allows you create an instance of a portlet. The portlet-ref value must match the portlet-name value given in the packaged portlet.xml . The instance-id value can be named anything, but it must match the instance-ref value given in the *-object.xml file we will explore below.
helloworld-object.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE deployments PUBLIC "-//JBoss Portal//DTD Portal Object 2.6//EN" "http://www.jboss.org/portal/dtd/portal-object_2_6.dtd"> <deployments> <deployment> <parent-ref>default.default</parent-ref> <if-exists>overwrite</if-exists> <window> <window-name>HelloWorldPortletWindow</window-name> <instance-ref>HelloWorldPortletInstance</instance-ref> <region>center</region> <height>1</height> </window> </deployment> </deployments>
The *-object.xml is responsible for creating/configuring windows, pages, and even portal objects. In our example, we are creating a portlet window, assigning it to a page, and specifying where it should appear on that page. This is a specific descriptor to JBoss Portal. Since 2.6 we can replace also the window section by the following which will do exactly the same.
<window> <window-name>HelloWorldPortletWindow</window-name> <content> <content-type>portlet</content-type> <content-uri>HelloWorldPortletInstance</content-uri> </content> <region>center</region> <height>1</height> </window>
The kind of declaration allows to declare for a window different kind of content types. You can see that as a generic way to declare content for a window. In our case the type of content is portlet and the content uri declares the HelloWorldPortletInstance. The content uri value is the identifier of the content. It is possible to declare windows with content type cms and use directly the path to the file in the CMS to make the window show cms content. That behavior is pluggable and it is virtually possible to plug in any kind of content.
<parent-ref>default.default</parent-ref>
Tells the portal where this portlet should appear. In this case, default.default specifies that this portlet should appear in the portal instance named default and the page named default .
<if-exists>overwrite</if-exists>
Instructs the portal to overwrite or keep this object if it already exists. Possible values are overwrite or keep . Overwrite will destroy the existing object and create a new one based on the content of the deployment. Keep will maintain the existing objct deployment or create a new one if it does not yet exist.
<window-name>HelloWorldPortletWindow</window-name>
Can be named anything.
<instance-ref>HelloWorldPortletInstance</instance-ref>
The value of instance-ref must match the value of instance-id found in the portlet-instances.xml .
<region>center</region> <height>1</height>
Specify the layout region and order this window will be found on the portal page.
To illustrate the relationship between the descriptors , we have provided this simple diagram
If you have downloaded the sample, you can execute the build.xml with ANT or inside your IDE. Executing the deploy target will compile all src files and produce a helloworldportlet.war under HelloWorldPortlet\helloworldportlet.war.
If you want to create an expanded war directory, after executing the above deploy target, you should execute the explode target.
The above target will produce the following:
This will deflate the helloworldportlet.war, and allow you to deploy it as an expanded directory. It will work just the same, with some additional benefits noted below:
The advantage to expanded war deployments is that you can modify xml descriptors, resource files jsp/jsf pages easily during development. Simply touch the web.xml to have JBoss Application Server hot-deploy the web appllication on a live-running server instance
Deploying a portlet is as simple as copying/moving the helloworldportlet.war in to the server deploy directory. Doing this on a running instance of the portal and application server, will trigger a hot-deploy :
18:25:56,366 INFO [Server] JBoss (MX MicroKernel) [4.0.5.GA (build: CVSTag=JBoss_4_0_5_GA date=2006000000)] Started in 1m:3s:688ms 18:26:21,147 INFO [TomcatDeployer] deploy, ctxPath=/helloworldportlet, warUrl=.../tmp/deploy/tmp35219helloworldportlet-exp.war/
Pointing your browser to http://localhost:8080/portal/ , should yield a view of our HelloWorldPortlet:
This section will introduce the reader to deploying a simple JSP portlet in JBoss Portal. It requires you download the HelloWorldJSPPortlet from PortletSwap.com, using this link .
This portlet will introduce you to using JSPs for view rendering and the portlet taglib for generating links.
Portlets are packaged in war files, just like other JEE applications. A typical portlet war file can also include servlets, resource bundles, images, html, jsps, and other static or dynamic files you would commonly include.
Included in the download bundle you should have one java source file: HelloWorldPortlet\src\main\org\jboss\portlet\hello\HelloWorldJSPPortlet.java , and it should contain the following:
package org.jboss.portlet.hello; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.GenericPortlet; import javax.portlet.PortletException; import javax.portlet.PortletRequestDispatcher; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.UnavailableException; import java.io.IOException; public class HelloWorldJSPPortlet extends GenericPortlet { protected void doView(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException { rResponse.setContentType("text/html"); String sYourName = (String) rRequest.getParameter("yourname"); if(sYourName != null) { rRequest.setAttribute("yourname", sYourName); PortletRequestDispatcher prd = getPortletContext() .getRequestDispatcher("/WEB-INF/jsp/view2.jsp"); prd.include(rRequest, rResponse); } else { PortletRequestDispatcher prd = getPortletContext() .getRequestDispatcher("/WEB-INF/jsp/view.jsp"); prd.include(rRequest, rResponse); } } public void processAction(ActionRequest aRequest, ActionResponse aResponse) throws PortletException, IOException, UnavailableException { String sYourname = (String) aRequest.getParameter("yourname"); // do something aResponse.setRenderParameter("yourname", sYourname); } protected void doHelp(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException { rResponse.setContentType("text/html"); PortletRequestDispatcher prd = getPortletContext() .getRequestDispatcher("/WEB-INF/jsp/help.jsp"); prd.include(rRequest, rResponse); } protected void doEdit(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException { rResponse.setContentType("text/html"); PortletRequestDispatcher prd = getPortletContext() .getRequestDispatcher("/WEB-INF/jsp/edit.jsp"); prd.include(rRequest, rResponse); } }
Now lets look at some of our methods:
protected void doHelp(RenderRequest rRequest, RenderResponse rResponse) { ... } // And protected void doEdit(RenderRequest rRequest, RenderResponse rResponse) { ... }
Support for these Modes must be declared in the portlet.xml. They will be triggered when a user clicks on the respective icons in the portlet window titlebar, or through generated links within the portlet.
public void processAction(ActionRequest aRequest, ActionResponse aResponse) throws PortletException, IOException, UnavailableException { String sYourname = (String) aRequest.getParameter("yourname"); // do something aResponse.setRenderParameter("yourname", sYourname); }
This method will be triggered upon clicking on an ActionURL from our view.jsp. It will retrieve yourname from the HTML form, and pass it along as a renderParameter to the doView().
rResponse.setContentType("text/html");
Just like in the servlet-world, you must declare what content-type the portlet will be responding in.
protected void doView(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException
In this case, our doView, is responsible for dispatching to the appropriate jsp view.jsp or view2.jsp , depending on the existence of the yourname parameter passed in from the processAction .
JBoss Portal requires certain descriptors be included in your portlet war, for different reasons. Some of these descriptors are defined by the Portlet Specification, and some are specific to JBoss Portal. For brevity, we only discuss the portlet.xml descriptor here. For discussion on the other descriptors, please view Section 5.2.1.4, “The Application Descriptors” or the chapter on descriptors: Section 6.2, “Portlet Descriptors” .
portlet.xml
<?xml version="1.0" encoding="UTF-8"?> <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" 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" version="1.0"> <portlet> <portlet-name>HelloWorldJSPPortlet</portlet-name> <portlet-class>org.jboss.portlet.hello.HelloWorldJSPPortlet</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>HelloWorld JSP Portlet</title> </portlet-info> </portlet> </portlet-app>
This file must adhere to its definition in the Portlet Specification. You may define more than one portlet application in this file.
Of importance in this tutorial are the two view jsps. The first, allows the user to input his name, which is then posted to the processAction method in our portlet class, set as a renderParameter , then the render method is invoked (in our case its the doView , which then dispatches to our view2.jsp .
Now lets have a look at our view.jsp :
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %> <portlet:defineObjects/> <div align="center"> This is a simple HelloWorld JSP Portlet. Type in a name and it will dispatch to the view2.jsp to print out your name. <br/> <form action="<portlet:actionURL><portlet:param name="page" value="mainview"/> </portlet:actionURL>" method="POST"> Name:<br/> <input type="text" name="yourname"/> </form> <br/> You can also link to other pages, using a renderURL, like <a href="<portlet:renderURL><portlet:param name="yourname" value="Roy Russo"> </portlet:param></portlet:renderURL>">this</a>. </div>
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
Define the portlet taglib. You do not need to bundle the portlet taglib, JBoss Portal will handle that for you.
<portlet:defineObjects/>
Calling defineObjects creates implicit objects in this jsp, that you can access, like: renderRequest, actionRequest, portletConfig .
<form action="<portlet:actionURL><portlet:param name="page" value="mainview"/> </portlet:actionURL>" method="POST">
We create an HTML form, but generate the URL it will post to, using the portlet tag library. In this case, notice how we are creating an actionURL , which will activate out processAction method, passing in any input parameters in the form.
<a href="<portlet:renderURL><portlet:param name="yourname" value="Roy Russo"> </portlet:param></portlet:renderURL>">
Likewise, we are able to create a link to our doView , by simply creating it with a renderURL , that passes in our yourname parameter.
If you have downloaded the sample, you can execute the build.xml with ANT or inside your IDE. Executing the deploy target will compile all src files and produce a helloworldportlet.war under HelloWorldPortlet\helloworldjspportlet.war.
If you want to create an expanded war directory, after executing the above deploy target, you should execute the explode target.
The above target will produce the following:
This will deflate the helloworldjspportlet.war, and allow you to deploy it as an expanded directory. It will work just the same, with some additional benefits noted below:
The advantage to expanded war deployments is that you can modify xml descriptors, resource files jsp/jsf pages easily during development. Simply touch the web.xml to have JBoss Application Server hot-deploy the web appllication on a live-running server instance
Deploying a portlet is as simple as copying/moving the helloworldjspportlet.war in to the server deploy directory. Doing this on a running instance of the portal and application server, will trigger a hot-deploy :
15:54:34,234 INFO [Server] JBoss (MX MicroKernel) [4.0.5.GA (build: CVSTag=JBoss_4_0_5_GA date=2006000000)] Started in 1m:9s:766ms 15:55:04,062 INFO [TomcatDeployer] deploy, ctxPath=/helloworldjspportlet, warUrl=.../tmp/deploy/tmp57782helloworldjspportlet-exp.war/
Pointing your browser to http://localhost:8080/portal/ , should yield a view of our HelloWorldPortlet:
This section will introduce the reader to deploying a simple JSF portlet in JBoss Portal. It requires you download the HelloWorldJSFPortlet from PortletSwap.com, using this link .
This portlet will introduce you to leveraging the JSF framework in portlet development.
Portlets are packaged in war files, just like other JEE applications. A typical portlet war file can also include servlets, resource bundles, images, html, jsps, and other static or dynamic files you would commonly include.
Like a typical JSF application, we also package our faces-config.xml that defines our managed-beans, converters, validators, navigation rules, etc...
JBoss Portal requires certain descriptors be included in your portlet war, for different reasons. Some of these descriptors are defined by the Portlet Specification, and some are specific to JBoss Portal. For brevity, we only discuss the portlet.xml and faces-config.xml descriptors here. For discussion on the other descriptors, please view Section 5.2.1.4, “The Application Descriptors” or the chapter on descriptors: Section 6.2, “Portlet Descriptors” .
portlet.xml
<?xml version="1.0" encoding="UTF-8"?> <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" 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" version="1.0"> <portlet> <portlet-name>HelloWorldJSFPortlet</portlet-name> <portlet-class>org.apache.myfaces.portlet.MyFacesGenericPortlet</portlet-class> <init-param> <name>default-view</name> <value>/WEB-INF/jsp/index.jsp</value> </init-param> <supports> <mime-type>text/html</mime-type> <portlet-mode>VIEW</portlet-mode> </supports> <portlet-info> <title>HelloWorld JSF Portlet</title> </portlet-info> </portlet> </portlet-app>
This file must adhere to its definition in the Portlet Specification. You may define more than one portlet application in this file. Now lets look at the portions that deal with our use of JSF:
Here we define our portlet class, as we normally would. However, note the use of the MyFacesGenericPortlet. In this case, we will allow the MyFacesGenericPortlet to handle all requests/responses from our users:
<portlet-class>org.apache.myfaces.portlet.MyFacesGenericPortlet</portlet-class>
We need to initialize the portlet with a default view page for it to render, much like a welcome page:
<init-param> <name>default-view</name> <value>/WEB-INF/jsp/index.jsp</value> </init-param>
faces-config.xml
<?xml version="1.0"?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN" "http://java.sun.com/dtd/web-facesconfig_1_0.dtd"> <faces-config> <managed-bean> <description>Basic UserBean</description> <managed-bean-name>user</managed-bean-name> <managed-bean-class>org.jboss.portlet.hello.bean.User</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <navigation-rule> <navigation-case> <from-outcome>done</from-outcome> <to-view-id>/WEB-INF/jsp/result.jsp</to-view-id> </navigation-case> </navigation-rule> </faces-config>
There is nothing special about the faces-config.xml included here. This application would work just as well outside of a portlet as it would inside a portlet container. In the above lines, we define a basic User Bean and a navigation rule to handle the submittal of the original form on the index.jsp.
If you have downloaded the sample, you can execute the build.xml with ANT or inside your IDE. Executing the deploy target will compile all src files and produce a helloworldjsfportlet.war under HelloWorldJSFPortlet\helloworldjsfportlet.war.
If you want to create an expanded war directory, after executing the above deploy target, you should execute the explode target.
The above target will produce the following:
This will deflate the helloworldjsfportlet.war, and allow you to deploy it as an expanded directory. It will work just the same, with some additional benefits noted below:
The advantage to expanded war deployments is that you can modify xml descriptors, resource files jsp/jsf pages easily during development. Simply touch the web.xml to have JBoss Application Server hot-deploy the web application on a live-running server instance
Deploying a portlet is as simple as copying/moving the helloworldjsfportlet.war in to the server deploy directory. Doing this on a running instance of the portal and application server, will trigger a hot-deploy :
22:30:03,093 INFO [TomcatDeployer] deploy, ctxPath=/helloworldjsfportlet, warUrl=.../tmp/deploy/tmp5571helloworldjsfportlet-exp.war/ 22:30:03,312 INFO [FacesConfigurator] Reading standard config org/apache/myfaces/resource/standard-faces-config.xml 22:30:03,390 INFO [FacesConfigurator] Reading config jar:file:/C:/jboss-4.0.5.GA/server/default/tmp/deploy/ tmp5504jboss-portal.sar-contents/lib/jsf-facelets.jar!/ META-INF/faces-config.xml 22:30:03,406 INFO [FacesConfigurator] Reading config jar:file:/C:/jboss-4.0.5.GA/ server/default/tmp/deploy/tmp5504jboss-portal.sar-contents/ lib/tomahawk.jar!/META-INF/faces-config.xml 22:30:03,468 INFO [FacesConfigurator] Reading config /WEB-INF/faces-config.xml 22:30:03,484 ERROR [LocaleUtils] Locale name null or empty, ignoring 22:30:03,640 INFO [MyFacesGenericPortlet] PortletContext 'C:\jboss-4.0.5.GA\server\ default\.\tmp\deploy\tmp5571helloworldjsfportlet-exp.war\' initialized.
Pointing your browser to http://localhost:8080/portal/ , should yield a view of our HelloWorldJSFPortlet: