GridSphere Portlet Reference Guide


Table of Contents

1. Portlet Concepts
2. Portlet Lifecycle
WebSphere Portlet Action Methods
JSR 168 Portlet Action Methods
WebSphere and JSR 168 Portlet Render Methods
3. Portlet Groups
Specifying a Group Descriptor
4. Portlet Layout Framework
Portlet Layout Components
Guest and template layouts
Specifying a layout within a portlet web application
5. Portlet Roles
Specifying a Role Descriptor
6. Portlet Service Framework
Portlet Service Architecture
Portlet Services Descriptor
Core Portlet Services
Portlet Service Example
Create service definition
Create service interface
Create service implementation
Access service from portlet
User Portlet Service Example
Create user service definition
Edit service interface
Create user service implementation
Access the user service from a portlet
Portlet Service Testing
7. Portlet Persistence
Configuration
Simple Persistence
The Persistence Manager
Mapping files
Usage
Storing data on a user behalf
8. GridSphere Authentication Modules
JAAS Authentication Module Configuration and Usage
9. Secure Directory
Usage and Examples
10. GridSphere Portal Specific Files
11. Additional Portlet Resources

List of Figures

6.1. Portlet Service Architecture UML

Chapter 1. Portlet Concepts

Portlets are defined as visual components that can be assimilated into portal web pages. Portlets provide "mini-applications" that can either display informational content or provide access to other services. The GridSphere portal allows users to customize their workspace by adding and removing portlets as needed. In addition to standard window states like minimized or maximized, portlets can also provide various "modes" such as view, edit, configure and help. As an example, consider a stock quote portlet that allows users to customize their stock quote information. View mode would display a user's stock information. Help mode provides users with informational content about the stock quote portlet and how to use it. Edit mode allows users to change the list of stocks they are intersted in monitoring. Finally, configure mode allows portlet administrators to change persistent settings such as the stock quote service that is contacted.

As of GridSphere 2.0, two portlet development models are supported. The original portlet model was based upon the IBM WebSphere® Portlet API v4.1+ which means that existing WebSphere portlet applications can be easily ported for use within GridSphere. In addition, GridSphere provides an implementation of the JSR 168 Portlet API standard supported by IBM, Sun, Oracle, Plumtree, and many other application server vendors. The GridSphere framework is packaged as a web application that provides a portlet container for managing deployed portlets. GridSphere provides a collection of core portlets as well as a development environment for the creation of new portlet applications, both the WebSphere model and the JSR 168 standard.

GridSphere provides built-in support for role based access control. A group is defined by a name, description and a collection of portlets that a user has access to including role access rights on a per portlet basis. Users may belong to one or more groups (meaning they have access to one or more portlet web applications) and they have a role within each group. the four supported roles are GUEST, USER, ADMIN and SUPER. A user with the GUEST role will obtain a generic view of the portal suitable to guests while a user that has logged on, will have the USER role and may be able to see the portlet personalized with their settings. A user with the ADMIN role can have access to a portlet's CONFIGURE mode described earlier and presumably configure a portlet's initialization settings. A user possesing the SUPER role can essentially do anything they want to any portlet and is essentially equivalent to having root access in an operating system. A portlet application may provide an optional group descriptor file, group.xml, which defines an initial group and access rules for the portlet collection.

This document is intended as a reference guide on the GridSphere portal and does not cover too much portlet development. Please see the GridSphere tutorials for developing portlets within GridSphere or see Additional Portlet Resources for a useful set of web links offering more information.

The Portlet Services API described in Portlet Service Framework provides a very clean approach for the creation of reusable "services" that perform a set of tasks for a given portlet. Using the portlet API, a service instance can be obtained providing the portlet with additional functionality.

The Portlet Service Framework section is generally applicable to both WebSphere and JSR 168 developed portlets. The GridSphere portal container supports both APIs by using the WebSphere portlet API to bootstrap a special PortletServlet that is a WebSphere style portlet that is responsible for loading JSR 168 portlets. Please read the paper GridSphere: An Advanced Portal Framework for more technical details.

Chapter 2. Portlet Lifecycle

The portlet lifecycle extends the servlet lifecycle by offering more control over the event processing required of a and the presentation rendering. Just as servlets have init and destroy methods, the portlet lifecycle methods listed below are responsible for the initialization and shutdown of concrete and application portlets. For every request made by a user, the service method is invoked which is responsible for invoking the appropriate portlet action method if one exists followed by the appropriate portlet render method for all portlets that are currently displayed on the portal page. All lifecycle methods throw a PortletException

  • Application portlet initialization is the first phase of startup. The portlet is instantiated with the PortletConfig object

        void init(PortletConfig config)
        

  • [Important]Important
    Concrete portlets only exist in the WebSphere portlet model
    The concrete portlet is placed into service and parameterized with a PortletSettings object.
        void initConcrete(PortletSettings settings)
        

  • The service method is invoked for every client request. Based on the portlet mode or portlet action, it invokes the appropriate action method if there is one followed by the render method of all displayed portlets.

        void service(PortletRequest req, PortletResponse res)
        

  • [Important]Important
    Concrete portlets only exist in the WebSphere portlet model
    The concrete portlet is taken out of service either dynamically when a portlet web application is unloaded or when the portal is shutdown

        void destroyConcrete()
        

  • The application portlet is taken out of service either dynamically when a portlet web application is unloaded or when the portal is shutdown

        void destroy()
        

WebSphere Portlet Action Methods

