Overview

This migration guide will help you migrate from Jetspeed version 1 to Jetspeed version 2. Note that there are currently no migration tools, nor are the plans to create a migration tool to convert portal resources from version 1 to version 2. This document provides only guidelines for migration.

With the development of the new portal standard (The Portlet API), the common portlet metaphor has changed quite drastically from the Turbine-based origins in version 1. The programming API is completely changed. There are no longer XREG files, but instead standard deployment descriptors. The are also new concepts introduced by the portlet standard such as portlet applications, portlet preferences, user attributes and init parameters that have no direct mapping from version 1. Creating a migration tool would be a large undertaking. The Jetspeed development team is not prepared to make this investment. By following the guidelines provided here, you can easily migrate your Jetspeed 1.x applications to Jetspeed 2. For an overview of architectural differences, see the document For Jetspeed-1 Users

Migration Table

The table below gives you an idea of how to migrate. We will cover each subject in more detail further on in this document.

1.x Feature2.x FeatureDescription
J1 Portlet Java CodePortlet API Standard CodeRewrite the java code to the new specification. Involves replacing Turbine action with standard processAction, and replacing Rundata with PortletRequest/Response
XREG Portlet Registryportlet.xml deployment descriptorThere are pretty big differences here. Migrate <portlet-entry> to <portlet> entries, <parameter> to <preference> or <init-param>
J1 PSMLJ2 PSMLMigrate Tabs to Folders and Pages, migrate to new tag syntax
XREG Security RegistrySecurity ConstraintsMigrate J1 security constraint format to J2 security constraint format
J1 ControllersJ2 LayoutsControllers are deprecated. Recommend using the new Jetspeed-2 Layout portlets. If porting necessary, HTML portions of VM code may port, but not context model variables
J1 ControlsJ2 Portlet DecoratorsControls are deprecated. Recommend using the new Jetspeed-2 Portlet Decorators. If porting necessary, HTML portions of VM code will port, but not context model variables
J1 Layouts, Screens, NavigationsJ2 Page (Layout) DecoratorsAll deprecated. Recommend using the new Jetspeed-2 Page (Layout) Decorators as a starting point to writing your own page decorators. HTML portions of VM code will port, but not context model variables

Portlet Applications

One of the most important differences in writing Jetspeed-2/Portlet API portlets is that you must package your portlet code separate from the Jetspeed portal. In Jetspeed-1, all the user code, the portlet business logic, is packaged in one big war file mixed in with the Jetspeed-1 implementation. The Portlet API clearly abolishes this practice of mixing the portal implementation with your portlets. Jetspeed-2 is packaged as a single web application itself. When you write your portlets for Jetspeed-2, you will need to write and package your own portlets. The portlet classes and deployment descriptors must all be packaged into a single war file, known as a portlet application. A portlet application contains one or more portlets, along with a deployment descriptor, the portlet.xml. A portlet application is an extension of a web application. The portlet.xml holds the definitions of one or more portlets and is analogous to the xreg files used in Jetspeed-1.

Java Code

In this section we demonstrate how to convert a Jetspeed-1 portlet to a JSR-168 Java Standard Portlet. This involves the following steps:

  • Converting the Portlet Init Java Code
  • Converting the Portlet getContent Java Code
  • Converting a Turbine Action

Jetspeed-1 portlet implementations are normally separated between two different Java source files.

  • The Portlet Source Code
  • The Turbine Action Source Code

The Portlet Source Code handles the View part of the MVC pattern. The getContent method is the standard method in Jetspeed-1 to call to render the content of a portlet. The corresponding methods in Jetspeed-2 and in the Portlet API, the doView, doEdit, doHelp. In the Portlet API terminology, this phase of portlet processing is known as the render phase. During the render phase, the portlet should not perform any business logic or other manipulation on the Model. All model manipulation should be left to the action phase

The Turbine Action performs the action phase of the portlet processing. During the action phase of the Portlet API standard, rendering of all other portlets is blocked until the action completes. This is also true in the Jetspeed-1/Turbine model.

Creating a new Portlet Class

The best place to get started in migrated your portlet is to create a new JSR-168 standard portlet. Simply create a new Java class inheriting from the GenericPortlet interface provided by the Portlet API. You can also use one of the frameworks or bridges available from Apache Portals or Spring MVC. The example below writes directly to the Portlet API. The code below can be used a skeleton for writing a portlet.


