home *** CD-ROM | disk | FTP | other *** search
- <?xml version="1.0" encoding="UTF-8"?>
- <!--
- Copyright 1999-2004 The Apache Software Foundation
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
- <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.0//EN" "document-v10.dtd">
-
- <document>
- <header>
- <title>Portal: Using forms</title>
- <subtitle>Overview</subtitle>
- <authors>
- <person name="Carsten Ziegeler" email="cziegeler@apache.org"/>
- </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 within 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 serves 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>
-