The Action methods handle any events that a portlet may have triggered. Any kind of form or hyperlink triggered event will cause the actionPerformed method to be executed. Other events included window events when a portlet is minimized, maximized, or resized and message events when a portlet has received a message from another portlet. The ActionEvent, WindowEvent and MessageEvent objects that get passed into the corresponding action methods contain the PortletRequest and PortletResponse objects.

  • The actionPerformed method is invoked when the portlet receives an action and must be implemented by the portlet developer. This method is performed before any rendering is done via doView, doEdit, etc.

        void actionPerformed(ActionEvent event)
        

  • The messageReceived method is invoked when the portlet receives a message.

        void messageReceived(MessageEvent event)
        

  • The windowMaximized method is invoked for a portlet when the portlet window is maximized.

        void windowMaximized(WindowEvent event)
        

  • The windowMinimized method is invoked for a portlet when the portlet window is minimized.

        void windowMinimized(WindowEvent event)
        

  • The windowResized method is invoked for a portlet when the portlet window is resized.

        void windowResized(WindowEvent event)
        

JSR 168 Portlet Action Methods

Under JSR 168 specification, the processAction method is invoked when the portlet receives an action. It is not possible to receive window state events or portlet messaging events under JSR 168.

  • The processAction method is invoked when the portlet receives an action and must be implemented by the portlet developer. This method is performed before any rendering is done via doView, doEdit, etc.

        void processAction(ActionRequest request, ActionResponse response)
        

WebSphere and JSR 168 Portlet Render Methods

The portlet container will render portlet presentation for all portlets that are currently visible in the page based on the mode they are in as described previously.

  • The doView method is invoked for a portlet when it is in VIEW mode.

        void doView(PortletRequest req, PortletResponse res )
        

  • The doEdit method is invoked for a portlet when it is in EDIT mode.

        void doEdit(PortletRequest req, PortletResponse res )
        

  • The doConfigure method is invoked for a portlet when it is in CONFIGURE mode. This mode is allowed only for portlet administrators and is intended to provide additional portlet configuration. Configure mode is supported in the WebSphere portlet API, but must be added as a custom mode using JSR 168.

        void doConfigure(PortletRequest req, PortletResponse res )
        

  • The doHelp method is invoked for a portlet when it is in HELP mode.

        void doHelp(PortletRequest req, PortletResponse res )
        

  • The doTitle method is invoked for a portlet during its rendering by the layout engine and can be implemented by a portlet developer to provide a customized title.

        void doTitle(PortletRequest req, PortletResponse res )
        

Chapter 3. Portlet Groups

As discussed in the introduction, GridSphere provides a concept for portlet groups that a user may belong to. A group can be created via the "Group Manager Portlet" or a webapp can define a group descriptor used to create a portlet group upon loading the webapp.

Specifying a Group Descriptor

An external portlet web application specifies a group definition in an XML descriptor file found in WEB-INF/group.xml. An example illustration is shown:

<portlet-group>  1
    <group-name>GridSphere</group-name> 2
    <group-description>Core GridSphere Group</group-description> 3
    <group-visibility>PUBLIC</group-visibility>  4
    <portlet-role-info> 5
        <portlet-class>
 org.gridlab.gridsphere.portlets.core.user.ProfileManagerPortlet.1
        </portlet-class> 6
        <required-role>USER</required-role>  7
    </portlet-role-info>
    <portlet-role-info>
        <portlet-class>
 org.gridlab.gridsphere.portlets.core.subscription.SubscriptionPortlet.1
        </portlet-class>
        <required-role>USER</required-role>
    </portlet-role-info>
    <portlet-role-info>
        <portlet-class>
 org.gridlab.gridsphere.portlets.core.layout.UserLayoutPortlet.1
        </portlet-class>
        <required-role>USER</required-role>
    </portlet-role-info>
    <portlet-role-info>
        <portlet-class>
 org.gridlab.gridsphere.portlets.core.admin.portlets.PortletApplicationManager.1
    </portlet-class>
        <required-role>SUPER</required-role>
    </portlet-role-info>
    <portlet-role-info>
        <portlet-class>
 org.gridlab.gridsphere.portlets.core.admin.users.UserManagerPortlet.1
    </portlet-class>
        <required-role>SUPER</required-role>
    </portlet-role-info>
    <portlet-role-info>
        <portlet-class>
 org.gridlab.gridsphere.portlets.core.admin.layout.LayoutManagerPortlet.1
    </portlet-class>
        <required-role>ADMIN</required-role>
    </portlet-role-info>
    <portlet-role-info>
        <portlet-class>
 org.gridlab.gridsphere.portlets.core.admin.groups.GroupManagerPortlet.1
    </portlet-class>
        <required-role>ADMIN</required-role>
    </portlet-role-info>
</portlet-group>
1

Every group descriptor must begin with a portlet-group element

2

A group must provide a group name

3

The group definition should say something meaningful about this group. Users will see the group name and description.

4

The group visibility specifies if any user can add themselves to this group or if it requires administrator approval. Valid values are "PUBLIC", where any user will see the group and have the ability to subscribe to it. If visibility is "PRIVATE", the user will see the group existence but requires administrator approval to add them. A group that is "HIDDEN" will not be displayed at all to users and requires an administrator to add members.

5

A portlet-group may contain one or more portlet-role-info elements that defines a portlet and associated role information

6

The portlet-class element defines the fully qualified portlet class name of this portlet (concrete portlet id) in the case of WebSphere style portlet application. In JSR 168 applications, it can be the fully qualified portlet class name or should specified as the webapp and the portlet name separated by a '#' e.g. jsrtutorial#ActionHelloPortlet

7

The required-role element may be one of USER, ADMIN, or SUPER defining which role a user must have to view this portlet.

Chapter 4. Portlet Layout Framework

The layout descriptor specifies a custom configuration for the layout of your portlets in the portal using a nested tabbed pane approach.

[Important]Important
If you define a layout descriptor in the portlet webapp, you must also include a group descriptor

The Portal Layout components closely resemble the AWT/Swing components found in the standard Java classes. The reason for this is twofold: One, to provide a very close API to create web based visual components easily by anyone familiar with Java GUI development under AWT or Swing. The other reason is to follow the "Composite" design pattern which allows for maximal flexibility in developing new layouts composed of various changing components by composing objects, or portal components, into a tree based structure. GridSphere creates customized user layouts composed that are represented as XML layout descriptors.

Portlet Layout Components

