Table of Contents
We would like to thank all developers that participate in the JBoss Portal project effort, Remy for his help and the Nodesk team that gave us that nice theme.
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.
What is really important to know about such portlets is that when a page is displayed it is divided into two distincts parts, an action part on one portlet followed by rendering parts for every porlets displayed on a page. A portal just aggregates all the chunks of HTML rendered by the different portlets of a page.
Before we even talk about portlets, let's talk about the container called portal.
A portal is basically a web application in which modules can be easily added or removed. We call those modules 'portlets'. A module can be as complex as a forum, a news management system or as simple as a text or text with images with no possible interaction.
On a single web page different portlets can appear at the same time, even though only one at a time can be displayed in its maximized mode (explained later).
A portal can be seen as pages with different areas and inside areas, different windows and each window having one portlet.

To define your portals, you need to create few XML files in order to declare your portlet, portlet instances, windows, pages and then your portals.
This file is used to declare the portlets of your application, following is an example of such a file
<?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
/opt/SUNWps/dtd/portlet.xsd" version="1.0">
<portlet>
<portlet-name>UserPortlet</portlet-name>
<portlet-class>org.jboss.nukes.core.portlet.user.UserPortlet</portlet-class>
<supported-locale>en</supported-locale>
<supported-locale>fr</supported-locale>
<resource-bundle>Resource</resource-bundle>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<portlet-info>
<title>User portlet</title>
</portlet-info>
</portlet>
<portlet>
<portlet-name>CMSPortlet</portlet-name>
<portlet-class>org.jboss.nukes.core.portlet.cms.CMSPortlet</portlet-class>
<init-param>
<description>Content Repository Type: (webdav|http)</description>
<name>repository</name>
<value>webdav</value>
</init-param>
<init-param>
<description>WebDAV server username</description>
<name>username</name>
<value>root</value>
</init-param>
<init-param>
<description>WebDAV server password</description>
<name>password</name>
<value>root</value>
</init-param>
<supported-locale>en</supported-locale>
<resource-bundle>Resource</resource-bundle>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
<portlet-mode>HELP</portlet-mode>
</supports>
<portlet-info>
<title>CMS portlet</title>
</portlet-info>
</portlet>
<portlet-app>
As you can see for any portlet you need to add a portlet tag, then you need to give extra information as follow:
After you defined all the portlets you need, you will need to define the instances that you will use.
<?xml version="1.0" standalone="yes"?>
<instances>
<instance>
<instance-name>UserPortletInstance</instance-name>
<component-name>UserPortlet</component-name>
<security>
<rules>
<rule group="Admins" patterns=".*:.*:.*" level="admin"/>
<rule group="Users" patterns=".*:.*:.*" level="read"/>
</rules>
</security>
</instance>
<instance>
<instance-name>CMSPortletInstance</instance-name>
<component-name>CMSPortlet</component-name>
</instance>
</instances>Again the file is pretty simple, the instancestag includes instance elements with:
You defined your portlets then your instances of portlet, now let's put them together on a page, to do so you can create files with -page.xml and put them either in the WEB-INF of a war file or in the deploy directory of JBoss.
Here is the page for the forums module as example:
<pages>
<portal-name>default</portal-name>
<page>
<page-name>forums</page-name>
<window>
<window-name>ForumsPortletWindow</window-name>
<instance-ref>/portal-forums.ForumsPortlet.ForumsPortletInstance</instance-ref>
<default>true</default>
<region>left</region>
<height>0</height>
</window>
</page>
</pages>
Again this is pretty straightforward. At first you need to defin in which portal this page should belongs to (we will see later how to define a portal). Then you define the pages, you can define as many page as you want, this is how a page is define:
Those files are used to define different portals. The files *-portal.xml can be include into a war file (WEB-INF directory) or directly in the deploy directory of JBoss.
<?xml version="1.0" encoding="UTF-8"?>
<portal>
<portal-name>default</portal-name>
<supported-modes>
<mode>VIEW</mode>
<mode>EDIT</mode>
<mode>HELP</mode>
</supported-modes>
<supported-window-states>
<window-state>NORMAL</window-state>
<window-state>MINIMIZED</window-state>
<window-state>MAXIMIZED</window-state>
</supported-window-states>
<pages>
<default-page>default</default-page>
<page>
<page-name>default</page-name>
<window>
<window-name>CMSPortletWindow</window-name>
<instance-ref>/nukes.CMSPortlet.CMSPortletInstance</instance-ref>
<default>true</default>
<region>left</region>
<height>0</height>
</window>
<window>
<window-name>UserPortletWindow1</window-name>
<instance-ref>/nukes.UserPortlet.UserPortletInstance</instance-ref>
<region>left</region>
<height>0</height>
</window>
</page>
<page>
<page-name>admin</page-name>
<window>
<window-name>UserPortletWindow2</window-name>
<instance-ref>/nukes.UserPortlet.UserPortletInstance</instance-ref>
<default>true</default>
<region>left</region>
<height>0</height>
</window>
<window>
<window-name>GroupPortletWindow</window-name>
<instance-ref>/nukes.GroupPortlet.GroupPortletInstance</instance-ref>
<region>right</region>
<height>1</height>
</window>
<window>
<window-name>AdminCMSPortletWindow</window-name>
<instance-ref>/nukes.AdminCMSPortlet.AdminCMSPortletInstance</instance-ref>
<region>left</region>
<height>4</height>
</window>
</page>
<page>
<page-name>test</page-name>
<window>
<window-name>DefaultPortletWindow</window-name>
<instance-ref>/nukes.DefaultPortlet.DefaultPorltetInstance</instance-ref>
<default>true</default>
<region>left</region>
<height>0</height>
</window>
<window>
<window-name>TestPortletWindow</window-name>
<instance-ref>/nukes.TestPortlet.TestPortletInstance</instance-ref>
<region>left</region>
<height>1</height>
</window>
<window>
<window-name>PreferencesPortletWindow</window-name>
<instance-ref>/nukes.PreferencesPortlet.PreferencesPortletInstance</instance-ref>
<region>left</region>
<height>2</height>
</window>
</page>
</pages>
</portal>This file is the descriptor of a portal, of course you can define several portals containing several pages. Here is how you define a portal:
Most of the time portals use very complicated urls, however it is possible to setup entry points in the portal that follow simple patterns.
Each portal container can contain multiple portals and within a givin portal, windows are organized in pages, a page simply being a collection of windows associated to a name.
Before reading this chapter you must know how to define a page and a portal, you can refer to the chapter about XML descriptors to have a better understanding of those notions.
Each portal container can contains multiple portals, also there is one special portal which is the default portal, i.e the one used when no portal is specified in particular.
The following examples show you how the selection is done.
"" "/" "/index.html" with no parameters "/portal" "/portal/" => default / "/index.html"
"/portal/blah.html" => default / "/blah.html"
"/portal/another/" => another / "/index.html"
"/portal/another/blah.html" => another / "/blah.html"
"files" "/files/" => default / "/index.html"
"/files/blah.html" => default / "/blah.html"
any other URL, like "/blah.html" is served from the another servlet (war files or security for instance)
It is possible to have multiple page per portal. As for portal there is a default page for a given portal. Once the portal has been selected, then a page must be used and all the windows present in that page will be rendered. The page selection mechanism is the following.
JSR 168 specifications does not define any particular security implementation even though you can get the authenticated user and its role.
In JBoss portal, each portlet defines its own security rules but the portal gives an easy way to implement it using the AuthorizationRealm obtained by NukesRenderRequest or NukesActionRequest.
The security mechanism works with rules, a rule consist in three elements:
The role that you want to apply the rule to
The context in which the rule will be applied
The credential given to the role in the context specified
A context is defined by the portlet developer, it is represented by an array of Strings. For example, the forum portlet is divided into sections and each sections are divided into forums. Typically a webmaster will want to grant premissions on whole sections and/or just some forums. {"CategoryName", "forumName"} could be a context for the forum called forumName of the category CAtegoryName. To define a context for a whole section, a user can use regular expression like {"CategoryName", ".*"} and it would define context on the whole category. Again this is just a matter of portlet developer choice. The meaning of a context for a particular portlet should be documented in the portlet guide.
The rights to give are the same for any portlet, we often want to add write or read access, JBoss portal defines 9 levels of privileges that are linked together. In the default configuration, a role has also the rights of roles with a lower number. For example, the level 8 has the rights of level 0 to 7.
All those levels have a name for their common usage
No restrict access to a role in a context
Can be used to give access to a summary of a story but not to the whole story
This gives reading access to a role
This gives the ability to add comments to a role if the portlet has such a feature
This should be used to add the possibility to add or remove some data entered by others
This should be used to allow a role to edit data on the portal
This should be used to allow a role to add content to the portal
Gives the right to delete content from the portal
This is the ultimate level, this gives rights to anything
As specified earlier, by default someone who has COMMENT access level also have READ, OVERVIEW and NONE acces levels. For even more flexibility, the portal allows you to change how the levels are dependant one to the other. This is done by modifying the authorization matrix in jboss.nukes.core.security.Level. You can then define which access level implies which other.
To define rules on a portlet, you need to adapt the nukes-instance.xml file. Inside a instance tag, you should add a security tag. This tag contains all the rules you want. For example, the following tags would give reading access on everything for the Users role and admin access to the Admins role. Of course you can define a finer grain by specifying the correct pattern.
<security>
<rules>
<rule role="Admins" patterns="" level="admin"/>
<rule role="Users" patterns="" level="read"/>
</rules>
</security>A portlet developer will need to make sure all the operations are correctly checked for credentials. To programatically do so, he will need to get a AuthorizationRealm from the NukesRequest then use this object to check against the user's roles.
AuthorizationRealm authorizationRealm = nukesRequest.getAuthorizationRealm();
boolean readAuthorized = authorizationRealm.isAuthorized("Users",
new String[] {"My Category", "My Forum"},
org.jboss.nukes.core.security.Level.ACCESS_READ);Getting the list of roles names is not always convenient, to simplify this task, the class org.jboss.nukes.core.portlet.PortletHelper has the following static method public static boolean isAuthorized(AuthorizationRealm authRealm, User user, String[] test, Level level), this method is even more convenient as you get the user from the NukesRequest. A call to this method will look like:
PortletHelper.isAuthorized(nukesRequest.getAuthorizationRealm(),
nukesRequest.getUser(),
new String[] {"My category", "My forum"},
Level.ACCESS_READ)This section described the steps to incorporate your own portlets in to JBoss Portal.
Assumptions:
/helloworld.war
/WEB-INF
/classes
/lib
/portlet.xml
/web.xml
/META-INF
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
version="1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">
<portlet>
<portlet-name>HelloWorldPortlet</portlet-name>
<portlet-class>com.myapp.portlet.HelloWorldPortlet</portlet-class>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>help</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<portlet-info>
<title>Hello World Portlet</title>
</portlet-info>
</portlet>
</portlet-app>
There are two files you will need to add under /WEB-INF for your portlet to work in Jboss Portal. The first is a helloworld-pages.xml. The portal will scan this file to find out which portal instance to target and what page name it will be in. In this case, we can access our portlet by going to http://localhost:8080/portal/index.html?page=hello
<pages>
<portal-name>default</portal-name>
<page>
<page-name>hello</page-name>
<window>
<window-name>HelloWorldPortletWindow</window-name>
<instance-ref>/portal-hello.HelloWorldPortlet.HelloWorldPortletInstance</instance-ref>
<default>true</default>
<region>user1</region>
<height>0</height>
</window>
</page>
</pages>
The second file needed under /WEB-INF is a portlet-instances.xml. This file maps the portlet name in your portlet.xml file to the portlet instance in your helloworld-pages.xml.
<?xml version="1.0" standalone="yes"?>
<instances>
<instance>
<instance-name>HelloWorldPortletInstance</instance-name>
<component-name>HelloWorldPortlet</component-name>
</instance>
</instances>
Now add these two files to your war and you should be able to access the helloworld portlet by going to http://localhost:8080/portal/index.html?page=hello.