Client media selection

The features described in this section are mostly new to Jetspeed 1.4b2. This documentation is a living document that may reflect changes that will occur until the release is out.

The Jetspeed layout engine uses a configurable matching algorithm to determine the type of content format to return to the client. This matching is based on the following parameters:

  • a definiton of the media types supported by the portal
  • a definition of the known user agents and their rendering capabilities
  • an algorithm that calculates how the clients are matched up to specific media types

Media Types

Media types represent the different document formats supported by the portal and are defined in the central Registry.

These media types definition typically associatee a well known MIME type with one or more required capabilities that will be used to differentiate between user-agents.

For example, in this registry definition, the "html" media type represents the markup that can be sent to full-blown HTML 3.2 client, supporting features like tables and images while the "htmlite" can be used to service user agrents without any table capabilities and "htmltext" will service user-agents without any image support.

<media-type-entry name="html">
  <mime-type>text/html</mime-type>
  <character-set>UTF-8</character-set>
  <meta-info>
    <title>HTML</title>
    <description>HTML for HTML 4.0 browsers</description>
  </meta-info>
  <capability-map>
    <capability>HTML_TABLE</capability>
    <capability>HTML_IMAGE</capability>
  </capability-map>
</media-type-entry>

<media-type-entry name="htmlite">
  <mime-type>text/html</mime-type>
  <character-set>UTF-8</character-set>
  <meta-info>
    <title>HTML Lite</title>
    <description>HTML without table support</description>
  </meta-info>
  <capability-map>
    <capability>HTML_IMAGE</capability>
  </capability-map>
</media-type-entry>

<media-type-entry name="htmltext">
  <mime-type>text/html</mime-type>
  <character-set>UTF-8</character-set>
  <meta-info>
    <title>HTML Text</title>
    <description>HTML without image support</description>
  </meta-info>
  <capability-map>
    <capability>HTML_TABLE</capability>
  </capability-map>
</media-type-entry>
    

Client descriptions

The client descriptions, which are also stored in the Registry, provide the portal engine with a simple definition of the client specific rendering capabilities.

A simple client entry will be typically composed of the following elements:

a user-agent pattern

This user-agent pattern, defined by a regular expression, will be tested against incoming User-agent identification header to identify it.

a list of supported MIME types

This list details all the MIME types supported by this client, in descending order of preference

a list of rendering capabilities

These optional capabilities help identify the actual client characteristics for the different supported MIME Types and select the corect media type. There's currently no formal capability defintions but they should match with those used in the Media types definition to have any effect.

<client-entry name="lynx">
  <user-agent-pattern>Lynx.*</user-agent-pattern>
  <manufacturer>GNU</manufacturer>
  <model>None</model>
  <version></version>
  <mimetype-map>
    <mimetype>text/html</mimetype>
  </mimetype-map>
  <capability-map>
    <capability>HTML_TABLE</capability>
    <capability>HTML_NESTED_TABLE</capability>
    <capability>HTML_FORM</capability>
    <capability>HTML_FRAME</capability>
    <capability>HTTP_COOKIE</capability>
  </capability-map>
</client-entry>
    

Since clients user agent identification strings are matched against the different client definitions pattern, the order of the definitions in the registry is important as the most specific patterns must be listed first else the generic ones will prevent them from being used.

Matching algorithm

There are actually 2 matching algorithms used in cunjunction with the client detection capabilities.

The first one is used to determine, for a client user-agent, on ordered list of media types supported by this client.

  1. find the first client definition whose pattern matches the client user agent string. If none are found or an invalid user agent string is used, the algorithm will use a preconfigured default user agent string.
  2. create an empty list of supported media types for this client
  3. for each mime type supported by the client
    1. append to the list all the Media entries of the same MIME type and such as all their capabilities are supported by the client definition. These entries are added in the order they are encountered in the Media registry
    2. append to the list all the Media entries of the same MIME type but whose capabilities are not completely supported. These entries are added in the order they are encountered in the Media registry

For example, for a user agent string of "Lynx/3.2 (Windows; U; NT 5.0) [en]" and the above Media and Client definitions, the algorithm will output the following list of ordered media types:

  • htmltext
  • html
  • htmlite