A portal layout is represented per-user as a PortletPage. A PortletPage can contain any number of portlet components. Generally, portal layout components inherit functionality from a PortletContainer that includes attributes for width, height, a CSS theme and optionally a required role. Other layout components listed below may be used in creating a layout descriptor. For more details on component attributes, see the Javadoc API.

Portlet Layout Components

PortletContent

Allows external content to be included in the layout using the include attribute. The content may be located in another deployed webapp as well. You need to specify the webapp name using the context attribute.

PortletTableLayout

Lays out components within a table

PortletRowLayout

Lays out components inside of a row

PortletColumnLayout

Lays out components inside of a column

PortletTabbedPane

A tabbed pane is a container for portlet tabs

PortletTab

A tab specifies a title and a portlet component that is displayed when the tab is selected. This is generally where portlet frames are placed

PortletFrame

A portlet frame is a visual representation of a portlet. It includes a title border and the classname of the portlet to invoke for rendering. Unless the attribute transparent is set to true, a title bar will be rendered.

SelectionContainer

A SelectionContainer is a container that contains a list of other components that selectively displays only of them. The only attribute that is necessary to provide is default which specifies the label of the component to be displayed by default if no other value has been set.

Guest and template layouts

The $CATALINA_HOME/webapps/gridsphere/WEB-INF/CustomPortal/layouts/GuestUserLayout.xml layout descriptor specifies the layout for all non-logged in users. This is essentailly the public portal layout. Modify this file as needed for your own portal. This can also be done via the LayoutManagerPortlet from the portal when logged in as an administrator. This layout creates an entire portal page as evidenced by the <portlet-page> tags. The following sample shows the relevant sections of the GuestUserLayout.xml.


<page-layout title="GridSphere Portal" keywords="gridsphere" icon="images/favicon.ico" renderkit="classic" refresh="600"> 1

<!-- Header components -->
<portlet-header> 2
    <table-layout style="header">
        <row-layout>
            <column-layout width="70%">
                <portlet-content include="/WEB-INF/CustomPortal/layouts/html/pagehead.html"/>
            </column-layout>
            <column-layout width="30%">
                <portlet-frame transparent="true" outer-padding="0" label="locale">
                    <portlet-class>org.gridlab.gridsphere.portlets.core.locale.LocalePortlet.1</portlet-class>
                </portlet-frame>
            </column-layout>
        </row-layout>
    </table-layout>
</portlet-header>

<!-- Tabbed Panes -->
<portlet-tabbed-pane selected="0" style="menu">
...
</portlet-tabbed-pane>

<!-- Footer components (if any) -->
    <portlet-footer> 3
        <table-layout style="footer">
            <row-layout>
                <column-layout>
                    <portlet-content include="/WEB-INF/CustomPortal/layouts/html/pagefooter.html"/>
                </column-layout>
            </row-layout>
        </table-layout>
    </portlet-footer>


</page-layout>
    
1

The page element specifies various parameters that will be used in the resulting output including a title, keywords (placed in HTML meta tags), page refresh in seconds, a favicon if you have one and the renderkit to be used. Currently GridSphere supports two renderkits, classic and cssmodern. The classic renderkit uses a combination of nested tables stylesheets. We have been developing the css renderkit which uses only stylesheets and no nested tables for greater flexibility. You are urged to try both and see which one works for your needs.

2

The header element can be used to define an appropriate portal header including a logo or banner and any portlets that should be displayed.

3

The footer element can be used to define a portal footer including links, copyright informaation

Once a user has successfully logged in, the layout created is formed by taking the $CATALINA_HOME/webapps/gridsphere/WEB-INF/CustomPortal/layouts/TemplateLayout.xml which specifies the portal page header and footer and incorporating all the layouts defined for each group that a user has memberbership. The TemplateLayout.xml may also need to be modified in the same way as the GuestUserLayout.xml described previously.

Specifying a layout within a portlet web application

An external portlet web application specifies the arrangement of portlets in an XML descriptor file found in WEB-INF/layout.xml. The layout descriptor specifies the organization of portlets within a double-tabbed pane. An example illustration is shown:

<portlet-tabbed-pane> 1
    <portlet-tab>
        <title lang="en">Examples</title> 2
        <portlet-tabbed-pane style="sub-menu">  3
            <portlet-tab order="50"> 4
                <title lang="en">Simple Examples</title>
                <table-layout>    5
                    <row-layout>  6
                        <column-layout width="50%> 7
                            <portlet-frame> 8
                                <portlet-class>
                org.myorg.portlets.examples.simpleone.1
                            </portlet-class>
                            </portlet-frame>
                        </column-layout width="50%>
                        <column-layout width="50%>
                            <portlet-frame label="simpletwo"> 9
                                <portlet-class>
                org.myorg.portlets.examples.simpletwo.1
                                </portlet-class>
                            </portlet-frame>
                        </column-layout>
                    </row-layout>
                </table-layout>
            </portlet-tab>
            <portlet-tab>
                <title lang="en">Demos</title>
                <table-layout>
                    <row-layout>
                        <column-layout>
                            <portlet-frame>
                                <name>DemoPortlet</name>
                                <portlet-class>
                org.gridlab.gridsphere.portlets.examples.DemoPortlet.1
                                </portlet-class>
                            </portlet-frame>
                        </column-layout>
                    </row-layout>
                </table-layout>
            </portlet-tab>
            <portlet-tab url="http://www.google.com"> 10
                <title lang="en">Google</title>
            </portlet-tab>
        </portlet-tabbed-pane>
    </portlet-tab>
</portlet-tabbed-pane>
1

Every layout descriptor must begin with a portlet-tabbed-pane element

2

The tab title is the title string that is presented in the portal layout. Multiple tab titles with different locales specified as two character ISO 639 values can be present for localization support.

4

The tab order is a number generally between 0 and 100 that specifies the order of the tab in this tab pane. If the tab number is undefined it will have a default of 20 applied to it.

3

