cziegeler 2002/06/14 00:09:12
Modified: src/documentation/xdocs/developing book.xml index.xml
src/documentation/xdocs/userdocs index.xml
src/java/org/apache/cocoon/components/pipeline/impl
CachingProcessingPipeline.java
Added: src/documentation/xdocs/developing/webapps
authentication.xml book.xml index.xml portal.xml
session.xml sunrise.xml sunshine.xml sunspot.xml
Removed: src/documentation/xdocs/developing authentication.xml
portal.xml session.xml
Log:
Updated documentation, it contains now both, the 2.0.x docs for auth and
portal and the latest docs
Revision Changes Path
1.10 +1 -4 xml-cocoon2/src/documentation/xdocs/developing/book.xml
Index: book.xml
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/documentation/xdocs/developing/book.xml,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- book.xml 1 Jun 2002 13:21:23 -0000 1.9
+++ book.xml 14 Jun 2002 07:09:11 -0000 1.10
@@ -20,10 +20,7 @@
</menu>
<menu label="Webapps">
- <menu-item label="Session Contexts" href="session.html"/>
- <menu-item label="Authentication" href="authentication.html"/>
- <menu-item label="Form Handling"
href="../howto/xmlform-wizard/howto-xmlform-wizard.html"/>
- <menu-item label="Portal" href="portal.html"/>
+ <menu-item label="Developing Webapps" href="webapps/index.html"/>
</menu>
<menu label="Java">
1.2 +3 -1 xml-cocoon2/src/documentation/xdocs/developing/index.xml
Index: index.xml
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/documentation/xdocs/developing/index.xml,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- index.xml 3 Jan 2002 12:31:03 -0000 1.1
+++ index.xml 14 Jun 2002 07:09:11 -0000 1.2
@@ -15,7 +15,9 @@
<p>Here will soon appear an overview of the developer perspective.
</p>
-
+ <p>If you are interested in developing real-world web-applications
requiring
+ form handling, authentication or even developing your own portal, have a
+ look at the <link href="webapps/index.html">web application
documentation</link>.</p>
<p>The actual developer documentation is available from the side-panel.
</p>
1.1
xml-cocoon2/src/documentation/xdocs/developing/webapps/authentication.xml
Index: authentication.xml
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN"
"../../dtd/document-v10.dtd">
<document>
<header>
<title>Authentication Framework</title>
<authors>
<person name="Carsten Ziegeler" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Introduction">
<note><strong>IMPORTANT:</strong> This document conforms to the
development version of Cocoon. So
you will only find these components in the current CVS. An early
alpha version is already
available in the latest release of Cocoon, you will find an
introduction <link href="sunrise.html">here</link>.
</note>
<p>The central point for building a web application is authentication.
The Cocoon
authentication package is a flexible module for authentication and
user management.
A user can be legitimated using any information available via any
source, e.g. a database or
LDAP. With this mechanism it is very easy and fast to use an
exisiting user
management/authentication system.</p>
</s1>
<s1 title="Sitemap-Components">
<p>The authentication Framework adds some actions to the sitemap: the
<em>auth-protect</em>
action, the <em>auth-login</em> action, the <em>auth-logout</em>
action
and the <em>auth-loggedIn</em> action. The
<em>authentication-manager</em> gets
the configuration for the authentication framework and the actions
controle the pipelines.
The <em>auth-login</em> and the <em>auth-logout</em> action control
the
authentication whereas the <em>auth-loggedIn</em> action controls the
application
flow.</p>
<p>The use of the authentication framework and its components is
described in the following
chapters.</p>
</s1>
<s1 title="User Authentication">
<p>One feature of the framework is the user authentication. A document
can be
accessible for everyone or it can be protected using this framework.
The process of
requesting a document can be described as follows:</p>
<ol>
<li>The user request a document (original document).
</li>
<li>The framework checks if this document is protected. If no
protection
is specified, the response to the request is this original document.
</li>
<li>The document is protected and the framework checks, if the user is
authenticated to view it.
</li>
<li>If the user is authenticated, the response is the original
document. If not the framework redirects to a special redirect-to
document. This
redirect-to document is freely configurable and can for example
contain
information about the unauthorized access and in addition a login
form.
</li>
<li>Using the login form an authentication resource can be called
with the corresponding user information (e.g. user id and
password). This
authentication resource uses the framework for the authentication
process.
</li>
<li>In case of a successful authentication the framework can redirect
to
the original document (or to any configured start document).
</li>
<li>If the authentication failed another document is invoked by
the framework displaying information to the user.
</li>
</ol>
<p>This process is only one example for a use-case of the framework. It
can be configured for any authentication scheme. All resources are
freely
configurable.</p>
<s2 title="The Authentication handler">
<p>The basic object for authentication is the authentication
handler. It controlles the access to the resources. Each resource
in the
sitemap can be related to exactly one authentication handler. All
resources belonging
to the same handler are protected in the same way. If a user has
access to the
handler, the user has the same access rights for all resouces of
this
handler.</p>
<p>Each authentication handler needs the following mandatory
configuration:</p>
<ul>
<li>A unique name.
</li>
<li>The authentication resource which does the real
authentication.
</li>
<li>The redirect-to document where the framework redirects to for
any
unauthorized request.
</li>
</ul>
<p>Using a unique name for each handler (only alphabetical characters
and digits are allowed for the handler name), the framework manages
different
handlers. So various parts of the sitemap can be protected in
different ways. A
document can be protected by calling this handler using the
<em>auth-protect</em>
action. The "auth-protect" action must be included in the pipeline
of the
resource. It gets the handler information as a parameter:</p>
<source><map:match pattern="protectedresource">
<map:act type="auth-protect">
<map:parameter name="handler" value="unique handler name"/>
<map:generate src="source/resource.xml"/>
</map:act>
...
</map:match></source>
<p>If the pipeline does not use the "auth-protect" action or the
parameter "handler" is missing, the document is accessible by any
user.</p>
</s2>
<s2 title="The redirect-to document">
<p>If the requested document is not accessible for the user, the
framework
redirects to a special redirect-to document. This document is a
mandatory
configuration of the authentication handler:</p>
<source><autentication-manager>
<handlers>
<!-- Now follows the handlers configuration -->
<handler name="unique">
<redirect-to uri="cocoon://loginpage"/> <!-- The login
resource -->
</handler>
</handlers>
</autentication-manager></source>
<p>This redirect-to document is an unprotected document in the
sitemap. For tracking which document was requested, the redirect-to
document
gets the request parameter "resource" with the value. In addition
all
parameters specified inside the <em>redirect-to</em> tag of the
handler
configuration are passed to the document.</p>
<p>This redirect-to document can contain a form for the user
authentication. This form should invoke the real login document
which is
described below.</p>
<p>The authentication process is done by the "auth-login" action.
The login resource contains this action: </p>
<source><map:match pattern="login">
<map:act type="auth-login">
<map:parameter name="handler" value="unique"/>
<map:parameter name="parameter_userid" value="request:name"/>
<map:parameter name="parameter_password" value="request:password"/>
<map:redirect-to uri="authentication-successful"/>
</map:act>
<!-- authentication failed: -->
<map:generate src="auth_failed.xml"/>
<map:transform src="tohtml.xsl"/>
<map:serialize/>
</map:match></source>
<p>The "auth-protect" action uses the handler parameter to call the
authentication resource of this handler. This authentication
resource needs to
know the information provided by the user. For each piece of
information an own
parameter is created which name starts with "parameter_". So in the
example
above, the authentication resource gets two parameters: userid and
password. As
the values for these parameters were send by a form they need to be
passed on
to the authentication resource. If you use "request:..." for the
value of a
parameter, the auth-login action will pass the actual value of that
request
parameter to the authentication resource.</p>
<p>If the user is not authenticated with this handler, the framework
calls
the authentication resource and passes it the parameters. If this
authentication is successful, the action returns an empty map and
the sitemap
commands inside the map:act are executed. If the authentication
fails, these
are skipped.</p>
<p>If the authentication is successful, a session object is created on
the server (if not already done). </p>
</s2>
<s2 title="The authentication resource">
<p>The last chapters described the authentication process but left out
details about the authentication itself. This chapter closes this
gap.</p>
<p>The authentication can be done by different components:</p>
<ul>
<li>A sitemap resource.
</li>
<li>A distant resource, e.g. requested via HTTP.
</li>
<li>A java class.
</li>
</ul>
<p>Using this flexible approach nearly any kind of authentication is
possible (e.g. database, LDAP). The authentication resource is
another
mandatory configuration of the authentication handler:</p>
<source><autentication-manager>
<handlers>
<!-- Now follows the handlers configuration -->
<handler name="unique">
<redirect-to uri="cocoon:raw://loginpage"/> <!-- The login
resource -->
<authentication uri="cocoon:raw://authenticationresource"/>
</handler>
</handlers>
</autentication-manager></source>
<p>If the authentication resource is a sitemap resource or a remote
resource, this resource is requested by the framework with the
given parameters from
the <em>auth-login</em> action (see previous chapter: parameters:
userid and
password). In addition all parameters inside the
<em>authentication</em> tag of
the handler configuration are passed to the resource. The response
for this
resource must contain valid XML conforming to the following
scheme:</p>
<source><authentication>
<ID>value</ID>
<role>rolename</role> <!-- optional -->
<data>
... resource specific data for the user
</data>
</authentication></source>
<p>The framework checks the response of the authentication resource
for the
given scheme: the root node must be named "authentication" and one
child called
"ID" must be present. In this case the authentication is
successfull and
the framework creates an authentication session context and stores
the XML inside. </p>
<p>The mandatory information inside this XML scheme, the "ID" tag, is
an unique identification for the given user inside the web
application. The
"role" is optional and can for example be used for categorizing
users and
displaying different functionality inside the Cocoon portal
engine).</p>
<p>Using the "data" node the authentication resource can pass any
information of the user into the session object.</p>
<p>If the authentication is not successful, the resource must create
an XML with the root node "authentication". In addition a "data"
node can be
added containing more information about the unsuccessful attempt.
This data
node is then added inside the "login" tag of the login resource
(see previous
chapter).</p>
</s2>
<s2 title="Logging out">
<p>The logout process is triggered by the "auth-logout"
action:</p>
<source><map:act type="auth-logout">
<map:parameter name="handler" value="unique"/>
</map:act></source>
<p>This action logs the user out of the given handler and removes all
information about this handler stored in the session.</p>
</s2>
<s2 title="Working With subsitemaps">
<p>The common solution for the framework and subsitemaps is to define
the
handler (in the main sitemap. The documents
in the subsitemap are then simply protected in the same way as if
the action
were declared in the main sitemap. This makes moving resources from
one sitemap
to the other very simple.</p>
<p><Strong>However, there is one drawback with this solution. After
you have started your server, make sure that first a resource using
the framework
from the main sitemap is invoked, before any of the
subsitemap!</Strong></p>
<p><Strong>The definition of handlers in a sub-sitemap is a TODO and
will be
available in the next release.</Strong></p>
</s2>
</s1>
<s1 title="User Management">
<p>In addition to the authentication the framework manages all kinds of
information belonging to the user in XML format. For this reason the
framework
creates an own session context called "authentication". All
information is stored in
this context.</p>
<p>The authentication information (the "authentication" scheme retrieved
from the authentication resource) is stored in this context, so you
can
retrieve and change the information using the session transformer and
the
usual getxml, setxml etc. commands, so we suggest you to read the
session
context document.</p>
<s2 title="Getting information from the context">
<p>Each information from within the context is gettable using an XML
tag:</p>
<source><session:getxml context="authentication"
path="/authentication/ID"/> <!-- Get the ID -->
<session:getxml context="authentication"
path="/authentication/data/username"/></source>
<p>The path expression is an absolute XPath-like expression where only
concrete nodes and attributes are allowed. The session transformer
replaced
the tag with the value of the first node found in the context, this
can either
be text or XML.</p>
</s2>
<s2 title="Setting information in the context">
<p>Using another tag information can be stored into the
context:</p>
<source><session:setxml context="authentication"
path="/authentication/data/usersername">
Mr. Sunshine
</session:setxml></source>
<p>Again the path is an absolute XPath-like expression where only
concrete nodes and attributes are allowed. If the requested node
exists,
the framework changes the value of that node. If the node does not
exists, the framework
adds it to the context with the given value.</p>
<p>The tag is removed from the resource.</p>
</s2>
</s1>
<s1 title="Application Management">
<p>A very useful feature for building and maintaining web applications
is the application management. It allows to configure different
applications and to manage the user data for these applications.</p>
<s2 title="Configuring an Application">
<p>A "authentication" application is related to one authentication
handler, so an
application is part of the authentication handler configuration:</p>
<source><autentication-manager>
<handlers>
<handler name="unique">
....redirect-to/authentication configuration
<applications> <!-- the applications for this handler
-->
<application name="unique">
<load uri="loadapp"/> <!-- optional -->
<save uri="saveapp"/> <!-- optional -->
</application>
</applications>
</handler>
</handlers>
</autentication-manager></source>
<p>A configuration for an application consists of a unique name (only
alphabetical characters and digits are allowed for the application
name) and
optional load and save resources. The application configuration can
contain
application specific configuration values for the various parts of
the
application, e.g. information for a portal.</p>
<p>On a successful authentication the framework invokes for each
application
of the handler the load resource (if present). The content or
result of the
load resource is stored into the session context.</p>
<p>The user does not always visit all sides or all applications at
once. So it is not necessary to load all applications in advance
when not all
information is needed. Each application can specify if the data is
loaded on
successful authentication or the first time needed:</p>
<source>....<application name="unique"
loadondemand="true"/>...</source>
<p>The load resource gets several parameters: all values of the
subnodes of the "authentication" node from the authentication
context (e.g. ID, role
etc.) and the parameter "application" with the unique name of the
application.
This unique name must not contain one of the characters '_', ':' or
'/'.</p>
<p>In addition the load and save resource get all parameters specified
inside the load / save tag of the handler configuration.</p>
</s2>
<s2 title="Configuring the resources">
<p>For managing the application the framework needs to know to which
application a resource belongs. So in addition to the handler
parameter the
auth-protect action gets the application name as a second
parameter:</p>
<source><map:match pattern="protectedresource">
<map:action type="auth-protect">
<map:parameter name="handler" value="unique handler name"/>
<map:parameter name="application" value="unique application name"/>
<map:generate src="source/resource.xml"/>
...
</map:action>
</map:match>
</source>
<p>With this mechanism each application resource can easily access its
and only its information. If a resource has no "application"
parameter it can
not access information of any application.</p>
</s2>
<s2 title="Getting, setting and saving application information">
<p>Analogue to the access of the authentication data a resource can
access its application data:</p>
<source><session:getxml context="authentication"
path="/application/username"/>
<session:setxml context="authentication"
path="/application/shoppingcart"><item1/><item2/></session:setxml></source>
<p>The path underlies the same restrictions and rules as always, but
it has to start with "/application/". </p>
</s2>
</s1>
<s1 title="Module Management">
<p>In addition to the application management the framework offers a
facility
called module management. It enhances the application management by
the
possibility to configure components for the application. For example
the Cocoon
portal engine needs information about where the portal profile
for the user is retrieved from, where the layout is stored etc. Now
each portal
needs this information. Assuming that a portal is an application each
application needs this information. As only the portal engine itself
knows what
information it needs, the module management is a standarized way for
configuring such components.</p>
<p>The module configuration is part of the application
configuration:</p>
<source><autentication-manager>
<handlers>
<handler name="unique">
....redirect-to/authentication configuration
<applications> <!-- the applications for this handler -->
<application name="unique">
...
<configuration name="portal">
...portal configuration
</configuration>
</application>
</applications>
</handler>
</handlers>
</autentication-manager></source>
<p>So whenever the portal engine is asked to build the portal it can
easily retrieve its configuration from the current application by
getting the
module configuration named "portal".</p>
</s1>
<s1 title="User Administration">
<p>Using the framework it is possible to add new roles to the system and
to
add new users. For this purpose, there are several optional entries
for the
authentication handler which provide the needed functionality:</p>
<source><autentication-manager>
<handlers>
<handler name="unique">
...redirect-to/authentication configuration...
<!-- Optional resource for loading user information -->
<load-users uri="cocoon:raw://financeresource-sunrise-loaduser"/>
<!-- Optional resource for loading roles information-->
<load-roles uri="cocoon:raw://financeresource-sunrise-roles"/>
<!-- Optional resource for creating a new user -->
<new-user uri="cocoon:raw://financeresource-sunrise-newuser"/>
<!-- Optional resource for creating a new role -->
<new-role uri="cocoon:raw://financeresource-sunrise-newrole"/>
<!-- Optional resource for changing user information -->
<change-user uri="cocoon:raw://financeresource-sunrise-newuser"/>
<!-- Optional resource for deleting a role -->
<delete-role uri="cocoon:raw://financeresource-sunrise-delrole"/>
<!-- Optional resource for deleting a user-->
<delete-user uri="cocoon:raw://financeresource-sunrise-deluser"/>
</handler>
</handlers>
</autentication-manager></source>
<p>The entries are described in the following subchapters. All tags can
have additional parameter definitions which are passed to the given
resource,
e.g:</p>
<source><!-- Optional resource for deleting a user-->
<delete-user uri="cocoon:raw://financeresource-sunrise-deluser">
<connection>database</connection>
<url>db:usertable</url>
</delete-user></source>
<s2 title="Getting Roles">
<p>The <em>load-roles</em> resource is invoked from the framework
whenever
it needs information about the available roles. This resource gets
the
parameter "type" with the value "roles" and should deliver an XML
schema with
the root node "roles" and for each role a subelement "role" with a
text child
of the rolename:</p>
<source><roles>
<role>admin</role>
<role>guest</role>
<role>user</role>
</roles></source>
</s2>
<s2 title="Getting Users">
<p>The <em>load-users</em> resource is called whenever information
about the available users is needed. There are three different uses
of this
resource:</p>
<ul>
<il>Loading all users: The resource gets the parameter "type"
with the value "users". It should then deliver all users in the
system.
</il>
<il>Loading all users of one role. The resource gets the
parameters "type" with the value "users" and "role" with the
rolename.
</il>
<il>Load information of one user. The resource gets the
parameters "type" with the value "user", "role" with the
rolename and "ID" with
the authentication ID of the user.
</il>
</ul>
<p>The XML format of the resource should look like the
following:</p>
<source><users>
<user>
<ID>authentication ID</ID>
<role>rolename</role>
<data>
... application specific data ...
</data>
</user>
<user>
...
</user>
...
</users></source>
</s2>
<s2 title="Creating a new role">
<p>The <em>new-role</em> resource creates a new role in the system. It
gets the parameters "type" with the value "role" and "role" with
the new
rolename.</p>
</s2>
<s2 title="Creating a new user">
<p>The <em>new-user</em> resource creates a new user with a role. It
gets the parameters <em>"type"</em> with the value <em>"user"</em>,
<em>"role"</em> with the rolename and <em>"ID"</em> with the new ID
for this
user.</p>
</s2>
<s2 title="Changing information of a user">
<p>The <em>change-user</em> resources changes information of a user.
It gets the parameters "type" with the value "user", "role" with
the rolename
and "ID" with the ID of the user. In addition all - application
specific -
information of this user is send as parameters.</p>
</s2>
<s2 title="Delete a user">
<p>The <em>delete-user</em> resource should delete a user. It gets the
parameters "type" with the value "user", "role" with the rolename
and "ID" with
the ID of the user.</p>
</s2>
<s2 title="Delete a role">
<p>The <em>delete-role</em> resources deletes a role. It gets the
parameters "type" with the value "role" and "role" with the
rolename .</p>
</s2>
</s1>
<s1 title="Configuration Summary">
<p>Here is a brief summary of the authentication handler configuration:
</p>
<source><autentication-manager>
<handlers>
<handler name="unique">
<redirect-to uri="cocoon:raw://loginpage"/> <!-- The
redirect-to resource -->
<authentication uri="cocoon:raw://authenticationresource"/>
<!-- Authentication resource -->
<load uri="cocoon:raw://authenticationsaveresource">
<!-- optional parameters -->
</load>
<!-- optional save resource -->
<save uri="cocoon:raw://authenticationsaveresource">
<!-- optional parameters -->
</save>
<applications>
<!-- the applications for this handler -->
<application name="unique">
<!-- Loading/Saving -->
<load uri="cocoon:raw://loadapp">
<!-- optional -->
<!-- optional parameters -->
</load>
<save uri="cocoon:raw://saveapp">
<!-- optional -->
<!-- optional parameters -->
</save>
<!-- module configurations: -->
<configuration name="portal">
...portal configuration
</configuration>
</application>
</applications>
</handler>
</handlers>
</autentication-manager></source>
</s1>
<s1 title="Pipeline Patterns">
<p>As explained in the previous chapters, the framework uses the
<em>auth-protect</em>
action for authentication and protecting documents. This chapter
shows some
common used pipeline patterns for using this framework.</p>
<s2 title="Single protected document">
<p>For protecting a document with an authentication handler only the
<em>auth-protect</em>
action with the parameter configuration for the handler is
required.</p>
<p>Pattern:</p>
<ol>
<li>Pipeline matching
</li>
<li>Using the <em>auth-protect</em> action for protecting
</li>
</ol>
<p>Example:</p>
<source><map:match pattern="protected">
<map:act type="auth-protect"> <!-- protect the resource -->
<map:parameter name="handler" value="myhandler"/>
<map:generate src="resource.xml"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:act>
</map:match></source>
<p>It is very important that the <em>auth-protect</em> action wrapps
the real
pipeline, as the pipeline is only invoked if the action grants
access. The
matching must be done before the action is checked as the action
performs a
redirect for this document.</p>
</s2>
<s2 title="Multiple protected documents">
<p>Often you want to protect a bunch of documents in the same way. One
solution is to use the single protected document pattern for each
document.
With the multiple protected document pattern you only have to use
the action
once for all documents and not within each document pipeline.</p>
<p>The prerequisite for this is a common matching pattern for the
documents:</p>
<ol>
<li>Pipeline pattern matching
</li>
<li>Using the <em>auth-protect</em> action for protection
</li>
<li>Pipeline matching
</li>
</ol>
<p>Example:</p>
<source><map:match pattern="protected-*">
<map:act type="auth-protect"> <!-- protect the resource -->
<map:parameter name="handler" value="myhandler"/>
<map:match pattern="protected-first">
<map:generate src="resource1.xml"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:match>
....
<map:match pattern="protected-second">
<map:generate src="resource2.xml"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:match>
</map:act>
</map:match></source>
<p>Very important - as explained with the single document pattern - is
the leading match before the action is performed. The second match
is required
to check which pipeline to use.</p>
</s2>
<s2 title="Controlling the Application Flow">
<p>If you want to create documents which behave different wheather you
are logged in or not, the <em>auth-loggedIn</em> action is the
component to
controll your application flow. This action checks if the user is
authenticated
for a given handler and calls all sitemap components inside the
<em>act</em>
tag.</p>
<source><map:match pattern="startpage">
<map:act type="auth-loggedIn"> <!-- check authentication -->
<map:parameter name="handler" value="myhandler"/>
<map:redirect-to uri="loggedInStartPage"/>
</map:act>
<map:generate src="startpage.xml"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:match></source>
<p>In the example above, if the user is already logged he is
redirected to the <em>loggedInStartPage</em> document. If he is not
logged in
for the given handler, the usual start page is generated.</p>
<p>Both actions, the <em>auth-protect</em> and the
<em>auth-loggedIn</em> action return - if the user is logged in for
the
given handler - all values from the context to the sitemap, e.g.
ID, role etc.
These values can be used within the other components:</p>
<source><map:match pattern"protected">
<map:act type="auth-protect"> <!-- protect the resource -->
<map:parameter name="handler" value="myhandler"/>
<!-- Append the ID of the user to the file name -->
<map:generate src="resource_{ID}.xml"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:act>
</map:match></source>
<p>But the <em>auth-loggedIn</em> action does not give the included
pipeline
access to the authentication context belonging to the handler. If
you want this, you
have to nest the <em>auth-protect</em> action inside!</p>
<source><map:match pattern"start">
<map:act type="auth-loggedIn"> <!-- check authentication -->
<map:parameter name="handler" value="myhandler"/>
<map:act type="auth-protect"> <!-- give access to the context
-->
<map:parameter name="handler" value="myhandler"/>
<map:generate src="getinfofromcontext.xml"/>
<map:transform src="session"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:act>
</map:act>
</map:match></source>
</s2>
</s1>
</body>
</document>
1.1
xml-cocoon2/src/documentation/xdocs/developing/webapps/book.xml
Index: book.xml
===================================================================
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//APACHE//DTD Cocoon Documentation Book V1.0//EN"
"../../dtd/book-cocoon-v10.dtd">
<book software="Apache Cocoon"
title="Apache Cocoon Developer Documentation"
copyright="@year@ The Apache Software Foundation">
<menu label="Navigation">
<menu-item label="Main" href="../../index.html"/>
<menu-item label="Dev Guide" href="../index.html"/>
</menu>
<menu label="Webapps">
<menu-item label="Overview" href="index.html"/>
<menu-item label="Session Contexts" href="session.html"/>
<menu-item label="Authentication" href="authentication.html"/>
<menu-item label="Form Handling"
href="../../howto/xmlform-wizard/howto-xmlform-wizard.html"/>
<menu-item label="Portal" href="portal.html"/>
</menu>
<menu label="Scratchpad">
<menu-item label="Session Contexts" href="sunshine.html"/>
<menu-item label="Authentication" href="sunrise.html"/>
<menu-item label="Portal" href="sunspot.html"/>
</menu>
</book>
1.1
xml-cocoon2/src/documentation/xdocs/developing/webapps/index.xml
Index: index.xml
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN"
"../dtd/document-v10.dtd">
<document>
<header>
<title>Webapps Developer Documentation</title>
<subtitle>Overview</subtitle>
<authors>
<person name="Carsten Ziegeler" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Overview">
<p>This section contains several documents about developing real-world web
applications
with Cocoon.</p>
<p>Some of these concepts are currently in development. The development of
the
<link href="session.html">Session handling</link>, the
<link href="authentication.html">authentication</link> framework and
the <link href="portal.html">portal framework</link> is nearly finished.
You will
find these components in the latest CVS version of Cocoon. The documentation
listed in the menu conforms to the current CVS version.</p>
<p>However, the current release @released.version@ contains alpha versions
in the
scratchpad area of these three components. So you can already have a look
at them. The
documentation in the "scratchpad" folder contains the description
conforming to the
scratchpad. But be warned that they are in the scratchpad area and will
change in
upcomming releases. So if you are really planning to use them, have a look
at the
latest CVS.
</p>
</s1>
</body>
</document>
1.1
xml-cocoon2/src/documentation/xdocs/developing/webapps/portal.xml
Index: portal.xml
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN"
"../../dtd/document-v10.dtd">
<document>
<header>
<title>Building Portals with Cocoon</title>
<authors>
<person name="Carsten Ziegeler" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Introduction">
<note><strong>IMPORTANT:</strong> This document conforms to the
development version of Cocoon. So
you will only find these components in the current CVS. An early
alpha version is already
available in the latest release of Cocoon, you will find an
introduction <link href="sunspot.html">here</link>.
</note>
<p>The portal engine of Cocoon provides the required
functionality to display user dependent content with a user defineable
layout.</p>
<p>The Cocoon portal defintion framework is an XML description of the
portal and the contained content. The rendering of the portal to the
needed
format (such as HTML) is done through stylesheets and is therefore
very
flexible.</p>
<p>A portal definition can be configured for all users (global), for
groups of users (group or role) and for the individual user. The
portal
admininstrator can use the provided tools to configure every aspect
of the
portal (from colours to content).</p>
<p>Each "blob" of portal content is contained in a "coplet"
(<em>Co</em>coon <em>p</em>ort<em>let</em>). coplets can
be configured into the portal on a per-user or per-group basis
allowing a
flexible content definition.</p>
<p>coplets can be minimized, maximized or even removed by the user if he
does not wish to see the content. However, the administrator may
configure
coplets to be mandatory, in which case they may not be removed.</p>
<p>The different portals are administrated by authentication
applications. Each
application can have its own portal.</p>
<p>This documentation explains the different resources for the portal,
the
configuration of a portal and how it creates the portal view derived
from
this information. After that all is put together by creating the
needed entries
in the sitemap for using and displaying a portal.</p>
</s1>
<s1 title="The Profile">
<p>A portal is built upon a profile which contains all necessary
information: the portal possibilites (the available coplets, the
possible
changes to the layout etc.) and the portal view (the layout for this
user and
the coplets he chose for himself). This profile is generated when a
user logs
into the application the portal belongs to. The building of the
profile is a
very flexible process which allows to have different configurations
for
different users.</p>
<p>In general the building of the profile consists of four steps:</p>
<ol>
<li>Building the base profile. This profile defines which
possibilites the portal has, which coplets are available to the
portal and
which parts of the profile can be changed by the user.
</li>
<li>Building the global profile. The base profile is enhanced by a
global delta which contains a predefined portal view. This
predefined portal
view is a starting point for all users.
</li>
<li>Building the role profile. The global profile is enhanced by a
role delta which contains a predefined portal view. This predefined
portal view
is a starting point for all users of that role.
</li>
<li>Building the user profile. The role profile is augmented by a
user delta which contains the portal for this specific user. An
optional user
status profile with often changing information can optional be
appended to the
profile.
</li>
</ol>
<p>Only step 1 and 2 are mandatory for the building process. Steps 3 and
4 are optional and depend on the configuration of the users and roles
in the
system.</p>
<p>Each delta (steps 2, 3 and 4) can modify the possibilites of the
portal and the configuration of the coplets. But it is not allowed to
add new
features or coplets. In addition a delta may contain a predefined
portal
view.</p>
<p>This building process is invoked each time the user logs into the
application. So a change to any profile (delta) is incorporated into
the user
profile: If e.g. a coplet , which a user has choosen for his portal
view, is
removed from the system, it is not available to the user anymore and
therefore
also removed from his portal view.</p>
<p>The global delta, the role delta and the user delta are very similar.
They only differ in the name of the root node.</p>
<s2 title="The Base Profile">
<p>The base profile consists of three data sources:</p>
<ol>
<li> The layout profile describes the possibilites and layout of
the portal.
</li>
<li>The coplets profile defines all available coplets for the
portal view.
</li>
<li>The type profile describes the parts of the profile which can
be changed by the user.
</li>
</ol>
<s3 title="The Layout Profile">
<p>The layout profile describes the overall layout of the portal
including if header or footer are present which colors and fonts
are used and
so on.</p>
<p>An example profile is shown below. The profile is enclosed in the
root node "layout-profile" and consists of the "portal" part and
the "coplets"
part:</p>
<source>
<layout-profile>
<portal>
<!-- This node contains the layout of the portal view -->
<layouts>
<layout>
<!-- The color of the background -->
<background>
<color>#ffffff</color>
</background>
<!-- The font and color for usual text -->
<font>
<type>Arial, Helvetica, sans-serif</type>
<size>2</size>
<color>black</color>
</font>
</layout>
</layouts>
<!-- The following means that the portal has a header area -->
<header>
<exists>true</exists>
</header>
<!-- The following means that the portal has 3 columns -->
<columns>
<number>3</number>
</columns>
<!-- The following means that the portal has not a footer area -->
<footer>
<exists>false</exists>
</footer>
</portal>
<coplets>
<!-- This node contains the layout of the coplets -->
<layouts>
<layout>
<title>
<!-- The layout of the title -->
<background>
<color>#46627A</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</title>
<content>
<!-- The layout of the content -->
<font>
<type>Arial</type>
<size>2</size>
<color>#000000</color>
</font>
<background>
<color>#ffffff</color>
</background>
</content>
</layout>
</layouts>
</coplets>
</layout-profile>
</source>
</s3>
<s3 title="The coplets Profile">
<p>The coplets profile contains all coplets which are available in
the system. It is an XML based resource with the root node
"coplets-profile".
All coplets are defined under a node called "coplets", so an
example profile
could look like this:</p>
<source> <coplets-profile>
<coplets>
<coplet id="bankingnews">
<resource uri="cocoon://coplet-banking.xml"/>
<transformation>
<!-- optional xsl transformation -->
<stylesheet>sunbank/styles/coplet.xsl</stylesheet>
</transformation>
<configuration>
<mandatory>false</mandatory>
<sizable>true</sizable>
<active>true</active>
<timeout>5000</timeout>
<!-- optional, milliseconds -->
<messages>
<!-- optional: Messages -->
<coplet_not_available>
Display this if the coplet is not available.
</coplet_not_available>
</messages>
</configuration>
<title>Banking News</title>
<status>
<visible>true</visible>
<size>max</size>
</status>
</coplet>
</coplets>
</coplets-profile>
</source>
<p>This example defines one coplet: the bankingnews coplet with the
title "Banking News". The title is displayed in the portal view
above the
coplet content. The most important part is the resource
definition. Using this
resource the coplet is displayed in the portalview of the user.
</p>
<ul>
<li>An uri, e.g.: <resource uri=".."/>. This URI can be a
local one which is retrieved using the sitemap or a distant
one which is
retrieved using an HTTP request. In both cases the resource
must deliver valid
XML for the coplet content. If you don't use a protocol, the
URI is assumed to
be a file.
</li>
<li>A java class delivering the content.
</li>
</ul>
<p>There a several mandatory configuration parameters for a coplet.
This configuration parameters can only be changed by the portal
administrator.
The user cannot change them for his portal view.</p>
<ul>
<li>mandatory: Indicates if the coplet can be removed by the
user or if it is always visible.
</li>
<li>sizable: Is the coplet sizable? If the value is true the
user can minimize this coplet in his portal view.
</li>
<li>active: Using this parameter, a coplet can be deactivated
for a distinct period of time. If a coplet is not active it
will not displayed
to the user even if he has configured it.
</li>
</ul>
<p>In addition there are some optional parameters:</p>
<ul>
<li>timeout: This is the time in milliseconds, the portal waits
to
get the coplet content. If the content is not available
within this time frame,
the coplet is declared as not available at the moment. The
default value for
the timeout can be set in the portal configuration (see next
chapter).
</li>
<li>handlesSizable: If this value is true, the coplet (or
better the resource) handles the sizing of this coplet
itselt. This means it
determines the data to be displayed if the coplet is
minimized or maximized. If
this value is false the portal displayes the whole coplet if
it is maximized and
only its title if it is minimized. This is the default
behaviour.
</li>
<li>handlesParameters: If this value is true (which is the
default value) the resource gets all configuration and status
parameters
passed, e.g. if the resource is an uri, the parameters are
passed as HTTP
request parameters.
</li>
<li>messages/coplet_not_available: If the coplet is not
available (e.g. external data where the server is not
available), a message is
displayed. With this optional parameter each coplet can get a
distinct message
which overrides the message provided by the user profile.
</li>
</ul>
<p>The status parameters can be changed by the user for configuring
his own portal view:</p>
<ul>
<li>visible: If a coplet is visible it is included in the
portal view. If it is not visible it is still configured for
the user but it
will not displayed.
</li>
<li>size: Currently two sizes (min and max) are distinquished.
</li>
</ul>
<p>If the source of the coplet needs additional transformation there
are two possibilities for doing the transformation. The first
one is creating a
pipeline in the sitemap for this coplet and the second one usses
the coplet
configuration for this. As the first one is the usual pipeline
creating process only the second one is covered here.</p>
<p>By defining the "transformation" node inside the "coplet" node,
the source of the coplet can be transformed with one or more
stylesheets. For
each stylesheet a "stylesheet" node with the value of the
stylesheet path has
to be created. The order of appearance determines the order of
processing. If
e.g. the source of a coplet is a class or a file, there is no
need to specify a
pipeline only for this coplet. Specifying a file/class as source
and a
"stylesheet" node has the same effect.</p>
<s4 title="Adding a new coplet">
<p>Adding new information to the portal requires four basic
steps:</p>
<ul>
<li>Defining the resource containing the information. For
external resources only the address (mainly an URI) and the
protocol (usually
HTTP) is required. Otherwise a new XML resource has to be
created with the new
content.
</li>
<li>Defining the stylesheet for the presentation of this
content.
</li>
<li>For local resources: Definition of the pipeline in the
sitemap. This pipeline must contain all necessary steps for
building the
information. It must deliver XML as the serialized format.
</li>
<li>Adding a new "coplet" node to the coplets profile.
</li>
</ul>
<p>After these steps are finished, the new coplet is
automatically
available for each user which logs in after the addition. If
the coplet is even
mandatory it will be added to the portal view of the user.</p>
<p>For more information see the chapter "The Pipelines".</p>
</s4>
<s4 title="Customizable coplets">
<p>Each coplet can have its own configuration, e.g. a weather
coplet should display the weather for a particular city
etc.</p>
<source> <coplets-profile>
<coplets>
<coplet id="bankingnews">
<resource uri="cocoon://coplet-banking.xml"/>
<customization uri="cocoon://customize-coplet-banking.xml"/>
<!-- optional -->
<transformation>
<!-- optional xsl transformation -->
<stylesheet>sunbank/styles/coplet.xsl</stylesheet>
</transformation>
<configuration>
<mandatory>false</mandatory>
<sizable>true</sizable>
<active>true</active>
<timeout>5000</timeout>
<!-- optional, milliseconds -->
<messages>
<!-- optional: Messages -->
<coplet_not_available>
Display this if the coplet is not available.
</coplet_not_available>
</messages>
<customizable>true</customizable>
<!-- optional -->
<persistent>false</persistent>
<!-- optional -->
</configuration>
<title>Banking News</title>
<status>
<visible>true</visible>
<size>max</size>
</status>
</coplet>
</coplets>
</coplets-profile>
</source>
<p>To declare a coplet as customizable it must get a
configuration
resource which is displayed to a user of this coplet to enter
all required
configuration values. This is done with the
<em>customization</em> tag. The
value for this tag has the same possibilities as the
<em>resource</em> tag,
usually the <em>uri</em> attribute points to a pipeline.</p>
<p>When a user has configured/choosen a customizable coplet,
the portal detects if this coplet has its configuration. If
it does not have one,
the customization resource of the coplet is displayed in the
portal view.
Otherwise the coplet itself is displayed.</p>
<p>In addition a customizable coplet can be persistent, e.g. the
configuration is saved for a longer period than the current
session of the
user. If the coplet is not persistent the configuration is
lost when the user
logs out. The next time he logs in, the customization page is
displayed to
configure this coplet again.</p>
<p>If you use persistent coplets you have to configure resources
for loading and saving the status profile (See
configuration). More about
writing customizable coplets can be found in the chapter
"Writing Customizable
coplets".</p>
</s4>
</s3>
<s3 title="The Type Profile">
<p>The type profile describes the possible values the user can
change for his portal view. Using this flexible approach the
portal
administrator can decide which user can choose what. For
example, a normal user
might change the layout and content of his portal view, but a
guest might not
be allowed to change anything, whereas the administrator can
change
everything.</p>
<p>The type profile is surrounded by the root node "type-profile".
It consists of two parts: the typedefs section and the elements
section. The
type profile can be compared with a programming language. The
typedefs section
declares all available types and the the elements section
declares all
variables with their corresponding types. A "variable" defines a
place or
element in the user profile which can be changed by the user.
The possibilites
for this element are defined by the type.</p>
<p>The typedefs contains enumerations, e.g. a set of possible values
with a user presentable name. In addition the portal has the
following predefined
types: STRING (arbitrary text), BOOLEAN (true or false), INTEGER
(a number) and
CARDINAL (a positiv number).</p>
<source><type-profile>
<typedefs>
<!-- The following types are defined by the portal: (Names are
casesensitiv!)
STRING, BOOLEAN, ENUMERATION, INTEGER, CARDINAL
-->
<typedef name="backgroundcolor" type="ENUMERATION">
<value name="weiss">#ffffff</value>
<value name="hellgrau">#cccccc</value>
<value name="hellgruen">#aab9bf</value>
<value name="dunkelgruen">#46627A</value>
</typedef>
<typedef name="textcolor" type="ENUMERATION">
<value name="weiss">white</value>
<value name="schwarz">black</value>
<value name="weiss">#ffffff</value>
<value name="hellgrau">#cccccc</value>
<value name="hellgruen">#aab9bf</value>
<value name="dunkelgruen">#46627A</value>
</typedef>
<typedef name="copletsize" type="ENUMERATION">
<value name="Maximized">max</value>
<value name="Minimized">min</value>
</typedef>
<typedef name="columnnumber" type="ENUMERATION">
<value name="1">1</value>
<value name="2">2</value>
<value name="3">3</value>
<value name="4">4</value>
<value name="5">5</value>
</typedef>
</typedefs>
</type-profile>
</source>
<p>The element section has the same structure a the user profile.
For each leave which is changeable by the user the elements
section contains an
entry for the type of this node. The node is enhanced by two
attributes: type
for the node type and description for a user readable title.
This information
is used by the portal to present the configuration screen for
the portal. It
displayes for each changeable leave a form field with the
corresponding
type.</p>
<source><type-profile>
<elements>
<layout-profile>
<portal>
<layouts>
<layout>
<!-- The user can change the background.
The possible values are taken from the enumeration
backgroundcolor. The user gets the title
"Background"
displayed for the form field. -->
<background>
<color type="backgroundcolor" description="Background"/>
</background>
<font>
<color type="textcolor" description="Font color"/>
</font>
</layout>
</layouts>
<columns>
<!-- The user can change the number of columns -->
<number type="columnnumber" description="Number of columns"/>
</columns>
</portal>
</layout-profile>
<portal-profile>
<content>
<!-- Using the * the following configuration is applied for
all columns regardless of their position. -->
<column position="*">
<width type="CARDINAL" description="Width"/>
<coplets>
<!-- Using the * the following configuration is applied for
each coplet. -->
<coplet id="*" position="*" number="*">
<status>
<!-- The user can change the visibility and size
of the coplet -->
<visible type="BOOLEAN" description="Visible"/>
<size type="copletsize" description="Size"/>
</status>
</coplet>
</coplets>
</column>
</content>
</portal-profile>
</elements>
</type-profile></source>
</s3>
</s2>
<s2 title="The Global Profile">
<p>The global delta, the role delta and the user delta are very
similar. They only differ in the name of the root node. So this
chapter only
describes the global delta and points out the differences between
the deltas at
the various place rather than repeating the same information in
different
chapters.</p>
<p>The global delta is enclosed in the root node "global-delta", the
role delta uses the node "role-delta" and the user delta the node
"user-delta".</p>
<p>In general a delta defines the differences between two profiles.
The portal deltas allow only adding and changing but not removing
nodes. Each
delta can contain the following parts: </p>
<ul>
<li>The layout delta containing the difference to the layout
profile.
</li>
<li>The coplets delta describing the differences to the coplets
profile.
</li>
<li>The portal profile containing a complete portal view. This
part is not a delta. If it is contained in a delta and the
profile already has
this information, that information is replaced by the one from
the delta.
Otherwise the delta information is added. For the global profile
the portal
profile is mandatory.
</li>
<li>The personal profile. This part contains personal information
of the user, e.g. are welcome text. For the global profile this
information
again is mandatory. It defines the possibilites the user has.
The role and the
user profile can only change this information. But they cannot
add any new
nodes.
</li>
</ul>
<p> So here is an example:</p>
<source><global-delta>
<!-- No difference to the base profile -->
<layout-delta/>
<!-- No difference to the base profile -->
<coplets-delta/>
<!-- This is the starting portal view for all users.
It has to be defined in the global profile -->
<portal-profile>
<!-- This is the content of the portal view -->
<content>
<header>
<coplet id="personalize" position="1">
<status>
<visible>true</visible>
<size>max</size>
</status>
</coplet>
</header>
<column position="1">
<width>28%</width>
<!-- The coplets are displayed in the order of their
position attribute in each column. -->
<coplets>
<coplet id="administration" number="1" position="1">
<status>
<visible>true</visible>
<size>max</size>
</status>
</coplet>
</coplets>
</column>
<column position="2">
<width>50%</width>
<coplets>
<coplet id="banknews" number="2" position="1"/>
</coplets>
</column>
<column position="3">
<width>22%</width>
<coplets/>
</column>
</content>
</portal-profile>
<personal-profile>
<greeting>Herzlich willkommen</greeting>
<messages>
<coplet_not_available>
The coplet is currently not available.
</coplet_not_available>
</messages>
</personal-profile>
</global-delta>
</source>
</s2>
<s2 title="The User Status Profile">
<p>The user status profile contains often changing information like
the configuration of configurable coplets, the last login time etc.
The user
status profile is optional, but if it is not accessible,
customizable coplets
are not possible.</p>
<p>For each customizable coplet which is in the portal view of the
user the status profile contains an XML block with the coplet
specific
configuration for this coplet.</p>
<source><status-profile>
<customization>
<!-- Custom information for each customizable coplet -->
<coplet id="popmail" number="3">
<host>mail</host>
<password>gsgdgsg</password>
<mailcount>4</mailcount>
<user>walter</user>
</coplet>
</customization>
</status-profile></source>
</s2>
</s1>
<s1 title="Configuring the portal">
<p>The configuration of the portal is actually a authentication
application
configuration. Please refer to the authentication documentation for
more information
about authentication handler and application configuration.</p>
<p>Inside your authentication handler configuration you define for each
portal
an application configuration for the portal like the example portal
called
"sunBank" below: <![CDATA[]]></p>
<source> <application name="sunBank">
<configuration name="portal">
<!-- This is the portal configuration -->
<portal-uri>finance-portal</portal-uri>
<profile-cache>true</profile-cache>
<process-coplets-parallel>false</process-coplets-parallel>
<default-coplet-timeout>10000</default-coplet-timeout>
<profile>
<!-- The resource for loading the layout profile -->
<layout-base uri="cocoon://financeresource-layoutprofile"/>
<!-- The resource for loading the base coplets profile -->
<coplet-base uri="cocoon://financeresource-copletprofile"/>
<!-- The optional resource for saving the base coplets profile -->
<coplet-base-save
uri="cocoon://financeresource-savecopletprofile"/>
<!-- The optional type resource -->
<type-base uri="cocoon://financeresource-types"/>
<!-- The optional type resource for the admin configuration -->
<admin-type-base uri="cocoon://financeresource-admintypes"/>
<!-- The resources for loading/saving the deltas -->
<global-delta-load uri="cocoon://financeresource-globalprofile"/>
<global-delta-save
uri="cocoon://financeresource-saveglobalprofile"/>
<role-delta-load uri="cocoon://financeresource-roleprofile"/>
<role-delta-save uri="cocoon://financeresource-saveroleprofile"/>
<user-delta-load uri="cocoon://financeresource-userprofile"/>
<user-delta-save uri="cocoon://financeresource-saveuserprofile"/>
<!-- Optional resources for loading/saving the status profile
which is required for persistent, customizable coplets
-->
<user-status-load
uri="cocoon://financeresource-loadstatusprofile"/>
<user-status-save
uri="cocoon://financeresource-savestatusprofile"/>
<!-- optional type resources -->
<global-type-delta uri="..."/>
<role-type-delta uri="..."/>
<user-type-delta uri="..."/>
</profile>
<!-- Redirect to this resource, if the user is not authenticated
to view that coplet -->
<auth-redirect>finance-portal</auth-redirect>
</configuration>
</application>
</source>
<s2 title="Global Portal Configuration">
<p>One mandatory configuration value for the portal is the
<em>portal-uri</em>. It must point to a pipeline which produces the
portal view
for a user (see next section for more information about the
pipelines).</p>
</s2>
<s2 title="Profile Caching">
<p>The portal contains an intelligent profile caching mechanism which
detects automatically changes to profiles and determines upon this
information
which profile must be rebuild. </p>
<p>Without profile caching a profile is build each time a user logs
in. With profile caching the profile is only build if there is no
cached
profile or if something has changed in the profiles for this user.
Only the
user status profile is not cached at all as it is often
changing.</p>
<p>By specifying the <em>profile-cache</em> tag in the the portal
configuration with the value <em>true</em> the profile caching is
turned on. If
the tag is not available no profile caching is performed.</p>
<p>If profile caching is turned on, the profiles should not be changed
by hand as the cache does not detect such changes. All changes to
the profiles
must be done using the portal tools. However if you change a
profile or part
of a profile by hand, make sure that you clean the cache
afterwords. Cleaning
the cache can be done either by the provided the portal tools or by
deleting all
files inside the cache directory.</p>
</s2>
<s2 title="Global coplet configuration">
<p>Usually the portal view is generated step by step, e.g. the coplets
are build one after the other. The portal can be configured to get
the coplets
content parallel to decrease the response time for the portal view.
By
specifying the <em>process-coplets-parallel</em> tag with the value
<em>true</em>, the coplets are processed parallel.</p>
<p>If the content of a coplet is not available, e.g. if the
contentresides on an external HTTP server, the processing of this
coplet can
take a "very long" time, e.g. until a timeout occures. The portal
monitors the
coplets and can stop the processing of a coplet after a distinct
period of
time. This period can be specified by the tag
"default-coplet-timeout" in
milliseconds. If the content of the coplet is not available after
the time has
expired, the coplet is declared as "not available". The default
timeout is 10
minutes.</p>
<p>For a fine-tuning of coplet timeouts, each coplet can get its own
timeout (see the sections below).</p>
</s2>
<s2 title="Profile Resources">
<p>Each part of the profile has a corresponding resource which is
invoked for loading or saving the profile part, e.g. one resource
for loading
the global profile delta and a separate one for saving it. The
loading
resources must deliver the xml described in the previous chapters.
</p>
<p>All resources get the parameter "application" with the name of the
corresponding application and "handler" with the name of the
authentication handler.
The list below shows the additional parameters for the other
resources.</p>
<ul>
<li>coplet-base: "profile" with value "coplet-base"
</li>
<li>coplet-base-save: "profile" with value "coplet-base"
</li>
<li>layout-base: "profile" with value "layout-base"
</li>
<li>type-base: "profile" with value "type-base"
</li>
<li>admin-type-base: "profile" with value "admin-type-base"
</li>
<li>global-delta-load: "profile" with value "global-delta"
</li>
<li>global-type-delta: "profile" with value "global-type-delta"
</li>
<li>global-delta-save: "profile" with value "global-delta"
</li>
<li>role-delta-load: "profile" with value "role-delta", "role"
with name of the role
</li>
<li>role-delta-save: "profile" with value "role-delta", "role"
with name of the role
</li>
<li>role-type-delta: "profile" with value "role-type-delta",
"role" with role name
</li>
<li>user-delta-load: "profile" with value "user-delta", "role"
with role name, "ID" with user ID
</li>
<li>user-delta-save: "profile" with value "user-delta", "role"
with role name, "ID" with user ID
</li>
<li>user-type-delta: "profile" with value "user-type-delta",
"role" with role name, "ID" with user ID
</li>
<li>user-status-load: "profile" with value "user-status", "role"
with role name, "ID" with the user ID
</li>
<li>user-status-save: "profile" with value "user-status", "role"
with role name, "ID" with the user ID
</li>
</ul>
</s2>
</s1>
<s1 title="The Pipelines">
<p>So far the chapters only described configuring the portal and writing
resources. This chapter closes the gap and explains the steps for
showing the
portal.</p>
<p>For defining the pipelines in the sitemap, the portal declares two
generators (the "portal" generator and the "portal-conf" generator)
and one
action ("portal-auth").</p>
<s2 title="Displaying the portal view">
<p>Displaying the portal view is a very simple step: defining a
pipeline with the "portal" as the generator, the auth-protect action
for defining the application and an stylesheet for creating the
presentation:
</p>
<source><map:match pattern="sunbank-portal">
<map:act type="auth-protect">
<!-- for getting the portal configuration -->
<map:parameter name="handler" value="portalhandler"/>
<map:parameter name="application" value="sunBank"/>
<map:generate type="portal"/>
<!-- generate the portal view -->
<map:transform src="sunbank/styles/portalHTML.xsl"/>
<!-- presentation in HTML -->
<map:serialize/>
</map:act>
</map:match>
</source>
<s3 title="The Generated Portal View">
<p>The XML generated by the "portal" generator is not exactly the
same as for the user profile. The portal optimizes and
reorganizes the profile.
All fields (or nodes) which are changeable have the attributes
"formdescription", "formpath" and "formtype". "formdescription"
is a user
readable description of the field, "formpath" is the name of the
form parameter
which can be used to set the value and "formtype" indicates the
type of the
field. The belonging type can be found in the types section of
the
profile.</p>
<source><!-- The portal indicates that the following is the
portal view -->
<portal>
<!-- The configuration of the portal -->
<configuration>
<!-- This is the uri which should be invoked for rebuilding the portal
view
and for changing the view. The parameter portalprofile is always
present and indicates the current profile. -->
<uri>finance-portlets?portalprofile=uprofile:sunBank:user_admin_cocoon</uri>
<!-- This is the uniquie portal profile ID -->
<profile>uprofile:sunBank:user_admin_cocoon</profile>
<media>html</media>
<!-- The current media: html or wap -->
</configuration>
<!-- Now the needed part of the layout profile: -->
<layout>
<portal>
<background>
<color formdescription="Hintergrundfarbe"
formpath="portalconf.0.0" formtype="backgroundcolor">#aab9bf</color>
</background>
<font>
<type>Arial, Helvetica, sans-serif</type>
<size>2</size>
<color formdescription="Schriftfarbe" formpath="portalconf.1.0"
formtype="textcolor">black</color>
</font>
</portal>
<coplets>
<title>
<background>
<color>#46627A</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</title>
<content>
<background>
<color>#000000</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</content>
</coplets>
</layout>
<!-- This is the portal view: -->
<header>
<coplet id="personalize" position="1" number="1">
<resource uri="financecoplet-personalize.xml"/>
<configuration>
<mandatory>true</mandatory>
<sizable>true</sizable>
<active>true</active>
</configuration>
<title>Personalisieren</title>
<status>
<visible>true</visible>
<size>max</size>
</status>
<content>..the coplet content...</content>
</coplet>
</header>
<columns number="3">
<column position="1" width="28%">
<coplet id="administration" position="1" number="1">
<resource uri="financecoplet-administration.xml"/>
<configuration>
<mandatory>false</mandatory>
<sizable>true</sizable>
<active>true</active>
</configuration>
<title>Portal Administration</title>
<status>
<visible formdescription="Sichtbar" formpath="portalconf.4.0"
formtype="BOOLEAN">true</visible>
<size formdescription="Groesse" formpath="portalconf.5.0"
formtype="copletsize">max</size>
</status>
<content>..the coplet content...</content>
</coplet>
....
</column>
<column position="2" width="50%">
...
</column>
<column position="3" width="22%">
...
</column>
</columns>
<!-- The personal information -->
<personal-profile>
<greeting>Hi there!</greeting>
<messages>
<coplet_not_available>The coplet is currently not
available.</coplet_not_available>
</messages>
</personal-profile>
</portal></source>
</s3>
</s2>
<s2 title="Administration of the portal view">
<p>Displaying the administration page of the portal is as simple as
displaying the portal. The difference lies in changing the
generator to the
"portal-conf" generator: </p>
<source><map:match pattern="sunbank-conf">
<map:act type="auth-protect">
<map:parameter name="handler" value="portalhandler"/>
<map:parameter name="application" value="sunBank"/>
<map:generate type="portal-conf"/>
<map:transform src="sunbank/styles/portalconfHTML.xsl"/>
<map:serialize/>
</map:act>
</map:match></source>
<p>Make sure to protect the portal configuration generator as the
administrator can change all profiles, clear the cache etc. It
should only be
available for real portal administrators.</p>
<s3 title="The Generated Administration View">
<p>The XML generated by the "portal-conf" generator is not exactly
the same as the user profile. The portal addes some information
to the profile.
All fields (or nodes) which are changeable have the attributes
"formdescription", "formpath" and "formtype". "formdescription"
is a user
readable description of the field, "formpath" is the name of the
form parameter
which can be used to set the value and "formtype" indicates the
type of the
field. The belonging type can be found in the types section of
the
profile.</p>
<source><!-- The portalconf node indicates that the following is
the portal administration view -->
<portalconf>
<!-- The configuration of the portal -->
<configuration>
<!-- This is the uri which should be invoked for rebuilding the portal
view
and for changing the view. The parameter portalprofile is always
present and indicates the current profile. -->
<uri>finance-portlets?portalprofile=uprofile:sunBank:user_admin_cocoon</uri>
<!-- This is the uniquie portal profile ID -->
<profile>uprofile:sunBank:user_admin_cocoon</profile>
<media>html</media>
<!-- The current media: html or wap -->
</configuration>
<!-- The layout profile, see chapter about the layout profile -->
<layout-profile>
<portal>
<layouts>
<layout>
<background>
<color formdescription="Hintergrundfarbe"
formpath="portalconf.0.0" formtype="backgroundcolor">#aab9bf</color>
</background>
<font>
<type>Arial, Helvetica, sans-serif</type>
<size>2</size>
<color formdescription="Schriftfarbe"
formpath="portalconf.1.0" formtype="textcolor">black</color>
</font>
</layout>
</layouts>
<header>
<exists>true</exists>
</header>
<columns>
<number formdescription="Anzahl" formpath="portalconf.2.0"
formtype="columnnumber">3</number>
</columns>
<footer>
<exists>false</exists>
</footer>
</portal>
<coplets>
<layouts>
<layout>
<title>
<background>
<color>#46627A</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</title>
<content>
<font>
<type>Arial</type>
<size>2</size>
<color>#000000</color>
</font>
<background>
<color>#ffffff</color>
</background>
</content>
</layout>
</layouts>
</coplets>
</layout-profile>
<!-- The coplets profile, see chapter about the coplets profile -->
<coplets-profile>
<coplets>
<coplet id="banknews">
<resource uri="onlinecoplet-banking.xml"/>
<configuration>
<mandatory>false</mandatory>
<sizable>true</sizable>
<active>true</active>
</configuration>
<title>Banking News</title>
<status>
<visible>true</visible>
<size>max</size>
</status>
</coplet>
...
</coplets>
</coplets-profile>
<!-- The type profile, see the chapter about the type profile -->
<typedefs>
...
</typedefs>
<!-- And now the portal view, see chapter about the portal profile -->
<portal-profile>
<content>
<header>
<coplet id="personalize" position="1" number="1">
<status>
<visible>true</visible>
<size>max</size>
</status>
</coplet>
</header>
<column position="1">
<width formdescription="Breite" formpath="portalconf.3.0"
formtype="CARDINAL">28%</width>
<coplets>
<coplet id="administration" position="1" number="2">
<status>
<visible formdescription="Sichtbar"
formpath="portalconf.4.0" formtype="BOOLEAN">true</visible>
<size formdescription="Groesse" formpath="portalconf.5.0"
formtype="copletsize">max</size>
</status>
</coplet>
...
</coplets>
</column>
<column position="2">
...
</column>
<column position="3">
...
</column>
</content>
</portal-profile>
<!-- The personal profile, see the corresponding chapter -->
<personal-profile>
<greeting>Hi there!</greeting>
<messages>
<coplet_not_available>The coplet is currently not
available.</coplet_not_available>
</messages>
</personal-profile>
</portalconf>
</source>
</s3>
</s2>
<s2 title="Changing the Profile">
<p>The profile can be changed using a HTTP request. The invoked
resources is the uri defined in the "configuration" section of the
portal view.
It contains already the needed parameter "portalprofile" with the
given value.
This parameter tells the portal which profile it should change.</p>
<p> Each field which is changeable has the parameters
"formdescription", "formtype" and "formpath". The "formdescription"
is a
user-readable text for this field. The "formtype" is the type of
the field. It
is a type name which has a corresponding entry in the type profile.
The type
profile contains all possible values for this particular type. The
"formpath"
contains the name of the field to change. So changing an field is
submitting a
form value with the name of "formpath" and one of the values
denoted by the
"formtype". </p>
<p>In addition to this the portal recognizes the special parameter
"portalcmd". It can control the appearance of the coplets. The
value of the
parameter is one of the following followed by '_', the coplet id
attribute,
another '_' and the coplet number attribute. For example minimizing
a coplet is
done by passing "portalcmd=minimize_1_3" to the request. The
commands are as
follows:</p>
<ul>
<li>"maximize" : Maximize the coplet.
</li>
<li>"minimize" : Minimize the coplet.
</li>
<li>"close" or "hide" : Close the coplet, it will not be
displayed in the portal view, but is still configured.
</li>
<li>"open" or "show" : A configured coplet will be included in
the portal view again.
</li>
<li>"delete" : Remove the coplet from the profile.
</li>
<li>"move" : Move the coplet to the column which is append to
value separated by '_'. So "portalcmd=move_1_3_2" would move the
coplet into
the 2nd column.
</li>
<li>"new" : Add a new coplet to the profile. Only the attribute
id of the coplet is passed. Instead of the number attribute the
column number
is appended. If instead "header" or "footer" is passed instead
of the column
number, the coplet is moved into that special area.
</li>
<li>"update" : Change from the customization view of the coplet
to the coplet content view.
</li>
</ul>
<p>The profile can be save persistent by sending the parameter
"portalcmd" with the value "save"in addition to the "portalprofile"
parameter.</p>
</s2>
<s2 title="Defining coplets">
<p>Defining a pipeline for a coplet is also very straightforward.
Together with your "real" pipeline for defining the content and
doing the
presentation, the "auth-protect" action is needed. This action
defines
the application and portal, the coplet (pipeline) belongs to:</p>
<source><map:match pattern="licence-coplet">
<!-- Get the application configuration -->
<map:act type="auth-protect">
<map:parameter name="handler" value="portalhandler"/>
<map:parameter name="application" value="sunBank"/>
<!-- secure the coplet: -->
<map:act type="portal-auth">
<map:parameter name="coplet" value="licencing"/>
</map:act>
<!-- The resource containg the licencing information: -->
<map:generate src="cocoon/licencing.xml"/>
<!-- present it in HTML -->
<map:transform src="sunbank/styles/HTML.xsl"/>
<!-- Serialize it to XML for including in the portal view: -->
<map:serialize/>
</map:act>
</map:match>
</source>
<p>In addition you can secure the pipeline of the coplet. So only
users
who can select this coplet in their profile can invoke the
pipeline.
This extra protection is performed by the "portal-auth" action:</p>
<source><map:match pattern="licence-coplet">
<!-- Get the application configuration -->
<map:act type="auth-protect">
<map:parameter name="handler" value="portalhandler"/>
<map:parameter name="application" value="sunBank"/>
<!-- secure the coplet: -->
<map:act type="portal-auth">
<map:parameter name="coplet" value="licencing"/>
</map:act>
<!-- The resource containg the licencing information: -->
<map:generate src="cocoon/licencing.xml"/>
<!-- present it in HTML -->
<map:transform src="sunbank/styles/HTML.xsl"/>
<!-- Serialize it to XML for including in the portal view: -->
<map:serialize/>
</map:act>
</map:match></source>
<p>In this example the coplet is protected by the use of the parameter
tag inside the "portal-auth" action. Only if the user is allowed to
view/configure the coplet with the ID "licencing", he can invoke
this resource.
If this security command is left out, everyone is able to get the
resource by
simply invoking it directly from the browser. However, if the
coplet is
protected it is not necessary that a user has choosen that coplet
for his
current portal view to invoke the resource. In addition it is
possible to
specify the parameter without a specific coplet name. This protects
the
resource as a coplet: Only users which are logged in to the portal
can view the
resource.</p>
</s2>
<s2 title="Getting Profile Information within a coplet">
<p>Each coplet has access to nearly all information of the profile,
including layout information and configuration. The coplet can
retrieve this
information using a special session context called <em>portal</em>.
With the
familiar commands of the <em>session</em> transformer
(<em>getxml</em> etc.)
the information can be included in the current xml stream of a
coplet.</p>
<p>The content of the context looks like the following:</p>
<source><layout>
<portal>
<background>
<color formdescription="Hintergrundfarbe" formpath="portalconf.0.0"
formtype="backgroundcolor">#aab9bf</color>
</background>
<font>
<type>Arial, Helvetica, sans-serif</type>
<size>2</size>
<color formdescription="Schriftfarbe" formpath="portalconf.1.0"
formtype="textcolor">black</color>
</font>
</portal>
<coplets>
<title>
<background>
<color>#46627A</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</title>
<content>
<background>
<color>#000000</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</content>
</coplets>
</layout>
<configuration>
<!-- This is the uri which should be invoked for rebuilding the portal
view
The parameter portalprofile is always
present and indicates the current profile. -->
<uri>finance-portlets?portalprofile=uprofile:sunBank:user_admin_cocoon</uri>
<!-- This is the uniquie portal profile ID -->
<profile>uprofile:sunBank:user_admin_cocoon</profile>
<media>html</media>
<!-- The current media: html or wap -->
</configuration>
</source>
<p>Using this information the coplet can layout itself with the layout
chosen by the user for the portal. For example a
<em><session:getxml
context="portal"
path="/layout/coplets/content/background/color"/></em> is
replaced by the session transformer with the color value for the
background
(here "#000000)".</p>
</s2>
<s2 title="Writing Customizable coplets">
<p>Writing a customizable coplet requires two task:</p>
<ol>
<li>Creating the resource for the customization of the coplet
</li>
<li>Creating a resource for the coplet content which uses the
configuration
</li>
</ol>
<p>The resource for the customization is very similar to the "real"
resource for the coplet. It is - in most cases - a pipeline which
delivers xml
and this xml is included in the portal view. Usually this xml
contains a form
for the user to define the configuration of the coplet.</p>
<p>The configuration of the coplet is available using the special
<em>portal</em> session context. For a customizable coplet this
context is
augmented with the current configuration of the coplet:</p>
<source><layout>
...
</layout>
<configuration>
...
<context>unique id for the coplet for external
applications</context>
</configuration>
<coplet-data>
... the configuration ....
</coplet-data></source>
<p>Using the Cocoon form handling it is very easy to write a
customization view for a coplet. The following example dispalys a
form for a
mail coplet which requires the configuration for a mail host, a
user name and a
password.</p>
<source><page
xmlns:session="http://cocoon.apache.org/session/1.0">
<!-- Define a form -->
<session:form name="popmail" method="POST">
<session:action>
<!-- The action is send to the pipeline redisplaying the portal
-->
<session:getxml context="portal" path="/configuration/uri"/>
</session:action>
<!-- Create the input fields for
host, username and password -->
<session:content>
<session:inputxml context="portal" path="/coplet-data/host"
name="Host" type="text"/>
<session:inputxml context="portal" path="/coplet-data/user"
name="User" type="text"/>
<session:inputxml context="portal" path="/coplet-data/password"
name="Password" type="password"/>
</session:content>
<!-- The submit button -->
<input type="submit" value="Customize"/>
</session:form>
</page></source>
<p>The <em>inputxml</em> tags assure that the information
provided by the user is automatically written into the
<em>portal</em> context
at the places provided.</p>
<p>Writing the resource for the coplet is as easy. The coplet can use
the <em>getxml</em> command to retrieve to configuration from the
<em>portal</em> context:</p>
<source><page
xmlns:session="http://cocoon.apache.org/session/1.0">
<!-- Get the configuration information out of the portal context -->
<!-- and feed it into the getmail command -->
<session:getmail>
<session:user>
<!-- Set the user -->
<session:getxml path="/coplet-data/user" context="portal"/>
</session:user>
<session:password>
<!-- Set the password -->
<session:getxml path="/coplet-data/password" context="portal"/>
</session:password>
<session:host>
<!-- Seet the host -->
<session:getxml path="/coplet-data/host" context="portal"/>
</session:host>
</session:getmail>
</page></source>
<p>Each time the coplet configuration changes the user status profile
is automatically saved.</p>
</s2>
<s2 title="External Resources and Customizable coplets">
<p>External resources which are configured with the same
authentication
handler and application as the portal can retrieve configuration
information
from a coplet. If the resource is invoked with the request parameter
<em>portalcontext</em> it has access to the same portal context as
the
coplet.</p>
<p>The value for the request parameter can be retrieved by the calling
resource, e.g. the coplet, from the <em>portal</em> context using
the path
<em>/configuration/context</em>. The external resource must have the
<em>portal-auth</em> action configured in its pipeline. The action
checks for the request parameter and grants the resource access to
the
<em>portal</em> context of the coplet.</p>
</s2>
</s1>
</body>
</document>
1.1
xml-cocoon2/src/documentation/xdocs/developing/webapps/session.xml
Index: session.xml
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN"
"../../dtd/document-v10.dtd">
<document>
<header>
<title>Session Management</title>
<authors>
<person name="Carsten Ziegeler" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Introduction">
<note><strong>IMPORTANT:</strong> This document conforms to the
development version of Cocoon. So
you will only find these components in the current CVS. An early
alpha version is already
available in the latest release of Cocoon, you will find an
introduction <link href="sunshine.html">here</link>.
</note>
<p>A session is a data storage which resides on the server and records
information about one single user. Cocoon creates a session on demand
and
from that point of time the user is tracked and information can be
stored
inside the session. Each following request of this user is linked to
the one
specific session, so there is always only one session per user on the
server.</p>
<p>To avoid a fast growing amount of sessions on the server and the
overcome potential security problems, a session has usually a valid
period of
time. If during this period no new request comes in from the user,
the session
object on the server will be destroyed by the server (this period of
time is
called session timeout). The web application often allows a user to
explictly
destroy a session.</p>
<p>The usual web applications create sessions during login of a user and
destroy them when the user logs out.</p>
<p>This document describes the basic Cocoon session management using
the session transformer.</p>
<p>The chapter "Special Contexts" explains some special
contexts which do not require a session. They are available
everytime. These
special contexts are the request context, the response context and the
temporary context.</p>
</s1>
<s1 title="Session Tracking">
<p>If a user has a session, Cocoon is able to connect new requests from
this user
to the session of the user. This is done by session tracking.
Basically,
the session tracking of Cocoon uses the session tracking of the
environment,
which is usually the servlet engine.
</p>
<p>There are two methods for session tracking: cookies and url rewriting.
If you
use cookies, you don't have to care about session tracking. Just refer
to
the documentation of your servlet engine on how to turn on cookies for
session
handling.</p>
<p>URL rewriting instead is a little bit complicated. For url rewriting,
each link
the user can select, needs a special session ID appended to this link.
Unfortunately, this is not done automatically by Cocoon or the servlet
engine.
You can either do this by hand or you can use the <em>encodeURL</em>
transformer
just before the <em>html serializer</em>.
</p>
</s1>
<s1 title="Sessions">
<p>The session action is responsible for creating and
terminating a session. It is controlled by a sitemap parameter named
"action".
This parameter can have the values "create" and "terminate". If no
parameter is
set, it defaults to "create".</p>
<p>The action either creates a new session immediately (if not already
available), or terminates it (if available).</p>
</s1>
<s1 title="Contexts">
<s2 title="session Transformer">
<p>The session transformer is responsible for interpreting the tags
and performing the actions required. The session transformer is
configured
in the sitemap and can be used inside a document. All tags must be
prefixed
with the session namespace. So the actual tag used in the document
will read
<em><session:xxxx></em>. The current namespace URI for the
session
transformer is <em>"http://cocoon.apache.org/session/1.0"</em>.</p>
</s2>
<s2 title="Context-Tags">
<p>A context is basically an application specific block of XML data in
the users session. Each context has a unique name.</p>
<p>The command <em>createcontext</em> is used to create a new context.
A <em>name</em> attribute must be given to the context in order to
identify it.
The following names may not be used: request, response, session,
context, temp, portal or authentication. If a context of the same
name already exists
then this command will have no effect.</p>
<p><em><createcontext name="mycontext"/></em></p>
<p>In order to delete a context the command <em>deletecontext</em> is
provided. Again a <em>name</em> attribute must be provided.</p>
<p><em><deletecontext name="mycontext"/></em></p>
<p>Once created, XML data can then be stored inside or read from a
given context.</p>
</s2>
<s2 title="Accessing context data">
<p>The data in a context can be dynamically accessed using the
following commands.</p>
<p></p>
<p><em>getxml</em> allows data to be read out of a context. A
<em>path</em> attribute describes the source of the data inside the
context and
consists of an XPath expression. All <em>path</em> values must be
absolute and
only nodes and attributes can be accessed. </p>
<p>An optional default value can also be provided to allow for the
nonexistence of the requested data.</p>
<p><em><getxml context="mycontext"
path="/User/Name"/></em></p>
<p><em><getxml context="mycontext"
path="/User/Name">Matthew</getxml></em></p>
<p>Attributes can also be accessed.</p>
<p><em><getxml context="mycontext"
path="/User/Name/@Age"/></em></p>
<p><em></em></p>
<p>Data can be written into a context using the <em>setxml</em>
command. It is possible to set values or nodes as the following
examples
show.</p>
<p><em><setxml context="mycontext"
path="/User/Name"/>Carsten</setxml></em></p>
<p><em><setxml context="mycontext"
path="/User/"/><Name>Carsten</Name></setxml></em></p>
<p></p>
<p>Using the <em>setxml</em> command causes all the nodes below the
target node to be deleted. If you wish to maintain the nodes and
manipulate
individual branches of the XML tree - then the session transformer
offers the
<em>mergexml</em> command.</p>
<p></p>
<p>Use the <em>removexml</em> command to remove nodes from the
context.</p>
<p><em><removexml context="mycontext"
path="/User/"/></em></p>
<s3 title="Example">
<p>The following example shows the use of several commands and in
particular how the <em>mergexml</em> command can be used to
manipulate context
data.</p>
<source><resource
xmlns:session="http://cocoon.apache.org/session/1.0">
<session:createcontext name="trackdemo"/>
<!-- build context data -->
<session:setxml context="trackdemo" path="/">
<context>
<users>
<user id="1">
<name>Carsten</name>
</user>
</users>
</context>
</session:setxml>
<session:mergexml context="trackdemo" path="/context">
<users>
<user id="1">
<name>Ziegeler</name>
<developer>true</developer>
</user>
<user id="2">
<name>Walter</name>
</user>
</users>
</session:mergexml>
<session:getxml context="trackdemo" path="/"/>
</resource></source>
<p>In the above example, a context for storing data is added. Using
the <em>setxml</em> command data is then stored into the
context. The following
<em>mergexml</em> command then changes the name of user-1 and
adds a further
tag. As there is no original user-2 the complete subtree is then
added to the
context.</p>
</s3>
</s2>
<s2 title="Reading and writing contexts">
<p>Aside from the described means of accessing data in a context,
the session transformer also provides for the reading and writing
of contexts. This can be
used to write an application context out to a database or to read an
application context in from a file.</p>
<p>The session transformer offers a very flexible way of defining the
source of the
context data. It is possible to specify a resource (defined in the
sitemap) or
a Java class. Using a resource allows for example the context data
to be read
from a database using the SQL Transformer. As this source is a
Cocoon
pipeline, the data can be generated and transformed before passing
into the
context. </p>
<p>When a context is created, it can get additional save and load URIs
which are used for loading/saving to/from the context:</p>
<p><em><createcontext name="mycontext" load="cocoon://load-from-db"
save="cocoon://save-to-db"/></em></p>
<p>These URIs can then be used inside a document to load data into a
context:</p>
<p><em><loadxml context="mycontext"/></em></p>
<p>This example would then load the context data via the resource
<em>load-from-db</em> which must be defined in the sitemap.</p>
<p>Parameters can be passed to and interpreted by the uri or the Java
class. This allows the context data to be read dependent on say the
current
user.</p>
<p><em><loadxml
context="mycontext"><user>ben</user></loadxml></em></p>
<p>The resource addressed by the uri will receive the parameters as
request-parameters. In addition the name of the context will always
be passed
as <em>contextname</em>.</p>
<p>Writing context data works in the same manner.</p>
<p><em><savexml context="mycontext"/></em></p>
<p>Both commands can use the optional <em>path</em> attribute:</p>
<p><em><loadxml context="mycontext" path="/user"/></em></p>
<p><em><savexml context="mycotnext" path="/user"/></em></p>
<p>The first command will read xml from the uri and store it in the
context under the node <em>user</em>, the second one saves only the
xml subtree
under the node <em>user</em> to the uri. The resource addressed by
the uri will
be passed in addition to the <em>contextname</em> parameter the
<em>path</em>
parameter with the corresponding value. If the <em>path</em>
attribute is not
present the <em>path</em> parameter will get the value
<em>"/"</em>.</p>
</s2>
</s1>
<s1 title="Special Contexts">
<p>Cocoon creates and maintains special contexts that allow the
applications to access the environment data. This allows the
read-only access
to such things as the HttpRequest or the HtppResponse using the same
XPath
commands previously described. These context do not require any
session, they
are everytime available.</p>
<s2 title="The Request Context - Accessing the Environment, Part One">
<p>The request context is an XML description of the current
HttpRequest. This context is a special read only context which can
be accessed
with the usual commands:</p>
<p><em><getxml context="request" path="/parameter"/></em></p>
<p>If you for example want to get the value of a parameter with the
name <em>username</em> you can include the following command in
your XML and it
will be replaced with the value of the parameter:</p>
<p><em><getxml context="request"
path="/parameter/username"/></em></p>
<p>This command will be replaced with all parameters from the current
request in XML format. If you wish to obtain the complete
querystring as it was
passed into Cocoon - without converting the data to XML - then you
can use
the "/querystring" path:</p>
<p><em><getxml context="request"
path="/querystring"/></em></p>
<p>The result will be a string in the format
"?param=aaa&...".</p>
<p>The complete context you can access via these commands has the
following XML format:</p>
<source><parameter>
<!-- All parameters: parameter names build the elements with the values
as text node childs -->
<firstparameter>value of parameter</firstparameter>
<secondparameter>value of parameter</secondparameter>
</parameter>
<querystring>the querystring with a leading '?' or
empty<querystring>
(The querystring contains only parameters send by the GET method)
<parametervalues>
<!-- All parameters. The tags are all inside the session namespace.
The generated xml can be used without modification for the
session:connection command. -->
<session:params>
<session:param>
<session:name>1st parameter name</session:name>
<session:value>1st parameter value</session:value>
</session:param>
...
<session:param>
<session:name>2nd parameter name</session:name>
<session:value>2nd parameter value</session:value>
</session:param>
</session:params>
<!-- If a parameter has more than one value, for each value a
<session:param> block is generated. -->
</parametervalues>
<attributes>
<!-- lists all attributes, attribute names build the elements
with the values as text node childs -->
</attributes>
<headers>
<!-- lists all headers, header names build the elements
with the values as text node childs -->
</headers>
<cookies>
<!-- lists all cookies -->
<cookie name="...">
<value>the cookie value</value>
<name>the name of the cookie</name>
<comment>value</comment>
<domain>value</domain>
<path>value</path>
<maxAge>value</maxAge>
<secure>value</secure>
<version>value</version>
</cookie>
</cookies>
<characterEncoding>value</characterEncoding>
<contentLength>value</contentLength>
<contentType>value</contentType>
<protocol>value</protocol>
<remoteAddress>value</remoteAddress>
<remoteHost>value</remoteHost>
<scheme>value</scheme>
<serverName>value</serverName>
<serverPort>value</serverPort>
<authType>value</authType>
<method>value</method>
<contextPath>value</contextPath>
<pathInfo>value</pathInfo>
<pathTranslated>value</pathTranslated>
<remoteUser>value</remoteUser>
<requestedSessionId>value</requestedSessionId>
<requestURI>value</requestURI>
<servletPath>value</servletPath>
<isRequestedSessionIdFromCookie>value</isRequestedSessionIdFromCookie>
<isRequestedSessionIdFromCookie>value</isRequestedSessionIdFromCookie>
<isRequestedSessionIdValid>value</isRequestedSessionIdValid></source>
</s2>
<s2 title="The Response Context - Accessing the Environment, Part Two">
<p>The response context is an XML description of the current
HttpResponse. This context is a special write only context which
can be
accessed with the usual commands:</p>
<p><em><session:setxml context="response"
path="/header"/></em></p>
<p>This command will be removed from the XML and the information will
be added to the response. Using the response context headers and
cookies can be
added.</p>
<s3 title="Adding headers">
<p>Headers can be added either by <em>setxml</em> or by
<em>appendxml</em>. If <em>setxml</em> is used, the header with
the name gets
the given value, regardless if the header had any value
beforehand or not. If
<em>appendxml</em> is used the value will be added.</p>
<source><session:setxml context="response"
path="/header/headername">The value</session:setxml>
or
<session:appendxml context="response" path="/header/headername">The
value</session:appendxml></source>
</s3>
<s3 title="Adding cookies">
<p>Cookies can be added either by setxml or by appendxml. There is
no difference between these commands.</p>
<source><session:setxml context="response" path="/cookie">
<!-- Now follows the cookie definition -->
<name>The cookie name</name>
<value>The value of the cookie</value>
<!-- The following are optional -->
<path>value</path>
<domain>value</domain>
<secure>true or false</secure>
<comment>value</comment>
<maxAge>value</maxAge>
<version>value</version>
</session:setxml></source>
</s3>
</s2>
<s2 title="The Temporary Context">
<p>The temporary context with the name <em>"temp"</em> is available on
each request. It is independent from the session and has no content
when a new
request starts. It can be used like any other context except that
the content
is lost when the current response is finished.</p>
<p>Using the tempory context it is possible to use store any xml
information for processing the current request.</p>
</s2>
</s1>
<s1 title="Form Handling">
<p>To get feedback or information from a user, forms are commonly used
to present input field in the browser. The usual approach for form
handling in
web application consists of two steps. The first request presents the
form to
the user. This form initiates a second request that processes the form
values.</p>
<p>Cocoon supports this two step process, in addition Cocoon offers
a single step approach.</p>
<s2 title="The common approach">
<p>The common approach consists of two steps or of creating two
resources. The first resource defines the form: All input fields
are declared,
each gets a unique name. This form invokes the second resource.</p>
<p>This resource uses the session transformer to get the values
provided by the user. The values are added by the browser to the
parameters of
the request. So using the request context and <em>getxml</em>, the
values can
be fetched.</p>
<p>If you want to create a form with two values - forename and surname
of the user, you could generate a base xml file with the
information about this
form:</p>
<source><page>
<form>
<action>form-handling-page</action>
<input name="forename" type="text"/>
<input name="surname" type="text"/>
</form>
</page></source>
<p>A stylesheet can transform this into valid html. The action tag
indicates that the "form-handling-page" should be invoked by
submitting the
values.</p>
<p>The "form-handling-page" is a pipeline which is declared in the
sitemap and uses the session transformer. It could also read the
following
xml:</p>
<source><page
xmlns:session="http://cocoon.apache.org/session/1.0">
<forename>
<session:getxml context="request" path="/parameter/forename"/>
</forename>
<surname>
<session:getxml context="request" path="/parameter/surname"/>
</surname>
</page></source>
<p>As the form values are appended to the request, <em>getxml</em>
with specifying the path (which is the parameter name used for the
input field)
inserts the value submitted by the user into the xml stream.</p>
<p>If you want to write the information in a session context, you must
wrap the whole xml inside a setxml:</p>
<source><page
xmlns:session="http://cocoon.apache.org/session/1.0">
<session:setxml context="userdata" path="/user">
<forename>
<session:getxml context="request" path="/parameter/forename"/>
</forename>
<surname>
<session:getxml context="request" path="/parameter/surname"/>
</surname>
</session:setxml>
</page></source>
<p>The user data is now stored inside the session context "userdata",
so the context has the following content:</p>
<source><user>
<forename>Walter</forename>
<surname>Walterson</surname>
</user></source>
</s2>
<s2 title="The Session Framework approach">
<p>The previous chapter showed the common approach for handling form
values. It forces the user to create two resources for a single form
handling.</p>
<p>Cocoon offers an advanced approach. Only one single resource is
created. This resources contains the information about the input
fields used
and in addition the information about where the submitted values
should be
stored inside the session.</p>
<p>The example from the previous chapter could look like this:</p>
<source><page
xmlns:session="http://cocoon.apache.org/session/1.0">
<session:form name="myform">
<session:action>the-next-page</session:action>
<session:content>
<session:inputxml name="forename" type="text" context="userdata"
path="/user/forename"/>
<session:inputxml name="surname" type="text" context="userdata"
path="/user/surname"/>
</session:content>
</session:form>
</page></source>
<p>The form tag starts the form definition. The name attribute is
required to distinct between different forms on the same page. The
action tag
defines the url invoked by the form and the content tag describes
the content
of the form: its input fields.</p>
<p>The <em>inputxml</em> tag tells Cocoon that the following request
contains form values which should be stored in the specified
context under the
given path. The session transformer transforms by removing the
namespace and
the context attribute:</p>
<source><page
xmlns:session="http://cocoon.apache.org/session/1.0">
<form action="the-next-page">
<inputxml name="forename" type="text"/>
<inputxml name="surname" type="text"/>
</form>
</page></source>
<p>A stylesheet can now generate the appropriate html (or any other
format). The main difference is, that the resource invoked by
submitting the
values has not to care about the form as Cocoon maintains the form
handling.
The only prerequisit is that a session for the current user and a
session
context to store the information exists.</p>
<p>The Cocoon approach allows a very easy way of form handling where
the resource which creates the form also handles the form.</p>
<p>For editing values - if the context already contains information
about the user - <em>inputxml</em> inserts the current value inside
the tag. So
the xml streamed would after a second run would look like this:</p>
<source><page
xmlns:session="http://cocoon.apache.org/session/1.0">
<form action="the-next-page">
<inputxml name="forename" type="text">Walter</inputxml>
<inputxml name="surname" type="text">Walterson</inputxml>
</form>
</page></source>
<p>Like <em>getxml</em> it is also possible to provide default values
for the input field, if the context does not contain any
information:</p>
<source><session:inputxml name="forename" context="userdata"
path="/user/forename">
Defaultname
</session:inputxml></source>
</s2>
</s1>
</body>
</document>
1.1
xml-cocoon2/src/documentation/xdocs/developing/webapps/sunrise.xml
Index: sunrise.xml
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN"
"../../dtd/document-v10.dtd">
<document>
<header>
<title>sunRise Documentation</title>
<authors>
<person name="Carsten Ziegeler" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Introduction">
<note><strong>IMPORTANT:</strong> sunRise (= authentication framework) is
part of the scratchpad area
of the current Cocoon
release. This means it is not officially released yet. The API and
functionality might change
before it is moved into the official release. Using this is at your
own risk!
If you want to catch the latest status of these components check out
Cocoon
from CVS and have a look at this <link
href="authentication.html">upto-date documentation</link>.
</note>
<p>The central point for building a web application is sunRise. It is a
flexible module for authentication and user management. A user can be
legitimated using any information available via any source, e.g. a
database or
LDAP. With this mechanism it is very easy and fast to use an
exisiting user
management/authentication system.</p>
</s1>
<s1 title="Sitemap-Components">
<p>sunRise adds some actions to the sitemap: the <en>sunRise-auth</en>
action, the <en>sunRise-login</en> action, the
<en>sunRise-logout</en> action
and the <en>sunRise-loggedIn</en> action. The <en>sunRise-auth</en>
action gets
the configuration for sunRise and controlles the pipelines. The
<en>sunRise-login</en> and the <en>sunRise-logout</en> action control
the
authentication the <en>sunRiseLoggedIn</en> action controlles the
application
flow.</p>
<p>The use of sunRise and its components is described in the following
chapters.</p>
</s1>
<s1 title="User Authentication">
<p>One feature of sunRise is the user authentication. A resource can be
accessible for everyone or it can be protected using sunRise. The
process of
requesting a resource can be described as follows:</p>
<ol>
<li>The user request a resource (original resource).
</li>
<li>sunRise checks if this resource is protected. If no protection
is specified, the response to the request is this original resource.
</li>
<li>The resource is protected and sunRise checks, if the user is
authenticated to view it.
</li>
<li>If the user is authenticated, the response is the original
resource. If not sunRise redirects to a special redirect-to
resource. This
redirect-to resource is freely configurable and can for example
contain
information about the unauthorized access and in addition a login
form.
</li>
<li>Using the login form an authentication resource can be called
with the corresponding user information (e.g. user id and
password). This
authentication resource uses sunRise for the authentication process.
</li>
<li>In case of a successful authentication sunRise can redirect to
the original resource (or to any configured start resource).
</li>
<li>If the authentication failed another resource is invoked by
sunRise displaying information to the user.
</li>
</ol>
<p>This process is only one example for a use-case of sunRise. sunRise
can be configured for any authentication scheme. All resources are
freely
configurable.</p>
<s2 title="The sunRise handler">
<p>The basic object for authentication in sunRise is the sunRise
handler. It controlles the access to the resources. Each resource
in the
sitemap can be related to exactly one sunRise handler. All
resources belonging
to the same handler are protected in the same way. If a user has
access to the
handler, the user has the same access rights for all resouces of
this
handler.</p>
<p>Each sunRise handler needs the following mandatory
configuration:</p>
<ul>
<li>A unique name.
</li>
<li>The authentication resource which does the real
authentication.
</li>
<li>The redirect-to resource where sunRise redirects to for any
unauthorized request.
</li>
</ul>
<p>Using a unique name for each handler (only alphabetical characters
and digits are allowed for the handler name), sunRise manages
different
handlers. So various parts of the sitemap can be protected in
different ways. A
resource can be protected by calling this handler using the
sunRise-auth
action. The "sunRise-auth" action must be included in the pipeline
of the
resource. It gets the handler information as a parameter:</p>
<source> <map:match pattern="protectedresource">
<map:act type="sunRise-auth">
<map:parameter name="handler" value="unique handler name"/>
<map:generate src="source/resource.xml"/>
</map:act>
...
</map:match>
</source>
<p>If the pipeline does not use the "sunRise-auth" action or the
parameter "handler" is missing, the resource is accessible by any
user.</p>
</s2>
<s2 title="The redirect-to resource">
<p>If the requested resource is not accessible for the user, sunRise
redirects to a special redirect-to resource. This resource is a
mandatory
configuration of the sunRise handler:</p>
<source><action name="sunRise-auth" ...>
<handlers> <!-- Now follows the handlers configuration -->
<handler name="unique">
<redirect-to uri="cocoon://loginpage"/> <!-- The login
resource -->
</handler>
</handlers>
</action>
</source>
<p>This redirect-to resource is an unprotected resource in the
sitemap. For tracking which resource was requested, the redirect-to
resource
gets the request parameter "resource" with the value. In addition
all
parameters specified inside the <en>redirect-to</en> tag of the
handler
configuration are passed to the resource.</p>
<p>This redirect-to resource can contain a form for the user
authentication. This form should invoke the real login resource
which is
described below.</p>
<p>The authentication process is done by the "sunRise-login" action.
The login resource contains this action: </p>
<source> <map:match pattern="login">
<map:act type="sunRise-login">
<map:parameter name="handler" value="unique"/>
<map:parameter name="parameter_userid"
value="request:name"/>
<map:parameter name="parameter_password"
value="request:password"/>
<map:redirect-to uri="authentication-successful"/>
</map:act>
<!-- authentication failed: -->
<map:generate src="auth_failed.xml"/>
<map:transform src="tohtml.xsl"/>
<map:serialize/>
</map:match></source>
<p>The "sunRise-auth" action uses the handler parameter to call the
authentication resource of this handler. This authentication
resource needs to
know the information provided by the user. For each piece of
information an own
parameter is created which name starts with "parameter_". So in the
example
above, the authentication resource gets two parameters: userid and
password. As
the values for these parameters were send by a form they need to be
passed on
to the authentication resource. If you use "request:..." for the
value of a
parameter, the sunRise-login action will pass the actual value of
that request
parameter to the authentication resource.</p>
<p>If the user is not authenticated with this handler, sunRise calls
the authentication resource and passes it the parameters. If this
authentication is successful, the action returns an empty map and
the sitemap
commands inside the map:act are executed. If the authentication
fails, these
are skipped.</p>
<p>If the authentication is successful, a session object is created on
the server (if not already done). </p>
</s2>
<s2 title="The authentication resource">
<p>The last chapters described the authentication process but left out
details about the authentication itself. This chapter closes this
gap.</p>
<p>The authentication can be done by different components:</p>
<ul>
<li>A sitemap resource.
</li>
<li>A distant resource, e.g. requested via HTTP.
</li>
<li>A java class.
</li>
</ul>
<p>Using this flexible approach nearly any kind of authentication is
possible (e.g. database, LDAP). The authentication resource is
another
mandatory configuration of the sunRise handler:</p>
<source><action name="sunRise" ...>
<handlers> <!-- Now follows the handlers configuration -->
<handler name="unique">
<redirect-to uri="cocoon:raw://loginpage"/> <!-- The
login resource -->
<authentication uri="cocoon:raw://authenticationresource"/>
</handler>
</handlers>
</action></source>
<p>If the authentication resource is a sitemap resource or a remote
resource, this resource is requested by sunRise with the given
parameters from
the <en>sunRise-login</en> action (see previous chapter:
parameters: userid and
password). In addition all parameters inside the
<en>authentication</en> tag of
the handler configuration are passed to the resource. The response
for this
resource must contain valid XML conforming to the following
scheme:</p>
<source><authentication>
<ID>value</ID>
<role>rolename</role> <!-- optional -->
<data>
... resource specific data for the user
</data>
</authentication></source>
<p>sunRise checks the response of the authentication resource for the
given scheme: the root node must be named "authentication" and one
child called
"ID" must be present. In this case the authentication is
successfull and
sunRise creates a sunRise session context and stores the XML
inside. </p>
<p>The mandatory information inside this XML scheme, the "ID" tag, is
an unique identification for the given user inside the web
application. The
"role" is optional and can for example be used for categorizing
users and
displaying different functionality inside sunSpot (the sunShine
portal
engine).</p>
<p>Using the "data" node the authentication resource can pass any
information of the user into the session object.</p>
<p>If the authentication is not successful, the resource must create
an XML with the root node "authentication". In addition a "data"
node can be
added containing more information about the unsuccessful attempt.
This data
node is then added inside the "login" tag of the login resource
(see previous
chapter).</p>
</s2>
<s2 title="Logging out">
<p>The logout process is triggered by the "sunRise-logout"
action:</p>
<source><map:act type="sunRise-logout">
<map:parameter name="handler" value="unique"/>
</map:act></source>
<p>This action logs the user out of the given handler and removes all
information about this handler stored in the session.</p>
</s2>
<s2 title="Working With subsitemaps">
<p>The common solution for sunRise and subsitemaps is to define the
handler (and therefore the sunRise action) in the main sitemap. The
resources
in the subsitemap are then simply protected in the same way as if
the action
were declared in the main sitemap. This makes moving resources from
one sitemap
to the other very simple.</p>
<p><Strong>However, there is one drawback with this solution. After
you have started your server, make sure that first a resource using
sunRise
from the main sitemap is invoked, before any of the
subsitemap!</Strong></p>
</s2>
</s1>
<s1 title="User Management">
<p>In addition to the authentication sunRise manages all kinds of
information belonging to the user in XML format. For this reason
sunRise
creates an own session context called sunRise. All information is
stored in
this context.</p>
<p>The authentication information (the "authentication" scheme retrieved
from the authentication resource) is stored in this context, so you
can
retrieve and change the information using the sunShine transformer
and the
usual getxml, setxml etc. commands, so we suggest you to read the
sunShine
context document.</p>
<s2 title="Getting information from the context">
<p>Each information from within the context is gettable using an XML
tag:</p>
<source><sunshine:getxml context="sunRise"
path="/authentication/ID"/> <!-- Get the ID -->
<sunshine:getxml context="sunRise"
path="/authentication/data/username"/></source>
<p>The path expression is an absolute XPath-like expression where only
concrete nodes and attributes are allowed. The sunShine transformer
replaced
the tag with the value of the first node found in the context, this
can either
be text or XML.</p>
</s2>
<s2 title="Setting information in the context">
<p>Using another tag information can be stored into the
context:</p>
<source><sunshine:setxml context="sunRise"
path="/authentication/data/usersername">
Mr. Sunshine
</sunshine:setxml></source>
<p>Again the path is an absolute XPath-like expression where only
concrete nodes and attributes are allowed. If the requested node
exists,
sunRise changes the value of that node. If the node does not
exists, sunRise
adds it to the context with the given value.</p>
<p>The tag is removed from the resource.</p>
</s2>
</s1>
<s1 title="Application Management">
<p>A very useful feature for building and maintaining web applications
is the application management of sunRise. It allows to configure
different
applications and to manage the user data for these applications.</p>
<s2 title="Configuring an Application">
<p>A "sunRise" application is related to one sunRise handler, so an
application is part of the sunRise handler configuration:</p>
<source><action name="sunRise" ...>
<handlers>
<handler name="unique">
....redirect-to/authentication configuration
<applications> <!-- the applications for this handler
-->
<application name="unique">
<load uri="loadapp"/> <!-- optional -->
<save uri="saveapp"/> <!-- optional -->
</application>
</applications>
</handler>
</handlers>
</action></source>
<p>A configuration for an application consists of a unique name (only
alphabetical characters and digits are allowed for the application
name) and
optional load and save resources. The application configuration can
contain
application specific configuration values for the various parts of
the
application, e.g. information for a portal.</p>
<p>On a successful authentication sunRise invokes for each application
of the handler the load resource (if present). The content or
result of the
load resource is stored into the session context.</p>
<p>The user does not always visit all sides or all applications at
once. So it is not necessary to load all applications in advance
when not all
information is needed. Each application can specify if the data is
loaded on
successful authentication or the first time needed:</p>
<source>....<application name="unique"
loadondemand="true"/>...</source>
<p>The load resource gets several parameters: all values of the
subnodes of the "authentication" node from the sunRise context
(e.g. ID, role
etc.) and the parameter "application" with the unique name of the
application.
This unique name must not contain one of the characters '_', ':' or
'/'.</p>
<p>In addition the load and save resource get all parameters specified
inside the load / save tag of the handler configuration.</p>
</s2>
<s2 title="Configuring the resources">
<p>For managing the application sunRise needs to know to which
application a resource belongs. So in addition to the handler
parameter the
sunRise action gets the application name as a second parameter:</p>
<source> <map:match pattern="protectedresource">
<map:action type="sunRise-auth">
<map:parameter name="handler" value="unique handler name"/>
<map:parameter name="application" value="unique application
name"/>
<map:generate src="source/resource.xml"/>
...
</map:action>
</map:match></source>
<p>With this mechanism each application resource can easily access its
and only its information. If a resource has no "application"
parameter it can
not access information of any application.</p>
</s2>
<s2 title="Getting, setting and saving application information">
<p>Analogue to the access of the authentication data a resource can
access its application data:</p>
<source><sunshine:getxml context="sunRise"
path="/application/username"/>
<sunshine:setxml context="sunRise"
path="/application/shoppingcart"><item1/><item2/></sunRise:setxml></source>
<p>The path underlies the same restrictions and rules as always, but
it has to start with "/application/". </p>
</s2>
</s1>
<s1 title="Module Management">
<p>In addition to the application management sunRise offers a facility
called module management. It enhances the application management by
the
possibility to configure components for the application. For example
sunSpot is
the sunShine portal engine. It needs information about where the
portal profile
for the user is retrieved from, where the layout is stored etc. Now
each portal
needs this information. Assuming that a portal is an application each
application needs this sunSpot information. As only sunSpot itself
knows what
information it needs, the module management is a standarized way for
configuring such components.</p>
<p>The module configuration is part of the application
configuration:</p>
<source><action name="sunRise" ...>
<handlers>
<handler name="unique">
....redirect-to/authentication configuration
<applications> <!-- the applications for this handler
-->
<application name="unique">
...
<configuration name="sunSpot">
...sunSpot configuration
</configuration>
</application>
</applications>
</handler>
</handlers>
</action></source>
<p>So whenever the module sunSpot is asked to build the portal it can
easily retrieve its configuration from the current application by
getting the
module configuration named "sunSpot".</p>
</s1>
<s1 title="sunRise User Administration">
<p>Using sunRise it is possible to add new roles to the system and to
add new users. For this purpose, there are several optional entries
for the
sunRise handler which provide the needed functionality:</p>
<source><action name="sunRise" ...>
<handlers>
<handler name="unique">
...redirect-to/authentication configuration...
<!-- Optional resource for loading user information -->
<load-users
uri="cocoon:raw://financeresource-sunrise-loaduser"/>
<!-- Optional resource for loading roles information-->
<load-roles
uri="cocoon:raw://financeresource-sunrise-roles"/>
<!-- Optional resource for creating a new user -->
<new-user
uri="cocoon:raw://financeresource-sunrise-newuser"/>
<!-- Optional resource for creating a new role -->
<new-role
uri="cocoon:raw://financeresource-sunrise-newrole"/>
<!-- Optional resource for changing user information -->
<change-user
uri="cocoon:raw://financeresource-sunrise-newuser"/>
<!-- Optional resource for deleting a role -->
<delete-role
uri="cocoon:raw://financeresource-sunrise-delrole"/>
<!-- Optional resource for deleting a user-->
<delete-user
uri="cocoon:raw://financeresource-sunrise-deluser"/>
</handler>
</handlers>
</action></source>
<p>The entries are described in the following subchapters. All tags can
have additional parameter definitions which are passed to the given
resource,
e.g:</p>
<source><!-- Optional resource for deleting a user-->
<delete-user uri="cocoon:raw://financeresource-sunrise-deluser">
<connection>database</connection>
<url>db:usertable</url>
</delete-user></source>
<s2 title="Getting Roles">
<p>The <en>load-roles</en> resource is invoked from sunRise whenever
it needs information about the available roles. This resource gets
the
parameter "type" with the value "roles" and should deliver an XML
schema with
the root node "roles" and for each role a subelement "role" with a
text child
of the rolename:</p>
<source><roles>
<role>admin</role>
<role>guest</role>
<role>user</role>
</roles></source>
</s2>
<s2 title="Getting Users">
<p>The <en>load-users</en> resource is called whenever information
about the available users is needed. There are three different uses
of this
resource:</p>
<ul>
<il>Loading all users: The resource gets the parameter "type"
with the value "users". It should then deliver all users in the
system.
</il>
<il>Loading all users of one role. The resource gets the
parameters "type" with the value "users" and "role" with the
rolename.
</il>
<il>Load information of one user. The resource gets the
parameters "type" with the value "user", "role" with the
rolename and "ID" with
the sunRise ID of the user.
</il>
</ul>
<p>The XML format of the resource should look like the
following:</p>
<source><users>
<user>
<ID>sunRise ID</ID>
<role>rolename</role>
<data> ... application specific data ... </data>
</user>
<user>
...
</user>
...
</users></source>
</s2>
<s2 title="Creating a new role">
<p>The <en>new-role</en> resource creates a new role in the system. It
gets the parameters "type" with the value "role" and "role" with
the new
rolename.</p>
</s2>
<s2 title="Creating a new user">
<p>The <en>new-user</en> resource creates a new user with a role. It
gets the parameters <en>"type"</en> with the value <en>"user"</en>,
<en>"role"</en> with the rolename and <en>"ID"</en> with the new ID
for this
user.</p>
<p>The sunrise transformer offers a tag to create a newuser:
<en>"adduser"</en>. The input for this element is all information
needed to add
a user including the ID and the role. All these values are then
passed on to
the <en>"new-user"</en> resource:</p>
<source><adduser>
<ID>New ID for this user</ID>
<role>The role</role>
<!-- and now application specific information in the following form:
<name_of_the_information>value</name_of_the_information>
-->
<firstname>x</firstname>
<lastname>y</lastname>
...
</adduser></source>
<p>In the example above a sunRise tries to create a new user with the
given <en>"ID"</en> and <en>"role"</en>. The <en>"new-user"</en>
resource gets
also the parameters <en>"firstname"</en> and <en>"lastname"</en>
with the
values <en>"X"</en> and <en>"Y"</en>.</p>
<p>If no user with this ID exists the "sunrise:adduser" element is
replaced with the element "success". Inside this element all the
values are
repeated inside the "values" element:</p>
<source><success>
<values>
<ID>New ID for this user</ID>
<role>The role</role>
<firstname>x</firstname>
<lastname>y</lastname>
</values>
</success></source>
<p>If a user already exists with this ID the response looks like
this:</p>
<source><error>
<id-exists/>
<values>
<ID>New ID for this user</ID>
<role>The role</role>
<firstname>x</firstname>
<lastname>y</lastname>
</values>
</error></source>
<p>If an error occurs the response is this:</p>
<source><error>
<exception/>
<values>
<ID>New ID for this user</ID>
<role>The role</role>
<firstname>x</firstname>
<lastname>y</lastname>
</values>
</error></source>
</s2>
<s2 title="Changing information of a user">
<p>The <en>change-user</en> resources changes information of a user.
It gets the parameters "type" with the value "user", "role" with
the rolename
and "ID" with the ID of the user. In addition all - application
specific -
information of this user is send as parameters.</p>
</s2>
<s2 title="Delete a user">
<p>The <en>delete-user</en> resource should delete a user. It gets the
parameters "type" with the value "user", "role" with the rolename
and "ID" with
the ID of the user.</p>
</s2>
<s2 title="Delete a role">
<p>The <en>delete-role</en> resources deletes a role. It gets the
parameters "type" with the value "role" and "role" with the
rolename .</p>
</s2>
</s1>
<s1 title="sunRise Configuration Summary">
<p>Here is a brief summary of the sunRise handler configuration: </p>
<source><action name="sunRise" ...>
<handlers>
<handler name="unique">
<redirect-to uri="cocoon:raw://loginpage"/> <!-- The
redirect-to resource -->
<!-- Authentication resource -->
<authentication uri="cocoon:raw://authenticationresource">
<!-- optional parameters -->
</load>
<!-- optional save resource -->
<save uri="cocoon:raw://authenticationsaveresource">
<!-- optional parameters -->
</save>
<applications> <!-- the applications for this handler
-->
<application name="unique">
<!-- Loading/Saving -->
<load uri="cocoon:raw://loadapp"> <!-- optional
-->
<!-- optional parameters -->
</load>
<save uri="cocoon:raw://saveapp"> <!-- optional
-->
<!-- optional parameters -->
</save>
<!-- module
configurations: -->
<configuration name="sunSpot">
...sunSpot configuration
</configuration>
</application>
</applications>
</handler>
</handlers>
</action></source>
</s1>
<s1 title="Pipeline Patterns">
<p>As explained in the previous chapters, sunRise uses the sunRise
action for authentication and protecting resources. This chapter
shows some
common used patterns of the pipelines for using sunRise.</p>
<s2 title="Single protected resource">
<p>For protecting a resource with a sunRise handler only the sunRise
action with the parameter configuration for the handler is
required.</p>
<p>Pattern:</p>
<ol>
<li>Pipeline matching
</li>
<li>Using the sunRise-auth action for protecting
</li>
</ol>
<p>Example:</p>
<source><map:match pattern="protected">
<map:act type="sunRise-auth"> <!-- protect the resource -->
<map:parameter name="handler" value="myhandler"/>
<map:generate src="resource.xml"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:act>
</map:match></source>
<p>It is very important that the sunRise action wrapps the real
pipeline, as the pipeline is only invoked if the action grants
access. The
matching must be done before the action is checked as the action
performs a
redirect for this resource.</p>
</s2>
<s2 title="Multiple protected resources">
<p>Often you want to protect a bunch of resources in the same way. One
solution is to use the single protected resource pattern for each
resource.
With the multiple protected resource pattern you only have to use
the action
once for all resources and not within each resource.</p>
<p>The prerequisite for this is a common pattern for the
resources:</p>
<ol>
<li>Pipeline pattern matching
</li>
<li>Using the sunRise action for protection
</li>
<li>Pipeline matching
</li>
</ol>
<p>Example:</p>
<source><map:match pattern="protected-*">
<map:act type="sunRise-auth"> <!-- protect the resource -->
<map:parameter name="handler" value="myhandler"/>
<map:match pattern="protected-first">
<map:generate src="resource1.xml"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:match>
....
<map:match pattern="protected-second">
<map:generate src="resource2.xml"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:match>
</map:act>
</map:match></source>
<p>Very important - as explained with the single resource pattern - is
the leading match before the action is performed. The second match
is required
to check which pipeline to use.</p>
</s2>
<s2 title="Controlling the Application Flow">
<p>If you want to create resources which behave different wheather you
are logged in or not, the <en>sunRiseLoggedIn</en> action is the
component to
controll your application flow. This action checks if the user is
authenticated
for a given handler and calls all sitemap components inside the
<en>act</en>
tag.</p>
<source><map:match pattern="startpage">
<map:act type="sunRise-loggedIn"> <!-- check authentication
-->
<map:parameter name="handler" value="myhandler"/>
<map:redirect-to uri="loggedInStartPage"/>
</map:act>
<map:generate src="startpage.xml"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:match></source>
<p>In the example above, if the user is already logged he is
redirected to the <en>loggedInStartPage</en> resource. If he is not
logged in
for the given handler, the usual start page is generated.</p>
<p>Both actions, the <en>sunRise-auth</en> and the
<en>sunRise-loggedIn</en> action return - if the user is logged in
for the
given handler - all values from the context to the sitemap, e.g.
ID, role etc.
These values can be used within the other components:</p>
<source><map:match pattern"protected">
<map:act type="sunRise-auth"> <!-- protect the resource -->
<map:parameter name="handler" value="myhandler"/>
<!-- Append the ID of the user to the file name -->
<map:generate src="resource_{ID}.xml"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:act>
</map:match></source>
<p>But the sunRise-loggedIn action does not give the included pipeline
access to the sunRise context belonging to the handler. If you want
this, you
have to nest the sunRise action inside!</p>
<source><map:match pattern"start">
<map:act type="sunRise-loggedIn"> <!-- check authentication
-->
<map:parameter name="handler" value="myhandler"/>
<map:act type="sunRise-auth"> <!-- give access to the
context -->
<map:parameter name="handler" value="myhandler"/>
<map:generate src="getinfofromcontext.xml"/>
<map:transform src="sunRise"/>
<map:transform src="toHTML"/>
<map:serialize/>
</map:act>
</map:act>
</map:match></source>
</s2>
</s1>
</body>
</document>
1.1
xml-cocoon2/src/documentation/xdocs/developing/webapps/sunshine.xml
Index: sunshine.xml
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN"
"../../dtd/document-v10.dtd">
<document>
<header>
<title>sunShine Session Management</title>
<authors>
<person name="Carsten Ziegeler" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Introduction">
<note><strong>IMPORTANT:</strong> sunShine (= session framework) is part
of the scratchpad area
of the current Cocoon
release. This means it is not officially released yet. The API and
functionality might change
before it is moved into the official release. Using this is at your
own risk!
If you want to catch the latest status of these components check out
Cocoon
from CVS and have a look at this <link href="session.html">upto-date
documentation</link>.
</note>
<p>A session is a data storage which resides on the server and records
information about one single user. sunShine creates a session on
demand and
from that point of time the user is tracked and information can be
stored
inside the session. Each following request of this user is linked to
the one
specific session, so there is always only one session per user on the
server.</p>
<p>To avoid a fast growing amount of sessions on the server and the
overcome potential security problems, a session has usually a valid
period of
time. If during this period no new request comes in from the user,
the session
object on the server will be destroyed by the server (this time
period is
called session timeout). The web application often allows a user to
explictly
destroy a session.</p>
<p>The usual web applications create sessions during login of a user and
destroy them when the user logs out.</p>
<p>This document describes the basic sunShine session management using
the sunShine Transformer.</p>
<p>The chapter "Special Contexts" explains some special sunShine
contexts which do not require a session. They are available
everytime. These
special contexts are the request context, the response context and the
temporary context.</p>
</s1>
<s1 title="Sessions">
<p>The sunShine-session actions is responsible for creating and
terminating a session. It is controlled by a sitemap parameter named
"action".
This parameter can have the values "create" and "terminate". If no
parameter is
set, it defaults to "create".</p>
<p>The action either creates a new session immediately (if not already
available), or terminates it (if available).</p>
</s1>
<s1 title="Contexts">
<s2 title="sunShine Transformer">
<p>The sunShine transformer is responsible for interpreting the tags
and performing the actions required. The sunShine transformer is
configured
into the sitemap and can be used inside a document. All tags must
be prefixed
with the sunShine namespace. So the actual tag used in the document
will read
<em><sunshine:xxxx></em>. The current namespace URI for
sunShine is
<em>"http://cocoon.apache.org/sunshine/1.0"</em>.</p>
</s2>
<s2 title="Context-Tags">
<p>A context is basically an application specific block of XML data in
the users session. Each context has a unique name.</p>
<p>The command <em>createcontext</em> is used to create a new context.
A <em>name</em> attribute must be given to the context in order to
identify it.
The following names may not be used: sunShine, request, response,
session,
context, temp, sunSpot or sunRise. If a context of the same name
already exists
then this command will have no effect.</p>
<p><em><createcontext name="mycontext"/></em></p>
<p>In order to delete a context the command <em>deletecontext</em> is
provided. Again a <em>name</em> attribute must be provided.</p>
<p><em><deletecontext name="mycontext"/></em></p>
<p>Once created, XML data can then be stored inside or read from a
given context.</p>
</s2>
<s2 title="Accessing context data">
<p>The data in a context can be dynamically accessed using the
following commands.</p>
<p></p>
<p><em>getxml</em> allows data to be read out of a context. A
<em>path</em> attribute describes the source of the data inside the
context and
consists of an XPath expression. All <em>path</em> values must be
absolute and
only nodes and attributes can be accessed. </p>
<p>An optional default value can also be provided to allow for the
nonexistence of the requested data.</p>
<p><em><getxml context="mycontext"
path="/User/Name"/></em></p>
<p><em><getxml context="mycontext"
path="/User/Name">Matthew</getxml></em></p>
<p>Attributes can also be accessed.</p>
<p><em><getxml context="mycontext"
path="/User/Name/@Age"/></em></p>
<p><em></em></p>
<p>Data can be written into a context using the <em>setxml</em>
command. It is possible to set values or nodes as the following
examples
show.</p>
<p><em><setxml context="mycontext"
path="/User/Name"/>Carsten</setxml></em></p>
<p><em><setxml context="mycontext"
path="/User/"/><Name>Carsten</Name></setxml></em></p>
<p></p>
<p>Using the <em>setxml</em> command causes all the nodes below the
target node to be deleted. If you wish to maintain the nodes and
manipulate
individual branches of the XML tree - then sunShine offers the
<em>mergexml</em> command.</p>
<p></p>
<p>Use the <em>removexml</em> command to remove nodes from the
context.</p>
<p><em><removexml context="mycontext"
path="/User/"/></em></p>
<s3 title="Example">
<p>The following example shows the use of several commands and in
particular how the <em>mergexml</em> command can be used to
manipulate context
data.</p>
<source>
<resource xmlns:sunshine="http://cocoon.apache.org/sunshine/1.0">
<sunshine:createcontext name="trackdemo"/>
<!-- build context data -->
<sunshine:setxml context="trackdemo" path="/">
<context>
<users>
<user id="1">
<name>Carsten</name>
</user>
</users>
</context>
</sunshine:setxml>
<sunshine:mergexml context="trackdemo" path="/context">
<users>
<user id="1">
<name>Ziegeler</name>
<developer>true</developer>
</user>
<user id="2">
<name>Walter</name>
</user>
</users>
</sunshine:mergexml>
<sunshine:getxml context="trackdemo" path="/"/>
</resource></source>
<p>In the above example, a context for storing data is added. Using
the <em>setxml</em> command data is then stored into the
context. The following
<em>mergexml</em> command then changes the name of user-1 and
adds a further
tag. As there is no original user-2 the complete subtree is then
added to the
context.</p>
</s3>
</s2>
<s2 title="Reading and writing contexts">
<p>Aside from the described means of accessing data in a context,
sunShine also provides for the reading and writing of contexts.
This can be
used to write an application context out to a database or to read an
application context in from a file.</p>
<p>sunShine offers a very flexible way of defining the source of the
context data. It is possible to specify a resource (defined in the
sitemap) or
a Java class. Using a resource allows for example the context data
to be read
from a database using the SQL Transformer. As this source is a
sunShine
resource, the data can be generated and transformed before passing
into the
context. </p>
<p>When a context is created, it can get additional save and load URIs
which are used for loading/saving to/from the context:</p>
<p><em><createcontext name="mycontext" load="cocoon://load-from-db"
save="cocoon://save-to-db"/></em></p>
<p>These URIs can then be used inside a document to load data into a
context:</p>
<p><em><loadxml context="mycontext"/></em></p>
<p>This example would then load the context data via the resource
<em>load-from-db</em> which must be defined in the sitemap.</p>
<p>Parameters can be passed to and interpreted by the uri or the Java
class. This allows the context data to be read dependent on say the
current
user.</p>
<p><em><loadxml
context="mycontext"><user>ben</user></loadxml></em></p>
<p>The resource addressed by the uri will receive the parameters as
request-parameters. In addition the name of the context will always
be passed
as <em>contextname</em>.</p>
<p>Writing context data works in the same manner.</p>
<p><em><savexml context="mycontext"/></em></p>
<p>Both commands can use the optional <em>path</em> attribute:</p>
<p><em><loadxml context="mycontext" path="/user"/></em></p>
<p><em><savexml context="mycotnext" path="/user"/></em></p>
<p>The first command will read xml from the uri and store it in the
context under the node <em>user</em>, the second one saves only the
xml subtree
under the node <em>user</em> to the uri. The resource addressed by
the uri will
be passed in addition to the <em>contextname</em> parameter the
<em>path</em>
parameter with the corresponding value. If the <em>path</em>
attribute is not
present the <em>path</em> parameter will get the value
<em>"/"</em>.</p>
</s2>
</s1>
<s1 title="Special Contexts">
<p>sunShine creates and maintains special contexts that allow the
applications to access the environment data. This allows the
read-only access
to such things as the HttpRequest or the HtppResponse using the same
XPath
commands previously described. These context do not require any
session, they
are everytime available.</p>
<s2 title="The Request Context - Accessing the Environment, Part One">
<p>The request context is an XML description of the current
HttpRequest. This context is a special read only context which can
be accessed
with the usual commands:</p>
<p><em><getxml context="request" path="/parameter"/></em></p>
<p>If you for example want to get the value of a parameter with the
name <em>username</em> you can include the following command in
your XML and it
will be replaced with the value of the parameter:</p>
<p><em><getxml context="request"
path="/parameter/username"/></em></p>
<p>This command will be replaced with all parameters from the current
request in XML format. If you wish to obtain the complete
querystring as it was
passed into sunShine - without converting the data to XML - then
you can use
the "/querystring" path:</p>
<p><em><getxml context="request"
path="/querystring"/></em></p>
<p>The result will be a string in the format
"?param=aaa&...".</p>
<p>The complete context you can access via these commands has the
following XML format:</p>
<source>
<parameter>
<-- All parameters: parameter names build the elements
with the values as text node childs -->
<firstparameter>value of parameter</firstparameter>
<secondparameter>value of parameter</secondparameter>
</parameter>
<-- The querystring contains only parameters send by the GET method -->
<querystring>the querystring with a leading '?' or
empty<querystring>
<-- All parameters. The tags are all inside the sunshine namespace.
The generated xml can be used without modification for the
sunshine:connection command. -->
<parametervalues>
<sunshine:params>
<sunshine:param>
<sunshine:name>1st parameter name</sunshine:name>
<sunshine:value>1st parameter value</sunshine:value>
</sunshine:param>
...
<sunshine:param>
<sunshine:name>2nd parameter name</sunshine:name>
<sunshine:value>2nd parameter value</sunshine:value>
</sunshine:param>
</sunshine:params>
<!-- If a parameter has more than one value, for each value a
<sunshine:param> block is generated. -->
</parametervalues>
<!-- lists all attributes, attribute names build the elements
with the values as text node childs -->
<attributes>
</attributes>
<!-- lists all headers, header names build the elements
with the values as text node childs -->
<headers>
</headers>
<!-- lists all cookies -->
<cookies>
<cookie name="...">
<value>the cookie value</value>
<name>the name of the cookie</name>
<comment>value</comment>
<domain>value</domain>
<path>value</path>
<maxAge>value</maxAge>
<secure>value</secure>
<version>value</version>
</cookie>
</cookies>
<characterEncoding>value</characterEncoding>
<contentLength>value</contentLength>
<contentType>value</contentType>
<protocol>value</protocol>
<remoteAddress>value</remoteAddress>
<remoteHost>value</remoteHost>
<scheme>value</scheme>
<serverName>value</serverName>
<serverPort>value</serverPort>
<authType>value</authType>
<method>value</method>
<contextPath>value</contextPath>
<pathInfo>value</pathInfo>
<pathTranslated>value</pathTranslated>
<remoteUser>value</remoteUser>
<requestedSessionId>value</requestedSessionId>
<requestURI>value</requestURI>
<servletPath>value</servletPath>
<isRequestedSessionIdFromCookie>value</isRequestedSessionIdFromCookie>
<isRequestedSessionIdFromCookie>value</isRequestedSessionIdFromCookie>
<isRequestedSessionIdValid>value</isRequestedSessionIdValid>
</source>
</s2>
<s2 title="The Response Context - Accessing the Environment, Part Two">
<p>The response context is an XML description of the current
HttpResponse. This context is a special write only context which
can be
accessed with the usual commands:</p>
<p><em><sunshine:setxml context="response"
path="/header"/></em></p>
<p>This command will be removed from the XML and the information will
be added to the response. Using the response context headers and
cookies can be
added.</p>
<s3 title="Adding headers">
<p>Headers can be added either by <em>setxml</em> or by
<em>appendxml</em>. If <em>setxml</em> is used, the header with
the name gets
the given value, regardless if the header had any value
beforehand or not. If
<em>appendxml</em> is used the value will be added.</p>
<source>
<sunshine:setxml context="response"
path="/header/headername">The
value</sunshine:setxml>
or
<sunshine:appendxml context="response"
path="/header/headername">The
value</sunshine:appendxml></source>
</s3>
<s3 title="Adding cookies">
<p>Cookies can be added either by setxml or by appendxml. There is
no difference between these commands.</p>
<source>
<sunshine:setxml context="response" path="/cookie">
<!-- Now follows the cookie definition -->
<name>The cookie name</name>
<value>The value of the cookie</value>
<!-- The following are optional -->
<path>value</path>
<domain>value</domain>
<secure>true or false</secure>
<comment>value</comment>
<maxAge>value</maxAge>
<version>value</version>
</sunshine:setxml></source>
</s3>
</s2>
<s2 title="The Temporary Context">
<p>The temporary context with the name <em>"temp"</em> is available on
each request. It is independent from the session and has no content
when a new
request starts. It can be used like any other context except that
the content
is lost when the current response is finished.</p>
<p>Using the tempory context it is possible to use store any xml
information for processing the current request.</p>
</s2>
</s1>
<s1 title="Form Handling">
<p>To get feedback or information from a user, forms are commonly used
to present input field in the browser. The usual approach for form
handling in
web application consists of two steps. The first request presents the
form to
the user. This form initiates a second request that processes the form
values.</p>
<p>sunShine supports this two step process, in addition sunShine offers
a single step approach.</p>
<s2 title="The common approach">
<p>The common approach consists of two steps or of creating two
resources. The first resource defines the form: All input fields
are declared,
each gets a unique name. This form invokes the second resource.</p>
<p>This resource uses the sunShine transformer to get the values
provided by the user. The values are added by the browser to the
parameters of
the request. So using the request context and <em>getxml</em>, the
values can
be fetched.</p>
<p>If you want to create a form with two values - forename and surname
of the user, you could generate a base xml file with the
information about this
form:</p>
<source>
<page>
<form>
<action>form-handling-page</action>
<input name="forename" type="text"/>
<input name="surname" type="text"/>
</form>
</page></source>
<p>A stylesheet can transform this into valid html. The action tag
indicates that the "form-handling-page" should be invoked by
submitting the
values.</p>
<p>The "form-handling-page" is a pipeline which is declared in the
sitemap and uses the sunShine transformer. It could also read the
following
xml:</p>
<source>
<page xmlns:sunshine="http://cocoon.apache.org/sunshine/1.0">
<forename>
<sunshine:getxml context="request" path="/parameter/forename"/>
</forename>
<surname>
<sunshine:getxml context="request" path="/parameter/surname"/>
</surname>
</page></source>
<p>As the form values are appended to the request, <em>getxml</em>
with specifying the path (which is the parameter name used for the
input field)
inserts the value submitted by the user into the xml stream.</p>
<p>If you want to write the information in a session context, you must
wrap the whole xml inside a setxml:</p>
<source>
<page xmlns:sunshine="http://cocoon.apache.org/sunshine/1.0">
<sunshine:setxml context="userdata" path="/user">
<forename>
<sunshine:getxml context="request" path="/parameter/forename"/>
</forename>
<surname>
<sunshine:getxml context="request" path="/parameter/surname"/>
</surname>
</sunshine:setxml>
</page></source>
<p>The user data is now stored inside the session context "userdata",
so the context has the following content:</p>
<source>
<user>
<forename>Walter</forename>
<surname>Walterson</surname>
</user></source>
</s2>
<s2 title="The sunShine approach">
<p>The previous chapter showed the common approach for handling form
values. It forces the user to create two resources for a single form
handling.</p>
<p>sunShine offers an advanced approach. Only one single resource is
created. This resources contains the information about the input
fields used
and in addition the information about where the submitted values
should be
stored inside the session.</p>
<p>The example from the previous chapter could look like this:</p>
<source>
<page xmlns:sunshine="http://cocoon.apache.org/sunshine/1.0">
<sunshine:form name="myform">
<sunshine:action>the-next-page</sunshine:action>
<sunshine:content>
<sunshine:inputxml name="forename" type="text"
context="userdata" path="/user/forename"/>
<sunshine:inputxml name="surname" type="text"
context="userdata" path="/user/surname"/>
</sunshine:content>
</sunshine:form>
</page></source>
<p>The form tag starts the form definition. The name attribute is
required to distinct between different forms on the same page. The
action tag
defines the url invoked by the form and the content tag describes
the content
of the form: its input fields.</p>
<p>The <em>inputxml</em> tag tells sunShine that the following request
contains form values which should be stored in the specified
context under the
given path. The sunShine transformer transforms by removing the
namespace and
the context attribute:</p>
<source>
<page xmlns:sunshine="http://cocoon.apache.org/sunshine/1.0">
<form action="the-next-page">
<inputxml name="forename" type="text"/>
<inputxml name="surname" type="text"/>
</form>
</page></source>
<p>A stylesheet can now generate the appropriate html (or any other
format). The main difference is, that the resource invoked by
submitting the
values has not to care about the form as sunShine maintains the
form handling.
The only prerequisit is that a session for the current user and a
session
context to store the information exists.</p>
<p>The sunShine approach allows a very easy way of form handling where
the resource which creates the form also handles the form.</p>
<p>For editing values - if the context already contains information
about the user - <em>inputxml</em> inserts the current value inside
the tag. So
the xml streamed would after a second run would look like this:</p>
<source>
<page xmlns:sunshine="http://cocoon.apache.org/sunshine/1.0">
<form action="the-next-page">
<inputxml name="forename" type="text">Walter</inputxml>
<inputxml name="surname" type="text">Walterson</inputxml>
</form>
</page></source>
<p>Like <em>getxml</em> it is also possible to provide default values
for the input field, if the context does not contain any
information:</p>
<source>
<sunshine:inputxml name="forename" context="userdata"
path="/user/forename">
Defaultname
</sunshine:xml></source>
</s2>
</s1>
</body>
</document>
1.1
xml-cocoon2/src/documentation/xdocs/developing/webapps/sunspot.xml
Index: sunspot.xml
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN"
"../../dtd/document-v10.dtd">
<document>
<header>
<title>Building Portals with sunSpot</title>
<authors>
<person name="Carsten Ziegeler" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Introduction">
<note><strong>IMPORTANT:</strong> sunSpot (= portal framework) is part of
the scratchpad area
of the current Cocoon
release. This means it is not officially released yet. The API and
functionality might change
before it is moved into the official release. Using this is at your
own risk!
If you want to catch the latest status of these components check out
Cocoon
from CVS and have a look at this <link href="portal.html">upto-date
documentation</link>.
</note>
<p>sunSpot is the portal engine of sunShine. It provides the required
functionality to display user dependent content with a user defineable
layout.</p>
<p>The sunShine portal defintion framework is an XML description of the
portal and the contained content. The rendering of the portal to the
needed
format (such as HTML) is done through stylesheets and is therefore
very
flexible.</p>
<p>A portal definition can be configured for all users (global), for
groups of users (group or role) and for the individual user. The
portal
admininstrator can use the provided tools to configure every aspect
of the
portal (from colours to content).</p>
<p>Each "blob" of portal content is contained in a "sunLet". sunLets can
be configured into the portal on a per-user or per-group basis
allowing a
flexible content definition.</p>
<p>sunLets can be minimized, maximized or even removed by the user if he
does not wish to see the content. However, the administrator may
configure
sunLets to be mandatory, in which case they may not be removed.</p>
<p>The different portals are administrated by sunRise applications. Each
application can have its own portal.</p>
<p>This documentation explains the different resources for sunSpot, the
configuration of a portal and how sunSpot creates the portal view
derived from
this information. After that all is put together by creating the
needed entries
in the sitemap for using and displaying a portal.</p>
</s1>
<s1 title="The Profile">
<p>A sunSpot portal is built upon a profile which contains all necessary
information: the portal possibilites (the available sunLets, the
possible
changes to the layout etc.) and the portal view (the layout for this
user and
the sunLets he chose for himself). This profile is generated when a
user logs
into the application the portal belongs to. The building of the
profile is a
very flexible process which allows to have different configurations
for
different users.</p>
<p>In general the building of the profile consists of four steps:</p>
<ol>
<li>Building the base profile. This profile defines which
possibilites the portal has, which sunLets are available to the
portal and
which parts of the profile can be changed by the user.
</li>
<li>Building the global profile. The base profile is enhanced by a
global delta which contains a predefined portal view. This
predefined portal
view is a starting point for all users.
</li>
<li>Building the role profile. The global profile is enhanced by a
role delta which contains a predefined portal view. This predefined
portal view
is a starting point for all users of that role.
</li>
<li>Building the user profile. The role profile is augmented by a
user delta which contains the portal for this specific user. An
optional user
status profile with often changing information can optional be
appended to the
profile.
</li>
</ol>
<p>Only step 1 and 2 are mandatory for the building process. Steps 3 and
4 are optional and depend on the configuration of the users and roles
in the
system.</p>
<p>Each delta (steps 2, 3 and 4) can modify the possibilites of the
portal and the configuration of the sunLets. But it is not allowed to
add new
features or sunLets. In addition a delta may contain a predefined
portal
view.</p>
<p>This building process is invoked each time the user logs into the
application. So a change to any profile (delta) is incorporated into
the user
profile: If e.g. a sunLet , which a user has choosen for his portal
view, is
removed from the system, it is not available to the user anymore and
therefore
also removed from his portal view.</p>
<p>The global delta, the role delta and the user delta are very similar.
They only differ in the name of the root node.</p>
<s2 title="The Base Profile">
<p>The base profile consists of three data sources:</p>
<ol>
<li> The layout profile describes the possibilites and layout of
the portal.
</li>
<li>The sunLets profile defines all available sunLets for the
portal view.
</li>
<li>The type profile describes the parts of the profile which can
be changed by the user.
</li>
</ol>
<s3 title="The Layout Profile">
<p>The layout profile describes the overall layout of the portal
including if header or footer are present which colors and fonts
are used and
so on.</p>
<p>An example profile is shown below. The profile is enclosed in the
root node "layout-profile" and consists of the "portal" part and
the "sunlets"
part:</p>
<source>
<layout-profile>
<portal> <!-- This node contains the layout of the portal view
-->
<layouts>
<layout>
<!-- The color of the background -->
<background>
<color>#ffffff</color>
</background>
<!-- The font and color for usual text -->
<font>
<type>Arial, Helvetica,
sans-serif</type>
<size>2</size>
<color>black</color>
</font>
</layout>
</layouts>
<!-- The following means that the sunSpot portal has a
header area -->
<header>
<exists>true</exists>
</header>
<!-- The following means that sunSpot has 3 columns -->
<columns>
<number>3</number>
</columns>
<!-- The following means that the sunSpot has not a footer
area -->
<footer>
<exists>false</exists>
</footer>
</portal>
<sunlets> <!-- This node contains the layout of the
sunLets -->
<layouts>
<layout>
<title> <!-- The layout of the title
-->
<background>
<color>#46627A</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</title>
<content> <!-- The layout of the content -->
<font>
<type>Arial</type>
<size>2</size>
<color>#000000</color>
</font>
<background>
<color>#ffffff</color>
</background>
</content>
</layout>
</layouts>
</sunlets>
</layout-profile>
</source>
</s3>
<s3 title="The sunLets Profile">
<p>The sunLets profile contains all sunLets which are available in
the system. It is an XML based resource with the root node
"sunlets-profile".
All sunLets are defined under a node called "sunlets", so an
example profile
could look like this:</p>
<source> <sunlets-profile>
<sunlets>
<sunlet id="bankingnews">
<resource uri="cocoon://sunlet-banking.xml"/>
<transformation> <!-- optional xsl transformation
-->
<stylesheet>sunbank/styles/sunlet.xsl</stylesheet>
</transformation>
<configuration>
<mandatory>false</mandatory>
<sizable>true</sizable>
<active>true</active>
<timeout>5000</timeout> <!-- optional,
milliseconds -->
<messages> <!-- optional: Messages
-->
<sunlet_not_available>
Display this if the sunLet is not available.
</sunlet_not_available>
</messages>
</configuration>
<title>Banking News</title>
<status>
<visible>true</visible>
<size>max</size>
</status>
</sunlet>
</sunlets>
</sunlets-profile></source>
<p>This example defines one sunLet: the bankingnews sunLet with the
title "Banking News". The title is displayed in the portal view
above the
sunLet content. The most important part is the resource
definition. Using this
resource the sunLet is displayed in the portalview of the user.
</p>
<ul>
<li>An uri, e.g.: <resource uri=".."/>. This URI can be a
local one which is retrieved using the sitemap or a distant
one which is
retrieved using an HTTP request. In both cases the resource
must deliver valid
XML for the sunLet content. If you don't use a protocol, the
URI is assumed to
be a file.
</li>
<li>A java class delivering the content.
</li>
</ul>
<p>There a several mandatory configuration parameters for a sunLet.
This configuration parameters can only be changed by the portal
administrator.
The user cannot change them for his portal view.</p>
<ul>
<li>mandatory: Indicates if the sunLet can be removed by the
user or if it is always visible.
</li>
<li>sizable: Is the sunLet sizable? If the value is true the
user can minimize this sunLet in his portal view.
</li>
<li>active: Using this parameter, a sunLet can be deactivated
for a distinct period of time. If a sunLet is not active it
will not displayed
to the user even if he has configured it.
</li>
</ul>
<p>In addition there are some optional parameters:</p>
<ul>
<li>timeout: This is the time in milliseconds, sunSpot waits to
get the sunLet content. If the content is not available
within this time frame,
the sunLet is declared as not available at the moment. The
default value for
the timeout can be set in the sunSpot configuration (see next
chapter).
</li>
<li>handlesSizable: If this value is true, the sunLet (or
better the resource) handles the sizing of this sunLet
itselt. This means it
determines the data to be displayed if the sunLet is
minimized or maximized. If
this value is false sunSpot displayes the whole sunLet if it
is maximized and
only its title if it is minimized. This is the default
behaviour.
</li>
<li>handlesParameters: If this value is true (which is the
default value) the resource gets all configuration and status
parameters
passed, e.g. if the resource is an uri, the parameters are
passed as HTTP
request parameters.
</li>
<li>messages/sunlet_not_available: If the sunLet is not
available (e.g. external data where the server is not
available), a message is
displayed. With this optional parameter each sunlet can get a
distinct message
which overrides the message provided by the user profile.
</li>
</ul>
<p>The status parameters can be changed by the user for configuring
his own portal view:</p>
<ul>
<li>visible: If a sunLet is visible it is included in the
portal view. If it is not visible it is still configured for
the user but it
will not displayed.
</li>
<li>size: Currently two sizes (min and max) are distinquished.
</li>
</ul>
<p>If the source of the sunLet needs additional transformation there
are two possibilities for doing the transformation. The first
one is creating a
pipeline in the sitemap for this sunLet and the second one usses
the sunLet
configuration for this. As the first one is the usual sunShine
pipeline
creating process only the second one is covered here.</p>
<p>By defining the "transformation" node inside the "sunlet" node,
the source of the sunLet can be transformed with one or more
stylesheets. For
each stylesheet a "stylesheet" node with the value of the
stylesheet path has
to be created. The order of appearance determines the order of
processing. If
e.g. the source of a sunLet is a class or a file, there is no
need to specify a
pipeline only for this sunLet. Specifying a file/class as source
and a
"stylesheet" node has the same effect.</p>
<s4 title="Adding a new sunLet">
<p>Adding new information to the portal requires four basic
steps:</p>
<ul>
<li>Defining the resource containing the information. For
external resources only the address (mainly an URI) and the
protocol (usually
HTTP) is required. Otherwise a new XML resource has to be
created with the new
content.
</li>
<li>Defining the stylesheet for the presentation of this
content.
</li>
<li>For local resources: Definition of the pipeline in the
sitemap. This pipeline must contain all necessary steps for
building the
information. It must deliver XML as the serialized format.
</li>
<li>Adding a new "sunlet" node to the sunLets profile.
</li>
</ul>
<p>After these steps are finished, the new sunLet is
automatically
available for each user which logs in after the addition. If
the sunLet is even
mandatory it will be added to the portal view of the user.</p>
<p>For more information see the chapter "The Pipelines".</p>
</s4>
<s4 title="Customizable sunLets">
<p>Each sunLet can have its own configuration, e.g. a weather
sunLet should display the weather for a particular city
etc.</p>
<source> <sunlets-profile>
<sunlets>
<sunlet id="bankingnews">
<resource uri="cocoon://sunlet-banking.xml"/>
<customization
uri="cocoon://customize-sunlet-banking.xml"/> <!-- optional -->
<transformation> <!-- optional xsl transformation
-->
<stylesheet>sunbank/styles/sunlet.xsl</stylesheet>
</transformation>
<configuration>
<mandatory>false</mandatory>
<sizable>true</sizable>
<active>true</active>
<timeout>5000</timeout> <!-- optional,
milliseconds -->
<messages> <!-- optional: Messages
-->
<sunlet_not_available>
Display this if the sunLet is not available.
</sunlet_not_available>
</messages>
<customizable>true</customizable> <!--
optional -->
<persistent>false</persistent> <!--
optional -->
</configuration>
<title>Banking News</title>
<status>
<visible>true</visible>
<size>max</size>
</status>
</sunlet>
</sunlets>
</sunlets-profile></source>
<p>To declare a sunLet as customizable it must get a
configuration
resource which is displayed to a user of this sunLet to enter
all required
configuration values. This is done with the
<em>customization</em> tag. The
value for this tag has the same possibilities as the
<em>resource</em> tag,
usually the <em>uri</em> attribute points to a pipeline.</p>
<p>When a user has configured/choosen a customizable sunLet,
sunSpot detects if this sunLet has its configuration. If it
does not have one,
the customization resource of the sunLet is displayed in the
portal view.
Otherwise the sunLet itself is displayed.</p>
<p>In addition a customizable sunLet can be persistent, e.g. the
configuration is saved for a longer period than the current
session of the
user. If the sunLet is not persistent the configuration is
lost when the user
logs out. The next time he logs in, the customization page is
displayed to
configure this sunLet again.</p>
<p>If you use persistent sunLets you have to configure resources
for loading and saving the status profile (See
configuration). More about
writing customizable sunLets can be found in the chapter
"Writing Customizable
sunLets".</p>
</s4>
</s3>
<s3 title="The Type Profile">
<p>The type profile describes the possible values the user can
change for his portal view. Using this flexible approach the
portal
administrator can decide which user can choose what. For
example, a normal user
might change the layout and content of his portal view, but a
guest might not
be allowed to change anything, whereas the administrator can
change
everything.</p>
<p>The type profile is surrounded by the root node "type-profile".
It consists of two parts: the typedefs section and the elements
section. The
type profile can be compared with a programming language. The
typedefs section
declares all available types and the the elements section
declares all
variables with their corresponding types. A "variable" defines a
place or
element in the user profile which can be changed by the user.
The possibilites
for this element are defined by the type.</p>
<p>The typedefs contains enumerations, e.g. a set of possible values
with a user presentable name. In addition sunSpot has the
following predefined
types: STRING (arbitrary text), BOOLEAN (true or false), INTEGER
(a number) and
CARDINAL (a positiv number).</p>
<source><type-profile>
<typedefs>
<!-- The following types are defined by sunSpot: (Names
are casesensitiv!)
STRING, BOOLEAN, ENUMERATION, INTEGER, CARDINAL
-->
<typedef name="backgroundcolor" type="ENUMERATION">
<value name="weiss">#ffffff</value>
<value name="hellgrau">#cccccc</value>
<value name="hellgruen">#aab9bf</value>
<value name="dunkelgruen">#46627A</value>
</typedef>
<typedef name="textcolor" type="ENUMERATION">
<value name="weiss">white</value>
<value name="schwarz">black</value>
<value name="weiss">#ffffff</value>
<value name="hellgrau">#cccccc</value>
<value name="hellgruen">#aab9bf</value>
<value name="dunkelgruen">#46627A</value>
</typedef>
<typedef name="sunletsize" type="ENUMERATION">
<value name="Maximized">max</value>
<value name="Minimized">min</value>
</typedef>
<typedef name="columnnumber" type="ENUMERATION">
<value name="1">1</value>
<value name="2">2</value>
<value name="3">3</value>
<value name="4">4</value>
<value name="5">5</value>
</typedef>
</typedefs>
</type-profile></source>
<p>The element section has the same structure a the user profile.
For each leave which is changeable by the user the elements
section contains an
entry for the type of this node. The node is enhanced by two
attributes: type
for the node type and description for a user readable title.
This information
is used by sunSpot to present the configuration screen for the
portal. It
displayes for each changeable leave a form field with the
corresponding
type.</p>
<source>
<type-profile>
<elements>
<layout-profile>
<portal><layouts>
<layout>
<!-- The user can change the background.
The possible values are taken from the enumeration
backgroundcolor. The user gets the title
"Background"
displayed for the form field. -->
<background>
<color type="backgroundcolor"
description="Background"/>
</background>
<font>
<color type="textcolor" description="Font
color"/>
</font>
</layout>
</layouts>
<columns>
<!-- The user can change the number of columns -->
<number type="columnnumber" description="Number of
columns"/>
</columns>
</portal>
</layout-profile>
<portal-profile>
<content>
<!-- Using the * the following configuration is applied
for
all columns regardless of their position. -->
<column position="*">
<width type="CARDINAL"
description="Width"/>
<sunlets>
<!-- Using the * the following configuration is
applied for
each sunlet. -->
<sunlet id="*" position="*"
number="*">
<status>
<!-- The user can change the visibility and
size
of the sunLet -->
<visible
type="BOOLEAN" description="Visible"/>
<size
type="sunletsize" description="Size"/>
</status>
</sunlet>
</sunlets>
</column>
</content>
</portal-profile>
</elements>
</type-profile></source>
</s3>
</s2>
<s2 title="The Global Profile">
<p>The global delta, the role delta and the user delta are very
similar. They only differ in the name of the root node. So this
chapter only
describes the global delta and points out the differences between
the deltas at
the various place rather than repeating the same information in
different
chapters.</p>
<p>The global delta is enclosed in the root node "global-delta", the
role delta uses the node "role-delta" and the user delta the node
"user-delta".</p>
<p>In general a delta defines the differences between two profiles.
The sunSpot deltas allow only adding and changing but not removing
nodes. Each
delta can contain the following parts: </p>
<ul>
<li>The layout delta containing the difference to the layout
profile.
</li>
<li>The sunlets delta describing the differences to the sunlets
profile.
</li>
<li>The portal profile containing a complete portal view. This
part is not a delta. If it is contained in a delta and the
profile already has
this information, that information is replaced by the one from
the delta.
Otherwise the delta information is added. For the global profile
the portal
profile is mandatory.
</li>
<li>The personal profile. This part contains personal information
of the user, e.g. are welcome text. For the global profile this
information
again is mandatory. It defines the possibilites the user has.
The role and the
user profile can only change this information. But they cannot
add any new
nodes.
</li>
</ul>
<p> So here is an example:</p>
<source><global-delta>
<!-- No difference to the base profile -->
<layout-delta>
</layout-delta>
<!-- No difference to the base profile -->
<sunlets-delta>
</sunlets-delta>
<!-- This is the starting portal view for all users.
It has to be defined in the global profile -->
<portal-profile>
<!-- This is the content of the portal view -->
<content>
<header>
<sunlet id="personalize" position="1">
<status>
<visible>true</visible>
<size>max</size>
</status>
</sunlet>
</header>
<column position="1">
<width>28%</width>
<!-- The
sunLets are displayed in the order of their
position attribute in each column. -->
<sunlets>
<sunlet id="administration" number="1"
position="1">
<status>
<visible>true</visible>
<size>max</size>
</status>
</sunlet>
</sunlets>
</column>
<column position="2">
<width>50%</width>
<sunlets>
<sunlet id="banknews" number="2"
position="1"/>
</sunlets>
</column>
<column position="3">
<width>22%</width>
<sunlets/>
</column>
</content>
</portal-profile>
<personal-profile>
<greeting>Herzlich willkommen</greeting>
<messages>
<sunlet_not_available>Das sunLet ist zur Zeit nicht
verfuegbar.</sunlet_not_available>
</messages>
</personal-profile>
</global-delta></source>
</s2>
<s2 title="The User Status Profile">
<p>The user status profile contains often changing information like
the configuration of configurable sunLets, the last login time etc.
The user
status profile is optional, but if it is not accessible,
customizable sunLets
are not possible.</p>
<p>For each customizable sunLet which is in the portal view of the
user the status profile contains an XML block with the sunLet
specific
configuration for this sunLet.</p>
<source><status-profile>
<customization>
<!-- Custom information for each customizable sunLet -->
<sunlet id="popmail" number="3">
<host>mail</host>
<password>gsgdgsg</password>
<mailcount>4</mailcount>
<user>walter</user>
</sunlet>
</customization>
</status-profile></source>
</s2>
</s1>
<s1 title="Configuring sunSpot">
<p>The configuration of sunSpot is actually a sunRise application
configuration. Please refer to the sunRise documentation for more
information
about sunRise handler and application configuration.</p>
<p>Inside your sunRise handler configuration you define for each portal
an application configuration for sunSpot like the example portal
called
"sunBank" below: <![CDATA[]]></p>
<source> <application name="sunBank">
<configuration name="sunSpot"> <!-- This is the portal
configuration -->
<portal-uri>finance-portal</portal-uri>
<profile-cache>true</profile-cache>
<process-sunlets-parallel>false</process-sunlets-parallel>
<default-sunlet-timeout>10000</default-sunlet-timeout>
<profile>
<!-- The resource for loading the layout profile -->
<layout-base
uri="cocoon://financeresource-layoutprofile"/>
<!-- The resource for loading the base sunlets profile
-->
<sunlet-base
uri="cocoon://financeresource-sunletprofile"/>
<!-- The optional resource for saving the base sunlets
profile -->
<sunlet-base-save
uri="cocoon://financeresource-savesunletprofile"/>
<!-- The optional type resource -->
<type-base uri="cocoon://financeresource-types"/>
<!-- The optional type resource for
the admin configuration -->
<admin-type-base
uri="cocoon://financeresource-admintypes"/>
<!-- The resources for loading/saving the deltas -->
<global-delta-load
uri="cocoon://financeresource-globalprofile"/>
<global-delta-save
uri="cocoon://financeresource-saveglobalprofile"/>
<role-delta-load
uri="cocoon://financeresource-roleprofile"/>
<role-delta-save
uri="cocoon://financeresource-saveroleprofile"/>
<user-delta-load
uri="cocoon://financeresource-userprofile"/>
<user-delta-save
uri="cocoon://financeresource-saveuserprofile"/>
<!-- Optional resources for loading/saving the status
profile
which is required for persistent, customizable sunLets
-->
<user-status-load
uri="cocoon://financeresource-loadstatusprofile"/>
<user-status-save
uri="cocoon://financeresource-savestatusprofile"/>
<!-- optional type resources -->
<global-type-delta uri="..."/>
<role-type-delta uri="..."/>
<user-type-delta uri="..."/>
</profile>
<!-- Redirect to this resource, if the user is not
authenticated
to view that sunLet -->
<auth-redirect>finance-portal</auth-redirect>
</configuration>
</application></source>
<s2 title="Global Portal Configuration">
<p>One mandatory configuration value for the portal is the
<em>portal-uri</em>. It must point to a pipeline which produces the
portal view
for a user (see next section for more information about the
pipelines).</p>
</s2>
<s2 title="Profile Caching">
<p>sunSpot contains an intelligent profile caching mechanism which
detects automatically changes to profiles and determines upon this
information
which profile must be rebuild. </p>
<p>Without profile caching a profile is build each time a user logs
in. With profile caching the profile is only build if there is no
cached
profile or if something has changed in the profiles for this user.
Only the
user status profile is not cached at all as it is often
changing.</p>
<p>By specifying the <em>profile-cache</em> tag in the sunSpot
configuration with the value <em>true</em> the profile caching is
turned on. If
the tag is not available no profile caching is performed.</p>
<p>If profile caching is turned on, the profiles should not be changed
by hand as the cache does not detect such changes. All changes to
the profiles
must be done using the sunSpot tools. However if you change a
profile or part
of a profile by hand, make sure that you clean the cache
afterwords. Cleaning
the cache can be done either by the provided sunSpot tools or by
deleting all
files inside the cache directory.</p>
</s2>
<s2 title="Global sunLet configuration">
<p>Usually the portal view is generated step by step, e.g. the sunLets
are build one after the other. sunSpot can be configured to get the
sunLets
content parallel to decrease the response time for the portal view.
By
specifying the <em>process-sunlets-parallel</em> tag with the value
<em>true</em>, the sunLets are processed parallel.</p>
<p>If the content of a sunLet is not available, e.g. if the
contentresides on an external HTTP server, the processing of this
sunLet can
take a "very long" time, e.g. until a timeout occures. sunSpot
monitors the
sunLets and can stop the processing of a sunLet after a distinct
period of
time. This period can be specified by the tag
"default-sunlet-timeout" in
milliseconds. If the content of the sunLet is not available after
the time has
expired, the sunLet is declared as "not available". The default
timeout is 10
minutes.</p>
<p>For a fine-tuning of sunLet timeouts, each sunLet can get its own
timeout (see the sections below).</p>
</s2>
<s2 title="Profile Resources">
<p>Each part of the profile has a corresponding resource which is
invoked for loading or saving the profile part, e.g. one resource
for loading
the global profile delta and a separate one for saving it. The
loading
resources must deliver the xml described in the previous chapters.
</p>
<p>All resources get the parameter "application" with the name of the
corresponding application and "handler" with the name of the
sunRise handler.
The list below shows the additional parameters for the other
resources.</p>
<ul>
<li>sunlet-base: "profile" with value "sunlet-base"
</li>
<li>sunlet-base-save: "profile" with value "sunlet-base"
</li>
<li>layout-base: "profile" with value "layout-base"
</li>
<li>type-base: "profile" with value "type-base"
</li>
<li>admin-type-base: "profile" with value "admin-type-base"
</li>
<li>global-delta-load: "profile" with value "global-delta"
</li>
<li>global-type-delta: "profile" with value "global-type-delta"
</li>
<li>global-delta-save: "profile" with value "global-delta"
</li>
<li>role-delta-load: "profile" with value "role-delta", "role"
with name of the role
</li>
<li>role-delta-save: "profile" with value "role-delta", "role"
with name of the role
</li>
<li>role-type-delta: "profile" with value "role-type-delta",
"role" with role name
</li>
<li>user-delta-load: "profile" with value "user-delta", "role"
with role name, "ID" with user ID
</li>
<li>user-delta-save: "profile" with value "user-delta", "role"
with role name, "ID" with user ID
</li>
<li>user-type-delta: "profile" with value "user-type-delta",
"role" with role name, "ID" with user ID
</li>
<li>user-status-load: "profile" with value "user-status", "role"
with role name, "ID" with the user ID
</li>
<li>user-status-save: "profile" with value "user-status", "role"
with role name, "ID" with the user ID
</li>
</ul>
</s2>
</s1>
<s1 title="The Pipelines">
<p>So far the chapters only described configuring sunSpot and writing
resources. This chapter closes the gap and explains the steps for
showing the
portal.</p>
<p>For defining the pipelines in the sitemap, sunSpot declares two
generators (the "sunSpotGenerator" and the "sunSpotConfGenerator")
and one
transformer ("sunSpot").</p>
<s2 title="Displaying the portal view">
<p>Displaying the portal view is a very simple step: defining a
pipeline with the "sunSpotGenerator" as the generator, the sunRise
transformer
for defining the application and an stylesheet for creating the
presentation:
</p>
<source> <map:match pattern="sunbank-portal">
<map:act type="sunRise-auth"/> <!-- for
getting the sunSpot configuration -->
<map:parameter name="handler"
value="sunshinehandler"/>
<map:parameter name="application"
value="sunBank"/>
<map:generate type="sunSpot"/> <!-- generate the
portal view -->
<map:transform
src="sunbank/styles/portalHTML.xsl"/> <!-- presentation in HTML -->
<map:serialize/>
</map:act>
</map:match></source>
<s3 title="The Generated Portal View">
<p>The XML generated by the "sunSpotGenerator" is not exactly the
same as for the user profile. sunSpot optimizes and reorganizes
the profile.
All fields (or nodes) which are changeable have the attributes
"formdescription", "formpath" and "formtype". "formdescription"
is a user
readable description of the field, "formpath" is the name of the
form parameter
which can be used to set the value and "formtype" indicates the
type of the
field. The belonging type can be found in the types section of
the
profile.</p>
<source><!-- The portal indicates that the following is the
portal view -->
<portal>
<!-- The configuration of the portal -->
<configuration>
<!-- This is the uri which should be invoked for rebuilding the
portal view
and for changing the view. The parameter sunspotprofile is always
present and indicates the current profile. -->
<uri>finance-portlets?sunspotprofile=uprofile:sunBank:user_admin_sunshine</uri>
<!-- This is the uniquie sunSpot profile ID -->
<profile>uprofile:sunBank:user_admin_sunshine</profile>
<media>html</media> <!-- The current media: html or
wap -->
</configuration>
<!-- Now the needed part of the layout profile: -->
<layout>
<portal>
<background>
<color formdescription="Hintergrundfarbe"
formpath="sunspotconf.0.0" formtype="backgroundcolor">#aab9bf</color>
</background>
<font>
<type>Arial, Helvetica,
sans-serif</type>
<size>2</size>
<color formdescription="Schriftfarbe"
formpath="sunspotconf.1.0" formtype="textcolor">black</color>
</font>
</portal>
<sunlets>
<title>
<background>
<color>#46627A</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</title>
<content>
<background>
<color>#000000</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</content>
</sunlets>
</layout>
<!-- This is the portal view: -->
<header>
<sunlet id="personalize" position="1" number="1">
<resource uri="financesunlet-personalize.xml"/>
<configuration>
<mandatory>true</mandatory>
<sizable>true</sizable>
<active>true</active>
</configuration>
<title>Personalisieren</title>
<status>
<visible>true</visible>
<size>max</size>
</status>
<content>..the sunLet content...</content>
</sunlet>
</header>
<columns number="3">
<column position="1" width="28%">
<sunlet id="administration" position="1"
number="1">
<resource uri="financesunlet-administration.xml"/>
<configuration>
<mandatory>false</mandatory>
<sizable>true</sizable>
<active>true</active>
</configuration>
<title>sunShine Administration</title>
<status>
<visible formdescription="Sichtbar"
formpath="sunspotconf.4.0" formtype="BOOLEAN">true</visible>
<size formdescription="Groesse"
formpath="sunspotconf.5.0" formtype="sunletsize">max</size>
</status>
<content>..the sunLet content...</content>
</sunlet>
....
</column>
<column position="2" width="50%">
...
</column>
<column position="3" width="22%">
...
</column>
</columns>
<!-- The personal information -->
<personal-profile>
<greeting>Hi there!</greeting>
<messages>
<sunlet_not_available>The sunLet is currently not
available.</sunlet_not_available>
</messages>
</personal-profile>
</portal></source>
</s3>
</s2>
<s2 title="Administration of the portal view">
<p>Displaying the administration page of the portal is as simple as
displaying the portal. The difference lies in changing the
generator to the
"sunSpotConfGenerator": </p>
<source> <map:match pattern="sunbank-conf">
<map:act type="sunRise-auth">
<map:parameter name="handler"
value="sunshinehandler"/>
<map:parameter name="application"
value="sunBank"/>
<map:generate type="sunSpot-conf"/>
<map:transform
src="sunbank/styles/portalconfHTML.xsl"/>
<map:serialize/>
</map:act>
</map:match>
</source>
<p>Make sure to protect the portal configuration generator as the
administrator can change all profiles, clear the cache etc. It
should only be
available for real sunSpot administrators.</p>
<s3 title="The Generated Administration View">
<p>The XML generated by the "sunSpotConfGenerator" is not exactly
the same as the user profile. sunSpot addes some information to
the profile.
All fields (or nodes) which are changeable have the attributes
"formdescription", "formpath" and "formtype". "formdescription"
is a user
readable description of the field, "formpath" is the name of the
form parameter
which can be used to set the value and "formtype" indicates the
type of the
field. The belonging type can be found in the types section of
the
profile.</p>
<source><!-- The portalconf node indicates that the following is
the portal administration view -->
<portalconf>
<!-- The configuration of the portal -->
<configuration>
<!-- This is the uri which should be invoked for rebuilding the
portal view
and for changing the view. The parameter sunspotprofile is always
present and indicates the current profile. -->
<uri>finance-portlets?sunspotprofile=uprofile:sunBank:user_admin_sunshine</uri>
<!-- This is the uniquie sunSpot profile ID -->
<profile>uprofile:sunBank:user_admin_sunshine</profile>
<media>html</media> <!-- The current media: html or
wap -->
</configuration>
<!-- The layout profile, see chapter about the layout profile -->
<layout-profile>
<portal>
<layouts>
<layout>
<background>
<color
formdescription="Hintergrundfarbe" formpath="sunspotconf.0.0"
formtype="backgroundcolor">#aab9bf</color>
</background>
<font>
<type>Arial, Helvetica,
sans-serif</type>
<size>2</size>
<color
formdescription="Schriftfarbe" formpath="sunspotconf.1.0"
formtype="textcolor">black</color>
</font>
</layout>
</layouts>
<header>
<exists>true</exists>
</header>
<columns>
<number formdescription="Anzahl"
formpath="sunspotconf.2.0" formtype="columnnumber">3</number>
</columns>
<footer>
<exists>false</exists>
</footer>
</portal>
<sunlets>
<layouts>
<layout>
<title>
<background>
<color>#46627A</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</title>
<content>
<font>
<type>Arial</type>
<size>2</size>
<color>#000000</color>
</font>
<background>
<color>#ffffff</color>
</background>
</content>
</layout>
</layouts>
</sunlets>
</layout-profile>
<!-- The sunLets profile, see chapter about the sunLets profile -->
<sunlets-profile>
<sunlets>
<sunlet id="banknews">
<resource uri="onlinesunlet-banking.xml"/>
<configuration>
<mandatory>false</mandatory>
<sizable>true</sizable>
<active>true</active>
</configuration>
<title>Banking News</title>
<status>
<visible>true</visible>
<size>max</size>
</status>
</sunlet>
...
</sunlets>
</sunlets-profile>
<!-- The type profile, see the chapter about the type profile -->
<typedefs>
...
</typedefs>
<!-- And now the portal view, see chapter about the portal profile
-->
<portal-profile>
<content>
<header>
<sunlet id="personalize" position="1"
number="1">
<status>
<visible>true</visible>
<size>max</size>
</status>
</sunlet>
</header>
<column position="1">
<width formdescription="Breite"
formpath="sunspotconf.3.0" formtype="CARDINAL">28%</width>
<sunlets>
<sunlet id="administration" position="1"
number="2">
<status>
<visible
formdescription="Sichtbar" formpath="sunspotconf.4.0"
formtype="BOOLEAN">true</visible>
<size
formdescription="Groesse" formpath="sunspotconf.5.0"
formtype="sunletsize">max</size>
</status>
</sunlet>
...
</sunlets>
</column>
<column position="2">
...
</column>
<column position="3">
...
</column>
</content>
</portal-profile>
<!-- The personal profile, see the corresponding chapter -->
<personal-profile>
<greeting>Hi there!</greeting>
<messages>
<sunlet_not_available>The sunLet is currently not
available.</sunlet_not_available>
</messages>
</personal-profile>
</portalconf></source>
</s3>
</s2>
<s2 title="Changing the Profile">
<p>The profile can be changed using a HTTP request. The invoked
resources is the uri defined in the "configuration" section of the
portal view.
It contains already the needed parameter "sunspotprofile" with the
given value.
This parameter tells sunSpot which profile it should change.</p>
<p> Each field which is changeable has the parameters
"formdescription", "formtype" and "formpath". The "formdescription"
is a
user-readable text for this field. The "formtype" is the type of
the field. It
is a type name which has a corresponding entry in the type profile.
The type
profile contains all possible values for this particular type. The
"formpath"
contains the name of the field to change. So changing an field is
submitting a
form value with the name of "formpath" and one of the values
denoted by the
"formtype". </p>
<p>In addition to this sunSpot recognizes the special parameter
"sunspotcmd". It can control the appearance of the sunLets. The
value of the
parameter is one of the following followed by '_', the sunLet id
attribute,
another '_' and the sunLet number attribute. For example minimizing
a sunLet is
done by passing "sunspotcmd=minimize_1_3" to the request. The
commands are as
follows:</p>
<ul>
<li>"maximize" : Maximize the sunLet.
</li>
<li>"minimize" : Minimize the sunLet.
</li>
<li>"close" or "hide" : Close the sunLet, it will not be
displayed in the portal view, but is still configured.
</li>
<li>"open" or "show" : A configured sunLet will be included in
the portal view again.
</li>
<li>"delete" : Remove the sunLet from the profile.
</li>
<li>"move" : Move the sunLet to the column which is append to
value separated by '_'. So "sunspotcmd=move_1_3_2" would move
the sunLet into
the 2nd column.
</li>
<li>"new" : Add a new sunLet to the profile. Only the attribute
id of the sunLet is passed. Instead of the number attribute the
column number
is appended. If instead "header" or "footer" is passed instead
of the column
number, the sunLet is moved into that special area.
</li>
<li>"update" : Change from the customization view of the sunLet
to the sunLet content view.
</li>
</ul>
<p>The profile can be save persistent by sending the parameter
"sunspotcmd" with the value "save"in addition to the
"sunspotprofile"
parameter.</p>
</s2>
<s2 title="Defining sunLets">
<p>Defining a pipeline for a sunLet is also very straightforward.
Together with your "real" pipeline for defining the content and
doing the
presentation, the "sunSpot-auth" action and the sunRise-auth action
are needed.
The first one for protecting the sunLet and the second one for
defining the
application the resource belongs to:</p>
<source> <map:match pattern="licence-sunlet">
<!-- Get the application configuration -->
<map:act type="sunRise-auth">
<map:parameter name="handler"
value="sunshinehandler"/>
<map:parameter name="application"
value="sunBank"/>
<!-- secure the sunLet: -->
<map:act type="sunSpot-auth">
<map:parameter name="sunLet" value="licencing"/>
</map:act>
<!-- The resource containg the licencing information:
-->
<map:generate src="sunshine/licencing.xml"/>
<!-- present it in HTML -->
<map:transform src="sunbank/styles/HTML.xsl"/>
<!-- Serialize it to XML for including in the portal view: -->
<map:serialize/>
</map:act>
</map:match></source>
<p>In this example the sunLet is protected by the use of the parameter
tag inside the "sunSpot-auth" action. Only if the user is allowed to
view/configure the sunLet with the ID "licencing", he can invoke
this resource.
If this security command is left out, everyone is able to get the
resource by
simply invoking it directly from the browser. However, if the
sunLet is
protected it is not necessary that a user has choosen that sunLet
for his
current portal view to invoke the resource. In addition it is
possible to
specify the parameter without a specific sunlet name. This protects
the
resource as a sunLet: Only users which are logged in to the portal
can view the
resource.</p>
</s2>
<s2 title="Getting Profile Information within a sunLet">
<p>Each sunLet has access to nearly all information of the profile,
including layout information and configuration. The sunLet can
retrieve this
information using a special session context called
<em>sunSpot</em>. With the
familiar commands of the <em>sunShine</em> transformer
(<em>getxml</em> etc.)
the information can be included in the current xml stream of a
sunLet.</p>
<p>The content of the context looks like the following:</p>
<source><layout>
<portal>
<background>
<color formdescription="Hintergrundfarbe"
formpath="sunspotconf.0.0" formtype="backgroundcolor">#aab9bf</color>
</background>
<font>
<type>Arial, Helvetica,
sans-serif</type>
<size>2</size>
<color formdescription="Schriftfarbe"
formpath="sunspotconf.1.0" formtype="textcolor">black</color>
</font>
</portal>
<sunlets>
<title>
<background>
<color>#46627A</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</title>
<content>
<background>
<color>#000000</color>
</background>
<font>
<type>Arial</type>
<size>2</size>
<color>#ffffff</color>
</font>
</content>
</sunlets>
</layout>
<configuration>
<!-- This is the uri which should be invoked for rebuilding the
portal view
The parameter sunspotprofile is always
present and indicates the current profile. -->
<uri>finance-portlets?sunspotprofile=uprofile:sunBank:user_admin_sunshine</uri>
<!-- This is the uniquie sunSpot profile ID -->
<profile>uprofile:sunBank:user_admin_sunshine</profile>
<media>html</media> <!-- The current media: html or
wap -->
</configuration></source>
<p>Using this information the sunLet can layout itself with the layout
chosen by the user for the portal. For example a
<em><sunshine:getxml
context="sunSpot"
path="/layout/sunlets/content/background/color"/></em> is
replaced by the sunShine transformer with the color value for the
background
(here "#000000)".</p>
</s2>
<s2 title="Writing Customizable sunLets">
<p>Writing a customizable sunLet requires two task:</p>
<ol>
<li>Creating the resource for the customization of the sunLet
</li>
<li>Creating a resource for the sunLet content which uses the
configuration
</li>
</ol>
<p>The resource for the customization is very similar to the "real"
resource for the sunLet. It is - in most cases - a pipeline which
delivers xml
and this xml is included in the portal view. Usually this xml
contains a form
for the user to define the configuration of the sunLet.</p>
<p>The configuration of the sunLet is available using the special
<em>sunSpot</em> session context. For a customizable sunLet this
context is
augmented with the current configuration of the sunLet:</p>
<source><layout>
...
</layout>
<configuration>
...
<context>unique id for the sunLet for external
applications</context>
</configuration>
<sunlet-data>
... the configuration ....
</sunlet-data></source>
<p>Using the sunShine form handling it is very easy to write a
customization view for a sunLet. The following example dispalys a
form for a
mail sunLet which requires the configuration for a mail host, a
user name and a
password.</p>
<source><page
xmlns:sunshine="http://cocoon.apache.org/sunshine/1.0">
<!-- Define a form -->
<sunshine:form name="popmail" method="POST">
<sunshine:action>
<!-- The action is send to the pipeline redisplaying the
portal -->
<sunshine:getxml context="sunSpot"
path="/configuration/uri"/>
</sunshine:action>
<!-- Create the input fields for
host, username and password -->
<sunshine:content>
<sunshine:inputxml context="sunSpot"
path="/sunlet-data/host" name="Host" type="text"/>
<sunshine:inputxml context="sunSpot"
path="/sunlet-data/user" name="User" type="text"/>
<sunshine:inputxml context="sunSpot"
path="/sunlet-data/password" name="Password" type="password"/>
</sunshine:content>
<!-- The submit button -->
<input type="submit" value="Customize"/>
</sunshine:form>
</page>
</source>
<p>The sunShine <em>inputxml</em> tags assure that the information
provided by the user is automatically written into the
<em>sunSpot</em> context
at the places provided.</p>
<p>Writing the resource for the sunLet is as easy. The sunLet can use
the <em>getxml</em> command to retrieve to configuration from the
<em>sunSpot</em> context:</p>
<source><page
xmlns:sunshine="http://cocoon.apache.org/sunshine/1.0">
<!-- Get the configuration information out of the sunSpot context
-->
<!-- and feed it into the getmail command -->
<sunshine:getmail>
<sunshine:user> <!-- Set the user -->
<sunshine:getxml path="/sunlet-data/user"
context="sunSpot"/>
</sunshine:user>
<sunshine:password> <!-- Set the password -->
<sunshine:getxml path="/sunlet-data/password"
context="sunSpot"/>
</sunshine:password>
<sunshine:host> <!-- Seet the host -->
<sunshine:getxml path="/sunlet-data/host"
context="sunSpot"/>
</sunshine:host>
</sunshine:getmail>
</page></source>
<p>Each time the sunLet configuration changes the user status profile
is automatically saved.</p>
</s2>
<s2 title="External Resources and Customizable sunLets">
<p>External resources which are configured with the same sunRise
handler and application as the portal can retrieve configuration
information
from a sunLet. If the resource is invoked with the request parameter
<em>sunspotcontext</em> it has access to the same sunSpot context
as the
sunLet.</p>
<p>The value for the request parameter can be retrieved by the calling
resource, e.g. the sunLet, from the <em>sunSpot</em> context using
the path
<em>/configuration/context</em>. The external resource must have the
<em>sunSpot-auth</em> action configured in its pipeline. The action
checks for the request parameter and grants the resource access to
the
<em>sunSpot</em> context of the sunLet.</p>
</s2>
</s1>
</body>
</document>
1.4 +3 -1 xml-cocoon2/src/documentation/xdocs/userdocs/index.xml
Index: index.xml
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/documentation/xdocs/userdocs/index.xml,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- index.xml 26 Apr 2002 14:09:22 -0000 1.3
+++ index.xml 14 Jun 2002 07:09:11 -0000 1.4
@@ -20,7 +20,9 @@
and actions. This guide will fill in the details, such as "So how do I
turn
this query into XML data".
</p>
-
+ <p>If you are interested in developing real-world web-applications
requiring
+ form handling, authentication or even developing your own portal, have a
+ look at the <link href="../developing/webapps/index.html">web
application documentation</link>.</p>
<p>
Come back often...this guide is being updated regularly.
</p>
1.25 +2 -2
xml-cocoon2/src/java/org/apache/cocoon/components/pipeline/impl/CachingProcessingPipeline.java
Index: CachingProcessingPipeline.java
===================================================================
RCS file:
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/pipeline/impl/CachingProcessingPipeline.java,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- CachingProcessingPipeline.java 13 Jun 2002 10:08:13 -0000 1.24
+++ CachingProcessingPipeline.java 14 Jun 2002 07:09:12 -0000 1.25
@@ -544,7 +544,7 @@
if (validity == null) {
if (i > 0 && i > cachedPipelineKey.size()) {
// shorten key
- for(int m=i; m <
this.pipelineValidityObjects.length; m++) {
+ for(int m=i; m < len; m++) {
this.pipelineCacheKey.removeLastKey();
}
SourceValidity[] copy = new SourceValidity[i];
----------------------------------------------------------------------
In case of troubles, e-mail: [EMAIL PROTECTED]
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]