import java.io.IOException;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;

public class HelloWorld extends GenericPortlet
{    
    public void init(PortletConfig config) 
    throws PortletException 
    {
    }
    public void doEdit(RenderRequest request, RenderResponse response)
    throws PortletException, IOException
    {
    }    
    public void doHelp(RenderRequest request, RenderResponse response)
    throws PortletException, IOException
    {
    }
    public void doView(RenderRequest request, RenderResponse response)
    throws PortletException, IOException
    {
    }
    public void processAction(ActionRequest request, ActionResponse actionResponse)
    throws PortletException, IOException
	{
	}    
}
		

To find out more about Portals Bridges and other Frameworks, explore these links:

Converting the Portlet Init Java Code

The Portlet Source code handles the Init phase of a portlet lifecycle. The init phase is very similar in both the Java Portlet API and in Jetspeed 1. Here we have an example of the init method of a Jetspeed-1 portlet:


    public void init() throws PortletException
    {
    }

			

The equivalent method in the Portlet API (Jetspeed-2) would be, note the difference being the PortletConfig parameter (although the exception classes are named the same, they are entirely different classes, one from Jetspeed-1, the other from the Portlet API):


    public void init(PortletConfig config) 
    throws PortletException 
    {
    }

			

In Jetspeed-1, you would normally access Turbine Services with static acccessors, for example:


            JetspeedSecurity.addUser(user);

In Jetspeed-2, Jetspeed Services the standard way to access Jetspeed Services is to get a handle in the init phase, for example:


    private UserManager userManager;
...
    public void init(PortletConfig config) 
    throws PortletException 
    {
        userManager = (UserManager)getPortletContext().getAttribute(CommonPortletServices.CPS_USER_MANAGER_COMPONENT);
        if (null == userManager)
        {
            throw new PortletException("Failed to find the User Manager on portlet initialization");
        }    
    }

Converting the Portlet getContent Java Code

In Jetspeed-1, the getContent method renders the content of your portlet. The render phase of Jetspeed-1 is implemented by the getContent method of your Portlet as defined by the Jetspeed-1 Portlet interface.


public ConcreteElement getContent(RunData rundata);

The only parameter passed in to the getContent method is a RunData parameter. RunData is a part of the Turbine web framework. RunData is basically a wrapper around the Servlet request and response, along with other Turbine-specific information. When writing portlets for Jetspeed-2, you write to the Portlet API.