Although not required, in general a tab contains either a sub-level tabbed pane or a portlet-panel

5

The table layout lays out components into a table using nested row-layout and column-layouts.

6

The row layout lays out components into a table row using nested column-layouts.

7

The table layout lays out components into a column whose width is defined by the width attribute as a relative percentage.

8

The portlet frame is specified as the concrete portlet id representing the portlet class. In the case of WebSphere style application, the concrete portlet id shoudl be used. For JSR 168 portlet applications, the webapp name and the portlet name (as expressed in <portlet-name> of portlet.xml) separated by a '#' should be used e.g. jsrportlets#WeatherPortlet. However, the portlet class name will also work, but does not guarantee uniqueness if multiple portlets with the same classname are declared in the portlet descriptor.

9

Assigning a label to a component means that it can be linked to in the portal and made bookmarkable.

10

Assigning a url to a tab allows the tab to link to an external web site and renders the specified url instead of creating a link that points back to the portal.

To learn more about possible attributes and component relationships, look at the layout-mapping.xml file in the GridSphere source. This defines the relationship between the portlet component classes and the XML descriptions.

Chapter 5. Portlet Roles

GridSphere provides the concept of roles that are used to categorize users and the restrictions they have. A role can be created or edited via the "Role Manager Portlet" or a webapp can define a role descriptor used to create new portlet roles upon loading the webapp. A role is defined by a role name and a role level. The role name may be any useful descriptive name, but the role level must be one of four defined levels:

  • GUEST
  • USER
  • ADMIN
  • SUPER

Specifying a Role Descriptor

An external portlet web application specifies a role definition in an XML descriptor file found in WEB-INF/role.xml. An example illustration is shown:

    <?xml version="1.0" encoding="UTF-8"?>
    <portlet-roles>
        <portlet-role>                            1
            <role-name>employee</role-name> 2
            <role-priority>USER</role-priority> 3
        </portlet-role>
        <portlet-role>
            <role-name>manager</role-name>
            <role-priority>ADMIN</role-priority>
        </portlet-role>
    </portlet-roles>
1

Every new role must begin with a portlet-role element

2

A role must provide a descriptive role name that is displayed to users

3

The role priority should be one of GUEST, USER, ADMIN, or SUPER.

Chapter 6. Portlet Service Framework

Portlet services encapsulate business or logic operations that can be re-used among portlets. The use of portlet services helps to minimize the amount of logic placed in a portlet and present it as a reusable library to other portlets. In addition, portlet services offer the following major advantages:
Persistence using built-in persistence framework makes it easy to serialize objects to a relational database
Method level security using built-in access control model makes it easy to provide "secure service" proxies that perform the proper operations based on the user's role
Integration with testing framework makes it easy to write JUnit tests

Portlet services can be easily used within the WebSphere portlet development model. Because JSR 168 specification does not have any concept of portlet services, a developer must use the JSR "ActionPortlet" subclass in order to get a portlet service instance.

Portlet Service Architecture

We borrow from the IBM WebSphere service interface to build a services architecture that we believe will allow for future integration with a standardized Portlet API. The UML object diagram of the services framework is shown below:

Figure 6.1. Portlet Service Architecture UML

Portlet Service Architecture UML

A PortletServiceFactory is responsible for creating, initializing and destroying portlet services. A PortletService defines a blank interface that is enhanced by the PortletServiceProvider interface which defines a lifecycle consisting of init() and destroy methods used when the service is initialized and shutdown. A portlet services descriptor is used to specify class information and initialization parameters that is accessed via the PortletServiceConfig.

Under the WebSphere portlet model, a portlet service can be obtained from a portlet using the PortletContext object. Because the method getService() returns a PortletService, it must be typecast to the approriate service instance:

ExampleService =
    (ExampleService)getPortletConfig().getContext().getService(ExampleService.class);
    

Notice that only the service interface is specified and the factory will use the appropriate service implementation specified in the services descriptor.

In JSR 168 portlet development, the ActionPortlet subclass of GenericPortlet must be used as it provides the necessary createPortletService method:

         ExampleService =
           (ExampleService)createPortletService(ExampleService.class);
        

A User Service provides two possibilities. In the first case, a service can provide logic appropriate for the user's request. For exaple, the method deleteUser(User user) in the UserManagerService requires that a user with the role SUPER requested the service instance. For any other service instance, the method will fail with a PortletServiceAuthorizationException. User services not only help provide a library that will "do the right thing" based on a client's role, but it makes the services much more robust and secure for other portlet developers to take advantage of. In the second case, a User Service simply provides a per user service instance. This can be useful for associating an independent service with a particular user.

Portlet Services Descriptor

The portlet services descriptor file located in WEB-INF/PortletServices.xml of the portlet web application specifies the services provided by this portlet web application. It is possible to specify multiple portlet service descriptors, as long as they are placed inside the WEB-INF/portlet-services directory of the portlet web application. GridSphere core services are defined in WEB-INF/GridSphereServices.xml of the gridsphere webapp. The following example shows service definitions for an example service.


       <portlet-services>  1

           <service>   2
               <name>Example Service</name>       3
               <description>Provides Special Capabilities</description>   4
               <interface>org.gridlab.gridsphere.services.core.example.ExampleService</interface>   5
               <implementation>
                    org.gridlab.gridsphere.services.core.example.impl.ExampleServiceImpl
               </implementation>  6
               <user-required>false</user-required>  7
               <load-on-startup>false</load-on-startup>  8
               <service-config>         9
                   <param-name>some parameter</param-name>
                   <param-value>some value</param-value>
               </service-config>
           </service>

       </portlet-services>

  
1

The portlet-services element delimits the start and end of a services descriptor

2

The services element delimits the start and end of a portlet service

3

The name of the portlet service. Not used currently, but could be used by tools, portlets, etc.

4

The description of the portlet service. Not used currently, but could be used by tools, portlets, etc.

5

The portlet service interface describing the services's methods

6

The portlet service implementation class that implements the portlet service interface

7

