Table of Contents
List of Figures
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.
Table of Contents
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 |
|---|---|
| Concrete portlets only exist in the WebSphere portlet model |
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 |
|---|---|
| Concrete portlets only exist in the WebSphere portlet model |
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()
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)
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)
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 )
Table of Contents
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.
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><group-name>GridSphere</group-name>
<group-description>Core GridSphere Group</group-description>
<group-visibility>PUBLIC</group-visibility>
<portlet-role-info>
<portlet-class> org.gridlab.gridsphere.portlets.core.user.ProfileManagerPortlet.1 </portlet-class>
<required-role>USER</required-role>
</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>
Table of Contents
The layout descriptor specifies a custom configuration for the layout of your portlets in the portal using a nested tabbed pane approach.
![]() | 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.
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
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.
Lays out components within a table
Lays out components inside of a row
Lays out components inside of a column
A tabbed pane is a container for portlet tabs
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
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.
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.
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"><!-- Header components --> <portlet-header>
<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>
<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>
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.
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><portlet-tab> <title lang="en">Examples</title>
<portlet-tabbed-pane style="sub-menu">
<portlet-tab order="50">
<title lang="en">Simple Examples</title> <table-layout>
<row-layout>
<column-layout width="50%>
<portlet-frame>
<portlet-class> org.myorg.portlets.examples.simpleone.1 </portlet-class> </portlet-frame> </column-layout width="50%> <column-layout width="50%> <portlet-frame label="simpletwo">
<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">
<title lang="en">Google</title> </portlet-tab> </portlet-tabbed-pane> </portlet-tab> </portlet-tabbed-pane>
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.
Table of Contents
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:
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:
Table of Contents
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 |
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:
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 in the user)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.
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>
<service>
<name>Example Service</name>
<description>Provides Special Capabilities</description>
<interface>org.gridlab.gridsphere.services.core.example.ExampleService</interface>
<implementation>
org.gridlab.gridsphere.services.core.example.impl.ExampleServiceImpl
</implementation>
<user-required>false</user-required>
<load-on-startup>false</load-on-startup>
<service-config>
<param-name>some parameter</param-name>
<param-value>some value</param-value>
</service-config>
</service>
</portlet-services>
Core Portlet Services
Provides login capabilities.
Provides authorization capabilities to portal users
Provides user administration capabilities
Provides layout modification capabilities
Provides a list of supported locales.
Provides portlet loading and unloading capabilities.
Provides text messaging capabilities.
Provides e-mail capabilities.
Provides a simple service for persistencing global gridsphere portal configuration settings.
Provides a simple service for tracking requests and providing persistence.
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 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>
<implementation>org.myorg.services.impl.StockQuoteServiceImpl</implementation>
<service-config>
<param-name>quote_service</param-name>
<param-value>quote.com</param-value>
</service-config>
</service>
Create a services interface as shown:
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 {
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
}
}
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");
...
}
}
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.
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>
<implementation>org.myorg.services.impl.StockQuoteServiceImpl</implementation>
<service-config>
<param-name>quote_service</param-name>
<param-value>quote.com</param-value>
</service-config>
</service>
Add the administrator required method below:
...
setQuoteService(String quoteService);
....
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() {}
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
}
}
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) {
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) {
// 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);
}
}
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);
}
....
Table of Contents
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.
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.
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!
}
null is returned.
PortletData pd = request.getData();
String value = pd.getAttribute("key");
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!
}
null is returned.
PortletPreferences prefs = request.getPreferences();
String value = prefs.getValue("key");
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.
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.
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.
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;
}
...
property name="Useroid" type="string" column="userid"/
User user = request.getUser();
result = (MyClass)pm.restore("from "+MyClass.class.getName()+" as sub where sub.Useroid='"+user.getID()+"'");
Table of Contents
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>
<name>PasswordAuth</name>
<description lang="en">Hashed password based authentication using GridSphere database</description>
<implementation>org.gridlab.gridsphere.services.core.security.auth.modules.impl.PasswordAuthModule</implementation>
<active>true</active>
<priority>100</priority>
<auth-config>
<param-name>aname</param-name>
<param-value>avalue</param-value>
</auth-config>
<error key="key1" lang="en">Password is not provided</error>
<error key="key2" lang="en">Incorrect password provided</error>
</auth-module>
</auth-modules>
| Every authentication module must begin with a auth-module element. |
| A name for this authentication module. |
| 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. |
| Every authentication module must specify an implementation class of the LoginAuthModule interface |
| If active is true, this module will be executed with the priority assigned to it. |
| 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. |
| 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. |
| 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.
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.
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.
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.
General portlet and web application development
Excellent site with links to articles in JSP, Servlets, Portlets, JSF, etc
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: