cziegeler 2004/02/12 01:26:46
Modified: src/documentation/xdocs/developing/webapps portal.xml
book.xml
src/documentation/xdocs/developing/portal book.xml index.xml
Added: src/documentation/xdocs/developing/portal events.xml
forms.xml
Log:
Updating docs
Revision Changes Path
1.6 +2 -0
cocoon-2.1/src/documentation/xdocs/developing/webapps/portal.xml
Index: portal.xml
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/documentation/xdocs/developing/webapps/portal.xml,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- portal.xml 15 Oct 2003 11:36:15 -0000 1.5
+++ portal.xml 12 Feb 2004 09:26:46 -0000 1.6
@@ -9,6 +9,8 @@
</header>
<body>
<s1 title="Introduction">
+ <note>This is the description of the "old" portal framework, please
also have
+ a look at the newer <link href="../portal/index.html">portal
block</link>.</note>
<p>The portal engine of Cocoon provides the required
functionality to display user dependent content with a user
defineable
layout.</p>
1.5 +2 -1
cocoon-2.1/src/documentation/xdocs/developing/webapps/book.xml
Index: book.xml
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/documentation/xdocs/developing/webapps/book.xml,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- book.xml 12 Oct 2003 13:16:32 -0000 1.4
+++ book.xml 12 Feb 2004 09:26:46 -0000 1.5
@@ -16,7 +16,8 @@
<menu-item label="Authentication" href="authentication.html"/>
<menu-item label="Simple Forms" href="forms.html"/>
<menu-item label="Form Handling"
href="../../userdocs/concepts/xmlform.html"/>
- <menu-item label="Portal" href="portal.html"/>
+ <menu-item label="Portal FW" href="portal.html"/>
+ <menu-item label="Portal Engine" href="../portal/index.html"/>
</menu>
</book>
1.4 +4 -1
cocoon-2.1/src/documentation/xdocs/developing/portal/book.xml
Index: book.xml
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/documentation/xdocs/developing/portal/book.xml,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- book.xml 12 Oct 2003 13:16:32 -0000 1.3
+++ book.xml 12 Feb 2004 09:26:46 -0000 1.4
@@ -13,9 +13,12 @@
<menu label="Portal">
<menu-item label="Introduction" href="index.html"/>
<menu-item label="Portal Engine" href="portal-block.html"/>
+ <menu-item label="Event Handling" href="events.html"/>
<menu-item label="Authentication" href="../webapps/authentication.html"/>
</menu>
-
+ <menu label="Samples">
+ <menu-item label="Form handling" href="forms.html"/>
+ </menu>
</book>
1.11 +3 -2
cocoon-2.1/src/documentation/xdocs/developing/portal/index.xml
Index: index.xml
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/documentation/xdocs/developing/portal/index.xml,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- index.xml 12 Nov 2003 10:39:06 -0000 1.10
+++ index.xml 12 Feb 2004 09:26:46 -0000 1.11
@@ -18,8 +18,9 @@
be used to quickly develop portal applications.</p>
<p>The new <link href="portal-block.html">portal engine</link> is a new
implementation of a portal engine which focuses on more flexibility
- and ease-of-use. The current state of this engine is <em>alpha</em>
- which means that the engine can still change in every aspect.</p>
+ and ease-of-use. In addition it supports the JSR-168. The current state of
+ this engine is <em>alpha</em> which means that the engine can still change
+ in some aspects.</p>
</s1>
<s1 title="Features">
1.1
cocoon-2.1/src/documentation/xdocs/developing/portal/events.xml
Index: events.xml
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN"
"../../dtd/document-v10.dtd">
<document>
<header>
<title>Portal: Event Handling</title>
<subtitle>Overview</subtitle>
<authors>
<person name="Carsten Ziegeler" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Overview">
<p>
This document gives an overview of the event handling of the portal
engine.
</p>
<p>
The sample portal that comes with the Cocoon distribution contains
several
working samples for event handling.
</p>
</s1>
<s1 title="Introduction">
<p>
The event handling is a central mechanism used in the portal engine.
Every
change (changes in status or layout, links etc) is propagated through an
event. The portal uses the publisher/subscribe paradigm, so each
component
that is interested in a specific event can subscribe itself for this
type
of event. In addition each component can send out events.
</p>
<p>
The processing of a portal request (a request send to the cocoon portal)
is divided into two parts: event handling and rendering. In the first
part
all events are processed. For example if the user clicks a link this
triggers an event that is published. Any receiver of this event might
in turn fire new events that are published as well.
</p>
<p>
When all events are processed, the first phase is finished and the
second
phase, the rendering, is started. At this point of time all event
handling
and all information exchange should be finished.
</p>
</s1>
<s1 title="Events and the request/response cycle">
<p>
In the Portal, an event is represented by a Java object. This event
object
contains all necessary information to process the event. So, in most
cases an
event contains the object to modify, what to modify and the value to
set.
For example, the minimize event for minimizing a coplet, contains the
coplet, the information to change the window state and the value
"minimize"
to set.
</p>
<p>
A component that processes this request is subscribed to this minimize
event
and when such an event is fired, it changes the window state of the
layout object to minimize. Every data this component needs is stored in
the event. This is a very important detail: the event is not directly
processed
(in this case) by the object that is changed (the coplet) but by a
central
subscribed component that changes the coplet.
</p>
<p>
Let's have a look how such an event is created:
</p>
<source>
Event event;
event = new ChangeCopletInstanceAspectDataEvent(
copletInstanceData,
"size",
SizingStatus.STATUS_MINIMIZEDD);
</source>
<p>
<em>Event</em> is just a marker interface, the concrete implementation
<em>ChangeCopletInstanceAspectDataEvent</em> implements this interface
and requires three pieces of information: the CopletInstanceData,
the information about what to change (size) and the new value.
</p>
<p>
If you want to fire this event, you have to publish it. Therefore you
need the event manager a central portal component. You can lookup this
component, fire the event and release the manager again. If you fire
the event, the event is directly published to all subscribed components.
</p>
<source>
EventManager manager = null;
try {
manager = serviceManager.lookup(EventManager.ROLE);
manager.getPublisher().publish(event);
} finally {
serviceManager.release(manager);
}
</source>
<p>
As noted above, the event will be directly fired. But usually in a
portal
application, events are not fired directly but are invoked by some user
action. This means, the user clicks on a link in the browser, the
request is targetted at Cocoon and the portal invokes the correct
events.
</p>
<p>
For this, a link (or a form action) must know, which event it should
fire, if it is clicked. So, in other words, a link is associated with
a concrete event. But on the other site, an event is a Java object and
we can only use
strings in URLs. So how does this work?
</p>
<p>
The part of the portal that generates the link, creates the event object
with all necessary data, transforms this event into a usable URI and
this
URI is the target of the link. When the user clicks on this link, the
portal
transforms the URI into the Java event object and fires the event.
</p>
<p>
The transformation Event->URI->Event is done by another portal
component,
the link service. Most portal components (apart from the event manager)
are available through another central component, the portal service. So
you need to have access to the portal service component. (Renderers e.g.
don't have to lookup the service by itself, they get it as a method
parameter).
</p>
<source>
PortalService service = null;
try {
service = serviceManager.lookup(PortalService.ROLE);
LinkService ls = service.getComponentManager().getLinkService();
String uri = getLinkURI( event );
// create a link that references the uri
} finally {
serviceManager.release(service);
}
</source>
<p>
That's all you have to do: create the event object, get the link
service,
transform the event into a URI using the service and then create the
(html) link using the URI. Everything else is handled by the portal for
you.
</p>
</s1>
<s1 title="Changing the State of a Coplet">
<p>
In most cases you want to change the state of a coplet because the user
performed an action. The portal engine provides you with some events
that you can directly use.
</p>
<ul>
<li>CopletJXPathEvent</li>
<li>ChangeCopletInstanceAspectDataEvent</li>
</ul>
<p>
The <em>CopletJXPathEvent</em> requires again three pieces of
information:
the coplet instance data to change, the JXPath expression that defines
the
data to change and the value:
</p>
<source>
Event event = new CopletJXPathEvent(copletInstanceData,
"attributes/username",
username);
</source>
<p>
In the previous chapter, we already saw an example of the usage of the
<em>ChangeCopletInstanceAspectDataEvent</em>.
</p>
<p>
It is of course possible that you write your own events for
changing the state of a coplet. But in this case make sure that
your own event implements the interface <em>CopletInstanceEvent</em>.
</p>
</s1>
<s1 title="Subscribing to Events">
<p>
If you are interested in events, you can subscribe to a specific event
type. As events are Java objects, you subscribe for all events of a
specific interface or class (and all of the subclasses).
Subscribing is done using the event manager:
</p>
<source>
EventManager manager = null;
try {
manager = serviceManager.lookup(EventManager.ROLE);
manager.getRegister().subscribe( myComponent );
} finally {
serviceManager.release(manager);
}
</source>
<p>
The component you subscribe must implement the Subscriber interface:
</p>
<source>
Subscriber interface:
public Class getEventType();
public void inform( Event event );
</source>
<p>
The getEventType() method returns the class/interfaces of the events
the component is interested and each time such an event occurs,
the inform() method is invoked.
</p>
<p>
For example one central component in the portal subscribes for
all events dealing with coplets, so it returns
<em>CopletInstanceEvent</em>
as the class in getEventType().
</p>
</s1>
<s1 title="Inter Coplet Communication">
<p>
A very interesting feature of the portal is inter-coplet communication.
The sample portal already has a simple sample where the name of an
image selected in an image gallery is transfered to a different coplet.
</p>
<p>
Now, there is only one (minor) problem: in the cocoon portal coplets
(or more precisly CopletInstanceData objects) are not components but
just data objects. So, a coplet can't directly register itself as
a subcriber for events.
</p>
<p>
Remember that we mentioned earlier on a central component that
processes
the change events for coplets? So, this is basically one possibility: if
you want to pass information from one coplet to another one, create
a CopletJXPathEvent and pass the information to the other coplet.
</p>
<p>
Imagine a form coplet where the user can enter a city. When this form is
processed by the form coplet, it can generate one (or more)
CopletJXPathEvents
and push the entered city information to a weather coplet and a hotel
guide
coplet. So, these two coplets display the information about the selected
city.
</p>
</s1>
<s1 title="Further Information">
<p>
The event.impl package contains all currently processed events, so you
can
study the events and see how to create them. In general most events are
created inside the renderers, especially the renderer aspects that
render
specific details (e.g. the sizing buttons for a coplet). So, you can
have
a look at the code as well.
</p>
<p>
There are several transformers that help in creating events inside a
Cocoon
pipeline. For example the <em>coplet transformer</em> can be used to
create links that contain events to change the status of a coplet or a
layout
object. The gallery sample uses this transformer as a demo.
</p>
</s1>
</body>
</document>
1.1
cocoon-2.1/src/documentation/xdocs/developing/portal/forms.xml
Index: forms.xml
===================================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN"
"../../dtd/document-v10.dtd">
<document>
<header>
<title>Portal: Using forms</title>
<subtitle>Overview</subtitle>
<authors>
<person name="Carsten Ziegeler" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Overview">
<p>This document gives an overview over how to use forms within the portal
engine.
</p>
<p>
The sample portal that comes with the Cocoon distribution contains a
working sample
for form handling.
</p>
</s1>
<s1 title="Including Applications">
<p>
The portal allows to include a complete web application (with forms,
links etc.)
that is build with Cocoon. Therefore it's possible to develop the forms
like you usually do with Cocoon without thinking about the portal. When
you
are finished just include this application into the portal as a coplet.
The following shows you how to configure such an application as a coplet.
</p>
<p>
For including complete applications, the portal offers a specific
coplet adapter,
the caching URI adapter. This is configured as the coplet base type:
<em>CachingURICoplet</em>.
So each coplet you configure has to use this base type.
</p>
<p>
For each application you have to configure a coplet data object in the
profile:
</p>
<source>
<![CDATA[...
<coplet-data id="app-test-two" name="standard">
<title>Application Test</title>
<coplet-base-data>CachingURICoplet</coplet-base-data>
<attribute>
<name>buffer</name>
<value xsi:type="java:java.lang.Boolean"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">true</value>
</attribute>
<attribute>
<name>handleParameters</name>
<value xsi:type="java:java.lang.Boolean"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">true</value>
</attribute>
<attribute>
<name>uri</name>
<value xsi:type="java:java.lang.String"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">cocoon:/coplets/html/application</value>
</attribute>
<attribute>
<name>temporary:application-uri</name>
<value xsi:type="java:java.lang.String"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">cocoon://samples/flow/jxcalc/</value>
</attribute>
</coplet-data>
...]]>
</source>
<p>
As usual, the coplet data gets a unique id, a title and in this case
the reference
to the <em>CachingURICoplet</em>. In addition the <em>buffer</em>
attribute is used
to buffer the output of the coplet which avoids broken responses in the
case of a
malformed stream comming from the included application.
</p>
<p>
The <em>handleParameters</em> attribute has to be set to <em>true</em>
as well, as
the application has to handle it's own request parameters (for links or
forms).
</p>
<p>
The <em>uri</em> attribute points to a Cocoon pipeline that will
include your
application. This is not the pipeline of your application itself. The
starting
URI for your application has to be configured using the attribute
<em>temporary:application-uri</em>.
</p>
<p>
With this configuration you can configure instances of the coplet for
each
user. In addition a user can have several instances of the same
application.
If you look at the provided samples, you see two instances of a flow
example
and two instances of a forms sample at the same time for each user.
</p>
<p>
However, if you allow several instances per user of the same
application,
this application has to be developed with this aspect in mind. More
about
this topic later on.
</p>
<p>
So, basically this is all you have to do. Develop your application
standalone
without the example and include it as outlined above. You can for
example
invoke the sample above (cocoon://samples/flow/jxcalc/) directly
without the
portal.
</p>
</s1>
<s1 title="Building forms">
<p>
In this chapter we demonstrate using a sample how to build forms that
can
be used with the portal. We will use Cocoon flow to define the logic for
the form, but for your own form you can of course use a different
approach
as well. If you want to have complex forms, you can also use Cocoon
forms
(Woody), but you have to be careful with correctly using JavaScript on
the client, which means you have to add the JavaScript to the response
in
the main portal pipeline and not by the form itself. Or you avoid using
JavaScript on the client :)
</p>
<p>
As outlined in the previous chapter, you can define your form handling
application
without taking care about the portal, so let's start developing it.
</p>
<s2 title="A Sample">
<p>
We will use flow for the logic. Each time the application is invoked,
the same
URI is used; this URI calls a flow function. Inside this function we
check
whether we have to display the form or a different (result) page.
So our sitemap looks like this:
</p>
<source>
<![CDATA[...
<map:match pattern="form">
<map:call function="form"/>
</map:match>
...]]>
</source>
<p>
We have one single function in the flow, that checks if a session
attribute already contains a value or not. If no value is stored
in the session, this means that either the form has to be displayed
or the user just submitted some values. So we have to distinguish
these
two cases as well:
</p>
<source>
<![CDATA[...
function form() {
// is the value stored in the session?
if ( cocoon.session.getAttribute("form") == null ) {
// No: is this a submit?
var name = cocoon.request.getParameter("name");
if ( name == null ) {
// No: display the form
cocoon.sendPage("page/form", {});
} else {
// It's a submit, so process the value
cocoon.session.setAttribute("form", name);
cocoon.sendPage("page/received", {"name" : name});
}
} else {
// just display the value
var name = cocoon.session.getAttribute("form");
cocoon.sendPage("page/content", {"name" : name});
}
}...]]>
</source>
<p>
This schema allows to use the same pipeline for all purposes. However,
if you want a different design, you could e.g. use a different
pipeline
for processing the form data etc.
</p>
<p>
In each case, the view is called which is a Cocoon pipeline. For
example the pipeline for the form reads an XML document that looks
like
this:
</p>
<source>
<![CDATA[...
<page>
<title>Form</title>
<content>
<form method="post" action="form">
<para>Please enter your <strong>name</strong>: <input type="text"
name="name"/></para>
<input type="submit" name="submit" value="Enter"/>
</form>
</content>
</page>
}...]]>
</source>
<p>
As already pointed out, you develop your application like you would
do without
the portal. Note in the sample above that the target of the form is
the
<em>form</em> pipeline, containing the call to the flow.
</p>
<p>
So, how does this work? Each link (or target of a form action) is
rewritten
by the portal engine. The link is transformed into an event. When now
the
user activates such a link (or form) the event is send to the portal
and
the portal updates the URI to call for the portlet. The
<em>portal-html-eventlink</em>
transformer does the rewriting of all links and forms in combination
with the <em>portal-coplet</em> transformer that is one of the last
transformers in the main portal pipeline.
</p>
<p>
Each application portlet that isn't changed during this single
request/response
cycle, isn't "activated" which means the corresponding application
pipeline
is not called.
</p>
<p>
The portal caches the response of an application and severes the
coplet out
of the cache until an action for this coplet is triggered.
</p>
</s2>
<s2 title="Several instances of an application">
<p>
If you allow the user to have several instances of the same
application,
the application has to be aware of this fact. Imagine that each
instance
should have its own data set, but as the user is the same, the session
is shared by the instances. So, a unique identifier for each instance
is required.
</p>
<p>
The portal framework already supplies this identifier and passes it
as a request parameter to the pipeline of your application. The name
of the parameter is <em>copletid</em> and the value is the unique id.
In our sample, we pass this identifier to the flow script using an
input module:
</p>
<source>
<![CDATA[...
<map:match pattern="form">
<map:call function="form">
<map:parameter name="copletId" value="{request-param:copletid}"/>
</map:call>
</map:match>
...]]>
</source>
<p>
In the flow script, we can now use this identifier to calculate a
unique
session key to store the information:
</p>
<source>
// get the coplet id
var cid = cocoon.parameters["copletId"];
var key = cid + "/myform";
</source>
<p>
From now on you can use this key to get/store session attributes etc.
In
addition you can use all features available to flow, like looking up
components and using them.
</p>
</s2>
<s2 title="Extending the Sample">
<p>
Although the sample is very simple (or more precisly the form is very
simple)
it demonstrates a possible way to build coplets that handle forms.
You can
use this as a guideline for your own forms.
</p>
<p>
If you need, e.g. validation of the form, you can simply add the
validation
in the flow script and return a corresponding view in the case of a
validation error. If you need a more complex processing, e.g. sending
an
email, you can simply add this in the flow script as well. Or you can
code the logic into a Java class and call this class from the flow
script.
</p>
<p>
In addition, you can use Cocoon forms with all the nice features
(widgets,
validation, binding etc.) as well. You only have to provide a working
set
of stylesheets that work in the portal.
</p>
</s2>
</s1>
</body>
</document>