This must be set to true for user services, where a User object will be supplied to create the service instance. The default is false

8

This should be set top true of the service should be initialized at startup time. Normally a service is initialized when it is first used. The default is false.

9

Although not actually used in this service, any service can be configure with supplied initialization settings expressed as string key value pairs in the displayed form

Core Portlet Services

GridSphere includes several core services that are used by the gridsphere portlets and may be used by other external portlets. For more details on methods provided by the services, consult the Javadoc API

Core Portlet Services

LoginService

Provides login capabilities.

AccessControlManagerService

Provides authorization capabilities to portal users

UserManagerService

Provides user administration capabilities

LayoutManagerService

Provides layout modification capabilities

LocaleService

Provides a list of supported locales.

PortletManagerService

Provides portlet loading and unloading capabilities.

TextMessagingService

Provides text messaging capabilities.

MailService

Provides e-mail capabilities.

PortalConfigService

Provides a simple service for persistencing global gridsphere portal configuration settings.

RequestService

Provides a simple service for tracking requests and providing persistence.

Portlet Service Example

In the following example we illustrate the StockQuoteService with a single method getStockQuotes() : List which returns a list of stock quotes obtained from the quote.com service.

Create service definition

Create a services definition entry in the WEB-INF/PortletServices.xml of the portlet web application


        ...

        <service>
            <name>Stock Quote Service</name>
            <description>Provides Stock Quotes</description>
            <interface>org.myorg.services.StockQuoteService</interface>   1
            <implementation>org.myorg.services.impl.StockQuoteServiceImpl</implementation>
            <service-config>
                <param-name>quote_service</param-name>
                <param-value>quote.com</param-value>
            </service-config>
        </service>

    
1

The class files should be named accordingly and must be located in any directory called services in the src directory in order for the template project build script to handle them properly.

Create service interface

Create a services interface as shown:

    package org.myorg.services.StockQuoteService;

    import org.gridlab.gridsphere.portlet.service;
    import java.util.List;

    public interface StockQuoteService extends PortletService { 1

        public List getStockQuotes();  2

    }
    
1

The StockQuoteService must subclass from PortletService

2

Single method getStockQuotes defined in the body

Create service implementation

Create a stock quote service implementation as shown:

    package org.myorg.services.impl.StockQuoteServiceImpl;

    import org.myorg.services.StockQuoteService;
    import org.gridlab.gridsphere.portlet.service.*;
    import org.gridlab.gridsphere.portlet.service.spi.PortletServiceProvider;
    import java.util.List;

    public class StockQuoteServiceImpl implements PortletServiceProvider, StockQuoteService { 1

        public void init(PortletServiceConfig config)       2
                    throws PortletServiceUnavailableException {
            // Place optional startup routines e.g. loading data from database
        }

        public void destroy() {                       3
            // Place optional shutdown routines here e.g. saving data to database
        }

        public List getStockQuotes() {
            // hypothetical code to return stock quotes
        }

    }
    
1

The StockQuoteServiceImpl must provide implementations for the StockQuoteService and the lifecycle routines from the PortletServiceProvider

2

The destroy() method provides a service with the ability to perform any initialization tasks before it used. The PortletServiceConfig object provides any initialization data required.

2

The destroy() method provides a service with the ability to perform any cleanup tasks before it is shutdown such as freeing database connections, etc.

Access service from portlet

The following skeleton portlet code demonstrates how to obtain a stock quote service:

    package org.myorg.portlets.StockQuotePortlet;

    // imports omitted

    public class StockQuotePortlet extends AbstractPortlet {

        public void actionPerformed(ActionEvent event) {
            PortletContext ctx = getPortletConfi().getContext();
            StockQuoteService quoteService = null;
            try {
                StockQuoteService quoteService = (StockQuoteService)ctx.getService(StockQuoteService.class);
            } catch (PortletServiceException e) {
                getPortletLog().error("Couldn't get quote service instance", e);
                return;
            }

            // get quotes and place in request
            List quotes = quoteService.getStockQuotes();
            req.setAttribute("stocks", quotes);
        }

        public void doView(PortletRequest req, PortletResponse res) {

            // display stock quotes
            List quotes = req.getAttribute("stocks");
            ...
        }

    }
    

User Portlet Service Example

Continuing with the stock quote example, assume we want to allow portal administrators the ability to configure the quote service that it gets stock information from. In this case, the StockQuoteService will become a user service.

Create user service definition

The only addition to the service definition is to set the user-required element to be true


        ...

        <service>
            <name>Stock Quote Service</name>
            <user-required>true</user-required>
            <description>Provides Stock Quotes</description>
            <interface>org.myorg.services.StockQuoteService</interface>   1
            <implementation>org.myorg.services.impl.StockQuoteServiceImpl</implementation>
            <service-config>
                <param-name>quote_service</param-name>
                <param-value>quote.com</param-value>
            </service-config>
        </service>

    
1

[Important]Important
Must set <user-required>true</user-required>

Edit service interface

Add the administrator required method below:


        ...

        setQuoteService(String quoteService);

        ....
    

Create user service implementation

Now an additional class is created that handles all authorization decisions and passes control to the original class. One useful approach is to copy the original implementation into a singleton as follows and provide implementations of all service methods.

    package org.myorg.services.impl.StockQuoteServiceFactory;

    import org.myorg.services.StockQuoteService;
    import org.gridlab.gridsphere.portlet.service.*;
    import org.gridlab.gridsphere.portlet.service.spi.PortletServiceProvider;
    import java.util.List;

    public class StockQuoteServiceFactory implements PortletServiceProvider, StockQuoteService {

        // create single instance
        private instance = new StockQuoteFactory();

        private StockQuoteServiceFactory() {}              1

        public static StockQuoteServiceFactory getInstance() {
            return instance;
        }

        public void init(PortletServiceConfig config)
                throws PortletServiceUnavailableException {
            // Place optional startup routines e.g. loading data from database
        }

        public void destroy() {
            // Place optional shutdown routines here e.g. saving data to database
        }

        public List getStockQuotes() {
            // hypothetical code to return stock quotes
        }

        public void setStockQuoteService(String quoteService) {
            // sets the quote service to be used for stock information
        }

    }
    