This algorithm is implemented in the BaseCapabilityMap implementation of the CapabilityMap interface.

The other algorithm is used to include this list of supported media types into the profile and template finding algorithms.

These algorithms will use this media list to iterate through all the media types before defaulting to a generic no media search. A typical search path would thus be:

  1. /user/anon/htmltext/en/US/default.psml
  2. /user/anon/htmltext/en/default.psml
  3. /user/anon/htmltext/default.psml
  4. /user/anon/html/en/US/default.psml
  5. /user/anon/html/en/default.psml
  6. /user/anon/html/default.psml
  7. /user/anon/htmlite/en/US/default.psml
  8. /user/anon/htmlite/en/default.psml
  9. /user/anon/htmlite/default.psml
  10. /user/anon/default.psml

Examples

This section details how to modify an out of the box Jetspeed installation to support 3 different sets of clients: Internet Explorer 4+ compatible, Netscape Navigator 4 compatible and W3C DOM compatible (Mozilla, Opera, etc...). This can be very useful if you plan to make heavy use of advanced CSS and DOM.

Step 1: Plan your media-types and update your Media Registry

To achieve the above plan, we decide to use the default "html" media to represent be W3C compliant and we'll create 2 variants, one called "ie5" for Internet Explorer like browsers and the other "ns4" for Netscape 4. These different entries will be differentiated based on their DHTML and TABLE capabilities since Netscape 4 has a known deficiency in handling deeply nested table.

<media-type-entry name="html">
  <mime-type>text/html</mime-type>
  <meta-info>
    <title>HTML</title>
    <description>DHTML for W3C DOM browsers</description>
  </meta-info>
  <capability-map>
    <capability>HTML_TABLE</capability>
    <capability>HTML_IMAGE</capability>
    <capability>HTML_NESTED_TABLE</capability>
    <capability>HTML_DOM_1</capability>
    <capability>HTML_CSS1</capability>
    <capability>HTML_CSSP</capability>
    <capability>HTML_JAVASCRIPT</capability>
  </capability-map>
</media-type-entry>

<media-type-entry name="ie5">
  <mime-type>text/html</mime-type>
  <meta-info>
    <title>HTML Internet Explorer</title>
    <description>DHTML for Internet Explorer</description>
  </meta-info>
  <capability-map>
    <capability>HTML_TABLE</capability>
    <capability>HTML_IMAGE</capability>
    <capability>HTML_NESTED_TABLE</capability>
    <capability>HTML_DOM_IE</capability>
    <capability>HTML_CSS1</capability>
    <capability>HTML_CSSP</capability>
    <capability>HTML_JAVASCRIPT</capability>
  </capability-map>
</media-type-entry>

<media-type-entry name="ns4">
  <mime-type>text/html</mime-type>
  <meta-info>
    <title>HTML Netscape</title>
    <description>DHTML for Navigator 4</description>
  </meta-info>
  <capability-map>
    <capability>HTML_TABLE</capability>
    <capability>HTML_IMAGE</capability>
    <capability>HTML_DOM_NS4</capability>
    <capability>HTML_LAYER</capability>
    <capability>HTML_JAVASCRIPT</capability>
  </capability-map>
</media-type-entry>
      
Step 2: Test your media definitions against your target clients

Before going further in customizing your site, make sure that the Client definition provided by Jetspeed will correctly match your target user agent with the intended media type. If run with DEBUG enabled, Jetspeed will write in your log file the user agent string recieved and how it has been matched.

Based on the above definitions and the defaule client.xreg registry, you should have the following results:

browserlist of selected medias
Internet Explorer 5+ie5 html ns4 xml
Netscape Navigator 4.xns4 html ie5
Mozilla 1.xhtml ie5 ns4 xml
Lynxhtml ie5 ns4
Konquerorns4 html ie5

Note that Opera is not listed because it would change depending on the user-agent announced configured in Opera and Konqueror is mapped to ns4 because it has no explicit matching client definition in the registry. In order to properly map these browsers to "html" media as expected, we would need to update the default client.xreg to add at the beginning of the file :

