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
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 Feature | 2.x Feature | Description |
---|---|---|
J1 Portlet Java Code | Portlet API Standard Code | Rewrite the java code to the new specification. Involves replacing Turbine action with standard processAction, and replacing Rundata with PortletRequest/Response |
XREG Portlet Registry | portlet.xml deployment descriptor | There are pretty big differences here. Migrate <portlet-entry> to <portlet> entries, <parameter> to <preference> or <init-param> |
J1 PSML | J2 PSML | Migrate Tabs to Folders and Pages, migrate to new tag syntax |
XREG Security Registry | Security Constraints | Migrate J1 security constraint format to J2 security constraint format |
J1 Controllers | J2 Layouts | Controllers 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 Controls | J2 Portlet Decorators | Controls 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, Navigations | J2 Page (Layout) Decorators | All 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 |
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.
In this section we demonstrate how to convert a Jetspeed-1 portlet to a JSR-168 Java Standard Portlet. This involves the following steps:
Jetspeed-1 portlet implementations are normally separated between two different Java source files.
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.
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:
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, 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"); } }
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 derivatives, 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
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 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); } ...
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:
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);
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();
The Jetspeed-1 Registries hold the following information:
This section will guide you through how to migrate each of these registries from Jetspeed-1 to Jetspeed-2
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 Attribute | J2 Element | |
---|---|---|
name | portlet-name | The name of the portlet. This name is unique to each portlet application, but not unique system-wide. |
hidden | No equivalent in the Portlet API, not applicable. | |
type | No equivalent in the Portlet API, not applicable. | |
parent | No equivalent in the Portlet API, not applicable. | |
application | No 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 Element | J2 Element | |
---|---|---|
classname | portlet-class | The implementing Java class. This class will need to be ported at the source level. |
media-type | supports, supports/mime-type, supports/portlet-mode | Media 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/title | title | The title of the Portlet. |
meta-info/description | description | The description of the portlet |
category | portlet-info/keywords | Where 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-ref | jetspeed-portlet.xml: js:security-constraint-ref | If 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 |
parameter | init-param | Parameters 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@name | init-param/name | The name of the init parameter |
parameter@value | init-param/value | The value of the init parameter |
parameter/meta-info/description | init-param/description | The description of the init parameter |
parameter | portlet-preferences/preference | As well as migrating to init-params, parameters may also be migrated as default preferences. Note that preferences can optionally be read-only. |
parameter@name | portlet-preferences/preference/name | The name of the preference |
parameter@value | portlet-preferences/preference/value | The value of the preference |
parameter@hidden | portlet-preferences/preference/read-only | Optionally you map want to map hidden values to read-only (true/false) |
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 Attribute | J2 Attribute | |
---|---|---|
security-entry@name | security-constraints-def@name | The name of the security constraint definition. This name is unique to the entire page.security file. |
meta-info/title | No equivalent in Jetspeed-2, not applicable. | |
meta-info/description | No equivalent in Jetspeed-2, not applicable. | |
access | security-constraint | Jetspeed-1 security-entries contain 0..n access elements, Jetspeed-2 security-constraint-defs contain 0..n security-constraint elements. |
access@action | security-constraint/permissions |
Actions in Jetspeed-1 are called Permissions in Jetspeed-2.
Both versions support wildcarding with the * character.
|
access/allow-if@role | security-constraint/roles | Jetspeed-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@group | security-constraint/groups | Jetspeed-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@user | security-constraint/users | Jetspeed-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-owner | security-constraints/owner | You 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. |
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.
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:
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.
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.
In Jetspeed-2, there is a well-defined portal resources that do not always have equivalents in Jetspeed-1:
2.x | 1.x | File |
---|---|---|
Page | Page | A .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 |
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.x | 2.x | |
---|---|---|
user | _user | Holds all user folders |
role | _role | Holds all role folders |
group | _group | Holds all group folders |
{mediatype} | _mediatype | Content per mime/mediatype |
{language} | _lanaguage | Content per language |
{country} | _country | Content 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
The Profiling algorithm discovers the correct page to display during a request. J1 has only two hard-coded algorithm for finding pages:
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.
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 Element | J2 Element | |
---|---|---|
portlets | page | The outermost container of all content found on a PSML page. |
portlets@id | page@id | System wide unique identifier for this page. |
metainfo/title | title | The Page Title. |
security-ref | security-constraints/security-constraints-ref | The security constraint reference (0..1 in Jetspeed-1, 0..n in Jetspeed-2) |
control | defaults/portlet-decorator | Requires 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. |
controller | defaults/layout-decorator | Requires 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/controller | page/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/entry | page/fragment/fragment@type="portlet" | A portlet window on a page. |
entry@id | fragment@id | The system-wide unique ID of the portlet window. |
entry@parent | fragment@name | The 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 |
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:
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:
Element | Description |
---|---|
MimeTypes | Mime Types supported by the portal such as text/html, text/xhtml.... |
MediaTypes | Mediat Types supported by the portal such as html, xml, wml... |
Capabilities | General capabilities of web clients that access the portal |
Clients | Supported Web Clients by the portal |
Roles | Define all roles defined to the initial configuration of the portal |
Groups | Define all groups defined to the initial configuration of the portal |
Users | Define all initial users defined to the initial configuration of the portal, minimally admin and guest(anon) users |
Permissions | Define initial J2EE security policy for this portal. Note that permissions are turned off by default. |
ProfilingRules | Define all the profiling rules in the initial portal such as role fallback, user-role-fallback, j1-emulation, default-j2, subsites and more |
Reference for Jetspeed-2 XML schemas:
Jetspeed-2 PSML | http://portals.apache.org/jetspeed-2/2.1/schemas/psml.xsd |
Jetspeed-2 Folder Metadata | http://portals.apache.org/jetspeed-2/2.1/schemas/folder-metadata.xsd |
Jetspeed-2 Seed Data | http://portals.apache.org/jetspeed-2/2.1/schemas/j2-seed.xsd |
Jetspeed-2 Security Constraints | http://portals.apache.org/jetspeed-2/2.1/schemas/page-security.xsd |
Jetspeed-2 Links | http://portals.apache.org/jetspeed-2/2.1/schemas/link.xsd |
Jetspeed-2 Extended Portlet Descriptor | http://portals.apache.org/jetspeed-2/2.1/schemas/jetspeed-portlet.xsd |
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.