1

To make a singleton, the constructor must be kept protected or private so that the getInstance() is used to return the single reference to this class.

The next step is to add the required security checks into the existing StockQuoteServiceImpl and configure it to use the StockQuoteServiceFactory just created.

    package org.myorg.services.impl.StockQuoteServiceImpl;

    import org.myorg.services.StockQuoteService;
    import org.gridlab.gridsphere.portlet.services.*;
    import org.gridlab.gridsphere.portlet.services.spi.PortletServiceProvider;
    import java.util.List;

    public class StockQuoteServiceImpl implements PortletServiceProvider, StockQuoteService {

        private StockQuoteServiceFactory quoteServiceFactory = null;

        private PortletServiceAuthorizer authorizer = null;

        public UserManagerServiceImpl(PortletServiceAuthorizer authorizer) { 1
           this.authorizer = authorizer;
        }

        public void init(PortletServiceConfig config)
                    throws PortletServiceUnavailableException {
            // Configure it to use StockQuoteServiceFactory
            quoteServiceFactory = StockQuoteServiceFactory.getInstance();
            quoteServiceFactory.init();
        }

        public void destroy() {
            // Place optional shutdown routines here e.g. saving data to database
            quoteServiceFactory.destroy();
        }

        public List getStockQuotes() {
            quoteServiceFactory.getStockQuotes();
        }

        public void setStockQuoteService(String quoteService) {     2
            // sets the quote service to be used for stock information

            // checks to see that the user invoking this method has super privilege or it will throw
            // a runtime AccessDenied Exception
            authorizer.authorizeSuperUser();

            quoteServiceFactory.setStockQuoteService(quoteService);
        }

    }
    
1

[Important]Important
The constructor of a user service implementation as defined in the descriptor file must require a PortletServiceAuthorizer object to be passed in. This is done by the PortletServiceFactory is created allowing for service methods to make authorization checks using the PortletServiceAuthorizer

2

The PortletServiceAuthorizer provides various authorization check methods that will throw a runtime AccessDeniedException in the event they fail. If the check succeeds the underlying StockQuoteServiceFactory method is invoked.

Access the user service from a portlet

The only difference from the previous example is passing in the User object to the getService() method.


        ...

        public void actionPerformed(ActionEvent event) {
            PortletContext ctx = getPortletConfig().getContext();
            PortletRequest req = event.getPortletRequest();
            User user = req.getUser();
            StockQuoteService quoteService = null;
            try {
                StockQuoteService quoteService = (StockQuoteService)ctx.getService(StockQuoteService.class, user);
            } catch (PortletServiceException e) {
                getPortletLog().error("Couldn't get quote service instance", e);
                return;
            }

            // get quotes and place in request
            List quotes = quoteService.getStockQuotes();
            req.setAttribute("stocks", quotes);
        }


        ....
    

Portlet Service Testing

The GridSphere testing framework relies on the JUnit and Jakarta Cactus testing frameworks to test portlet services that are deployed to a Tomcat container where they are tested. Check the tests directory in GridSphere to see how unit tests are created for services.

Chapter 7. Portlet Persistence

GridSphere provides a persistence framework implemented using Hibernate Persistence Layer. It provides methods to store objects to a SQL based database and supports many database types.

Configuration

The configuration file for the PersistenceManager is $GRIDSPHERE_SOURCE/webapps/gridsphere/WEB-INF/persistence/hibernate.properties. For the available configuration options please see the Hibernate website. By default it is configured to use HSQL, a pure Java in-memory database useful for testing and development. For a production environment we strongly recommend to use a standalone database such as MySQL, etc.

To use another database, after installing GridSphere, configure the $CATALINA_HOME/webapps/gridsphere/WEB-INF/CustomPortal/database/hibernate.properties file with the proper paramers. Place the JDBC driver jar file in $CATALINA_HOME/common/lib and run "ant create-database" in the gridsphere directory.

Simple Persistence

Making data persistent in portlets is done using the PortletData object under WebSphere portlet API and the PortletPreferences object using the JSR 168 portlet API.

In general when requiring persistence in a WebSphere portlet, first see if the PortletData object can meet your needs. Although, it only provides a container for simple String key/value pairs it can go a long way.

                    PortletData pd = request.getData();
                    pd.setAttribute("key", value);
                    try {
                    pd.store();
                    } catch (IOException e) {
                    // something went wrong while storing the data!
                    }
                
This would store the String value under the key 'key'. Getting data back is as easy as storing data. If no value is found null is returned.
                    PortletData pd = request.getData();
                    String value = pd.getAttribute("key");
                
PortletData saved values are on a per user basis.

JSR 168 provides a PortletPreferences object available from the PortletRequest. It can also store key-value pairs (only in the processAction method and not in a render method).

                            PortletPreferences prefs = request.getPreferences();
                            prefs.setValue("key", value);
                            try {
                            prefs.store();
                            } catch (IOException e) {
                            // something went wrong while storing the data!
                            }
                
This would store the String value under the key 'key'. Getting data back is as easy as storing data. If no value is found null is returned.
                            PortletPreferences prefs = request.getPreferences();
                            String value = prefs.getValue("key");
                
PortletPreferences saved values are on a per user basis.

The Persistence Manager

The PersistenceManagerRdbms interface defines methods for retrieving, creating, updating and deleting objects from the database. A PersistenceManagerException is thrown in the case that an error occurs.

Mapping files

In order to persistent your own objects you need to write hibernate mapping files. These have go into the $PROJECT_ROOT/webapp/persistence directory. This can be either one file or multiple files.

Usage