<client-entry name="opera">
  <user-agent-pattern>.*Opera.*</user-agent-pattern>
  <manufacturer>Opera</manufacturer>
  <model></model>
  <version></version>
  <mimetype-map>
    <mimetype>text/html</mimetype>
  </mimetype-map>
  <capability-map>
    <capability>HTML_3_2</capability>
    <capability>HTML_JAVA</capability>
    <capability>HTML_JAVASCRIPT</capability>
    <capability>HTML_TABLE</capability>
    <capability>HTML_NESTED_TABLE</capability>
    <capability>HTML_FORM</capability>
    <capability>HTML_FRAME</capability>
    <capability>HTML_IMAGE</capability>
    <capability>HTML_PLUGIN</capability>
    <capability>HTML_CSS1</capability>
    <capability>HTML_CSSP</capability>
    <capability>HTML_IFRAME</capability>
    <capability>HTML_DOM_1</capability>
    <capability>HTTP_COOKIE</capability>
  </capability-map>
</client-entry>

<client-entry name="konqueror">
  <user-agent-pattern>.*Konqueror.*</user-agent-pattern>
  <manufacturer>Opera</manufacturer>
  <model></model>
  <version></version>
  <mimetype-map>
    <mimetype>text/html</mimetype>
  </mimetype-map>
  <capability-map>
    <capability>HTML_3_2</capability>
    <capability>HTML_JAVA</capability>
    <capability>HTML_JAVASCRIPT</capability>
    <capability>HTML_TABLE</capability>
    <capability>HTML_NESTED_TABLE</capability>
    <capability>HTML_FORM</capability>
    <capability>HTML_FRAME</capability>
    <capability>HTML_IMAGE</capability>
    <capability>HTML_PLUGIN</capability>
    <capability>HTML_CSS1</capability>
    <capability>HTML_CSSP</capability>
    <capability>HTML_IFRAME</capability>
    <capability>HTML_DOM_1</capability>
    <capability>HTTP_COOKIE</capability>
  </capability-map>
</client-entry>
      
Step 3: Customize your templates

You can now start creating browser specific templates by creating "ie5" and "ns4" directories where necessary and defining your templates there. The search mechanism settings will ensure that if no specific "ns4" or "ie5" resource is found, the default "html" one will be used so that you don't have to duplicate all your templates that don't use any browser specific features.

In this scenario, there's probably no need to consider setting up specific PSML resources for "ie5" or "ns4" but for some other usage scenarios it may be useful.

Capability API

The capability API defined in package org.apache.jetspeed.capability is very simple since it consists only of one CapabiltyMap interface and one CapabilityMapFactory factory.

The default CapabilityMap implementation is a wrapper around a Registry ClientEntry.

The CapabilityMap associated with a request can be retrieved from the JetspeedRunData object with the getCapability() method and can thus be used by default in all the Velocity templates if you wish to test for a specific capability.

Examples

The first example presents how a portlet can programatically adjust its content based on the CapabilityMap:

import org.apache.jetspeed.portal.portlets.AbstractPortlet;
import org.apache.jetspeed.portal.PortletException;
import org.apache.turbine.util.RunData;
import org.apache.jetspeed.services.rundata.JetspeedRunData;
import org.apache.jetspeed.capability.CapabilityMap;
import org.apache.ecs.ConcreteElement;
import org.apache.ecs.html.*;

public class HelloClientPortlet extends AbstractPortlet
{
    public ConcreteElement getContent(RunData data)
    {
    	CapabilityMap cm = 
    	  ((JetspeedRunData)data).getCapability();
    	String message = "Hello "+cm.getAgent();
    	
    	if (cm.hasCapability("HTML_TABLE"))
    	{
    	    return new Table().append(
    	               new TR().append(
    	                   new TD().append(
    	                       mesage
    	                   )
    	               )
    	           )
    	}
    	else
    	{
    	    return new P().append(message);
    	}
    }
}
      

The same effect can be achieved within a VelocityPortlet template by using the following sequence:

#if $data.Capability.hasCapability("HTML_TABLE")
<table><tr><td>
#else
<p>
#end
Hello $data.Capability.Agent
#if $data.Capability.hasCapability("HTML_TABLE")
</td></tr></table>
#else
</p>
#end