jford 2004/04/09 07:54:17
Added: tutorial/xdocs/7 index.xml registry.xml actioncontext.xml
customization.xml events.xml velocity.xml
resolution.xml deploy.xml velocitytemplate.xml
Log:
Converted Chapter 7 of the tutorial to the xdoc format
Revision Changes Path
1.1 jakarta-jetspeed/tutorial/xdocs/7/index.xml
Index: index.xml
===================================================================
<?xml version="1.0"?>
<!--
Copyright 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.
-->
<document>
<properties>
<author email="[EMAIL PROTECTED]">David Sean Taylor</author>
<title>Velocity Portlet</title>
</properties>
<body>
<section name="Velocity Portlet">
<p>
Tutorial 7 introduces the Velocity Portlet. This section covers:
</p>
<p>
<ul>
<li>1. <a href="velocity.html">Introduction to Velocity</a></li>
<li>2. <a href="registry.html">Velocity Portlets in the Registry</a></li>
<li>3. <a href="velocitytemplate.html">The Velocity Template</a></li>
<li>4. <a href="resolution.html">Template Resolution</a></li>
<li>5. <a href="actioncontext.html">Velocity Actions and the Context</a></li>
<li>6. <a href="customization.html">Portlet Customization and Parameter
Styles</a></li>
<li>7. <a href="events.html">Action Events</a></li>
<li>8. <a href="deploy.html">Deploy</a></li>
</ul>
</p>
<p>
Let's get started. From the JPortal distribution root directory, type:
</p>
<p>
<source>
<![CDATA[
ant tutorial-7
]]>
</source>
</p>
<p>
Recommend bringing up these files in your editor:
</p>
<p>
<ul>
<li>1. webapp/WEB-INF/conf/t7-portlets.xreg</li>
<li>2. webapp/WEB-INF/psml/user/anon/html/default.psml</li>
<li>3. webapp/WEB-INF/psml/user/turbine/html/default.psml</li>
<li>4.
src/java/com/bluesunrise/jportal/modules/actions/portlets/TutorialStockQuoteAction1.java</li>
<li>5.
src/java/com/bluesunrise/jportal/modules/actions/portlets/TutorialStockQuoteAction2.java</li>
<li>6.
src/java/com/bluesunrise/jportal/modules/actions/portlets/CobiJonesPortletAction.java</li>
<li>7. webapp/WEB-INF/templates/vm/portlet/html/stock-quote1.vm</li>
<li>8. webapp/WEB-INF/templates/vm/portlet/html/stock-quote2.vm</li>
<li>9. webapp/WEB-INF/templates/vm/portlet/html/cobi-jones-form.vm</li>
<li>10. webapp/WEB-INF/conf/JPortalTurbine.properties</li>
</ul>
</p>
<p>
since we will reference them in tutorial 7.
</p>
</section>
</body>
</document>
1.1 jakarta-jetspeed/tutorial/xdocs/7/registry.xml
Index: registry.xml
===================================================================
<?xml version="1.0"?>
<!--
Copyright 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.
-->
<document>
<properties>
<author email="[EMAIL PROTECTED]">David Sean Taylor</author>
<title>Velocity Portlets in the Registry</title>
</properties>
<body>
<section name="Velocity Portlets in the Registry">
<p>
There is no need to extend this portlet class, just define your porlet entry in the
registry as a child of this class and provide your template and action class (extended
from GenericMVCAction) and you are good to go.
</p>
<p>
Velocity Portlets are defined like any other portlet: in the portlet registry. In
tutorial 7 we define two new portlets:
</p>
<hr />
<source>
<![CDATA[
<portlet-entry name="TutorialStockQuote1" hidden="false" type="ref"
parent="Velocity" application="false">
...
<parameter name="template" hidden="true"
value="tutorial-stock-quote1"/>
<parameter name="action" hidden="true"
value="portlets.TutorialStockQuoteAction1" />
...
</portlet-entry>
<portlet-entry name="TutorialStockQuote2" hidden="false" type="ref"
parent="Velocity" application="false">
...
<parameter name="template" hidden="true"
value="tutorial-stock-quote2" />
<parameter name="action" hidden="true"
value="portlets.TutorialStockQuoteAction2" />
...
</portlet-entry>
]]>
</source>
<p>
When defining a Velocity portlet, there are two required parameters: the template
and the action. The template defines the Velocity template which will generate the
portlet content.
It is your MVC View component. The action is the controller, and it has several
responsibilities including handling action events and populating the context.
The templates should be placed in the portlets subdirectory of one of your Velocity
template paths. The action is placed in the module path, conventionally under the
portlets directory of the root actions directory.
</p>
<p>
Also note that a Velocity portlet can derive from one of two Velocity portlets: <a
href="http://portals.apache.org/jetspeed-1/apidocs/org/apache/jetspeed/portal/portlets/VelocityPortlet.html">Velocity</a>
or <a
href="http://portals.apache.org/jetspeed-1/apidocs/org/apache/jetspeed/portal/portlets/CustomizerVelocityPortlet.html">CustomizerVelocity</a>.
The only difference being that the Velocity portlet uses the default Jetspeed
portlet customizer, where as the CustomizerVelocity portlet is expected to provide its
own customization. Look at the Weather Portlet as an example of a CustomizerVelocity
portlet providing its own customization.
</p>
<hr />
<source>
<![CDATA[
<portlet-entry name="TutorialStockQuote1" hidden="false" type="ref"
parent="Velocity" application="false">
...
</portlet-entry>
<portlet-entry name="WeatherPortlet" hidden="false" type="ref"
parent="CustomizerVelocity" application="false" >
...
</portlet-entry>
]]>
</source>
</section>
</body>
</document>
1.1 jakarta-jetspeed/tutorial/xdocs/7/actioncontext.xml
Index: actioncontext.xml
===================================================================
<?xml version="1.0"?>
<!--
Copyright 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.
-->
<document>
<properties>
<author email="[EMAIL PROTECTED]">David Sean Taylor</author>
<title>Velocity Portlet Actions</title>
</properties>
<body>
<section name="Velocity Portlet Actions">
<p>
Velocity Actions are Java classes, they are where you put your controlling logic for
your code. Here you will do any backend processing necessary to retrieve or store
dynamic information, and then populate the Velocity context with your model so that
the template may display the dynamic content.
</p>
<p>
First, let’s look at the code for the <b>TutorialStockQuoteAction8</b>.
This portlet retrieves stock quotes from a web service.
There is only one method in this Velocity portlet action, the <a
href="http://portals.apache.org/jetspeed-1/apidocs/org/apache/jetspeed/modules/actions/portlets/JspPortletAction.html#buildNormalContext(org.apache.jetspeed.portal.Portlet,%20org.apache.velocity.context.Context,%20org.apache.turbine.util.RunData)">buildNormalContext</a>
method.
The <a
href="http://portals.apache.org/jetspeed-1/apidocs/org/apache/jetspeed/webservices/finance/stockmarket/StockQuoteService.html">StockQuoteService</a>
comes with the Jetspeed deployment.
It returns an array of <a
href="http://portals.apache.org/jetspeed-1/apidocs/org/apache/jetspeed/webservices/finance/stockmarket/StockQuote.html">StockQuote</a>
objects when you ask for a quote on a array of stock symbols.
</p>
<p>
<source>
<![CDATA[
public class TutorialStockQuoteAction1 extends VelocityPortletAction
{
private static final String SYMBOLS = "symbols";
private static final String COLUMNS = "columns";
private static final String QUOTES = "quotes";
private static final String[] ALL_COLUMNS =
{"Symbol","Price","Change","Volume"};
protected void buildNormalContext(VelocityPortlet portlet,
Context context,
RunData rundata)
{
try
{
// Get reference to stock quote web service
StockQuoteService service = (StockQuoteService)
TurbineServices.getInstance().
getService(StockQuoteService.SERVICE_NAME);
// Retrieve portlet parameters
String symbols = PortletConfigState.getParameter(portlet,
rundata, SYMBOLS, "IBM,MSFT,ORCL,SUNW");
// Request stock quote(s) from the stock quote web service
String[] symbolArray = StringUtils.stringToArray(
symbols, ",");
StockQuote[] quotes = service.fullQuotes(symbolArray);
// Place appropriate objects in Velocity context
context.put(QUOTES, quotes);
context.put(COLUMNS, ALL_COLUMNS);
}
catch (Exception e)
{
Log.error(e);
}
}
]]>
</source>
</p>
<p>
The array of stock quotes is put in the context and is made available to the
template. The template can then pull out the stock records that it needs, iterating
over the array of stock quotes:
</p>
<p>
<source>
<![CDATA[
#foreach ($quote in $quotes)
<tr>
#entryCell ($quote.Symbol)
#entryCell ($quote.Price)
#entryCell ($quote.Change)
#entryCell ($quote.Volume)
</tr>
#end
]]>
</source>
</p>
<p>
The above method call retrieves value of the symbols parameter using the following
algorithm:
</p>
<p>
Let’s take a closer look at the <a
href="http://portals.apache.org/jetspeed-1/apidocs/org/apache/jetspeed/modules/actions/portlets/VelocityPortletAction.html">VelocityPortletAction</a>
class,
and see how the processAction phase is nicely handled for you by inheriting from
this class.
There are three important methods than you can implement in your velocity action.
Remember from section <a href="../6/lifecycle.html">6.2 on the Portlet Life
Cycle</a>, the processAction phase occurs before the render phase.
So the following methods will be called before the template is processed, allowing
for you to cleanly populate the JSP request attributes first, depending on the portlet
<a href="../6/modes.html">mode</a>.
</p>
<p>
<table>
<tr>
<td>Method</td>
<td>Portlet Mode</td>
</tr>
<tr>
<td>BuildNormalContext</td>
<td>View</td>
</tr>
<tr>
<td>buildConfigureContext</td>
<td>Customize (Edit)</td>
</tr>
<tr>
<td>buildMaximizedContent</td>
<td>Maximize</td>
</tr>
</table>
</p>
<p>
Using this approach you can easily customize your portlet to generate different
content depending on the mode of the request.
Often, the maximize content is the same as the normal context.
In the default implementation of <b>buildConfigureContext</b>, the normal context is
called.
You can override this method to specially handle maximize mode.
The <b>buildConfigureContext</b> is available if you want to provide your own
customization as we will do further on in this chapter.
To go with the default portal customizer provided by Jetspeed, just don’t override
this method.
</p>
</section>
</body>
</document>
1.1 jakarta-jetspeed/tutorial/xdocs/7/customization.xml
Index: customization.xml
===================================================================
<?xml version="1.0"?>
<!--
Copyright 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.
-->
<document>
<properties>
<author email="[EMAIL PROTECTED]">David Sean Taylor</author>
<title>Portlet Customization and Parameter Styles</title>
</properties>
<body>
<section name="Portlet Customization and Parameter Styles">
<p>
The next portlet example illustrates editing your portlet parameters using the
default Portlet Customizer.
The first portlet titled "Tutorial Stock Portfolio" in this tutorial uses the
default customizer.
The second portlet titled "Tutorial Stock Portfolio with parameter styles"
illustrates how to enhance the parameter edit fields in the default Portlet Customizer.
</p>
<p>
To see these examples working, you will need to login as the turbine/turbine user.
First let's look again at the first portlet that doesn't have any parameter styles
so that we can see the customizer before and after.
</p>
<subsection name="The Default Portlet Customizer">
<p>
You can customize a portlet by clicking a portlet’s customize action button.
<img src="../images/image007-1.jpg" width="23" height="27"/>
With the default deployment, portlets cannot be customized for the anonymous user.
Since the anonymous user PSML resource is shared, this is probably a good idea.
But for that odd case where you need anonymous customization of portlets, it is
possible.
Modify the <b>JetspeedSecurity.properties</b> file:
</p>
<p>
<source>
<![CDATA[
services.JetspeedSecurity.actions.anon.disable=false
]]>
</source>
</p>
<p>
For now just logon as turbine/turbine.
Click on the customize action button <img src="../images/image007-1.jpg" width="23"
height="27"/> for the first portlet titled "Tutorial Stock Portfolio".
You will see the Default Portlet Customizer.
This customizer will display all of the non-hidden portlet-entry parameters:
</p>
<p>
<img src="../images/image007-2.jpg" width="534" height="198"/>
</p>
<p>
The Title and Skin parameters are always customizable.
Remember from <a href="../6/index.html">Tutorial 6</a>, all parameters that are
edited are not stored back to the registry.
The edited parameters are stored to the PSML resource for the current logged on
user.
Thus if we change the title of this portlet, it will only change for the user
"turbine" and only for this one particular instance of this portlet on this page.
Likewise for all other parameters.
If you are logged on as a user with the admin role, you can also change the security
constraint for this portlet instance.
Only when logged on as a user with the admin role, a third drop-down list of
security constraints is displayed.
See <a href="../4/index.html">Tutorial 4</a> for details.
</p>
<p>
The third parameter shown above, "Symbols", is a parameter that we defined for this
portlet.
It is the list of stock symbols for the portlet instance.
</p>
<p>
<source>
<![CDATA[
<parameter name="symbols" value="MSFT,IBM,ORCL,SUNW" type=""
hidden="false" cachedOnName="true" cachedOnValue="true">
<meta-info>
<title>Symbols</title>
<description>List of comma-separated stock symbols</description>
</meta-info>
</parameter>
]]>
</source>
</p>
<p>
The read-only meta-info parameters title and description are listed in the portlet
customizer from the registry entry above.
The value of the parameter obviously comes from the value attribute.
Now let's see how we can enhance parameter customization using Parameter Styles.
</p>
</subsection>
<subsection name="The Default Portlet Customizer with Parameter Styles">
<p>
Parameter styles are custom widgets which allow you to present portlet parameter
using something other than the default input text box control.
These widgets can be as simple as text area control or as complex as a pop up
calendar control.
</p>
<p>
The second portlet titled "Tutorial Stock Portfolio with parameter styles"
illustrates how to enhance the parameter edit fields in the default Portlet
Customizer.
Its action class is <b>TutorialStockQuoteAction2</b>.
This portlet also retrieves stock quotes from a web service, just like the first
example.
The only difference is that we will show you how to use <a
href="../12/index.html">Parameter Styles</a> to make your portlet's customization more
dynamic.
</p>
<p>
Logon as turbine/turbine. Click on the customize action button <img
src="../images/image007-1.jpg" width="23" height="27"/> for the second portlet titled
"Tutorial Stock Portfolio with parameter styles".
You will see the Default Portlet Customizer with two custom widgets:
</p>
<p>
<img src="../images/image007-3.jpg" width="553" height="227"/>
</p>
<p>
The "Symbols" parameter has a <b>TextArea</b> parameter style, and a new parameter
"Columns" has a <b>CheckBoxGroup</b> style.
The columns parameter lets us customize which columns are displayed in view mode.
If you don't want to see all stock quote columns, just uncheck the column.
</p>
<p>
Looking at the registry entry, we have created several parameter styles. First there
is the Symbols widget, it has a <b>TextArea</b> style:
</p>
<p>
<source>
<![CDATA[
<parameter name="symbols" value="MSFT,IBM,ORCL,SUNW" type="style"
hidden="false" cachedOnName="true" cachedOnValue="true">
<meta-info>
<title>Symbols</title>
<description>List of comma-separated stock symbols</description>
</meta-info>
</parameter>
<parameter name="symbols.style" value="TextArea" hidden="true"
cachedOnName="true" cachedOnValue="true"/>
]]>
</source>
</p>
<p>
The default value for all portlet instances is provided in the value attribute of
the <b>symbols</b> parameter.
Again, when a user customizes this portlet, its values are not stored back to the
registry but to the PSML resource for the particular portlet instance.
The meta-info title and description are displayed by the customizer.
The <b>symbols</b> parameter is linked to the <b>symbols.style</b> by name, and the
parameter style <b>TextArea</b> is selected there.
</p>
<p>
The next parameter is the <b>columns</b> parameter, which allows you to choose which
columns will be displayed in the portlet’s view mode.
</p>
<p>
<source>
<![CDATA[
<parameter name="columns" value="Symbols,Price,Change,Volume" type="style"
hidden="false" cachedOnName="true" cachedOnValue="true">
<meta-info>
<title>Columns</title>
<description>Columns to display</description>
</meta-info>
</parameter>
<parameter name="columns.style.items" value="Symbol,Price,Change,Volume"
hidden="true" cachedOnName="true" cachedOnValue="true"/>
<parameter name="columns.style.layout" value="$eastwest" hidden="true"
cachedOnName="true" cachedOnValue="true"/>
<parameter name="columns.style" value="CheckBoxGroup" hidden="true"
cachedOnName="true" cachedOnValue="true"/>
]]>
</source>
</p>
<p>
The column headers strings are defined in the value attribute for the parameter
style.
The style is set to be a <b>CheckBoxGroup</b>.
The layout of the check boxes is controlled by the layout style, which automatically
aligns the check boxes vertically or horizontally using the keywords:
<b>$eastwest</b> or <b>$northsouth</b>.
The names of the check box items are defined in the <b>columns.style.items</b>
parameter.
</p>
<p>
The action class is responsible for displaying the content in view mode. The action
class for our portlet only handles normal (view mode) processing. It let’s the base
class handle default processing for maximize and customize modes.
</p>
<p>
<source>
<![CDATA[
protected void buildNormalContext(VelocityPortlet portlet,
Context context,
RunData rundata)
{
try
{
// Get reference to stock quote web service
StockQuoteService service = (StockQuoteService)
TurbineServices.getInstance().
getService(StockQuoteService.SERVICE_NAME);
// Retrieve portlet parameters
String symbols = PortletConfigState.getParameter(portlet,
rundata, SYMBOLS, "IBM,MSFT,ORCL,SUNW");
String columns = PortletConfigState.getParameter(portlet,
rundata, COLUMNS,
StringUtils.arrayToString(ALL_COLUMNS, ","));
String[] selectedColumnsArray =
StringUtils.stringToArray(columns, ",");
// Request stock quote(s) from the stock quote web service
String[] symbolArray = StringUtils.stringToArray(symbols,",");
StockQuote[] quotes = service.fullQuotes(symbolArray);
// Place appropriate objects in Velocity context
context.put(QUOTES, quotes);
context.put(SELECTED_COLUMNS, selectedColumnsArray);
context.put(COLUMNS, columns);
]]>
</source>
</p>
<p>
Three objects are put into the Velocity context: $quotes, $columns, and
$selected-columns. These objects are then used to generate the content of the portlet
in view and maximize modes. Two changes are made in the second example. First only
the selected headers from the customizer are displayed:
</p>
<p>
<source>
<![CDATA[
#foreach ($column in $selected-columns)
#headerCell ($column)
#end
]]>
</source>
</p>
<p>
Secondly, only the selected column-values are displayed:
</p>
<p>
<source>
<![CDATA[
#foreach ($quote in $quotes)
<tr>
#if ($columns.indexOf("Symbol") >= 0) #entryCell ($quote.Symbol) #end
#if ($columns.indexOf("Price") >= 0) #entryCell ($quote.Price) #end
#if ($columns.indexOf("Change") >= 0) #entryCell ($quote.Change) #end
#if ($columns.indexOf("Volume") >= 0) #entryCell ($quote.Volume) #end
</tr>
#end
]]>
</source>
</p>
</subsection>
</section>
</body>
</document>
1.1 jakarta-jetspeed/tutorial/xdocs/7/events.xml
Index: events.xml
===================================================================
<?xml version="1.0"?>
<!--
Copyright 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.
-->
<document>
<properties>
<author email="[EMAIL PROTECTED]">David Sean Taylor</author>
<title>Action Events</title>
</properties>
<body>
<section name="Action Events">
<p>
Action events allow you tie events that occur on the user interface, such as a form
being submitted, or a button clicked, to post back to a specific event handler on a <a
href="http://portals.apache.org/jetspeed-1/apidocs/org/apache/jetspeed/modules/actions/portlets/VelocityPortletAction.html">VelocityPortletAction</a>
class.
We will look at a third Velocity portlet that demonstrates action events to perform
user actions.
This portlet is a simple data entry form with 5 input fields.
The data is stored in the session for the current user, but does not persist past
the lifetime of the session.
</p>
<p>
<source>
<![CDATA[
<portlet-entry name="CobiJonesPortlet" hidden="false" type="ref"
parent="Velocity" application="false">
<meta-info>
<title>The Cobi Jones Portlet</title>
<description>Tutorial showing an Action Event Executing, dedicated
to the man Cobi</description>
</meta-info>
<parameter name="template" value="cobi-jones-form" hidden="true"/>
<parameter name="action" value="portlets.CobiJonesPortletAction"
hidden="true" />
<media-type ref="html"/>
<category group="Jetspeed">tutorial</category>
</portlet-entry>
]]>
</source>
</p>
<p>
And here is what the portlet looks like when running:
</p>
<p>
<a href="../images/image007-4.jpg" width="308" heigth="234" />
</p>
<p>
When you press �Save Cobi�, the values on the form are passed to the Turbine
(the MVC controller servlet), from where you can get the values of the input fields
into your Java action class. Let's look at our action event:
</p>
<p>
<source>
<![CDATA[
public void doUpdate(RunData rundata, Context context) throws Exception
{
Player player = (Player)rundata.getUser().getTemp(PLAYER);
if (null == player)
{
player = createNewPlayer();
rundata.getUser().setTemp(PLAYER, player);
}
String cobi = rundata.getParameters().getString(INPUT_FIRST_NAME);
String jones = rundata.getParameters().getString(INPUT_LAST_NAME);
if (!cobi.equalsIgnoreCase("Cobi") ||
!jones.equalsIgnoreCase("Jones"))
{
rundata.getRequest().setAttribute(COBI_ERROR,
"Hey now, you cant substitute Cobi with "
+ cobi + " " + jones + "!");
}
player.setFirstName(cobi);
player.setLastName(jones);
player.setPosition(rundata.getParameters().getString(INPUT_POSITION));
player.setCaps(rundata.getParameters().getInt(INPUT_CAPS));
player.setActive(rundata.getParameters().getBoolean(INPUT_ACTIVE));
rundata.getUser().setTemp(PLAYER, player);
}
]]>
</source>
</p>
<p>
This code above is from the <b>CobiJonesPortletAction</b>.
This is the action event.
As we found out in <a href="actioncontext.html">previous section</a>, Velocity
action have three standard methods: <b>BuildNormalContext</b>,
<b>BuildConfigureContext</b>, and <b>BuildMaximizedContext</b>.
In addition, you can zero or more action events.
Action events are how your portlet code reacts to user interface interactions.
In our example, we have a simple data entry form.
The "Save Cobi" button is a submit button which posts the contents of the HTML form
back to the portlet.
</p>
<p>
We can get the contents of the form from the <b>rundata</b> parameter passed into
our action event.
Jetspeed puts all the form parameters into a parameter parser object.
You can get strings and other data types and then set the values into the portlet
session.
</p>
<p>
<source>
<![CDATA[
String cobi = rundata.getParameters().getString(INPUT_FIRST_NAME);
...
player.setActive(rundata.getParameters().getBoolean(INPUT_ACTIVE));
]]>
</source>
</p>
<p>
In this simple example state is kept in the servlet session.
In future examples we can store the values to the database.
Jetspeed provides methods to get and set objects into the session:
</p>
<p>
<source>
<![CDATA[
rundata.getUser().setTemp(PLAYER, player);
...
Player player = (Player)rundata.getUser().getTemp(PLAYER);
]]>
</source>
</p>
<p>
Let's look at how to setup form posting from the Velocity template
(<b>cobi-jones-form.vm</b>):
</p>
<p>
<source>
<![CDATA[
<form method="post"
action="$jslink.setAction("portlets.CobiJonesPortletAction")">
...
<input type="submit" name="eventSubmit_doUpdate" value="Save Cobi"/>
]]>
</source>
</p>
<p>
First, the form must link back to the current portal page.
The <b>$jslink</b> tool handles this.
Next the action must be specified.
We specify the action to be our portlet's action with the <b>setAction</b> parameter
on the action attribute of the form element.
The submit input requires a convention for finding the correct event on the
specified action: you must prefix the name attribute of the action with the string
"<b>eventSubmit_</b>" and then enter the name of the action event method.
In this case, it is "<b>eventSubmit_doUpdate</b>".
</p>
<p>
The input fields are specified using standard Jetspeed data entry macros defined in
</p>
<p>
<source>
<![CDATA[
<tr>
#formCell ("First Name" "firstname" $player.FirstName)
</tr>
<tr>
#formCell ("Last Name" "lastname" $player.LastName)
</tr>
<tr>
#formCell ("Position" "position" $player.Position)
</tr>
<tr>
#formCell ("Caps" "caps" $player.Caps)
</tr>
<tr>
#formCheckBox2 ("Active" "active" $player.Active)
</tr>
]]>
</source>
</p>
<p>
The first parameter to <b>#formCell</b> is the input caption, the second is the
input's name attribute, and the third is the player object from the Velocity context.
Ensure that the input's name attribute is the same as in your Java action event:
</p>
<p>
<source>
<![CDATA[
#formCell ("Position" "position" $player.Position)
public static final String INPUT_POSITION = "position";
player.setPosition(rundata.getParameters().getString(INPUT_POSITION));
]]>
</source>
</p>
<p>
Finally, the <b>doUpdate</b> action event shows how to do some basic exception
handling by passing an exception string from the action event to the
<b>BuildNormalContext</b> method.
</p>
<p>
<source>
<![CDATA[
if (!cobi.equalsIgnoreCase("Cobi") ||
!jones.equalsIgnoreCase("Jones"))
{
rundata.getRequest().setAttribute(COBI_ERROR,
"Hey now, you cant substitute Cobi with "
+ cobi + " " + jones + "!");
}
]]>
</source>
</p>
<p>
We set the error message text into a servlet request attribute (from the <a
href="http://java.sun.com/products/servlet/2.2/javadoc/javax/servlet/ServletRequest.html#setAttribute(java.lang.String,%20java.lang.Object)">Servlet
API</a>), and then later on in the pipeline, in the <b>BuildNormalContext</b> method,
we check for existence of the error message text and display an error message in case
an exception occurred in the action event.
</p>
<p>
<source>
<![CDATA[
// make sure they don't sub Cobi!
String cobiError = (String)rundata.getRequest().getAttribute(COBI_ERROR);
if (null != cobiError)
{
context.put(COBI_ERROR, cobiError);
}
]]>
</source>
</p>
<p>
This error message is then retrieved from the context in the template:
</p>
<p>
<source>
<![CDATA[
#if ($cobierror)
<tr>
<td colspan="2">
<table bgcolor="red">
<tr>
<td>
$cobierror
</td>
</tr>
</table>
</td>
</tr>
#end
]]>
</source>
</p>
</section>
</body>
</document>
1.1 jakarta-jetspeed/tutorial/xdocs/7/velocity.xml
Index: velocity.xml
===================================================================
<?xml version="1.0"?>
<!--
Copyright 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.
-->
<document>
<properties>
<author email="[EMAIL PROTECTED]">David Sean Taylor</author>
<title>Introduction to Velocity</title>
</properties>
<body>
<section name="Introduction to Velocity">
<p>
<a
href="http://jakarta.apache.org/velocity/user-guide.html#What%20is%20Velocity?">Velocity</a>
is a Java-based template engine.
It permits web page designers to reference methods defined in Java code.
Web designers can work in parallel with Java programmers to develop web sites
according to the Model-View-Controller (MVC) model, meaning that web page designers
can focus solely on creating a well-designed site, and programmers can focus solely on
writing top-notch code.
Velocity separates Java code from the web pages, making the web site more
maintainable over the long run and providing a viable alternative to <a
href="http://java.sun.com/products/jsp/">Java Server Pages</a> (JSP) or <a
href="http://www.php.net/">PHP</a>.
</p>
<p>
Jetspeed has a Velocity templating service built directly into the Jetspeed engine.
Many of the controls and controllers are Velocity-driven to create the layout of the
portal. You can also base your portlets on Velocity. This means that your portlets
will also follow the MVC design pattern, separating content from code.
</p>
<p>
The examples in tutorials 5 and 6 were useful for you to learn the Portlet
interface.
However, overriding the getContent method of the portlet interface is not good
practice.
We recommend abstracting the content generation phase by basing your portlets on one
of the MVC-based portlets provided in the Jetspeed distribution;
such as
<a
href="http://portals.apache.org/jetspeed-1/portlet_config_JSP.html">JSPPortlet</a>,
<a
href="http://portals.apache.org/jetspeed-1/portlet_config_XSL.html">XSLTPortlet</a>,
<a
href="http://portals.apache.org/jetspeed-1/portlet_config_RSS.html">RSSPortlet</a>,
<a
href="http://portals.apache.org/jetspeed-1/portlet_config_HTML.html">HTMLPortlet</a>
or of course the
<a
href="http://portals.apache.org/jetspeed-1/portlet_config_Velocity.html">VelocityPortlet</a>.
</p>
<p>
A Velocity portlet is made up of the typical MVC components:
</p>
<p>
<table>
<tr>
<td>MVC Component</td>
<td>Velocity Component</td>
</tr>
<tr>
<td>Model</td>
<td>Java Objects put in the context</td>
</tr>
<tr>
<td>View</td>
<td>Template</td>
</tr>
<tr>
<td>Controller</td>
<td>Your Velocity Action</td>
</tr>
</table>
</p>
<p>
The controller is your Velocity Action class.
The base <a
href="http://portals.apache.org/jetspeed-1/portlet_config_Velocity.html">VelocityPortlet</a>
class should rarely have to be modified.
Your view is a Velocity template, which will generate the content of your portlet by
pulling out dynamic model information from the Velocity context.
The getContent method of the <a
href="http://portals.apache.org/jetspeed-1/portlet_config_Velocity.html">VelocityPortlet</a>
should never be edited. All content is generated by the template, as designed in our
MVC design pattern.
</p>
<p>
The Life Cycle phases of a portlet are also enhanced with the Velocity portlet.
</p>
<p>
<table>
<tr>
<td>Phase</td>
<td>Method</td>
</tr>
<tr>
<td>Init</td>
<td>init</td>
</tr>
<tr>
<td>ProcessAction</td>
<td>Velocity Action and Action Events</td>
</tr>
<tr>
<td>Render</td>
<td>Template is called by Velocity Portlet</td>
</tr>
<tr>
<td>Destroy</td>
<td>--none--</td>
</tr>
</table>
</p>
<p>
Velocity portlets are really about dynamic content.
If you have static content, there is no real benefit to using a Velocity portlet;
take a look at one of the static content generation portlets such as the <a
href="http://portals.apache.org/jetspeed-1/portlet_config_HTML.html">HTMLPortlet</a>
instead.
The basic function of Velocity is really very simple, it substitutes live Java
objects into a Velocity template.
There is an online tutorial with great examples <a
href="http://jakarta.apache.org/velocity/user-guide.html#What%20is%20Velocity?">here</a>.
</p>
<p>
Let's look at simple introductory example, but we recommend visiting the Velocity
site and investing some time in their well-written tutorials.
</p>
<hr />
<source>
<![CDATA[
<HTML>
<BODY>
Hello $customer.Name!
<br/>
Here is a list of your current subscriptions:<br/><br/>
<table>
#foreach( $subscription in $subscriptions )
#if ( $customer.isSubscribed($subscription) )
<tr>
<td>
$subscription.Name
</td>
</tr>
#end
#end
</table>
</BODY>
</HTML>
]]>
</source>
<p>This example is not included with the examples source code distribution.</p>
<p>
The above is an example Velocity template that displays all subscriptions for a
given customer.
There are two dynamic model objects that we are working with: the customer and
subscriptions.
Velocity uses a very simple syntax for model variables, simply prefix the variable
with a $ sign.
The designer can then access all public methods and accessors of that Java object.
Velocity uses Java reflection to find the methods.
Thus in our example above, the customer object has a getter and setter for the Name
attribute.
You don't need to specify the get prefix, Velocity will figure it out.
</p>
<p>
Velocity provides a small set of directives for logic control.
Most commonly used are #if and #foreach.
#foreach will iterate over any Java 2 collection or array.
The #if statement above calls a public method to check if the customer is subscribed
to a subscription.
Finally, the subscription name is displayed in a table column by getting the Name
attribute.
</p>
<p>
So where did these two variables ($customer, $subscriptions) come from?
</p>
<p>
They came from your action class. We will look into how to program an action class
in more detail later in this section.
Right now it's important to understand that your action class puts your model
objects into a Velocity construct called the 'context'.
The context is where all variables are made accessible to a template.
The context is the common liaison between your model and view.
Here is how the Java code would put an object into the context:
</p>
<hr />
<p>
<source>
Customer customer = CustomerPeer.retrieveByPK(primaryKey);
context.put("customer", customer);
List subscriptions = SubscriptionPeer.doSelect(criteria);
context.put("subscriptions", subscriptions);
</source>
This example is not included with the examples source code distribution.
</p>
<p>There is another tutorial on Velocity at <a
href="http://www.javaworld.com/javaworld/jw-12-2001/jw-1228-velocity-p2.html">Java
World</a>.
Now that we have a basic understanding of the Velocity context and templates, let's
get back to the Velocity Portlet.
The MVC components are all configured in the portlet registry.</p>
</section>
</body>
</document>
1.1 jakarta-jetspeed/tutorial/xdocs/7/resolution.xml
Index: resolution.xml
===================================================================
<?xml version="1.0"?>
<!--
Copyright 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.
-->
<document>
<properties>
<author email="[EMAIL PROTECTED]">David Sean Taylor</author>
<title>Template Resolution</title>
</properties>
<body>
<section name="Template Resolution">
<p>
Where should templates be placed in the web application?
By convention, Jetspeed looks for JSP Portlet templates in the Jetspeed deployment
under <b>/WEB-INF/templates/jsp/portlets/html</b> (for HTML portlets).
Similarly, WML portlets would be found under
<b>/WEB-INF/templates/jsp/portlets/wml</b>.
The resolution of portlet templates is based on several configuration files and a
resolution algorithm.
</p>
<p>
The <b>TurbineResources.properties</b> is where the first part of the configuration
goes:
</p>
<p>
<source>
<![CDATA[
services.JspService.templates = /WEB-INF/templates/vm, /WEB-INF/mytemplates/vm
]]>
</source>
</p>
<p>
You can specify multiple paths by comma-separating the paths.
Secondly, the <b>JetspeedResources.properties</b> must be updated with the same
path, but to root directory containing all templates (both JSP and VM).The list may
also be comma-separated.
</p>
<p>
<source>
<![CDATA[
services.TemplateLocator.templateRoot=/WEB-INF/templates,/WEB-INF/mytemplates
]]>
</source>
</p>
<p>
The template resolution algorithm finds the template. The resolver is a service and
is pluggable. The default service has a resolution algorithm much like how the
Profiler service resolves PSML resources.
</p>
<p>
Templates resources may be optionally localised. Templates are localized by placing
them in sub-directories based on language and country code abbreviations. The
language-code sub-directory contains one or more country-code subdirectories.
</p>
<p>
The language-code directory name is specified with an ISO-639 standard two-character
language abbreviation. The country-code subdirectory is optional, and is specified
with an IS0-3166 standard two-character country code abbreviation.
</p>
<p>
An example:
</p>
<p>
<source>
<![CDATA[
vm
|-- portlets
|-- html
|-- fr // french language
|-- FR // France country-code
|-- BE // Belgium country-code
]]>
</source>
NOTE: The country codes must be in upper-case
</p>
<p>
For a given locale of fr_FR, and an HTML request, the search order for a template
named grenouille.jsp would be:
</p>
<p>
<source>
<![CDATA[
vm/portlets/html/fr/FR/grenouille.vm
vm/portlets/html/fr/grenouille.vm
vm/portlets/html/grenouille.vm
vm/portlets/grenouille.vm
]]>
</source>
</p>
<p>
The template locator looks at the "Content Language" HTML header for locale specific
settings. If there are multiple settings, all settings will be searched until the
first resource is found. (This is currently not supported)
</p>
<p>
For a complete list of ISO-639 standard language abbreviations, see:
</p>
<p>
<a
href="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt">http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt</a>
</p>
<p>
For a complete list of ISO-3166 standard country code abbreviations, see:
</p>
<p>
<a
href="http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html">http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html</a>
</p>
</section>
</body>
</document>
1.1 jakarta-jetspeed/tutorial/xdocs/7/deploy.xml
Index: deploy.xml
===================================================================
<?xml version="1.0"?>
<!--
Copyright 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.
-->
<document>
<properties>
<author email="[EMAIL PROTECTED]">David Sean Taylor</author>
<title>Deploy</title>
</properties>
<body>
<section name="Deploy">
<p>
To deploy the system, type:
</p>
<p>
<source>
<![CDATA[
ant deploy (or hotdeploy)
]]>
</source>
</p>
<p>
Use hotdeploy if you have already deployed the system once. This simply saves some
time in packaging the JPortal deployment. Next point your browser at:
</p>
<p>
<a
href="http://localhost:8080/jportal/portal">http://localhost:8080/jportal/portal</a>
</p>
<p>
You should see the new Velocity portlets in the default pane:
</p>
</section>
</body>
</document>
1.1 jakarta-jetspeed/tutorial/xdocs/7/velocitytemplate.xml
Index: velocitytemplate.xml
===================================================================
<?xml version="1.0"?>
<!--
Copyright 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.
-->
<document>
<properties>
<author email="[EMAIL PROTECTED]">David Sean Taylor</author>
<title>The Velocity Template</title>
</properties>
<body>
<section name="The Velocity Template">
<p>
Let"s have a look at the Velocity template for our first example:
<b>tutorial-stock-quote1.vm</b>
It"s a very simple example of displaying live stock quotes from a web service.
The stock quotes are returned in a collection of quote records, called $quotes.
Also, the column headers are in a collection of strings called $columns.
</p>
<hr />
<source>
<table>
<tr>
<td>
<table border="true" cellspacing="1" cellpadding="3">
<tr>
#foreach ($column in $columns)
#headerCell ($column)
#end
</tr>
#foreach ($quote in $quotes)
<tr>
#entryCell ($quote.Symbol)
#entryCell ($quote.Price)
#entryCell ($quote.Change)
#entryCell ($quote.Volume)
</tr>
#end
</table>
</td>
</tr>
</table>
</source>
<p>
Accessors get the attributes: symbol, price, change and volume.
Also notice that there are some macros: <b>#headerCell</b> and <b>#entryCell</b>.
The macros are defined in a common <a
href="http://jakarta.apache.org/velocity/user-guide.html#Velocimacros">Velocimacro</a>
file that is shared across Jetspeed.
<a
href="http://jakarta.apache.org/velocity/user-guide.html#Velocimacros">Velocimacro</a>
are great for defining little snippets of templates that can be included into other
templates.
</p>
<hr />
<code>
services.VelocityService.velocimacro.library = GlobalMacros.vm
</code>
<p>
The macros in question are defined in the <b>GlobalMacros.vm</b> file. A macro
definition takes parameters. Macros can include macros:
</p>
<hr />
<code>
#macro (formCell $label $name $value)
#formLabel("$label")
#formTextField("$name" "$value")
#end
</code>
<p>
Similarly, common snippets can simple be parsed into the template directly:
</p>
<hr />
<code>
#parse ("/portlets/html/tree-row-browser.vm")
</code>
</section>
</body>
</document>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]