In the case that a portlet requires more sophisticated storage, the best approach is to create a separate portlet service for this management. See Portlet Service Example The following listing illustrates the storage/retrieval/update of an object to the database using the persitence manager.


                    PersistenceManagerRdbms pm =
                    PersistenceManagerFactory.createPersistenceManagerRdbms("webappname");

                    data.setName("test");

                    // store persistent data
                    pm.store(data);

                    // now retrieve it
                    PMData testdata = (PMData)pm.restore("from PMData where name='test'");

                    // modify it
                    testdata.setName("test2");

                    // update
                    pm.update(testdata);

                

This example persists the 'data' object. The restore method will restore the first object from the storage matching the given criteria. If you do want to restore a list of object you need to use restorelist instead.

The PersistenceManager is fairly useful for most simple mappings and each database transaction is atomic; a session is opened and closed for each operation. Sometimes for performace reasons, you might want to keep a session open to perform several operations at the application level. In this case, you should consider getting a Session from the PersistenceManager and working with it directly to persist your objects. In addition you can also get a Transaction object as well. The Session is associated with a ThreadLocale object so only one session is created per thread so requests to getSession will not result in new Session objects unless necessary. Finally invoke closeSession from the PersistenceManager before output is returned to the client.

Storing data on a user behalf

If you do want to store data on behalf of the user (such like a history of commands) you have to modify your objects you want to store. In pure Hibernate you would simply just stick the userobject in there. Since the userobject is immutable for third party webapps and the way Hibernate works you have to use another method to store data. Every userobject has a unique ID attached to it. The recommned way is that you creating a variable along with getter/setter methods in your class which you want to make persistent. The class would have information like this:
                    ...
                    private String useroid = null;

                    public String getUseroid() {
                        return useroid;
                    }

                    public void setUseroid(String useroid) {
                        this.useroid = useroid;
                    }
                    ...
                
The referring mappingfile would need one more line to save this information.
                    property name="Useroid" type="string" column="userid"/
                
Now you can store and update your data. To restore it you owuld have to use something like:
                    User user = request.getUser();
                    result = (MyClass)pm.restore("from "+MyClass.class.getName()+" as sub where sub.Useroid='"+user.getID()+"'");
                

Chapter 8. GridSphere Authentication Modules

GridSphere provides a pluggable way to specify "authetication modules" used for authenticating users to the portal. The model is very similar to the PAM (Pluggable Authentication Modules) approach used in Unix in that modules may be "stackable" such that each module that is selected as active also has a priority associated with it. This makes it possible for instance to default to the GridSphere password based authentication module if some other module with a higher priority fails at first.

The following major design parameters were used to develop the authentication modules approach.

  • An authentication module is described by an XML descriptor file called authmodules.xml located in WEB-INF directory of web application. As a proprietary extension, GridSphere will load in authentication modules specified in a third-party portlet application if one exists.

  • All authentication modules conform to a common interface, such that a new authentication module implementation can be supported if it implements the LoginAuthModule interface.

  • A key method of the LoginAuthModule interface is the void checkAuthentication(User user, String password) throws AuthenticationException which assumes that any authentication decision may be made basded upon a user object (which contains profile information i.e. name, email, organization) and a password value.

  • Authentication modules that are ACTIVE will be executed upon attempted login. Modules can be set active either in the descriptor, or via the Login Configuration portlet at run-time. By default, the password authentication module which uses the password stored in the gridsphere database is active.

  • A module has a priority number associated with it. All active modules are executed until authentication is successful starting with the module with the highest priority == lowest priority number associated with it.

  • Generic configuration attributes may be associated with an authentication module

Below is the authmodules.xml descriptor that is bundled in GridSphere and defines the default PasswordAuthModule.

      <auth-modules>
          <auth-module> 1
              <name>PasswordAuth</name>  2
              <description lang="en">Hashed password based authentication using GridSphere database</description> 3
              <implementation>org.gridlab.gridsphere.services.core.security.auth.modules.impl.PasswordAuthModule</implementation> 4
              <active>true</active> 5
              <priority>100</priority> 6
              <auth-config> 7
                  <param-name>aname</param-name>
                  <param-value>avalue</param-value>
              </auth-config>
              <error key="key1" lang="en">Password is not provided</error> 8
              <error key="key2" lang="en">Incorrect password provided</error>
          </auth-module>
      </auth-modules>
    
1

Every authentication module must begin with a auth-module element.

2

A name for this authentication module.

3

A human understandable description of the authentication module that will be displayed in the Login configuration portlets for administrators to see. To support additional locales, just add additional description elements.

4

Every authentication module must specify an implementation class of the LoginAuthModule interface

5

If active is true, this module will be executed with the priority assigned to it.

6

Every authentication module must specify a priority. The core GS PasswordAuthModule has a priority of 100, so a priority number that higher will be executed after the password authentication module. One that is lower will be performed beforehand.

7

Configuration parameters may be used to provide some parametrization to the module. For instance to specify some third-party authentication service or to pass in additional variables that you don't wish to hardcode in the implementation class itself.

8

Error messages can be localized and displayed to users when authentication is unsuccessful. An AuthenticationException constructed with the key attribute value should be thrown that will result in the proper locale dependent error message being displayed.

Developing a new authentication module is pretty straightforward. You would first create or add new entry to authmodules.xml describing the authentication module as explained above. The real work is the implementation of the LoginAuthModule interface. For convenience, it is recommended to subclass from org.gridlab.gridsphere.services.core.security.auth.modules.impl.BaseAuthModule which provides additional help for handling auth module configuration attributes. For additional examples, please look at the PasswordAuthModule.java class that is found in the GridSphere source code or the CredAuthModule.java source in the gridportlets codebase which handles authentication using grid certificates and the MyProxy service.

JAAS Authentication Module Configuration and Usage

The JAAS module is included in GridSphere and is specified in the authmodules.xml file:

            <auth-module>
                <name>GridSphere JAAS Integration</name>
                <description lang="en">Integration with JAAS-based Authentication of the container</description>
                <implementation>org.gridlab.gridsphere.services.core.security.auth.modules.impl.JaasAuthModule</implementation>
                <active>true</active>
                <priority>50</priority>
                <auth-config>
                    <param-name>contextName</param-name>
                    <param-value>Gridsphere</param-value>
                </auth-config>
            </auth-module>
       