public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException
{
    response.setContentType("text/html");
    ...

The doView method is the Portlet API equivalent of the getContent method of the Jetspeed-1 API. The Portlet API has the concept of portlet modes. There are three default portlet modes view, edit, and help. For each of these modes, there are three methods you can override in your portlet: doView, doEdit and doHelp. Notice that where the Jetspeed-1 API has one RunData parameter, the Portlet API is more like the Servlet API, with two parameters, the RenderRequest and RenderResponse. One of the biggest parts of migrating your app will be to convert RunData references to RenderRequests and RenderResponses. Before starting, we recommend taking a training course on the Portlet API, or learning the API yourself by reading the Portlet specification as well as any articles or books on the subject. A good book to get started on the Portlet API is Portlets and Apache Portals.

When rendering content, Jetspeed 1 makes use of a HTML construction kit called ECS. All rendering goes through Turbine and ECS. The return type of the getContent method is a ConcreteElement, which is defined in the ECS API. Here is the typical way to generate output from a portlet in Jetspeed-1:


...
String helloString = "Hello World. This is the portlet output in view mode.";
return new org.apache.jetspeed.util.JetspeedClearElement(helloString);        

When rendering content in Jetspeed-2, the Portlet API uses a streaming interface:


response.setContentType("text/html");
String helloString = "Hello World. This is the portlet output in view mode.";

// using Java writers
response.getWriter().println(helloString);

.. OR ...

// using Java streaming
response.getPortletOutputStream().write(helloString.getBytes());

Of course you can use JSPs or Velocity with either Jetspeed-1 or Jetspeed-2. With Jetspeed-1, the common practice is to make use of the Jetspeed-1 GenericMVCPortlet or one of its derivitives, the VelocityPortlet or the JspPortlet. Both the VelocityPortlet and JspPortlet are really just GenericMVCPortlets. Here is the xreg example of a WeatherPortlet which extends the GenericMVCPortlet by setting its parent to Velocity


    <portlet-entry name="WeatherPortlet" hidden="false" type="ref" parent="Velocity" application="false">
        <parameter name="template" value="weather" hidden="true"/>
    </portlet-entry>

The template parameter is named weather. Since this is a Velocity MVC portlet, Jetspeed-1 knows to look under the WEB-INF/templates/vm/portlets/html directory to find weather.vm. The MVC portlet will automatically handle the details of dispatching to this Velocity template to render your portlet. Here is the actual contents of the velocity template. Note that we don't have to write any portlet Java code in this case, but only the actual template.


#if (!$weather_city_info)
<BR>${l10n.WEATHER_PLEASE_CUSTOMIZE_YO_VM}<br><BR>
#else
<a href="http://www.wunderground.com/${weather_city_info}.html"
target="_blank"><img src="http://banners.wunderground.com/banner/${weather_style}/language/www/${weather_city_info}.gif"
alt="Click for ${weather_city_info} Forecast" border="0"></a>
#end

With Jetspeed-2 and the Portlet API, we can make use of the Velocity Bridge or the JSP Bridge to delegate to portlets. The simplest case is just dispatching the call yourself to the JSP or Velocity servlet. Here is an example of dispatching to a JSP from the doView:


protected void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException
{
    PortletContext context = getPortletContext();
    ResourceBundle resource = getPortletConfig().getResourceBundle(request.getLocale());
    request.setAttribute("viewMessage", resource.getString("preference.label.MyModeIsView"));
    PortletRequestDispatcher rd = context.getRequestDispatcher("/WEB-INF/demo/preference/pref-view.jsp");
    rd.include(request, response);
}

And here is an example of the WeatherPortlet extending the Velocity Bridge, and making use of the Portlet API User Preferences feature, note that we do not directly create a dispatcher here, but the framework will do that automatically:


import org.apache.portals.bridges.velocity.GenericVelocityPortlet;
...

public class WeatherPortlet extends GenericVelocityPortlet
{
...

public void doView(RenderRequest request, RenderResponse response)
        throws PortletException, IOException
{
    Context context = super.getContext(request);

    String cityInfo = (String) request.getPortletSession().getAttribute(
            WEATHER_CITY_INFO);

    PortletPreferences prefs = request.getPreferences();
    String city = prefs.getValue(WEATHER_CITY, "Bakersfield");
    String state = prefs.getValue(WEATHER_STATE, "CA");
    String station = prefs.getValue(WEATHER_STATION, null);
    cityInfo = getCityInfo(city, state, station);
    context.put(WEATHER_CITY_INFO, cityInfo);

    String style = prefs.getValue(WEATHER_STYLE, "infobox");
    context.put(WEATHER_STYLE, style);
    response.setProperty("david", "taylor");
    super.doView(request, response);
}

And here is the Velocity template to render the portlet content:


#if (!$weather_city_info)
Please configure your Weather settings.
#else
<a href="http://www.wunderground.com/${weather_city_info}.html"  
target="_blank"><img src="http://banners.wunderground.com/banner/$!weather_style/language/www/${weather_city_info}.gif"
alt="Click for $weather_city_info Forecast" border="0"></a>
#end

Converting a Turbine Action

The Portlet API defines several phases of execution during the processing of a portlet page. The action phase is designed to be executed before the render phase of a portlet. There can only be one action phase targeting only one portlet. Once the action phase completes, then the render phase for all portlets on a page can be executed. Thus the action phase is said to be a blocking phase, meaning that it must complete before the render phase for each portlet on the page can commence. Actions are usually some kind of user interaction that manipulates the Model of the MVC framework, such as a user submitting a form and updating the model, or adding or deleting a record. The concept of actions ports fairly well from Turbine and Jetspeed-1 to Jetspeed-2 and the Portlet API. Whereas Turbine has the concept of one class per action, the Portlet API has an entry point for all actions to come through as a method on your portlet. Frameworks such as the Spring MVC framework provide better abstractions for modeling one method per action.

Lets again look at the WeatherPortlet with Jetspeed-1. First the xreg defines the actions:


        <parameter name="action" value="portlets.WeatherAction" hidden="true"/>

We must then implement the action class which are usually placed in the Jetspeed-1 webapp class loader space. Here is the code for the WeatherAction, which extends a Jetspeed-1 framework class VelocityPortletAction:


public class WeatherAction extends VelocityPortletAction
{

    protected void buildNormalContext( VelocityPortlet portlet,
                                       Context context,
                                       RunData rundata )
    {

        String cityInfo = PortletConfigState.getParameter(portlet, rundata, WEATHER_CITY_INFO, null);
        //if (cityInfo == null)
        //{
            String city = portlet.getPortletConfig().getInitParameter(WEATHER_CITY);
            String state = portlet.getPortletConfig().getInitParameter(WEATHER_STATE);
            String station = portlet.getPortletConfig().getInitParameter(WEATHER_STATION);
            cityInfo = getCityInfo(city, state, station);            
        //}
        context.put(WEATHER_CITY_INFO, cityInfo);
        //PortletConfigState.setInstanceParameter(portlet, rundata, WEATHER_CITY_INFO, cityInfo);

        String style = PortletConfigState.getParameter(portlet, rundata, WEATHER_STYLE, "infobox");
        context.put(WEATHER_STYLE,style);
    }

In Jetspeed-1 there is some really bad architecture interfering with easily writing portlets. Here in our action, we are actually implementing the View portion of our code by populating the Velocity context with context.put statements. Please beware that all code implemented in the buildNormalContext method should be ported to the doView method of the Portlet API. Note how the actual portlet must be passed in as the first parameter to the buildNormalContext method.

The actual action code implemented as do.. methods on your action class will need to be ported to the processAction method on the Portlet API.


    public void doInsert(RunData rundata, Context context)
        throws Exception
    {

The doInsert method is linked by Turbine to an action in the Velocity template with the eventSubmit_ prefix:


<input type="submit" name="eventSubmit_doInsert" value="${l10n.USER_FORM_ADD_USER_VM}"/>

Here is the equivalent in the Portlet API (Jetspeed-2):


    public void processAction(ActionRequest actionRequest, ActionResponse actionResponse) 
        throws PortletException, IOException

The Portlet API provides two parameters to the processAction method: the ActionRequest and ActionResponse.

Request Parameters, Portlet Modes, Window States

Request parameters are accessed via RunData in Jetspeed-1:


	String name = rundata.getParameters().getString("username");

With the Portlet API, portlet request parameters are accessed via the ActionRequest:


   String name = actionRequest.getParameter("username");

With the Portlet API, you can check the Portlet Mode or Window State:


        if (actionRequest.getPortletMode() == PortletMode.EDIT)
        {
        	if ( !request.getWindowState().equals(WindowState.MINIMIZED))
        	{
        	...        

The basic Portlet API does not have a way to map actions to methods as in Jetspeed-1. If you would like this kind of behavior, we recommend using the Spring MVC Portlet framework Here we demonstrate using portlet request parameters per form to map to specific actions:


		String action = actionRequest.getParameter(SecurityResources.PORTLET_ACTION);
        if (action != null && action.equals("remove.user"))
        {
            removeUser(actionRequest, actionResponse);
        }
        else if (action != null && action.equals("add.new.user"))
        {
            PortletMessaging.cancel(actionRequest, SecurityResources.TOPIC_USERS, SecurityResources.MESSAGE_SELECTED);
        }
        else if (action != null && action.equals("add.user"))
        {
            addUser(actionRequest);
        }
		...

Persisting State: The Portlet Session

The Portlet API provides built-in support for persistence of Portlet state in the session. The Portlet Session is similar to the setTemp methods in Turbine/Jetspeed-1, or the session support built into the Servlet API. The Session is for persisting state associated with the current user session. There are two kinds of session state supported by the Portlet API:

  • Application Session State: the session variable is shared by all portlets in a portlet application
  • Portlet Session State: the session variable is specific to the one portlet instance window

Here is how we would get and set session information in Jetspeed-1, using the Turbine RunData API. Note that for both Jetspeed-1 and Jetspeed-2, the object put in the session must be serializable:

			
             rundata.getUser().setTemp(ACCOUNT_INFO, accountInfo);
             ...
             AccountInfo accountInfo = (AccountInfo)rundata.getUser().getTemp(ACCOUNT_INFO);

In here is the equivalent in Jetspeed-2 using the Portlet API:

	
        AccountInfo accountInfo = (AccountInfo)
        	actionRequest.getPortletSession().getAttribute(ACCOUNT_INFO, PortletSession.PORTLET_SCOPE);
        -- or --
        AccountInfo accountInfo = (AccountInfo)        
	        actionRequest.getPortletSession().getAttribute(ACCOUNT_INFO, PortletSession.APPLICATION_SCOPE);        
		
		-- the setters --
		PortletSession session = actionRequest.getPortletSession();
		session.setAttribute(ACCOUNT_INFO, accountInfo, PortletSession.PORTLET_SCOPE);
		-- or --
		session.setAttribute(ACCOUNT_INFO, accountInfo, PortletSession.APPLICATION_SCOPE);		

Persisting State: User Preferences

The Portlet API provides a second persistence mechanism: User Preferences. User Preferences are fields of information stored on a per user/per portlet window basis. The equivalent in Jetspeed-1 is Portlet Instance data, which is stored in the Jetspeed-1 Portlet Registry as name/value pair parameter XML elements. Looking at the XREG file in Jetspeed-1, we have:

	
        <parameter name="weather_city_info" value="US/IN/Bloomington" hidden="true"/>

The Portlet API allows you to define default values for preferences in the portlet.xml deployment descriptor. The user-specific values are stored in the Jetspeed Preferences database. Here is an example of the default value for a preference as it would be defined in the deployment descriptor:

	
            <preference>
                <name>weather_city</name>
                <value>Oakland</value>
            </preference>

Jetspeed-1 provides the PortletInstance interface on every portlet for accessing preference-like information. Whereas the preference information is per-user and per-instance in Jetspeed-2, in Jetspeed-1 preference information accessed via the PortletInstance interface is only per-instance(per PortletWindow) specific. These values are stored in the PSML file associated with the PortletWindow. Please note that the values can still be user-specific when you are using the default mechanism for locating pages, which is by user. This means that in Jetspeed-1 preferences (or parameters) are made user-specific by the nature of how pages are retrieved. Since a page is located under a user home directory, then the preference is naturally per user.

With Jetspeed-1, here we can retrieve PortletInstance data:


        // where "this" is a Jetspeed-1 Portlet object
    	PortletInstance instance = this.getInstance(rundata);
    	String value = instance.getAttribute("favoriteColor", "blue");
    	-- or --
    	this.getAttribute("favoriteColor", "blue", rundata);
    	
    	-- we can set preference data the same way in Jetspeed-1    	
    	PortletInstance instance = this.getInstance(rundata);
    	instance.setAttribute("favoriteColor", "red");
    	-- or --
    	this.setAttribute("favoriteColor", "red", rundata);

With the Portlet API in Jetspeed-2, we can use the Portlet Preferences in a more direct manner. Remember that the store() method must always be called after all modifications to the prefs during a request:


        PortletPreferences prefs = actionRequest.getPreferences();
        String color = prefs.getAttribute("favoriteColor", "blue");
        ...
        prefs.setAttribute("favoriteColor", "red");        
        prefs.store();        
        
        // note that you can also retrieve multivalues for prefs
        String values[] = actionRequest.getPreferences().getValues("stocks", defaultValues);
        
        // or retrieve all preferences as a Map
        Map allPrefs = actionRequest.getPreferences().getMap();        

Registries

The Jetspeed-1 Registries hold the following information:

  • Portlet Definitions
  • Security Definitions
  • Web Clients and Media Type Registries
  • Skins Definitions
  • Controller Definitions
  • Control Definitions

This section will guide you through how to migrate each of these registries from Jetspeed-1 to Jetspeed-2

Portlet Definitions

Jetpeed-1 requires that all portlets are defined in an XML file known as an XREG file (XML Registry). Jetspeed-2 stores its portlet registry in the database. In Jetspeed-1, the XML registry is on the file system under the jetspeed webapp under WEB-INF/conf. There can be one or more portlet registry entries. All portlets are defined with the element type portlet-entry.

Migrating your Jetspeed-1 portlet registries to Jetspeed-2 registries requires writing a new Portlet API standard portlet.xml definition file. We do not provide an XSLT transform to do this for you. Whereas the portlet.xml is defined by the Java Standard Portlet API, Jetspeed allows for additional information to be defined specific to the Jetspeed portal: the jetspeed-portlet.xml can hold Jetspeed-specific deployment configurations. Some of the XREG elements map to the portlet.xml, whereas others will map to the jetspeed-portlet.xml as noted in the tables below. The table below describes how to map each XML attribute of the portlet-entry element to its equivalent in the Portlet API portlet.xml or jetspeed-portlet.xml. Note that we are mapping in this table from XML attributes to XML elements in the portlet.xml or jetspeed-portlet.xml:

J1 AttributeJ2 Element
nameportlet-nameThe name of the portlet. This name is unique to each portlet application, but not unique system-wide.
hiddenNo equivalent in the Portlet API, not applicable.
typeNo equivalent in the Portlet API, not applicable.
parentNo equivalent in the Portlet API, not applicable.
applicationNo equivalent in the Portlet API, not applicable.

Continuing with the Portlet XREG conversion, lets now look at how to convert the XML elements of the portlet-entry element. The table below describes how to map each XML element to its equivalent in the Portlet API portlet.xml:

J1 ElementJ2 Element
classnameportlet-classThe implementing Java class. This class will need to be ported at the source level.
media-typesupports, supports/mime-type, supports/portlet-modeMedia types supported by the portlet must be mapped to one or more supports elements, with subelements of mime-type and portlet-mode pairs.
meta-info/titletitleThe title of the Portlet.
meta-info/descriptiondescriptionThe description of the portlet
categoryportlet-info/keywordsWhere there are multiple categories elements, keywords are comma-separated. In Jetspeed-2, you can configure categories in the Portlet-Selector administrative portlet based on keywords.
security-refjetspeed-portlet.xml: js:security-constraint-refIf you port your Security constraints definitions, you can keep the same security definition names. Just note that security constraint definitions are referenced from the jetspeed-portlet.xml, not portlet.xml
parameterinit-paramParameters in Jetspeed-1 should normally map to init-params in the Portlet API. These are read only values that can only be changed by the administrator
parameter@nameinit-param/nameThe name of the init parameter
parameter@valueinit-param/valueThe value of the init parameter
parameter/meta-info/descriptioninit-param/descriptionThe description of the init parameter
parameterportlet-preferences/preferenceAs well as migrating to init-params, parameters may also be migrated as default preferences. Note that preferences can optionally be read-only.
parameter@nameportlet-preferences/preference/nameThe name of the preference
parameter@valueportlet-preferences/preference/valueThe value of the preference
parameter@hiddenportlet-preferences/preference/read-onlyOptionally you map want to map hidden values to read-only (true/false)

Security Definitions

Jetspeed-1 supports a Security Constraint XML definition language that is very similiar to the XML security constraint definitions in Jetspeed-2. Jetpeed-1 requires that all security definitions are defined in an XML file known as an XREG file (XML Registry). Jetspeed-2 stores its security registry either in an XML file or in the database. In Jetspeed-1, the XML registry is on the file system under the jetspeed webapp under WEB-INF/conf. There can be one or more security registry entries. All security constraints are defined with the element type security-entry.

Migrating your Jetspeed-1 security constraints registries to Jetspeed-2 registries requires writing a new page.security XML definition file. We do not provide an XSLT transform to do this for you. The table below describes how to map each XML attribute of the security-entry element to its equivalent in the Portlet API portlet.xml or jetspeed-portlet.xml. Note that we are mapping in this table from XML attributes to XML elements in the portlet.xml or jetspeed-portlet.xml:

J1 AttributeJ2 Attribute
security-entry@namesecurity-constraints-def@nameThe name of the security constraint definition. This name is unique to the entire page.security file.
meta-info/titleNo equivalent in Jetspeed-2, not applicable.
meta-info/descriptionNo equivalent in Jetspeed-2, not applicable.
accesssecurity-constraintJetspeed-1 security-entries contain 0..n access elements, Jetspeed-2 security-constraint-defs contain 0..n security-constraint elements.
access@actionsecurity-constraint/permissions Actions in Jetspeed-1 are called Permissions in Jetspeed-2. Both versions support wildcarding with the * character.
  • Jetspeed-1 default actions are view, customize, maximize, minimize, info, close.
  • Jetspeed-2 default permissions are view, edit, help, print
access/allow-if@rolesecurity-constraint/rolesJetspeed-1 constrains by role through allow-if elements with a role attribute. Jetspeed-2 constrains by role with the roles element and a comma-separated list of one or more roles
access/allow-if@groupsecurity-constraint/groupsJetspeed-1 constrains by group through allow-if elements with a group attribute. Jetspeed-2 constrains by group with the groups element and a comma-separated list of one or more groups
access/allow-if@usersecurity-constraint/usersJetspeed-1 constrains by user through allow-if elements with a user attribute. Jetspeed-2 constrains by user with the users element and a comma-separated list of one or more users, or the wildcard * to specify all users.
access/allow-if-ownersecurity-constraints/ownerYou can set the constraint to be only accessible by the owner of the page. In Jetspeed-1, this is implied by the location of the page. With Jetspeed-2 you must explicity name the owner in the element text of the owner element.

Web Clients and Media Type Registries

The Web Clients and Media Type registries are already ported to Jetspeed-2 and a part of the core system. Jetspeed-2 stores these registries in the database. However these tables can be populated using seed data as described in the section below on seed data.

Skins

The Skin registries are not directly portable to Jetspeed-2. Jetspeed-2 has moved towards a more standard CSS based skinning approach. There are two basic skinning techniques which can be combined:

  • 1. Portlet API Standard Skins - see PLT.C of the portlet specification. A standard set of CSS styles are defined for global skinning of portlet content.
  • 2. Jetspeed Decorators - Decorators can define their own skins which can then be leveraged by portlets by accessing these styles. The default decorators in Jetspeed also define the PLT.C styles as well

Controllers

Controllers are deprecated in Jetspeed-2. There is no direct mapping for converting the Java code. Instead you will need to rewrite a new Layout portlet, or more likely simply use one of the existing Layout Portlets that come with Jetspeed, which are quite flexible. The default layout portlets in Jetspeed support multi-column grids, nesting portlets, and complete customization using the Portlet Customizer.

Controls

Controls are deprecated in Jetspeed-2. There is no direct mapping for converting the Java code. Instead you will need to rewrite a new Portlet decorator, or more likely simply use one of the existing Portlet decorators that come with Jetspeed, which are quite flexible.

PSML

The Jetspeed Sitemap

The Jetspeed Sitemap defines the navigational space of all pages in the portal. Both versions 1 and 2 have similiar hiearchical file system-like site maps. Both contain a root folder /, which in turn contains a tree of subfolders, where each subfolder can contain pages or more subfolders.

Site Resources

In Jetspeed-2, there is a well-defined portal resources that do not always have equivalents in Jetspeed-1:

2.x1.xFile
PagePageA .psml file.
Folder--A folder.metadata file, one per folder, N/A in Jetspeed-1
Link--A .link file, N/A in Jetspeed-1
Menu--Menus are defined in folder.metadata, N/A in Jetspeed-1

Reserved Directories

There are reserved directories available in both versions. The naming is a little different. Any directory starting with an underscore (_) in Jetspeed-2 is considered a control directory and can be used by the profiler (see below) to locate special directories based on runtime criteria such as the user name or the roles of the user. Jetspeed-1 has a hard-coded set of reserved (control) directories that are hard-coded into the profiling rules.

1.x2.x
user_userHolds all user folders
role_roleHolds all role folders
group_groupHolds all group folders
{mediatype}_mediatypeContent per mime/mediatype
{language}_lanaguageContent per language
{country}_countryContent per country code

Where the J1 directory names are actually the names of the reserved directory, such as {mediatype} would be actually html or {language} would be en. J2 requires specifing control directories (_) such as _mediatype/html, or _language/en

Profiling

The Profiling algorithm discovers the correct page to display during a request. J1 has only two hard-coded algorithm for finding pages:

  • J1 user/mediatype/language/country fallback
  • J1 rollback

Note that these settings are system wide and must be changed on a per portal basis. J1 expects an explicit container order of mediatype / language / country

J2 has a profiling rules engine that takes dynamic runtime user information, and using profiling rules discovers the rules based on the algorithm defined in the rules. In J2 profiling rules are defined on a per user basis, although there is a system-wide default profiling rule.

Differences in PSML Page

Jetpeed-1 requires that all portlets are defined in an XML file known as an XREG file (XML Registry). Jetspeed-2 stores its portlet registry in the database. In Jetspeed-1, PSML files can be stored under the jetspeed webapp under WEB-INF/psml. Or, Jetspeed-1 supports storing PSML files in the database. In Jetspeed-2, PSML files can be stored under the jetspeed webapp under WEB-INF/pages or WEB-INF/min-pages. Or, Jetspeed-2 supports storing PSML files in the database.

Migrating your Jetspeed-1 PSML files to Jetspeed-2 PSML files requires porting the files manually, or writing a database conversion utility or XSLT transform. We do not provide an XSLT transform to do this for you. The table below describes how to map each XML element or attribute from Jetspeed-1 to Jetspeed-2:

J1 ElementJ2 Element
portletspageThe outermost container of all content found on a PSML page.
portlets@idpage@idSystem wide unique identifier for this page.
metainfo/titletitleThe Page Title.
security-refsecurity-constraints/security-constraints-refThe security constraint reference (0..1 in Jetspeed-1, 0..n in Jetspeed-2)
controldefaults/portlet-decoratorRequires porting your controls to J2 portlet decorators, or at least mapping the names to existing decorators in Jetspeed-2. Or you can use a global portlet decorator and ignore this optional setting.
controllerdefaults/layout-decoratorRequires porting your Turbine controllers, screens navigations to J2 layout(page) decorators, or at least mapping the names to existing page decorators in Jetspeed-2. Or you can use a global portlet decorator and ignore this optional setting.
portlets/portlets/...page/fragment/..., type="layout"Sub-containers of fragments or portlets. In Jetspeed-2, fragments can be either containers or portlet definitions. Only fragments with the type of layout can be a container holding more fragments and containers.
portlets/portlets/controllerpage/fragment@type=layout@name={layout-name}Controllers roughly map to fragments of type = layout, named by the name attribute. Note that layouts are implemented as portlets and must be specified as PA::portlet-name.
portlets/entrypage/fragment/fragment@type="portlet"A portlet window on a page.
entry@idfragment@idThe system-wide unique ID of the portlet window.
entry@parentfragment@nameThe portlet registry reference. In Jetspeed-2 the name of the portlet must be specified as PA::portlet-name
entry/layout/property@name="column"@value={column}fragment/property@name="column"@value={column}The property containing the column position
entry/layout/property@name="row"@value={row}fragment/property@name="row"@value={row}The property containing the row position

Menus vs Tabs

There is a big difference with the navigational aspects, or menus, between Jetspeed-1 and Jetspeed-2. Jetspeed-1 restricts menus navigation to navigation amongst tabs. Tabs are defined within a PSML page. Tabs are simply subcontainers in the PSML page, defined by the portlets element. Whereas Jetspeed-1 does support navigation to other pages, the Tabbing Menus do not directly support it without writing a specific portlet to act as an external link.

Jetspeed-2 menu navigations map directly onto the Portal Site. Thus menu tabs represent portal resources. Menus in Jetspeed-2 can point to folders, pages or links. This more naturally allows the user to navigate over the entire portal site.

When migrating PSML files from Jetspeed-1 to Jetspeed-2, depending on whether you use advanced Jetspeed-1 controllers such as Card or Tab controllers, you may find that the pages do not port to Jetspeed-2 very well. In consideration of the lack of migration tools, this leaves two immediate options:

  • Rewrite your PSML files to better map to the Jetspeed-2 site constructs, folders and multiple pages.
  • Enhance Jetspeed-2 to support card and tab controller behavior

XML API - Seed Data

Jetspeed-2 defines an XML API for populating the initial "Seed" data for your portal. Populating your seed data via the XML API provides an alternative to populating database data with database-specific and hard to read SQL scripts. Additionally, the XML API can be used for importing and exporting data, or backing up and restoring from your Jetspeed-2 database.

The XML API also provides a migration path over the maintenance cycle of your Jetspeed portal. The XML API was first implemented in version 2.1. To migrate your data from version 2.1 to 2.2, (if there are any database schema changes), the XML API can be used to migrate (by exporting and importing) across versions.

As of 2.1, the Jetspeed API supports the following elements:

ElementDescription
MimeTypesMime Types supported by the portal such as text/html, text/xhtml....
MediaTypesMediat Types supported by the portal such as html, xml, wml...
CapabilitiesGeneral capabilities of web clients that access the portal
ClientsSupported Web Clients by the portal
RolesDefine all roles defined to the initial configuration of the portal
GroupsDefine all groups defined to the initial configuration of the portal
UsersDefine all initial users defined to the initial configuration of the portal, minimally admin and guest(anon) users
PermissionsDefine initial J2EE security policy for this portal. Note that permissions are turned off by default.
ProfilingRulesDefine all the profiling rules in the initial portal such as role fallback, user-role-fallback, j1-emulation, default-j2, subsites and more

Where to Get Started?

The best place to get started is to create your own custom portal. This process is defined online at Apache. The Jetspeed Tutorial will take you through the initial steps of setting up your own (custom) Jetspeed portal, including setting up XML seed data, PSML, custom decorations and portlet applications.