Author: thomas.heute(a)jboss.com
Date: 2009-12-09 06:43:22 -0500 (Wed, 09 Dec 2009)
New Revision: 978
Removed:
portal/trunk/docs/reference-guide/en/modules/portlets/Sample_Basic_Portlet.xml
Modified:
portal/trunk/docs/reference-guide/en/modules/Portlets.xml
portal/trunk/docs/reference-guide/en/modules/portlets/AJAX_in_GateIn_Framework.xml
portal/trunk/docs/reference-guide/en/modules/portlets/Create_a_WebUI_Portlet.xml
portal/trunk/docs/reference-guide/en/modules/portlets/Groovy_Templates.xml
portal/trunk/docs/reference-guide/en/modules/portlets/Portlet_Lifecycle.xml
Log:
More cleanup/fix
Modified: portal/trunk/docs/reference-guide/en/modules/Portlets.xml
===================================================================
--- portal/trunk/docs/reference-guide/en/modules/Portlets.xml 2009-12-09 08:59:26 UTC (rev
977)
+++ portal/trunk/docs/reference-guide/en/modules/Portlets.xml 2009-12-09 11:43:22 UTC (rev
978)
@@ -2,31 +2,11 @@
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
]>
<chapter id="chap-Reference_Guide-Portlet_development">
- <!--
-
- Copyright (C) 2009 eXo Platform SAS.
-
- This is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of
- the License, or (at your option) any later version.
-
- This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this software; if not, write to the Free
- Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
-
- --><title>Portlet development</title>
+ <title>Portlet development</title>
<xi:include href="portlets/WebUI.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="portlets/AJAX_in_GateIn_Framework.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="portlets/Groovy_Templates.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="portlets/Create_a_WebUI_Portlet.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="portlets/Portlet_Lifecycle.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="portlets/Sample_Basic_Portlet.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
</chapter>
Modified:
portal/trunk/docs/reference-guide/en/modules/portlets/AJAX_in_GateIn_Framework.xml
===================================================================
---
portal/trunk/docs/reference-guide/en/modules/portlets/AJAX_in_GateIn_Framework.xml 2009-12-09
08:59:26 UTC (rev 977)
+++
portal/trunk/docs/reference-guide/en/modules/portlets/AJAX_in_GateIn_Framework.xml 2009-12-09
11:43:22 UTC (rev 978)
@@ -131,7 +131,8 @@
</para>
<para>
Done. Your portlet is ready to accept Ajax calls from
- your client.
+ your
+ client.
</para>
</section>
@@ -154,10 +155,14 @@
</programlisting>
<para>
in a groovy code block. The event function will create an
- url starting
- with <literal>javascript:</literal> so you have to make sure this
- code can be executed in your environment.
- </para>
+ url
+ starting
+ with
+ <literal>javascript:</literal>
+ so you have to make sure this
+ code can be executed in your
+ environment.
+ </para>
<para>
If your operation must update the content of a component,
you have to
@@ -196,57 +201,103 @@
<title>How JavaScript works</title>
<para>
All the javascript is managed by the file
- 02eXoresources:javascript/eXo/portal/PortalHttpRequest.js in the portal
project.
+
<filename>02eXoresources:javascript/eXo/portal/PortalHttpRequest.js</filename>
in
+ the portal project.
</para>
<para>
In this class, you will find 4 functions/classes (detailed
below):
<itemizedlist>
- <listitem><para>PortletResponse</para></listitem>
- <listitem><para>PortalResponse</para></listitem>
- <listitem><para>AjaxRequest</para></listitem>
-
<listitem><para>HttpResponseHandler</para></listitem>
+ <listitem>
+ <para>PortletResponse</para>
+ </listitem>
+ <listitem>
+ <para>PortalResponse</para>
+ </listitem>
+ <listitem>
+ <para>AjaxRequest</para>
+ </listitem>
+ <listitem>
+ <para>HttpResponseHandler</para>
+ </listitem>
</itemizedlist>
</para>
<para>
- and 6 functions : {code}
+ and 6 functions:
</para>
<itemizedlist>
<listitem>
<para>
- ajaxGet // Calls doRequest with an url in GET mode
+ ajaxGet(url, callback)
</para>
+ <para>This is the main entry method for every Ajax calls to
+ the GateIn Portal
+ It is simply a dispatcher method that fills some init fields before
+ calling the doRequest() method</para>
</listitem>
<listitem>
<para>
- ajaxPost // Calls doRequest with an url in POST mode
+ ajaxPost(formElement, callback) // Calls doRequest
+ with an url in POST mode
</para>
+ <para>This method is called when a HTTP POST should be done
+ but in an AJAX
+ case some maniputalions are needed. Once
+ the content of the form is placed
+ into a string object,
+ the call is delegated to the doRequest() method </para>
</listitem>
<listitem>
<para>
- doRequest // Creates the AjaxRequest and
- HttpResponseHandler objects, and
- lauches the request
- process
+ doRequest(method, url, queryString, callback)
</para>
+ <para>
+ The doRequest() method takes incoming request from GET
+ and POST calls
+ The second argument is the URL to target on
+ the server
+ The third argument is the query string object
+ which is created out of a
+ form element, this value is not null only when there is a POST request.
+ <orderedlist>
+ <listitem>
+ <para>An AjaxRequest object is instanciated, it
+ holds the reference to the XHR method</para>
+ </listitem>
+ <listitem>
+ <para>An HttpResponseHandler object is instantiated
+ and its methods like
+ ajaxResponse, ajaxLoading, ajaxTimeout are associated with the
one from
+ the AjaxRequest and will be called by the XHR during the process
+ method</para>
+ </listitem>
+ </orderedlist>
+ </para>
</listitem>
<listitem>
<para>
- ajaxAbort // Cancels the current request
- </para>
+ ajaxAbort()
+ </para>
+ <para>Cancels the current request</para>
</listitem>
<listitem>
<para>
- ajaxAsyncGetRequest // Allows to create and execute a
- sync or async GET request
- </para>
+ ajaxAsyncGetRequest(url, async)
+ </para>
+ <para>Allows to create and execute a
+ sync or async GET
+ request
+ </para>
</listitem>
<listitem>
<para>
- ajaxRedirect // A simple javascript redirection with
+ ajaxRedirect(url)
+ </para>
+ <para>A simple javascript redirection with
window.location.href
- {code} that are the entry points of
- these classes. You
+ that are the entry points of
+ these
+ classes. You
shouldn't have to call explicitly these
functions, since
the template file and the portlet class
@@ -265,7 +316,7 @@
gets the
response elements from the xml returned by Ajax, and
store them
- in the corresponding attributes : {code}
+ in the corresponding attributes :
</para>
<itemizedlist>
<listitem>
@@ -303,7 +354,6 @@
<para>
blocksToUpdate // An array containing the containers
to update with this script
- {code}
</para>
</listitem>
</itemizedlist>
@@ -322,7 +372,7 @@
<literal>PortletResponse</literal>
s (
<literal>portletResponses</literal>
- ) and two other attributes : {code}
+ ) and two other attributes :
</para>
<itemizedlist>
<listitem>
@@ -332,7 +382,7 @@
</listitem>
<listitem>
<para>
- script // Javascript code to update {code}
+ script // Javascript code to update
</para>
</listitem>
</itemizedlist>
@@ -356,7 +406,6 @@
<title>HttpResponseHandler</title>
<para>
This class provides methods to handle the Ajax response.
- {code}
</para>
<itemizedlist>
<listitem>
@@ -386,7 +435,6 @@
<listitem>
<para>
ajaxLoading // shows the loading popup and mask layer
- {code}
</para>
</listitem>
</itemizedlist>
Modified:
portal/trunk/docs/reference-guide/en/modules/portlets/Create_a_WebUI_Portlet.xml
===================================================================
---
portal/trunk/docs/reference-guide/en/modules/portlets/Create_a_WebUI_Portlet.xml 2009-12-09
08:59:26 UTC (rev 977)
+++
portal/trunk/docs/reference-guide/en/modules/portlets/Create_a_WebUI_Portlet.xml 2009-12-09
11:43:22 UTC (rev 978)
@@ -2,77 +2,78 @@
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
]>
<section id="sect-Reference_Guide-Create_a_WebUI_Portlet">
- <title>Create a WebUI Portlet</title>
- <section id="sect-Reference_Guide-Create_a_WebUI_Portlet-Overview">
- <title>Overview</title>
- <para>
- This example is based on the testPortlet in portal/trunk/portlet/test.
+ <title>Create a WebUI Portlet</title>
+ <section id="sect-Reference_Guide-Create_a_WebUI_Portlet-Overview">
+ <title>Overview</title>
+ <para>
+ TODO: Create example (This one doesn't exist anymore). Overall this chapter
need to be reviewed, any taker ? :)
+ </para>
+ <para>
+ This example is based on the testPortlet in portal/trunk/portlet/test.
+ </para>
+ </section>
+
+ <section
+
id="sect-Reference_Guide-Create_a_WebUI_Portlet-Configure_the_portlet">
+ <title>Configure the portlet</title>
+
+ <section
id="sect-Reference_Guide-Create_a_WebUI_Portlet-Folder_tree">
+ <title>Folder tree</title>
+ <para>
+ On Eclipse (or any IDE), create a new Java Project, and create this folder
tree :
+ </para>
+ <programlisting>src
+ | main
+ | |- java
+ | |- resources
+ | |- webapp</programlisting>
+
+ </section>
+
+ <section id="sect-Reference_Guide-Create_a_WebUI_Portlet-pom.xml">
+ <title>pom.xml</title>
+ <para>
+ Create the pom.xml, at root level of the project, like this :
</para>
- </section>
-
- <section
id="sect-Reference_Guide-Create_a_WebUI_Portlet-Configure_the_portlet">
- <title>Configure the portlet</title>
+
+ <programlisting role="XML"><![CDATA[<project>
+ <parent>
+ <groupId>org.exoplatform.portal</groupId>
+ <artifactId>config</artifactId>
+ <version>trunk</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.gatein.example.portlet.testRomain</artifactId>
+ <packaging>war</packaging>
+ <version>1.0.0</version>
+ <name>gatein.portlets.testRomain</name>
+ <description>Romain Test Portlet</description>
+ <dependencies>
+ <dependency>
+ <groupId>org.exoplatform.portal</groupId>
+ <artifactId>exo.portal.webui.portal</artifactId>
+ <version>${org.exoplatform.portal.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.exoplatform.portal</groupId>
+ <artifactId>exo.portal.webui.eXo</artifactId>
+ <version>${org.exoplatform.portal.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <finalName>testRomain</finalName>
+ </build>
+</project>]]></programlisting>
+ </section>
+ <section>
+ <title>UITestRomainPortlet.java</title>
<para>
- Stuff Goes Here?
+ In java/testRomain/portlet/component/, we will create the UITestRomainPortlet.java
file for the portlet :
</para>
- </section>
-
- <section id="sect-Reference_Guide-Create_a_WebUI_Portlet-Folder_tree">
- <title>Folder tree</title>
- <para>
- On Eclipse, create a new Java Project, and create this folder tree :
- </para>
- <para>
- <pre> src | main | |- java | |- resources | |- webapp
</pre>
- </para>
- </section>
-
- <section id="sect-Reference_Guide-Create_a_WebUI_Portlet-pom.xml">
- <title>pom.xml</title>
- <para>
- Create the pom.xml, at root level of the project, like this :
- </para>
-<programlisting><project>
- <parent>
- <groupId>org.exoplatform.portal</groupId>
- <artifactId>config</artifactId>
- <version>trunk</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>exo.portal.portlet.testRomain</artifactId>
- <packaging>war</packaging>
- <version>${org.exoplatform.portal.version}</version>
- <name>exo-portal.portlets.test Romain</name>
- <url>http://www.exoplatform.org</url>
- <description>Romain Test Portlet</description>
- <dependencies>
- <dependency>
- <groupId>org.exoplatform.portal</groupId>
- <artifactId>exo.portal.webui.portal</artifactId>
- <version>${org.exoplatform.portal.version}</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.exoplatform.portal</groupId>
- <artifactId>exo.portal.webui.GateIn</artifactId>
- <version>${org.exoplatform.portal.version}</version>
- <scope>provided</scope>
- </dependency>
- </dependencies>
- <build>
- <finalName>testRomain</finalName>
- </build>
-</project>
-</programlisting>
- <para>
- 1.1 UITestRomainPortlet.java
- </para>
- <para>
- In java/testRomain/portlet/component/, we will create the UITestRomainPortlet.java
file of the portlet :
- </para>
-
-<programlisting>package testRomain.portlet.component;
+<programlisting role="JAVA"><![CDATA[package
org.gatein.example.portlet.testRomain;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.core.lifecycle.UIApplicationLifecycle;
import org.exoplatform.webui.core.UIPortletApplication;
@@ -85,32 +86,31 @@
public UITestRomainPortlet() throws Exception {
}
-}
-</programlisting>
+}]]></programlisting>
</section>
-
+ <!--
<section
id="sect-Reference_Guide-Create_a_WebUI_Portlet-testRomain.xml">
<title>testRomain.xml</title>
<para>
- In src/main/resources/tomcat/, create a testRomain.xml file : {code} <Context
path="/test"
docBase="../../../GateInProjects/portal/trunk/portlet/testPortletRomain/src/main/webapp"
debug="0" reloadable="true" /> {code}
+ In src/main/resources/tomcat/, create a testRomain.xml file :
+ <programlisting><![CDATA[<Context path="/test"
docBase="../../../GateInProjects/portal/trunk/portlet/testPortletRomain/src/main/webapp"
debug="0" reloadable="true" />]]></programlisting>
</para>
<para>
docBase must be set to webapp path of the portlet when you are in the tomcat bin
directory.
</para>
</section>
-
+ -->
+
<section
id="sect-Reference_Guide-Create_a_WebUI_Portlet-Portlet_Groovy_Template">
<title>Portlet Groovy Template</title>
<para>
In src/main/webapp, create the groovy template for the portlet. The path to this file
must match the path you set in the java file, in our case :
groovy/testRomain/portlet/UITestRomainPortlet.gtmpl
</para>
-<programlisting><div
id="<%=uicomponent.getId();%>">
- HelloWorld!images/!!
-</div>
-</programlisting>
+<programlisting role="HTML"><![CDATA[<div
id="<%=uicomponent.getId();%>">
+ HelloWorld
+</div>]]></programlisting>
</section>
-
<section id="sect-Reference_Guide-Create_a_WebUI_Portlet-Skin_Folder">
<title>Skin Folder</title>
<para>
@@ -131,49 +131,47 @@
Create the file configuration.xml in WEB-INF/conf/portlet/testPortletRomain/. Content
of tag <ui-component-root> must match your package organization.
</para>
-<programlisting><webui-configuration>
- <application>
-
<ui-component-root>testRomain.portlet.component.UITestRomainPortlet</ui-component-root>
-
<state-manager>org.exoplatform.webui.application.portlet.ParentAppStateManager</state-manager>
- </application>
-</webui-configuration>
-</programlisting>
+<programlisting role="XML"><![CDATA[<webui-configuration>
+ <application>
+
<ui-component-root>testRomain.portlet.component.UITestRomainPortlet</ui-component-root>
+
<state-manager>org.exoplatform.webui.application.portlet.ParentAppStateManager</state-manager>
+ </application>
+</webui-configuration>]]></programlisting>
+ </section>
+ <section>
+ <title>portlet.xml</title>
<para>
- 1.1 portlet.xml
- </para>
- <para>
In WEB-INF, create file portlet.xml :
</para>
-<programlisting><?xml version="1.0"
encoding="UTF-8"?>
-<portlet-app version="1.0"
xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
+<programlisting role="XML"><![CDATA[<?xml version="1.0"
encoding="UTF-8"?>
+<portlet-app version="1.0"
xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1...
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">
- <portlet>
- <description xml:lang="EN">Test Portlet
Romain</description>
- <portlet-name>TestRomain</portlet-name>
- <display-name xml:lang="EN">Test Portlet
Romain</display-name>
-
<portlet-class>org.exoplatform.webui.application.portlet.PortletApplicationController</portlet-class>
- <init-param>
- <name>webui.configuration</name>
- <!-- must match the path to configuration file -->
-
<value>/WEB-INF/conf/portlet/testPortletRomain/configuration.xml</value>
- </init-param>
- <expiration-cache>0</expiration-cache>
- <supports>
- <mime-type>text/html</mime-type>
- <portlet-mode>help</portlet-mode>
- </supports>
- <supported-locale>en</supported-locale>
-
<resource-bundle>locale.testRomainPortlet</resource-bundle>
- <portlet-info>
- <title>TestPortletRomain</title>
- <short-title>TestPortlet</short-title>
- <keywords>test</keywords>
- </portlet-info>
- </portlet>
-</portlet-app>
-</programlisting>
+
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1...
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">
+ <portlet>
+ <description xml:lang="EN">Test Portlet Romain</description>
+ <portlet-name>TestRomain</portlet-name>
+ <display-name xml:lang="EN">Test Portlet Romain</display-name>
+
<portlet-class>org.exoplatform.webui.application.portlet.PortletApplicationController</portlet-class>
+ <init-param>
+ <name>webui.configuration</name>
+ <!-- must match the path to configuration file -->
+
<value>/WEB-INF/conf/portlet/testPortletRomain/configuration.xml</value>
+ </init-param>
+ <expiration-cache>0</expiration-cache>
+ <supports>
+ <mime-type>text/html</mime-type>
+ <portlet-mode>help</portlet-mode>
+ </supports>
+ <supported-locale>en</supported-locale>
+ <resource-bundle>locale.testRomainPortlet</resource-bundle>
+ <portlet-info>
+ <title>TestPortletRomain</title>
+ <short-title>TestPortlet</short-title>
+ <keywords>test</keywords>
+ </portlet-info>
+ </portlet>
+</portlet-app>]]></programlisting>
</section>
<section id="sect-Reference_Guide-Create_a_WebUI_Portlet-web.xml">
@@ -182,126 +180,143 @@
In WEB-INF, create file web.xml :
</para>
-<programlisting><?xml version="1.0"
encoding="ISO-8859-1"?>
-<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application
2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
-<web-app>
- <!-If define the Portlet Application name MUST end with .par->
- <display-name>test</display-name>
- <description> This application is a portlet. It can not be used outside a
portal.
- This web.xml file is mandatory in each .par archive file. </description>
- <listener>
-
<listener-class>org.exoplatform.services.portletcontainer.impl.servlet.PortletApplicationListener</listener-class>
- </listener>
- <servlet>
- <servlet-name>PortletWrapper</servlet-name>
- <servlet-class>org.exoplatform.services.portletcontainer.impl.servlet.ServletWrapper</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>PortletWrapper</servlet-name>
- <url-pattern>/PortletWrapper</url-pattern>
- </servlet-mapping>
-</web-app>
-</programlisting>
+<programlisting role="XML"><![CDATA[<?xml version="1.0"
encoding="ISO-8859-1"?>
+<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application
2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
+<web-app>
+ <!-If define the Portlet Application name MUST end with .par->
+ <display-name>test</display-name>
+ <description> This application is a portlet. It can not be used outside a portal.
+ This web.xml file is mandatory in each .par archive file. </description>
+ <listener>
+
<listener-class>org.exoplatform.services.portletcontainer.impl.servlet.PortletApplicationListener</listener-class>
+ </listener>
+ <servlet>
+ <servlet-name>PortletWrapper</servlet-name>
+ <servlet-class>org.exoplatform.services.portletcontainer.impl.servlet.ServletWrapper</servlet-class>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>PortletWrapper</servlet-name>
+ <url-pattern>/PortletWrapper</url-pattern>
+ </servlet-mapping>
+</web-app>]]></programlisting>
+ </section>
+ </section>
+ <section>
+ <title>Use the Portlet</title>
<para>
- 1 Use the Portlet
- </para>
- <para>
Compile your portlet, deploy it, and add it to the portal.
</para>
<para>
Now, we will add a button in the portlet. This button will open a popup with a message
inside.
</para>
+ <section>
+ <title>Add a button</title>
<para>
- 1.1 Add a button In the groovy template, add this code :
+ In the groovy template, add this code :
</para>
-<programlisting><div class="UIAction">
- <div class="ActionContainer">
- <div class="ActionButton">
- <div class="LightBlueStyle">
- <div class="ButtonLeft">
- <div class="ButtonRight">
- <div class="ButtonMiddle">
- <a href="<%=uicomponent.event("OpenPopup",
"")%>">Open Popup</a>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
-</div>
-</programlisting>
+<programlisting role="HTML"><![CDATA[<div
class="UIAction">
+ <div class="ActionContainer">
+ <div class="ActionButton">
+ <div class="LightBlueStyle">
+ <div class="ButtonLeft">
+ <div class="ButtonRight">
+ <div class="ButtonMiddle">
+ <a href="<%=uicomponent.event("OpenPopup",
"")%>">Open Popup</a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>]]></programlisting>
+ </section>
+ <section>
+ <title>Add a listener</title>
<para>
- 1.1 Add a listener In the java file, in @ComponentConfig, add this code :
+ In the java file, in @ComponentConfig, add this code :
</para>
-<programlisting>events = {
+<programlisting role="JAVA"><![CDATA[events = {
@EventConfig(listeners = UITestRomainPortlet.OpenPopupActionListener.class)
-}
-</programlisting>
+}]]></programlisting>
<para>
Remark : XXXActionLister.class XXX must match the name you set for the event in the
groovy.
</para>
-<programlisting>static public class OpenPopupActionListener extends
EventListener<UITestRomainPortlet> {
- public void execute(Event<UITestRomainPortlet> event) throws Exception
{
+<programlisting role="JAVA"><![CDATA[static public class
OpenPopupActionListener extends EventListener<UITestRomainPortlet> {
+ public void execute(Event<UITestRomainPortlet> event) throws Exception {
System.out.println("HelloWorld");
}
-}
-</programlisting>
+}]]></programlisting>
+ </section>
+ <section>
+ <title>Redeploy</title>
<para>
- 1.1 Redeploy
- </para>
- <para>
Redeploy the portlet and click on the button. You will see "HelloWorld" in
your console. If you don't change in the portlet, try to redeploy and reboot the
tomcat server.
</para>
+ </section>
+ </section>
+ <section>
+ <title>Add a "HelloWorld" popup</title>
<para>
- 1 Add a "HelloWorld" popup
- </para>
- <para>
Now, we will add a popup which say "HelloWorld" when you click on the
button.
</para>
<para>
First, create the groovy template of the popup : in webapp/groovy/testRomain/portlet,
create UIHelloWorldPopupContent.gtmpl :
</para>
-<programlisting><div
id="<%=uicomponent.getId();%>">
- HelloWorld in a popup!images/!!
-</div>
-</programlisting>
+<programlisting role="HTML"><![CDATA[<div
id="<%=uicomponent.getId();%>">
+ HelloWorld in a popup
+</div>]]></programlisting>
<para>
In java/testRomain/portlet/component, create the java file for the popup look like :
{code} package testRomain.portlet.component;
</para>
+ <programlisting role="JAVA"><![CDATA[package
testRomain.portlet.component;
+import org.exoplatform.webui.config.annotation.ComponentConfig;
+import org.exoplatform.webui.core.UIComponent;
+import org.exoplatform.webui.core.lifecycle.UIApplicationLifecycle;
+
+@ComponentConfig(
+ lifecycle = UIApplicationLifecycle.class,
+ template = "app:/groovy/testRomain/portlet/UIHelloWorldPopupContent.gtmpl"
+ )
+public class UIHelloWorldPopupContent extends UIComponent {
+
+ public UIHelloWorldPopupContent() throws Exception {
+ }
+
+}]]></programlisting>
<para>
- import org.exoplatform.webui.config.annotation.ComponentConfig; import
org.exoplatform.webui.core.UIComponent; import
org.exoplatform.webui.core.lifecycle.UIApplicationLifecycle;
+ In UITestRomainPortlet.java, we will create the popup at the portlet creation (in the
constructor) :
</para>
+<programlisting role="JAVA"><![CDATA[public UITestRomainPortlet()
throws Exception {
+ UIPopupWindow popup = addChild(UIPopupWindow.class, null, null);
+ popup.setWindowSize(400, 300);
+
+ UIHelloWorldPopupContent popupContent =
createUIComponent(UIHelloWorldPopupContent.class, null, null);
+ popup.setUIComponent(popupContent);
+ popup.setRendered(false);
+ ]]></programlisting>
<para>
- @ComponentConfig( lifecycle = UIApplicationLifecycle.class, template =
"app:/groovy/testRomain/portlet/UIHelloWorldPopupContent.gtmpl" )
- </para>
- <para>
- public class UIHelloWorldPopupContent extends UIComponent
- </para>
- <para>
- public UIHelloWorldPopupContent() throws Exception { }{ } {code}
- </para>
- <para>
- In UITestRomainPortlet.java, we will create the popup at the portlet creation (in the
constructor) : {code} public UITestRomainPortlet() throws Exception UIPopupWindow popup =
addChild(UIPopupWindow.class, null, null); popup.setWindowSize(400, 300);
- </para>
- <para>
- {UIHelloWorldPopupContent popupContent =
createUIComponent(UIHelloWorldPopupContent.class, null, null);
popup.setUIComponent(popupContent); popup.setRendered(false); } {code}
- </para>
- <para>
At the beginning, we set the popup not visible. As you see, we add a children to the
Portlet. So, if we want to see the content of it, we must add this in
UITestPortletRomain.gtmpl :
</para>
-<programlisting><% uicomponent.renderChildren(); %>
-</programlisting>
+<programlisting><![CDATA[<% uicomponent.renderChildren();
%>]]></programlisting>
<para>
This makes the portlet generate the content of all child components.
</para>
<para>
- Change the treatment of the event, replace the println by : {code} public static class
OpenPopupActionListener extends EventListener<UITestRomainPortlet> public
void execute(Event<UITestRomainPortlet> event) throws Exception {
UITestRomainPortlet portlet = event.getSource(); UIPopupWindow popup =
portlet.getChild(UIPopupWindow.class); popup.setRendered(true); popup.setShow(true); }{ }
{code}
+ Change the treatment of the event, replace the println by :
</para>
+ <programlisting role="JAVA"><![CDATA[public static class
OpenPopupActionListener extends EventListener<UITestRomainPortlet> {
+ public void execute(Event<UITestRomainPortlet> event) throws Exception {
+ UITestRomainPortlet portlet = event.getSource();
+ UIPopupWindow popup = portlet.getChild(UIPopupWindow.class);
+ popup.setRendered(true);
+ popup.setShow(true);
+ }
+}]]></programlisting>
<para>
When user clicks on the button, the popup is shown.
</para>
Modified: portal/trunk/docs/reference-guide/en/modules/portlets/Groovy_Templates.xml
===================================================================
--- portal/trunk/docs/reference-guide/en/modules/portlets/Groovy_Templates.xml 2009-12-09
08:59:26 UTC (rev 977)
+++ portal/trunk/docs/reference-guide/en/modules/portlets/Groovy_Templates.xml 2009-12-09
11:43:22 UTC (rev 978)
@@ -2,144 +2,237 @@
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
]>
<section id="sect-Reference_Guide-Groovy_Templates">
- <!--
+ <title>Groovy Templates</title>
+ <section id="sect-Reference_Guide-Groovy_Templates-Overview">
+ <title>Overview</title>
+ <para>
+ This article gives a glance at the Groovy language, and
+ explains how to
+ configure the portlet and and the groovy
+ template.
+ </para>
+ <para>
+ It's recommended to read also
+ <xref linkend="sect-Reference_Guide-AJAX_in_GateIn_Framework"
/>
+ in order to understand better the communication between the
+ Groovy Template and the portlet.
+ </para>
+ </section>
- Copyright (C) 2009 eXo Platform SAS.
-
- This is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of
- the License, or (at your option) any later version.
-
- This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this software; if not, write to the Free
- Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
-
- --><title>Groovy Templates</title>
- <section id="sect-Reference_Guide-Groovy_Templates-Overview">
- <title>Overview</title>
- <para>
- This article gives a glance at the Groovy language, and explains how to configure the
portlet and and the groovy template.
+ <section id="sect-Reference_Guide-Groovy_Templates-Basic_structure">
+ <title>Basic structure</title>
+ <para>
+ The structure of a template is very easy :
</para>
- <para>
- It's recommended to read also <xref
linkend="sect-Reference_Guide-AJAX_in_GateIn_Framework" /> in order to
understand better the communication between the Groovy Template and the portlet.
- </para>
- </section>
-
- <section id="sect-Reference_Guide-Groovy_Templates-Basic_structure">
- <title>Basic structure</title>
- <para>
- The structure of a template is very easy :
- </para>
- <itemizedlist>
- <listitem>
- <para>
- The HTML code
+ <itemizedlist>
+ <listitem>
+ <para>
+ The HTML code
</para>
- </listitem>
- <listitem>
- <para>
- zero or more groovy language code blocks, enclosed by <% ... %>
- </para>
- </listitem>
- </itemizedlist>
- <para>
- The HTML code in the template doesn't have to contain the
<code>html</code>, or
<code>body</code> tags. Hence, you can use a groovy template
for a component that will be rendered in another component.
- </para>
- <para>
- Example : <emphasis
role="bold">UIPortalApplication.gtmpl</emphasis> template (<emphasis
role="bold">/GateInProjects/portal/trunk/web/portal/src/main/webapp/groovy/portal/webui/workspace/</emphasis>)
- </para>
-
-<programlisting><!DOCTYPE html
+ </listitem>
+ <listitem>
+ <para>
+ zero or more groovy language code blocks, enclosed by
+ <% ... %> </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ The HTML code in the template doesn't have to contain the
+ <literal>html</literal>
+ , or
+ <literal>body</literal>
+ tags. Hence, you can use a groovy template for a component that
+ will be rendered in another component.
+ </para>
+ <para>
+ Example :
+ </para>
+
+ <programlisting role="HTML"><![CDATA[<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<%
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<%
import org.exoplatform.webui.core.UIComponent;
def currentPage = uicomponent.getCurrentPage();
...
-%>
+%>
...
- <div class="$uicomponent.skin"
id="UIPortalApplication">
- <%uicomponent.renderChildren();%>
+ <div class="$uicomponent.skin" id="UIPortalApplication">
+ <%uicomponent.renderChildren();%>
+ </div>]]>
</programlisting>
- </section>
-
- <section id="sect-Reference_Guide-Groovy_Templates-Groovy_language">
- <title>Groovy language</title>
- <para>
- Groovy is a scripting language for Java. Here are a few examples on how to use it, but
you can find more information in <ulink
url="http://groovy.codehaus.org/Documentation">the full
documentation</ulink>.
+ </section>
+
+ <section id="sect-Reference_Guide-Groovy_Templates-Groovy_language">
+ <title>Groovy language</title>
+ <para>
+ Groovy is a scripting language for Java. Here are a few
+ examples on how to use it, but you can find more information in
+ <ulink
url="http://groovy.codehaus.org/Documentation">the full
documentation</ulink>
+ .
+ </para>
+ <para>
+ This language looks like Java a lot, so it's very easy to
+ use. Examples :
+ </para>
+ <para>
+ Variables definition :
+ </para>
+ <programlisting>int min = 1;
+def totalPage = uicomponent.getAvailablePage();
+String name = "uiPortlet";
+categories = uicomponent.getItemCategories();
+String columns = uicomponent.getColumns();</programlisting>
+ <para>Other expressions :</para>
+ <programlisting><![CDATA[for(category in categories) { ... }
+for(i in min..max) { ... } // min and max are int variables
+println "</div>" ;
+println """
+ <div class="Item">
+ <div class="OverflowContainer">
+""";
+<%=uicomponent.getToolbarStyle();%> // <%= to avoid a call of println method
+import org.exoplatform.portal.config.model.PageNode;]]></programlisting>
+ </section>
+
+ <section
+
id="sect-Reference_Guide-Groovy_Templates-Linking_a_portlet_with_a_template">
+ <title>Linking a portlet with a template</title>
+
+ <section
+ id="sect-Reference_Guide-Groovy_Templates-Portlet_configuration">
+ <title>Portlet configuration</title>
+ <para>
+ The configuration of a portlet is partly made with
+ <literal>ComponentConfig</literal> annotations (others are
+ ComponentConfigs, EventConfig, etc). One of the parameters
+ of
+ this annotation is called
+ <literal>template</literal>, where you can define the path
+ to
+ the template file associated with this portlet.
</para>
- <para>
- This language looks like Java a lot, so it's very easy to use. Examples :
+ <para>
+ To specify this parameter to your portlet, just add this
+ statement to your configuration annotation, for example in
+ <emphasis
role="bold">src:/portlet/exoadmin/src/main/java/org/exoplatform/applicationregistry/webui/component/
+ </emphasis>
+ you find
+ <emphasis
role="bold">UIApplicationForm.java</emphasis>
+ :
+ </para>
+
+ <programlisting>@ComponentConfig(
+ lifecycle = UIFormLifecycle.class,
+ template = "system:/groovy/webui/form/UIFormWithTitle.gtmpl",
+ events = {
+ @EventConfig(listeners = UIApplicationForm.SaveActionListener.class),
+ @EventConfig(phase = Phase.DECODE, listeners =
UIApplicationForm.CancelActionListener.class)
+ }
+)</programlisting>
+ <para>
+ You see that the path is in the namespace called "system",
+ "system" is a reference to the portal webapp. In this webapp
+ you find some reusable groovy templates, just open the
+ folder
+ <emphasis
role="bold">src:/web/portal/src/main/webapp/groovy/webui/form/
+ </emphasis>
+ to see them.
+ </para>
+ <para>
+ As you want to create your own template, create a groovy
+ file
+ in your webbapp and refer to it. Please use the
+ namespace "app"
+ for refering to the same webapp as your
+ component. GateIn
+ always puts the component templates in a
+ folder like
+
"/webapp/groovy/<literal>your_portlet_name</literal>/webui/component".
+ </para>
+ <programlisting>template =
"app:/groovy/your_portlet_name/webui/component/your_component.gtmpl"</programlisting>
+ <para>
+ You can now edit your template file.
</para>
- <para>
- Variables definition : {code} int min = 1; def totalPage =
uicomponent.getAvailablePage(); String name = "uiPortlet"; categories =
uicomponent.getItemCategories(); String columns = uicomponent.getColumns(); {code} Other
expressions : {code} for(category in categories) { ... } // easy to use for loop for(i in
min..max) { ... } // min and max are int variables println
"</div>" ; println """ <div
class="Item"> <div class="OverflowContainer">
"""; <%=uicomponent.getToolbarStyle();%> // <%= to
avoid a call of println method import org.exoplatform.portal.config.model.PageNode;
{code}
+ </section>
+
+ <section
id="sect-Reference_Guide-Groovy_Templates-The_template_file">
+ <title>The template file</title>
+ <para>
+ As we said before, the template file is composed of HTML
+ code and
+ groovy code blocks. There are a few things more that
+ you
+ need
+ to know to fully link your portlet with your
+ template.
</para>
- </section>
-
- <section
id="sect-Reference_Guide-Groovy_Templates-Linking_a_portlet_with_a_template">
- <title>Linking a portlet with a template</title>
- <para>
- Stuff Goes Here?
- </para>
- </section>
-
- <section
id="sect-Reference_Guide-Groovy_Templates-Portlet_configuration">
- <title>Portlet configuration</title>
- <para>
- The configuration of a portlet is partly made with
{style:type=span|font-family=courier new,courier}ComponentConfig {style}annotations
(others are ComponentConfigs, EventConfig, etc). One of the parameters of this annotation
is called {style:type=span|font-family=courier new,courier}template{style}, where you can
define the path to the template file associated with this portlet.
- </para>
- <para>
- To specify this parameter to your portlet, just add this statement to your
configuration annotation, for example in <emphasis
role="bold">/GateInProjects/portal/trunk/portlet/exoadmin/src/main/java/org/exoplatform/applicationregistry/webui/component/</emphasis>
you find <emphasis role="bold">UIApplicationForm.java</emphasis>:
- </para>
-
-<programlisting>@ComponentConfig(
- lifecycle = UIFormLifecycle.class,
- template = "system:/groovy/webui/form/UIFormWithTitle.gtmpl",
- events = {
- @EventConfig(listeners = UIApplicationForm.SaveActionListener.class),
- @EventConfig(phase = Phase.DECODE, listeners =
UIApplicationForm.CancelActionListener.class)
- }
-)
-</programlisting>
- <para>
- You see that the path is in the namespace called "system",
"system" is a reference to the portal webapp. In this webapp you find some
reusable groovy templates, just open the folder <emphasis
role="bold">/GateInProjects/portal/trunk/web/portal/src/main/webapp/groovy/webui/form/</emphasis>
to see them.
- </para>
- <para>
- As you want to create your own template, create a groovy file in your webbapp and
refer to it. Please use the namespace "app" for refering to the same webapp as
your component. GateIn always puts the component templates in a folder like
"/webapp/groovy/your<emphasis>portlet</emphasis>name/webui/component".
- </para>
-
-<programlisting>template =
"app:/groovy/your_portlet_name/webui/component/your_component.gtmpl"
-</programlisting>
- <para>
- You can now edit your template file.
- </para>
- </section>
-
- <section id="sect-Reference_Guide-Groovy_Templates-The_template_file">
- <title>The template file</title>
- <para>
- As we said before, the template file is composed of HTML code and groovy code blocks.
There are a few things more that you need to know to fully link your portlet with your
template.
- </para>
- <para>
- If your template defines the UI of a component, you have an access to this component
instance (the java object) using the variable {style:type=span|font-family=courier
new,courier}uicomponent{style}. This should be the case almost all the time, but we
recommend that you check that your java class inherits from UIComponent before you use
this variable. With this {style:type=span|font-family=courier new,courier}uicomponent
{style}variable, you can access all the attributes and functions of your component, to use
them in your template. Example : UIPageIterator.gtmpl {code} <% def currentPage =
uicomponent.getCurrentPage(); %> ... <a
href="<%=uicomponent.event("ShowPage","$currentPage")%>"
class="Icon
LastTopPageIcon"><span></span></a>
{code}
- </para>
- <para>
- This example shows that {style:type=span|font-family=courier new,courier}uicomponent
{style}can be used to make Ajax calls, thanks to the {style:type=span|font-family=courier
new,courier}event {style}method. See <xref
linkend="sect-Reference_Guide-AJAX_in_GateIn_Framework" /> for more details.
- </para>
- <para>
- Another variable that you can use is {style:type=span|font-family=courier
new,courier}{style}<emphasis>ctx. It gives access to the context in which the
template is processed. Hence, you can get some elements like the request, the Javscript
manager, or the resource resolver (</emphasis>ctx.appRes). Examples : {code}
<% def rcontext = <emphasis>ctx.getRequestContext() ;
rcontext.getJavascriptManager().importJavascript('GateIn.webui.UIPopupWindow');</emphasis>ctx.appRes(popupId
+ ".title."+ title); %> {code}
- </para>
- <para>
- If you use your template to define the user interface of a component that includes a
form, you can access the instance of UIForm in a variable named
{style:type=span|font-family=courier new,courier}uiform{style}. The UIForm class provides
the methods, {style:type=span|font-family=courier new,courier}begin(){style} and
{style:type=span|font-family=courier new,courier}end(){style}, that write the HTML tags of
the form. Your form class must inherit from <literal>UIForm</literal>, in this
class you add the input elements (fields, checkboxes, lists) which you wish to use in your
form. In your groovy template you can render your input elements using
{style:type=span|font-family=courier new,courier}{style}{code}{ uiform.renderField(field)
}{code}
- </para>
- </section>
+ <para>
+ If your template defines the UI of a component, you have
+ an access to
+ this component instance (the java object) using
+ the variable
+ <literal>uicomponent</literal>. This should be the case
+ almost
+ all the time, but we recommend that you check that
+ your java
+ class inherits from UIComponent before you use this
+ variable.
+ With this <literal>uicomponent</literal> variable, you can access
all
+ the
+ attributes and functions of your component, to use them
+ in your
+ template. Example : UIPageIterator.gtmpl:
+ </para>
+ <programlisting><![CDATA[<%
+ def currentPage = uicomponent.getCurrentPage();
+%>
+...
+<a
href="<%=uicomponent.event("ShowPage","$currentPage")%>"
class="Icon LastTopPageIcon">
+ <span></span>
+</a>]]></programlisting>
+ <para>
+ This example shows that <literal>uicomponent</literal> can be
used to make Ajax
+ calls,
+ thanks to the <literal>event</literal> method. See
+ <xref linkend="sect-Reference_Guide-AJAX_in_GateIn_Framework"
/>
+ for more details.
+ </para>
+ <para>
+ Another variable that you can use is
+ <literal>ctx</literal>. It gives access to the context in which
the
+ template is processed. Hence, you can get some elements
+ like
+ the request, the Javscript manager, or the resource
+ resolver (ctx.appRes).
+ Examples :
+ </para>
+ <programlisting><![CDATA[<%
+ def rcontext = ctx.getRequestContext() ;
+ context.getJavascriptManager().importJavascript('GateIn.webui.UIPopupWindow');
+ ctx.appRes(popupId + ".title."+ title);
+%>]]></programlisting>
+ <para>
+ If you use your template to define the user interface of a
+ component that includes a form, you can access the instance
+ of
+ UIForm in a variable named
+ <literal>uiform</literal>. The UIForm class provides the
+ methods, <literal>begin()</literal> and
+ <literal>end()</literal>,
+ that write the HTML tags of the
+ form. Your form class must
+ inherit from
+ <literal>UIForm</literal>
+ , in this class you add the input elements (fields,
+ checkboxes,
+ lists) which you wish to use in your form. In
+ your groovy
+ template you can render your input elements using
+ <literal>uiform.renderField(field)</literal>
+ </para>
+ </section>
+ </section>
</section>
Modified: portal/trunk/docs/reference-guide/en/modules/portlets/Portlet_Lifecycle.xml
===================================================================
--- portal/trunk/docs/reference-guide/en/modules/portlets/Portlet_Lifecycle.xml 2009-12-09
08:59:26 UTC (rev 977)
+++ portal/trunk/docs/reference-guide/en/modules/portlets/Portlet_Lifecycle.xml 2009-12-09
11:43:22 UTC (rev 978)
@@ -2,70 +2,77 @@
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
]>
<section id="sect-Reference_Guide-Portlet_Lifecycle">
- <!--
+ <title>Portlet Lifecycle</title>
+ <section id="sect-Reference_Guide-Portlet_Lifecycle-Overview">
+ <title>Overview</title>
+ <para>
+ The goal of this chapter is not to talk about the Portlet API
+ specification lifecycle but more about GateIn UI framework to
+ easily develop portlets.
+ </para>
+ <para>
+ The web framework used here has been completely developed by GateIn and
+ perfectly suits the portal environment, it even allows to send
+ events from the portlet UIComponents to the Portal ones.
+ </para>
+ <para>
+ Of course using the GateIn web framework to build portlets is not
+ necessary and any other web framework that supports portlet
+ environment can be used. But all GateIn portlets that are part
+ of GateIn products are developed using that framework and we
+ provide several UI components that can be used in different
+ abstracted contexts such as the portal itself or some portlets.
+ </para>
+ <para>
+ This chapter is not a tutorial on how to write portlets, it
+ will go in the details of the code implementation and logic;
+ hence it is intended for advanced developers. It is also
+ advised to read the
+ <xref linkend="sect-Reference_Guide-Portal_Lifecycle" />
+ article before as the that article explains concepts that are
+ similar and top hierarchy classes that are shared.
+ </para>
+ </section>
- Copyright (C) 2009 eXo Platform SAS.
-
- This is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of
- the License, or (at your option) any later version.
-
- This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this software; if not, write to the Free
- Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ <section id="sect-Reference_Guide-Portlet_Lifecycle-Portlet_init">
+ <title>Portlet init</title>
+ <para>
+ The main entry point for configuring a portlet is in the
+ <emphasis role="bold">portlet.xml</emphasis>
+ file located in the portlet application WAR. Every portlet that
+ shall be built using the GateIn web framework must reference
+ the
+ <emphasis
role="bold">PortletApplicationController</emphasis>
+ . The portlet configuration such as the root component is
+ defined in a
+ <emphasis role="bold">configuration.xml</emphasis>
+ file. The path to this configuration.xml file is defined in the
+ init-param "
+ <emphasis role="bold">webui.configuration</emphasis>
+ " of porlet.xml.
+ </para>
- --><title>Portlet Lifecycle</title>
- <section id="sect-Reference_Guide-Portlet_Lifecycle-Overview">
- <title>Overview</title>
- <para>
- The goal of this chapter is not to talk about the Portlet API specification lifecycle
but more about GateIn UI framework to easily develop portlets.
- </para>
- <para>
- The web framework used here has been completely developed by GateIn and perfectly
suits the portal environment, it even allows to send events from the portlet UIComponents
to the Portal ones.
- </para>
- <para>
- Of course using the GateIn web framework to build portlets is not necessary and any
other web framework that supports portlet environment can be used. But all GateIn portlets
that are part of GateIn products are developed using that framework and we provide several
UI components that can be used in different abstracted contexts such as the portal itself
or some portlets.
- </para>
- <para>
- This chapter is not a tutorial on how to write portlets, it will go in the details of
the code implementation and logic; hence it is intended for advanced developers. It is
also advised to read the <xref
linkend="sect-Reference_Guide-Portal_Lifecycle" /> article before as the that
article explains concepts that are similar and top hierarchy classes that are shared.
- </para>
- </section>
-
- <section id="sect-Reference_Guide-Portlet_Lifecycle-Portlet_init">
- <title>Portlet init</title>
- <para>
- The main entry point for configuring a portlet is in the <emphasis
role="bold">portlet.xml</emphasis> file located in the portlet
application WAR. Every portlet that shall be built using the GateIn web framework must
reference the <emphasis
role="bold">PortletApplicationController</emphasis> . The portlet
configuration such as the root component is defined in a <emphasis
role="bold">configuration.xml</emphasis> file. The path to this
configuration.xml file is defined in the init-param "<emphasis
role="bold">webui.configuration</emphasis>" of porlet.xml.
- </para>
-
-<programlisting> <portlet>
- <description xml:lang="EN">Content
Portlet</description>
- <portlet-name>ContentPortlet</portlet-name>
- <display-name xml:lang="EN">Content
Portlet</display-name>
-
<portlet-class>org.exoplatform.webui.application.portlet.PortletApplicationController</portlet-class>
+ <programlisting><![CDATA[<portlet>
+ <description xml:lang="EN">Content Portlet</description>
+ <portlet-name>ContentPortlet</portlet-name>
+ <display-name xml:lang="EN">Content Portlet</display-name>
+
<portlet-class>org.exoplatform.webui.application.portlet.PortletApplicationController</portlet-class>
- <init-param>
- <name>webui.configuration</name>
-
<value>/WEB-INF/conf/portlet/content/ContentPortlet/webui/configuration.xml</value>
- </init-param>
-</programlisting>
+ <init-param>
+ <name>webui.configuration</name>
+
<value>/WEB-INF/conf/portlet/content/ContentPortlet/webui/configuration.xml</value>
+ </init-param>
+</portlet>]]></programlisting>
<para>
The structure of the <emphasis
role="bold">configuration.xml</emphasis> file is exactly the same as
the <emphasis>webui-configuration.xml</emphasis>which we have already
introduced in the <xref linkend="sect-Reference_Guide-Portal_Lifecycle" />
article. In the case of the content portlet it looks like:
</para>
-<programlisting><webui-configuration>
- <application>
-
<ui-component-root>org.exoplatform.content.webui.component.UIContentPortlet</ui-component-root>
-
<state-manager>org.exoplatform.webui.application.portlet.ParentAppStateManager</state-manager>
- </application>
-</webui-configuration>
-</programlisting>
+<programlisting><![CDATA[<webui-configuration>
+ <application>
+
<ui-component-root>org.exoplatform.content.webui.component.UIContentPortlet</ui-component-root>
+
<state-manager>org.exoplatform.webui.application.portlet.ParentAppStateManager</state-manager>
+ </application>
+</webui-configuration>]]></programlisting>
<para>
The <emphasis
role="bold">PortletApplicationController</emphasis> class extends the
<emphasis role="bold">GenericPortlet</emphasis> class defined in the
Portlet API specification.
</para>
@@ -73,25 +80,24 @@
All methods like <emphasis>processAction()</emphasis> or
<emphasis>render()</emphasis> are delegated to the <emphasis
role="bold">PortletApplication</emphasis>. The creation and caching
inside the <emphasis role="bold">WebController</emphasis> object is
described in the following method:
</para>
-<programlisting> /**
- * try to obtain the PortletApplication from the WebAppController.
- *
- * If it does not exist a new PortletApplication object is created, init and cached in
the
- * controller
- */
- private PortletApplication getPortletApplication() throws Exception {
- PortalContainer container = PortalContainer.getInstance() ;
- WebAppController controller =
- (WebAppController)container.getComponentInstanceOfType(WebAppController.class) ;
- PortletApplication application = controller.getApplication(applicationId_) ;
- if(application == null) {
- application = new PortletApplication(getPortletConfig()) ;
- application.onInit() ;
- controller.addApplication(application) ;
- }
- return application ;
+<programlisting><![CDATA[/**
+ * try to obtain the PortletApplication from the WebAppController.
+ *
+ * If it does not exist a new PortletApplication object is created, init and cached in
the
+ * controller
+ */
+private PortletApplication getPortletApplication() throws Exception {
+ PortalContainer container = PortalContainer.getInstance() ;
+ WebAppController controller =
+ (WebAppController)container.getComponentInstanceOfType(WebAppController.class) ;
+ PortletApplication application = controller.getApplication(applicationId_) ;
+ if(application == null) {
+ application = new PortletApplication(getPortletConfig()) ;
+ application.onInit() ;
+ controller.addApplication(application) ;
}
-</programlisting>
+ return application ;
+}]]></programlisting>
</section>
<section
id="sect-Reference_Guide-Portlet_Lifecycle-Portlet_request_handler">
@@ -107,80 +113,78 @@
The code of the method in PortletApplication is described here. The business logic is
shown in the javadoc:
</para>
-<programlisting> /**
- * The processAction() method is the one modelled according to the Portlet API
specification
- *
- * The process is quite simple and here are te different steps done in the method:
- *
- * 1) The current instance of the WebuiRequestContext (stored in a ThreadLocal in the
class) is referenced
- * 2) A new request context of type PortletRequestContext (which extends the class
WebuiRequestContext) is
- * created as a child of the current context instance
- * 3) The new context is place inside the ThreadLocal and hence overides its parent one
there,
- * only for the portlet request lifeciclye
- * 4) The method onStartRequest() is called in all the ApplicationLifecycle objects
referenced in the webui
- * configuration XML file
- * 5) The StateManager object (in case of portlet it is an object of type
ParentAppStateManager) is used to get the RootComponent
- * also referenced in the XML configuration file
- * 6) The methods processDecode(UIApplication, WebuiRequestContext) and
processAction(UIApplication, WebuiRequestContext)
- * are then called
- * 7) Finally, a flag, to tell that the processAction phase was done, in the context is
set to true and the parent
- * context is restored in the Threadlocal
- */
- public void processAction(ActionRequest req, ActionResponse res) throws Exception {
- WebuiRequestContext parentAppRequestContext =
WebuiRequestContext.getCurrentInstance() ;
- PortletRequestContext context = createRequestContext(req, res,
parentAppRequestContext) ;
- WebuiRequestContext.setCurrentInstance(context) ;
- try {
- for(ApplicationLifecycle lifecycle : getApplicationLifecycle()) {
- lifecycle.onStartRequest(this, context) ;
- }
- UIApplication uiApp = getStateManager().restoreUIRootComponent(context) ;
- context.setUIApplication(uiApp) ;
- processDecode(uiApp, context) ;
- if(!images/context.isResponseComplete() &&!images/
context.getProcessRender()) {
- processAction(uiApp, context) ;
- }
- } finally {
- context.setProcessAction(true) ;
- WebuiRequestContext.setCurrentInstance(parentAppRequestContext) ;
+<programlisting><![CDATA[/**
+ * The processAction() method is the one modelled according to the Portlet API
specification
+ *
+ * The process is quite simple and here are te different steps done in the method:
+ *
+ * 1) The current instance of the WebuiRequestContext (stored in a ThreadLocal in the
class) is referenced
+ * 2) A new request context of type PortletRequestContext (which extends the class
WebuiRequestContext) is
+ * created as a child of the current context instance
+ * 3) The new context is place inside the ThreadLocal and hence overides its parent one
there,
+ * only for the portlet request lifeciclye
+ * 4) The method onStartRequest() is called in all the ApplicationLifecycle objects
referenced in the webui
+ * configuration XML file
+ * 5) The StateManager object (in case of portlet it is an object of type
ParentAppStateManager) is used to get the RootComponent
+ * also referenced in the XML configuration file
+ * 6) The methods processDecode(UIApplication, WebuiRequestContext) and
processAction(UIApplication, WebuiRequestContext)
+ * are then called
+ * 7) Finally, a flag, to tell that the processAction phase was done, in the context is
set to true and the parent
+ * context is restored in the Threadlocal
+ */
+public void processAction(ActionRequest req, ActionResponse res) throws Exception {
+ WebuiRequestContext parentAppRequestContext = WebuiRequestContext.getCurrentInstance()
;
+ PortletRequestContext context = createRequestContext(req, res, parentAppRequestContext)
;
+ WebuiRequestContext.setCurrentInstance(context) ;
+ try {
+ for(ApplicationLifecycle lifecycle : getApplicationLifecycle()) {
+ lifecycle.onStartRequest(this, context) ;
+ }
+ UIApplication uiApp = getStateManager().restoreUIRootComponent(context) ;
+ context.setUIApplication(uiApp) ;
+ processDecode(uiApp, context) ;
+ if(!images/context.isResponseComplete() &&!images/
context.getProcessRender()) {
+ processAction(uiApp, context) ;
}
+ } finally {
+ context.setProcessAction(true) ;
+ WebuiRequestContext.setCurrentInstance(parentAppRequestContext) ;
}
-</programlisting>
+}]]></programlisting>
<para>
The <emphasis role="bold">PortletRequestContext</emphasis>
extends <emphasis role="bold">WebuiRequestContext</emphasis> class
and acts as a wrapper on top of all the portlet request information:
</para>
-<programlisting> /**
- * In this method we try to get the PortletRequestContext object from the attribute map
of the parent
- * WebuiRequestContext.
- *
- * If it is not cached then we create a new instance, if it is cached then we init it
with the correct
- * writer, request and response objects
- *
- * We finally cache it in the parent attribute map
- *
- */
- private PortletRequestContext createRequestContext(PortletRequest req, PortletResponse
res,
- WebuiRequestContext
parentAppRequestContext) throws IOException {
- String attributeName = getApplicationId() + "$PortletRequest" ;
- PortletRequestContext context =
- (PortletRequestContext) parentAppRequestContext.getAttribute(attributeName) ;
- Writer w = null ;
- if(res instanceof RenderResponse){
- RenderResponse renderRes = (RenderResponse)res;
- renderRes.setContentType("text/html; charset=UTF-8");
- w = renderRes.getWriter() ;
- }
- if(context!images/= null) {
- context.init(w, req, res) ;
- } else {
- context = new PortletRequestContext(this, w, req, res) ;
- parentAppRequestContext.setAttribute(attributeName, context) ;
- }
- context.setParentAppRequestContext(parentAppRequestContext) ;
- return context;
+<programlisting><![CDATA[/**
+ * In this method we try to get the PortletRequestContext object from the attribute map
of the parent
+ * WebuiRequestContext.
+ *
+ * If it is not cached then we create a new instance, if it is cached then we init it
with the correct
+ * writer, request and response objects
+ *
+ * We finally cache it in the parent attribute map
+ *
+ */
+private PortletRequestContext createRequestContext(PortletRequest req, PortletResponse
res,
+ WebuiRequestContext
parentAppRequestContext) throws IOException {
+ String attributeName = getApplicationId() + "$PortletRequest" ;
+ PortletRequestContext context =
+ (PortletRequestContext) parentAppRequestContext.getAttribute(attributeName) ;
+ Writer w = null ;
+ if(res instanceof RenderResponse){
+ RenderResponse renderRes = (RenderResponse)res;
+ renderRes.setContentType("text/html; charset=UTF-8");
+ w = renderRes.getWriter() ;
}
-</programlisting>
+ if(context!images/= null) {
+ context.init(w, req, res) ;
+ } else {
+ context = new PortletRequestContext(this, w, req, res) ;
+ parentAppRequestContext.setAttribute(attributeName, context) ;
+ }
+ context.setParentAppRequestContext(parentAppRequestContext) ;
+ return context;
+}]]></programlisting>
<para>
In the PortletApplication, the line
</para>
@@ -188,7 +192,7 @@
<emphasis>UIApplication uiApp =
getStateManager().restoreUIRootComponent(context);</emphasis> asks the StateManager
defined for the portlet to get the UI root component. In the case of a portlet the root
component must extend UIPortletApplication.
</para>
-<programlisting>public class ParentAppStateManager extends StateManager {
+<programlisting><![CDATA[public class ParentAppStateManager extends StateManager
{
/**
* This method simply delegate the call to the same method of the parent
WebuiRequestContext
@@ -197,38 +201,37 @@
public UIApplication restoreUIRootComponent(WebuiRequestContext context) throws
Exception {
WebuiRequestContext pcontext = (WebuiRequestContext)
context.getParentAppRequestContext() ;
return pcontext.getStateManager().restoreUIRootComponent(context) ;
- }
-</programlisting>
+ }]]></programlisting>
<para>
Hence this is the PortalStateManager that will also handle the extraction of the root
component.
</para>
-<programlisting> public UIApplication restoreUIRootComponent(WebuiRequestContext
context) throws Exception {
- context.setStateManager(this) ;
- WebuiApplication app = (WebuiApplication)context.getApplication() ;
-
- /*
- * If the request context is of type PortletRequestContext, we extract the parent
context which will
- * allow to get access to the PortalApplicationState object thanks to the session id
used as the key for the
- * syncronised Map uiApplications
- */
- if(context instanceof PortletRequestContext) {
- WebuiRequestContext preqContext = (WebuiRequestContext)
context.getParentAppRequestContext() ;
- PortalApplicationState state = uiApplications.get(preqContext.getSessionId()) ;
- PortletRequestContext pcontext = (PortletRequestContext) context ;
- String key = pcontext.getApplication().getApplicationId() ;
- UIApplication uiApplication = state.get(key) ;
- if(uiApplication!images/= null) return uiApplication;
- synchronized(uiApplications) {
- ConfigurationManager cmanager = app.getConfigurationManager() ;
- String uirootClass = cmanager.getApplication().getUIRootComponent() ;
- Class type =
Thread.currentThread().getContextClassLoader().loadClass(uirootClass) ;
- uiApplication = (UIApplication)app.createUIComponent(type, null, null, context) ;
- state.put(key, uiApplication) ;
- }
- return uiApplication ;
+<programlisting><![CDATA[public UIApplication
restoreUIRootComponent(WebuiRequestContext context) throws Exception {
+ context.setStateManager(this) ;
+ WebuiApplication app = (WebuiApplication)context.getApplication() ;
+
+ /*
+ * If the request context is of type PortletRequestContext, we extract the parent
context which will
+ * allow to get access to the PortalApplicationState object thanks to the session id
used as the key for the
+ * syncronised Map uiApplications
+ */
+ if(context instanceof PortletRequestContext) {
+ WebuiRequestContext preqContext = (WebuiRequestContext)
context.getParentAppRequestContext() ;
+ PortalApplicationState state = uiApplications.get(preqContext.getSessionId()) ;
+ PortletRequestContext pcontext = (PortletRequestContext) context ;
+ String key = pcontext.getApplication().getApplicationId() ;
+ UIApplication uiApplication = state.get(key) ;
+ if(uiApplication!images/= null) return uiApplication;
+ synchronized(uiApplications) {
+ ConfigurationManager cmanager = app.getConfigurationManager() ;
+ String uirootClass = cmanager.getApplication().getUIRootComponent() ;
+ Class type = Thread.currentThread().getContextClassLoader().loadClass(uirootClass)
;
+ uiApplication = (UIApplication)app.createUIComponent(type, null, null, context) ;
+ state.put(key, uiApplication) ;
}
-</programlisting>
+ return uiApplication ;
+ }
+}]]></programlisting>
</section>
<section id="sect-Reference_Guide-Portlet_Lifecycle-Render_phase">
@@ -237,88 +240,85 @@
The render method business logic is quite similar to processAction().
</para>
-<programlisting> /**
- * The render method business logic is quite similar to the processAction() one.
- *
- * 1) A PortletRequestContext object is created (or extracted from the cache if it
already exists)
- * and initialized
- * 2) The PortletRequestContext replaces the parent one in the WebuiRequestContext
ThreadLocal object
- * 3) If the portal has already called the portlet processAction() then the call to all
onStartRequest of
- * the ApplicationLifecycle has already been made, otherwise we call them
- * 4) The ParentStateManager is also used to get the UIApplication, as we have seen it
delegates the call
- * to the PortalStateManager which caches the UI component root associated with the
current application
- * 5) the processRender() method of the UIPortletApplucaton is called
- * 6) Finally, the method onEndRequest() is called on every ApplicationLifecycle
referenced in the portlet
- * configuration XML file and the parent WebuiRequestContext is restored
- *
- */
- public void render(RenderRequest req, RenderResponse res) throws Exception {
- WebuiRequestContext parentAppRequestContext =
WebuiRequestContext.getCurrentInstance() ;
- PortletRequestContext context = createRequestContext(req, res,
parentAppRequestContext) ;
- WebuiRequestContext.setCurrentInstance(context) ;
+<programlisting><![CDATA[/**
+ * The render method business logic is quite similar to the processAction() one.
+ *
+ * 1) A PortletRequestContext object is created (or extracted from the cache if it
already exists)
+ * and initialized
+ * 2) The PortletRequestContext replaces the parent one in the WebuiRequestContext
ThreadLocal object
+ * 3) If the portal has already called the portlet processAction() then the call to all
onStartRequest of
+ * the ApplicationLifecycle has already been made, otherwise we call them
+ * 4) The ParentStateManager is also used to get the UIApplication, as we have seen it
delegates the call
+ * to the PortalStateManager which caches the UI component root associated with the
current application
+ * 5) the processRender() method of the UIPortletApplucaton is called
+ * 6) Finally, the method onEndRequest() is called on every ApplicationLifecycle
referenced in the portlet
+ * configuration XML file and the parent WebuiRequestContext is restored
+ *
+ */
+public void render(RenderRequest req, RenderResponse res) throws Exception {
+ WebuiRequestContext parentAppRequestContext = WebuiRequestContext.getCurrentInstance()
;
+ PortletRequestContext context = createRequestContext(req, res, parentAppRequestContext)
;
+ WebuiRequestContext.setCurrentInstance(context) ;
+ try {
+ if(!context.hasProcessAction()) {
+ for(ApplicationLifecycle lifecycle : getApplicationLifecycle()) {
+ lifecycle.onStartRequest(this, context) ;
+ }
+ }
+ UIApplication uiApp = getStateManager().restoreUIRootComponent(context) ;
+ context.setUIApplication(uiApp) ;
+ if(!context.isResponseComplete()) {
+ UIPortletApplication uiPortletApp = (UIPortletApplication)uiApp;
+ uiPortletApp.processRender(this, context) ;
+ }
+ uiApp.setLastAccessApplication(System.currentTimeMillis()) ;
+ } finally {
try {
- if(!context.hasProcessAction()) {
- for(ApplicationLifecycle lifecycle : getApplicationLifecycle()) {
- lifecycle.onStartRequest(this, context) ;
- }
- }
- UIApplication uiApp = getStateManager().restoreUIRootComponent(context) ;
- context.setUIApplication(uiApp) ;
- if(!context.isResponseComplete()) {
- UIPortletApplication uiPortletApp = (UIPortletApplication)uiApp;
- uiPortletApp.processRender(this, context) ;
+ for(ApplicationLifecycle lifecycle : getApplicationLifecycle()) {
+ lifecycle.onEndRequest(this, context) ;
}
- uiApp.setLastAccessApplication(System.currentTimeMillis()) ;
- } finally {
- try {
- for(ApplicationLifecycle lifecycle : getApplicationLifecycle()) {
- lifecycle.onEndRequest(this, context) ;
- }
- } catch (Exception exception){
- log.error("Error while trying to call onEndRequest of the portlet
ApplicationLifecycle",
- exception);
- }
- WebuiRequestContext.setCurrentInstance(parentAppRequestContext) ;
+ } catch (Exception exception){
+ log.error("Error while trying to call onEndRequest of the portlet
ApplicationLifecycle",
+ exception);
}
+ WebuiRequestContext.setCurrentInstance(parentAppRequestContext) ;
}
-</programlisting>
+}]]></programlisting>
<para>
The processRender() call made on the UIPortletApplication is shown now:
</para>
-<programlisting> /**
- * The default processRender for an UIPortletApplication handles two cases:
- *
- * A. Ajax is used
- * ~UWC_TOKEN_START~1255420331108~UWC_TOKEN_END~
- * If Ajax is used and that the entire portal should not be re rendered, then an
AJAX fragment is
- * generated with information such as the portlet id, the portlet title, the
portlet modes, the window
- * states as well as the HTML for the block to render
- *
- * B. A full render is made
- * ----
- * a simple call to the method super.processRender(context) which will delegate
the call to all the
- * Lifecycle components
- *
- */
- public void processRender(WebuiApplication app, WebuiRequestContext context) throws
Exception {
- WebuiRequestContext pContext =
(WebuiRequestContext)context.getParentAppRequestContext();
- if(context.useAjax() &&!images/pContext.getFullRender()) {
- Writer w = context.getWriter() ;
-
- Set<UIComponent> list = context.getUIComponentToUpdateByAjax() ;
-// if(list == null) list = app.getDefaultUIComponentToUpdateByAjax(context) ;
- if(list!images/= null) {
- if(getUIPopupMessages().hasMessage())
context.addUIComponentToUpdateByAjax(getUIPopupMessages()) ;
- for(UIComponent uicomponent : list) {
- renderBlockToUpdate(uicomponent, context, w) ;
- }
- return ;
+<programlisting><![CDATA[/**
+ * The default processRender for an UIPortletApplication handles two cases:
+ *
+ * A. Ajax is used
+ * ----
+ * If Ajax is used and that the entire portal should not be re rendered, then an AJAX
fragment is
+ * generated with information such as the portlet id, the portlet title, the portlet
modes, the window
+ * states as well as the HTML for the block to render
+ *
+ * B. A full render is made
+ * ----
+ * a simple call to the method super.processRender(context) which will delegate the
call to all the
+ * Lifecycle components
+ *
+ */
+public void processRender(WebuiApplication app, WebuiRequestContext context) throws
Exception {
+ WebuiRequestContext pContext =
(WebuiRequestContext)context.getParentAppRequestContext();
+ if(context.useAjax() &&!images/pContext.getFullRender()) {
+ Writer w = context.getWriter() ;
+
+ Set<UIComponent> list = context.getUIComponentToUpdateByAjax() ;
+ if(list!images/= null) {
+ if(getUIPopupMessages().hasMessage())
context.addUIComponentToUpdateByAjax(getUIPopupMessages()) ;
+ for(UIComponent uicomponent : list) {
+ renderBlockToUpdate(uicomponent, context, w) ;
}
+ return ;
}
- super.processRender(context) ;
}
-</programlisting>
+ super.processRender(context) ;
+}]]></programlisting>
</section>
</section>
Deleted: portal/trunk/docs/reference-guide/en/modules/portlets/Sample_Basic_Portlet.xml
===================================================================
---
portal/trunk/docs/reference-guide/en/modules/portlets/Sample_Basic_Portlet.xml 2009-12-09
08:59:26 UTC (rev 977)
+++
portal/trunk/docs/reference-guide/en/modules/portlets/Sample_Basic_Portlet.xml 2009-12-09
11:43:22 UTC (rev 978)
@@ -1,33 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
-]>
-<section id="sect-Reference_Guide-Sample_Basic_Portlet">
- <!--
-
- Copyright (C) 2009 eXo Platform SAS.
-
- This is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of
- the License, or (at your option) any later version.
-
- This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this software; if not, write to the Free
- Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
-
- --><title>Sample Basic Portlet</title>
- <para>
- This sample shows a basic 1.0 portlet.
- </para>
- <para>
- Download the redirectportlet.war file in the attachment section.
- </para>
-</section>
-
-