Once this is in place, we need to configure JAAS to authenticate with some external source. As an example, we are going to use the JBoss JAAS LoginModule to authenticate with an LDAP server. The necessary classes are contained in the jboss-common.jar and jbosssx.jar included with a standard JBoss Application Server distribution (see http://www.jboss.com/products/jbossas/downloads). With these libraries in our class path, we then need to create a standard JAAS configuration file. This file can be named anything and can be placed anywhere. For our example, we will call it jaas.config and place it into the configuration directory of our Application Server. Here is what the file should contain:

            Gridsphere {
                org.jboss.security.auth.spi.LdapLoginModule required
                    java.naming.factory.initial="com.sun.jndi.ldap.LdapCtxFactory"
                    java.naming.provider.url="ldap://ldap.gridsphere.org:389/"
                    java.naming.security.authentication="simple"
                    java.naming.security.protocol="plain"
                    principalDNPrefix="uid="
                    principalDNSuffix=",ou=users,dc=gridsphere,dc=org"
                    rolesCtxDN="ou=roles,dc=gridsphere,dc=org"
                    uidAttributeID="uid"
                    roleAttributeID="memberUid"
                    roleAttributeIsDN="true"
                    roleNameAttributeID="cn"
                ;
            };
        

Of course, this will need to be modified for your specific LDAP configuration and schema. See the JBoss documentation on the LdapLoginModule for more information on how to configure it, including how to use it with Active Directory: http://www.jboss.org/wiki/Wiki.jsp?page=LdapLoginModule Following this same kind of configuration you can use any JAAS LoginModule, as long as it issues a NameCallback and PasswordCallback for authentication purposes. This can include other third-party JAAS LoginModules or custom JAAS LoginModules that you develop. Finally, we have to get the JVM to load our JAAS configuration at the time that our Application Server is started. This is done with the java.security.auth.login.config system property. For example, to do this in Tomcat on Windows, we would modify bin\catalina.bat to include the following:

            set JAVA_OPTS=%JAVA_OPTS% -Djava.security.auth.login.config=%CATALINA_HOME%/conf/jaas.config
        
See the documentation for your specific Application Server for information on how to set system properties for the JVM.

Chapter 9. Secure Directory

Table of Contents

Usage and Examples

Usage and Examples

Chapter 10. GridSphere Portal Specific Files

The following shows the directory layout of the deployed gridsphere web application located in $CATALINA_HOME/webapps/gridsphere:

  • html -- general GS HTML files

  • javascript/gridsphere.js -- core GS javascript functions

  • jsp -- core portlet JSP files

  • themes -- a theme consists of modifying CSS files and creating theme specific icons and gifs. See themes/default for an example

  • WEB-INF -- directory containing GS configuration files and application descriptors

    • GridSphereServices.xml -- used to configure GS authentication modules. See next chapter for more details

    • authmodules.xml -- used to configure GS authentication modules. See next chapter for more details

    • group.xml -- Specifies core gridsphere group as "hidden", all users by definition are in gridsphere group.

    • portlet.xml -- GS core portlet descriptor

    • layout.xml -- defines the associated user layout for the gridsphere group. Gets copied over to CustomPortal/layouts/groups/gridsphere.xml upon installation.

    • roles.xml -- Specifies core GridSphere roles GUEST, USER, ADMIN and SUPER.

    • classes -- contains localized properties files for core portlets and log4j.properties file. Modify this file to add/remove logging information.

    • lib -- contains gridsphere core portlets and tag library jar files

    • mappings -- contains all the mapping files used by Castor XML to unmarshal portlet, layout and other descriptors.

    • persistence -- contains all the persistence mapping files used by Hibernate to associate SQL tables with the referenced Java classes

    • test -- contains a couple fake descriptor files used for testing with JUnit

    • tlds -- contains the tag library descriptor files for both the UI tag library and JSR 168 portlet tag library

    • tmfconfig -- contains text messaging related configuration files

    • gridsphere.properties -- Specifies gridsphere portal parameters including http, https port to use when generating URLs, JSR 168 portalet API version, gridsphere release version, etc.

    • CustomPortal -- directory containing persisted GridSphere portal layouts, index of portlet webapps to be loaded and database

      • database

        • hibernate.properties -- the hibernate configuration file contains database settings for Hypersonic SQL used as the default database. To use another database modify these settings

        • gridsphere.properties -- various SQL settings for the default Hypersonic SQL database

        • gridsphere.script -- the actual flat file GS database used by Hypersonic SQL the default SQL database provided

      • layouts

        • ErrorLayout.xml -- the error layout descriptor specifies a layout to be rendered in case a portal error occurs

        • TemplateLayout.xml -- specifies the template layout used for logged-in users. The final user's layout is constructed by rendering the template adn the included user layout if one exists and the group layouts for the groups the user is subscribed to. GridSphere is started.

        • GuestUserLayout.xml -- specifies the layout used for guests (all non-logged in users). Modify this file to suit your needs. GridSphere is started.

        • html -- directory containing customized banner and footer html pages GridSphere is started.

        • users -- directory containing customized user layout descriptors GridSphere is started.

        • groups -- directory containing group layout descriptors GridSphere is started.

      • portlets -- directory containing names of portlet applications to load when GridSphere is started.

Chapter 11. Additional Portlet Resources

Many resources exist on both the WebSphere portlet model and the JSR 168 Portlet API standard. The following lists websites useful for both models as well as generic portlet and web application sites.

JSR 168 portlet API and model

WebSphere portlet development information

The architecture of GridSphere and API definitions of key portlet concepts matches the portlet API provided by IBM WebSphere to a large extent. An excellent source of more information on portlets and portlet development is the IBM WebSphere Portal Zone and the following IBM WebSphere documents: