blob: eb9c4ec28473c857770c525f42391c932761b71f [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN" "../dtd/document-v10.dtd">
<document>
<header>
<title>DELI</title>
<authors>
<person name="Mark H. Butler" email="mark-h_butler@hp.com"/>
</authors>
</header>
<body>
<s1 title="Introduction">
<p>In order for a web server
to provide optimized content to different clients it requires a description of the
capabilities of the client. Two new compatible standards have been created for
describing delivery context based on the
<link href="http://www.w3.org/RDF/">Resource Description Framework (RDF)</link>:
<link href="http://www.w3.org/Mobile/CCPP/">Composite Capabilities / Preferences Profile (CC/PP)</link>
created by the <link href="http://www.w3.org">W3C</link> and
<link href="http://www1.wapforum.org/tech/terms.asp?doc=WAP-248-UAProf-20010530-p.pdf">User Agent Profile (UAProf)</link>
created by the
<link href="http://www.wapforum.org">WAP Forum</link>.
These standards allow the efficient transmission of
delivery context information to the server even via low bandwidth wireless networks.
Instead of sending an entire profile with every request,
a client only sends a reference to a profile, stored on a third device known
as a profile repository, along with a list of differences specific to this particular
client. The process of reassembling the final profile from
the profile references and differences is known as profile resolution.</p>
<p>
<link href="http://www-uk.hpl.hp.com/">HP Labs</link>
has produced an open-source library called DELI that allows Java servlets to resolve HTTP requests
containing CC/PP or UAProf information and query the resolved
profile. This document describes how DELI may be used
within Apache Cocoon. For more information on the DELI library please refer to the
<link href="http://www-uk.hpl.hp.com/people/marbut/">DELI web-site</link>.
DELI currently uses
<link href="http://www.hpl.hp.com/semweb/jena-top.html">Jena</link>, an RDF
Framework developed at HP Labs. For more details of Jena see Brian McBride's
<link href="http://www-uk.hpl.hp.com/people/bwm/papers/20001221-paper/">paper</link>
and the HP Labs
<link href="http://www.hpl.hp.com/semweb/">Semantic Web activity</link> homepage.</p>
</s1>
<s1 title="CC/PP">
<p>CC/PP is described in
<link href="http://www.w3.org/TR/CCPP-struct-vocab/">CC/PP Structure and Vocabularies</link>,
<link href="http://www.w3.org/TR/2000/WD-CCPP-ra-20000721/">CC/PP Requirements and Architecture</link> and
<link href="http://www.w3.org/TR/2000/WD-CCPP-ta-20000721/">CC/PP Terminology and Abbreviations</link>.
A CC/PP profile is broadly constructed as a two level hierarchy:
a profile has a number of components and each component has a number
of attributes. A protocol for transmitting CC/PP profiles has been
<link href="http://www.w3.org/TR/NOTE-CCPPexchange">proposed</link> but is based on an experimental
variant of HTTP known as <link href="http://www.w3.org/Protocols/HTTP/ietf-http-ext/">HTTP-ex</link> so is not compatible with existing servers.
Therefore DELI uses the W-HTTP protocol proposed by UAProf. This has identical functionality to the CC/PP
protocol based on HTTP-ex, but is compatible with HTTP/1.1.</p>
</s1>
<s1 title="UAProf">
<p>The UAProf specification is based on the CC/PP specification. Like CC/PP,
a UAProf profile is a two level hierarchy composed of components and
attributes. Unlike CC/PP, the UAProf specification also proposes a vocabulary
- a specific set of components and attributes - to describe the next
generation of WAP phones.
The specification also describes two protocols for transmitting the profile
>from the client to the server. Currently DELI only supports the W-HTTP protocol.</p>
<p>Profiles using the UAProf vocabulary consist of six components:
HardwarePlatform, SoftwarePlatform, NetworkCharacteristics, BrowserUA,
WapCharacteristics and PushCharacteristics. These components contain attributes.
In DELI each attribute has a distinct name and has an associated collection type,
attribute type and resolution rule. In UAProf there are three collection types:</p>
<ul>
<li>
<code>Simple</code> contains a single value e.g. ColorCapable in HardwarePlatform. </li>
<li>
<code>Bag</code> contains multiple unordered values e.g. BluetoothProfile in the
HardwarePlatform component.</li>
<li>
<code>Seq</code> contains multiple ordered values e.g. Ccpp-AcceptLanguage
in the SoftwarePlatform component.</li>
</ul>
<p>In addition attributes can have one of four attribute types:</p>
<ul>
<li>
<code>String</code> e.g. BrowserName in BrowserUA.</li>
<li>
<code>Boolean</code> e.g. ColorCapable in HardwarePlatform.</li>
<li>
<code>Number</code> is a positive integer e.g. BitsPerPixel in HardwarePlatform.</li>
<li>
<code>Dimension</code> is a pair of positive integers e.g. ScreenSize in HardwarePlatform.</li>
</ul>
<p>Finally attributes are associated with a resolution rule:</p>
<ul>
<li>
<code>Locked</code> indicates the final value of an attribute is the first
occurrence of the attribute outside the default description block.</li>
<li>
<code>Override</code> indicates the final value of an attribute is the last occurrence
of the attribute outside the default description block.</li>
<li>
<code>Append</code> indicates the final value of the attribute is the
list of all occurrences of the attribute outside the default
description block.</li>
</ul>
<p>The UAProf vocabulary is described using the file <code>uaprofspec.xml</code>.
This describes the attribute name, component,
collectionType, attributeType and resolution rule of each component.
The vocabulary description file has the following format:</p>
<source><![CDATA[
<?xml version="1.0"?>
<vocabspec>
<attribute>
<name>CcppAccept</name>
<component>SoftwarePlatform</component>
<collectionType>Bag</collectionType>
<attributeType>Literal</attributeType>
<resolution>Append</resolution>
</attribute>
</vocabspec>
]]></source>
<p>DELI can also read vocabularies described using RDF schemas. The WAP Forum have
published two such schemas to describe the two versions of UAProf currently in use. However
RDF Schema does not provide an easy way of describing attributeType or resolution rule.
Therefore the UAProf schemas store this information in the comments field for each attribute.
Therefore DELI also parses the comments fields to create the vocabulary. This is not an ideal
solution so hopefully a more robust way of representing this information will be used in later versions of UAProf.</p>
</s1>
<s1 title="W-HTTP Protocol">
<p>An
example W-HTTP request using this protocol is shown below:</p>
<source><![CDATA[
GET /ccpp/html/ HTTP/1.1
Host: localhost
x-wap-profile:"http://127.0.0.1:8080/ccpp/profiles/test09defaults.rdf",
"1-Rb0sq/nuUFQU75vAjKyiHw=="
x-wap-profile-diff:1;<?xml version="1.0"?>
<rdf:RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:prf="http://www.wapforum.org/profiles/UAPROF/ccppschema-20010430#">
<rdf:Description rdf:ID="MyDeviceProfile">
<prf:component>
<rdf:Description rdf:ID="HardwarePlatform">
<rdf:type
rdf:resource="http://www.wapforum.org/profiles/UAPROF/ccppschema-
20010426#HardwarePlatform"/>
<prf:BitsPerPixel>16</prf:BitsPerPixel>
</rdf:Description>
</prf:component>
</rdf:Description>
</rdf:RDF>
]]></source>
<p>The first two lines
describe the resource that is being requested by the client,
http://localhost/ccpp/html, and the method being used to make
the request, GET, and the protocol being used HTTP/1.1. The
remaining lines of the request describe the device delivery context.
This is specified using a profile reference and a profile-diff.
The profile is referenced via the x-wap-profile line and has the URI</p>
<source><![CDATA[
http://127.0.0.1:8080/ccpp/profiles/test09defaults.rdf.
]]></source>
<p>After the profile reference, there is a value</p>
<source><![CDATA[
1-Rb0sq/nuUFQU75vAjKyiHw==
]]></source>
<p>known as a profile-diff digest.
The first part of the profile-diff-digest, 1-, is the profile-diff
sequence number. This is used to indicate the order of the
profile-diffs and to indicate which profile-diff the profile-diff
digest refers to. The remainder of the profile-diff digest is
generated by applying the
<link href="http://www.faqs.org/rfcs/rfc1321.html">MD5 message digest algorithm</link> and Base64
algorithm to the corresponding profile-diff. The MD5 algorithm
takes as input a message of arbitary length and produces as output
a 128-bit "fingerprint" or "message-digest" of the input.
The
<link href="http://www.faqs.org/rfcs/rfc2045.html">Base64 algorithm</link> takes as input arbitary binary data and
produces as output printable encoding data.</p>
<p>After the profile-diff digest, the next line contains the
x-wap-profile-diff. This request header field also has a
profile-diff sequence number which indicates that this
profile-diff corresponds to the previous
profile-diff-digest. The profile-diff itself consists of the XML
fragment which spans the remainder of the request. Multi-line
request header fields are permitted by the HTTP/1.1 specification
as long as each subsequent line starts with either a tab character
or a whitespace. </p>
<p>When the server receives a HTTP request with UAProf
request headers, it has to perform profile resolution
i.e. retrieve the referenced profile(s) and any further
profiles referenced via default blocks. It then has to
merge these profiles and the profile-diffs while
applying the UAProf resolution rules.</p>
</s1>
<s1 title="Configuring DELI">
<p>In order to use DELI, you need to enable the DELI component.
In addition, you may want to configure DELI using <code>deliConfig.xml</code>, the DELI
configuration file or <code>legacyDevices.xml</code>, the
DELI legacy device support file.</p>
<s2 title="Cocoon.xconf">
<p>In order to use DELI you need to configure Deli and specify
the configuration file. You can either
do this in <code>deli.xconf</code> in which case you will need to rebuild
Cocoon or change the deployed <code>cocoon.xconf</code> in the web-server WEB-INF directory:</p>
<source><![CDATA[
<deli class="org.apache.cocoon.components.deli.DeliImpl">
<parameter name="deli-config-file" value="deli/config/deliConfig.xml"/>
</deli>
]]></source>
</s2>
<s2 title="Sitemap.xmap">
<p>In order to make profile information available to your stylesheet then you
need to add <code><![CDATA[<map:parameter name="use-deli" value="true"/>]]></code> to the
match that specifies your stylesheet in <code>sitemap.xmap</code>. Here is the match used for the deli test stylesheet:
</p>
<source><![CDATA[
<map:match pattern="deli.html">
<map:generate src="docs/samples/hello-page.xml"/>
<map:transform src="stylesheets/deli_test.xsl" type="deli">
<map:parameter name="use-deli" value="true"/>
</map:transform>
<map:serialize type="html"/>
</map:match>
]]></source>
</s2>
<s2 title="Main Configuration File">
<p>DELI also has its own
configuration files that are found in the <code>resources\deli\config</code> directory.
The most important one, <code>deliConfig.xml</code> is used to configure the main DELI options:</p>
<source><![CDATA[
<?xml version="1.0"?>
<deli>
<localProfilesFile>WEB-INF/deli/config/localProfiles.xml</localProfilesFile>
<localProfilesPath>WEB-INF/deli/legacyProfiles</localProfilesPath>
<useLocalProfilesIfNoCCPP>true</useLocalProfilesIfNoCCPP>
<useLocalProfilesInAdditionToCCPP>false</useLocalProfilesInAdditionToCCPP>
<debug>false</debug>
<printDefaults>true</printDefaults>
<printProfileBeforeMerge>false</printProfileBeforeMerge>
<processUndefinedAttributes>true</processUndefinedAttributes>
<useCapabilityClasses>false</useCapabilityClasses>
<capabilityClassFile>WEB-INF/deli/config/capClass.xml</capabilityClassFile>
<namespaceConfigFile>WEB-INF/deli/config/namespaceConfig.xml</namespaceConfigFile>
<!-- note that the default uri is also hardcoded -->
<rdfsUri>http://www.w3.org/1999/PR-rdf-schema-19990303#</rdfsUri>
<rdfsUri>http://www.w3.org/TR/PR-rdf-schema#</rdfsUri>
</deli>
]]></source>
<p>This file can contain a number of configuration directives described in
in the following sections:</p>
<s3 title="Caching options">
<p>The caching options control how the server
caches referenced profiles. DELI can either cache
profiles indefinitely or update stale profiles after a set
interval. It is also possible to configure the maximum size
of the profile cache.</p>
<table>
<tr>
<th>Element Name</th>
<th>Default Value</th>
<th>Description</th>
</tr>
<tr>
<td>maxCachedProfileLifetime</td>
<td>24 hours</td>
<td>The maximum lifetime of a cached profile in hours.</td>
</tr>
<tr>
<td>maxCacheSize</td>
<td>100</td>
<td>The maximum number of profiles in the profile cache.</td>
</tr>
<tr>
<td>refreshStaleProfiles</td>
<td>false</td>
<td>Do we refresh cached profiles after the maximum lifetime has expired?</td>
</tr>
</table>
</s3>
<s3 title="Debugging options">
<p>The debugging options are used to control the
information that DELI prints to the Servlet engine console.</p>
<table>
<tr>
<th>Element Name</th>
<th>Default Value</th>
<th>Description</th>
</tr>
<tr>
<td>debug</td>
<td>true</td>
<td>Is the automatic debug log information turned on?</td>
</tr>
<tr>
<td>printDefaults</td>
<td>true</td>
<td>Print both default and override values of attributes for debugging purposes?</td>
</tr>
<tr>
<td>printProfileBeforeMerge</td>
<td>false</td>
<td>Print the profile before merging for debugging purposes?</td>
</tr>
</table>
</s3>
<s3 title="Legacy device options">
<p>As already mentioned DELI can support legacy devices
by recognising the user-agent string supplied by a client
and mapping it on to a profile. In order to use this facility
it is necessary to supply an XML file that contains information
about legacy device user-agent strings and the corresponding
profile URLs. The format for the legacy device file is
described in a subsequent section. </p>
<table>
<tr>
<th>Element Name</th>
<th>Default Value</th>
<th>Description</th>
</tr>
<tr>
<td>useLocalProfilesIfNoCCPP</td>
<td>true</td>
<td>Use the legacy device database if devices send no CC/PP information?</td>
</tr>
<tr>
<td>localProfilesFile</td>
<td>legacyDevice.xml</td>
<td>The file containing the legacy device database.</td>
</tr>
</table>
</s3>
<s3 title="Protocol options">
<p>It is
possible to switch on whitespace normalisation in profile-diffs
prior to calculating the profile-diff-digest so that additional
whitespaces added by the proxy are ignored. To use this option clients must also support whitespace normalisation.</p>
<table>
<tr>
<th>Element Name</th>
<th>Default Value</th>
<th>Description</th>
</tr>
<tr>
<td>normaliseWhitespaceInProfileDiff</td>
<td>true</td>
<td>Is whitespace normalisation of the profile-diff prior to calculating the profile-diff-digest turned on?</td>
</tr>
</table>
</s3>
<s3 title="Vocabulary options">
<p>DELI has a number of vocabulary options. Firstly
it is possible to configure the vocabulary using an
XML file, or if you are using UAProf using a UAProf RDF Schema.
You can find examples of both approaches in this distribution.
Secondly it is possible to
specify the URI to be used for the RDF namespace.
Thirdly it is possible to set the string used to represent
components and defaults in the vocabulary. This is important
because the two standards currently use different cases for
the first letter of default elements (CC/PP uses "default"
whereas UAProf uses "Default"). </p>
<table>
<tr>
<th>Element Name</th>
<th>Default Value</th>
<th>Description</th>
</tr>
<tr>
<td>vocabularyFile</td>
<td>uaprofspec.xml</td>
<td>The file containing the vocabulary specification.</td>
</tr>
<tr>
<td>schemaVocabularyFile</td>
<td>ccppschema-20000405.rdfs</td>
<td>The file containing the vocabulary specification as an UAProf RDF Schema.
Use the attribute <code>namespace</code> to configure which namespace the schema corresponds to.</td>
</tr>
<tr>
<td>rdfUri</td>
<td>http://www.w3.org/1999/02/22-rdf-syntax-ns#</td>
<td>The namespace used for RDF constructs.</td>
</tr>
<tr>
<td>componentProperty</td>
<td>component</td>
<td>The name for components.</td>
</tr>
<tr>
<td>defaultProperty</td>
<td>Default</td>
<td>The name for defaults</td>
</tr>
</table>
</s3>
</s2>
<s2 title="Configuring Legacy Devices">
<p>It is easy to configure DELI to recognise legacy
devices via user-agent strings. A user-agent string is a string sent by the client to
the server as part of the HTTP request. It allows different browsers to be identified.
The legacy device configuration file maps user-agent
strings on to profile either on the local filestore or on a profile repository.
By default this is done in the <code>legacyDevice.xml</code> file which
has the following format:</p>
<source><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<devices>
<!-- Alcatel -->
<device>
<ua value="Alcatel-BF4/2.0" profile="Alcatel_OT512.rdf"/>
</device>
<device>
<ua value="Alcatel-BE4/1.0" profile="Alcatel_OT301.rdf"/>
</device>
</devices>
]]></source>
<p>Where <code>vale</code> is a device unique string found in
the user-agent string of the device and <code>profile</code> is either a local file or a URL
for the appropriate legacy profile. </p>
</s2>
</s1>
<s1 title="Writing CC/PP and UAProf aware stylesheets">
<p>Once you have got DELI running on Cocoon, the next
step in creating a CC/PP aware site is to create some stylesheets that
use profile information. DELI makes CC/PP or UAProf attributes available
to XSLT stylesheets as parameters. In the process of doing this, DELI 'flattens' the profiles
by omitting the component information. Hence to retrieve the
<code>CcppAccept</code> attribute you use the XPath <code>deli-capabilities/browser/CcppAccept</code>
whereas to retrieve the <code>ScreenSize</code> attribute you use the
XPath <code>deli-capabilities/browser/ScreenSize</code>.
In addition where attributes contain multiple values e.g. Bags or Sequences
those values are separated using <code><![CDATA[<li>]]></code> elements.
Hence to retrieve the individual elements you use the XPath
<code>deli-capabilities/browser/CcppAccept/li</code>.
The following code demonstrates how to retrieve both a simple and a complex
attribute. For more complex examples see the <code>deli_test.xsl</code> stylesheet with Cocoon.</p>
<source><![CDATA[
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="deli-capabilities"/>
<xsl:template match="/">
<xsl:if test="contains($deli-capabilities/browser/CcppAccept/li,'wml')">
<xsl:call-template name="wmldevice"/>
</xsl:if>
<xsl:if test="not(contains($deli-capabilities/browser/CcppAccept/li,'wml'))">
<xsl:call-template name="htmldevice"/>
</xsl:if>
</xsl:template>
<xsl:template name="wmldevice">
<wml>
<card id="init" newcontext="true">
<p>
<xsl:call-template name="capabilities"/>
</p>
</card>
</wml>
</xsl:template>
<xsl:template name="htmldevice">
<html>
<head>
<title>Test Page for DELI in Cocoon</title>
</head>
<body>
<xsl:call-template name="capabilities"/>
</body>
</html>
</xsl:template>
<xsl:template name="capabilities">
<xsl:if test="$deli-capabilities/browser/ImageCapable">
ImageCapable: <xsl:value-of select="$deli-capabilities/browser/ImageCapable"/>
<br/>
</xsl:if>
<xsl:if test="$deli-capabilities/browser/CcppAccept">
CcppAccept:
<xsl:for-each select="$deli-capabilities/browser/CcppAccept/li">
<xsl:value-of select="."/>,
</xsl:for-each>
<br/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
]]></source>
</s1>
<s1 title="Incorporating DELI into other Cocoon components">
<p>If you want to use DELI in other Cocoon components, DELI needs to go through an
initialization phase in order to read in configuration files. This occurs in
<code>initialization()</code> in DeliImpl.java in the Cocoon DELI component in this line:</p>
<source>
Workspace.getInstance().configure(this.servletContext, this.deliConfig);
</source>
<p>i.e. it constructs a DELI workspace object. In addition, DeliImpl.java has a number
of methods to get profile information, but the one which is of most use is <code>getProfile()</code>.
For examples of how to call DELI, see DeliTransformer.java - here are the relevant pieces.</p>
<p>First import DELI:</p>
<source>
import org.apache.cocoon.components.deli.Deli;
</source>
<p>Then in compose(), initialize DELI:</p>
<source>
if (this.manager.hasComponent(Deli.ROLE)) {
if (this.getLogger().isDebugEnabled()) {
getLogger().debug("Looking up " + Deli.ROLE);
}
this.deli = (Deli) this.manager.lookup(Deli.ROLE);
} else {
if (this.getLogger().isDebugEnabled()) {
getLogger().debug("Deli is not available");
}
}
</source>
<p> Then in getLogicSheetParameters, call DELI to get
a profile and convert it into a DOM tree to give to XSLT as a parameter:</p>
<source>
if (this.deli != null &#38;&#38; this._useDeli) {
try {
Request request = ObjectModelHelper.getRequest(objectModel);
if (map == null) {
map = new HashMap();
}
org.w3c.dom.Document deliCapabilities = this.deli.getUACapabilities(request);
map.put("deli-capabilities", deliCapabilities);
} catch (Exception e) {
getLogger().error("Error setting DELI info", e);
}
}
</source>
<p>
However, you don't want to pipe DELI to XSLT so here is some more
example code showing how to use DELI in Cocoon if you want to use the
DELI API directly:</p>
<p>Import the deli component and the DELI API:</p>
<source>
import org.apache.cocoon.components.deli.Deli;
import com.hp.hpl.deli.Profile;
import com.hp.hpl.deli.ProfileAttribute;
</source>
<p>Add code to initialize the compose method as before</p>
<source>
public void compose(ComponentManager manager) throws ComponentException
{
try
{
deli = (Deli)manager.lookup(Deli.ROLE);
}
catch(ComponentException ce)
{
logger.log(Level.ERROR, "Cannot get ref to Deli", ce);
ce.printStackTrace();
}
}
</source>
<p>Some example code that shows how to extract WmlDeckSize from a
DELI profile</p>
<source>
try
{
Profile theProfile = deli.getProfile(request);
if(theProfile != null)
{
ProfileAttribute attrib = theProfile.getAttribute("WmlDeckSize");
if(attrib != null)
{
Vector temp = (Vector)attrib.get();
if(temp != null)
{
deckSizeString = temp.get(0).toString();
System.out.println("Determined WmlDeckSize from DELI: " + deckSizeString);
}
}
}
if(deckSizeString == null)
{
deckSizeString = "1100";
System.out.println("Using fallback WmlDeckSize of " + deckSizeString);
}
}
catch(Exception ex)
{
System.out.println(ex.toString());
ex.printStackTrace();
}
}
</source>
</s1>
<s1 title="More information ?">
<p>For more information on the DELI library please refer to the
<link href="http://www-uk.hpl.hp.com/people/marbut/">DELI web-site</link>.</p>
</s1>
</body>
</document>