Added:
websites/production/struts/content/development/2.x/docs/struts-2-portlet-tutorial.html
==============================================================================
---
websites/production/struts/content/development/2.x/docs/struts-2-portlet-tutorial.html
(added)
+++
websites/production/struts/content/development/2.x/docs/struts-2-portlet-tutorial.html
Wed Jul 17 09:31:08 2013
@@ -0,0 +1,714 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you 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.
+-->
+<html>
+<head>
+ <LINK type="text/css" rel="stylesheet"
href="https://struts.apache.org/css/default.css">
+ <style type="text/css">
+ .dp-highlighter {
+ width:95% !important;
+ }
+ </style>
+ <style type="text/css">
+ .footer {
+ background-image:
url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif');
+ background-repeat: repeat-x;
+ background-position: left top;
+ padding-top: 4px;
+ color: #666;
+ }
+ </style>
+ <link href='http://struts.apache.org/highlighter/style/shCoreStruts.css'
rel='stylesheet' type='text/css' />
+ <link href='http://struts.apache.org/highlighter/style/shThemeStruts.css'
rel='stylesheet' type='text/css' />
+ <script src='http://struts.apache.org/highlighter/js/shCore.js'
type='text/javascript'></script>
+ <script
src='http://struts.apache.org/highlighter/js/shBrushJava.js'
type='text/javascript'></script>
+
+ <script type="text/javascript">
+ SyntaxHighlighter.defaults['toolbar'] = false;
+ SyntaxHighlighter.all();
+ </script>
+ <script type="text/javascript" language="javascript">
+ var hide = null;
+ var show = null;
+ var children = null;
+
+ function init() {
+ /* Search form initialization */
+ var form = document.forms['search'];
+ if (form != null) {
+ form.elements['domains'].value = location.hostname;
+ form.elements['sitesearch'].value = location.hostname;
+ }
+
+ /* Children initialization */
+ hide = document.getElementById('hide');
+ show = document.getElementById('show');
+ children = document.all != null ?
+ document.all['children'] :
+ document.getElementById('children');
+ if (children != null) {
+ children.style.display = 'none';
+ show.style.display = 'inline';
+ hide.style.display = 'none';
+ }
+ }
+
+ function showChildren() {
+ children.style.display = 'block';
+ show.style.display = 'none';
+ hide.style.display = 'inline';
+ }
+
+ function hideChildren() {
+ children.style.display = 'none';
+ show.style.display = 'inline';
+ hide.style.display = 'none';
+ }
+ </script>
+ <title>Struts 2 Portlet Tutorial</title>
+</head>
+<body onload="init()">
+<table border="0" cellpadding="2" cellspacing="0" width="100%">
+ <tr class="topBar">
+ <td align="left" valign="middle" class="topBarDiv" align="left" nowrap>
+ <a href="home.html">Home</a> > <a
href="guides.html">Guides</a> > <a
href="plugin-developers-guide.html">Plugin Developers
Guide</a> > <a href="portlet-plugin.html">Portlet
Plugin</a> > <a href="struts-2-portlet-tutorial.html">Struts 2
Portlet Tutorial</a>
+ </td>
+ <td align="right" valign="middle" nowrap>
+ <form name="search" action="http://www.google.com/search"
method="get">
+ <input type="hidden" name="ie" value="UTF-8" />
+ <input type="hidden" name="oe" value="UTF-8" />
+ <input type="hidden" name="domains" value="" />
+ <input type="hidden" name="sitesearch" value="" />
+ <input type="text" name="q" maxlength="255" value="" />
+ <input type="submit" name="btnG" value="Google Search" />
+ </form>
+ </td>
+ </tr>
+</table>
+
+<div id="PageContent">
+ <div class="pageheader" style="padding: 6px 0px 0px 0px;">
+ <!-- We'll enable this once we figure out how to access (and save) the
logo resource -->
+ <!--img src="/wiki/images/confluence_logo.gif" style="float: left;
margin: 4px 4px 4px 10px;" border="0"-->
+ <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts
2 Documentation</div>
+ <div style="margin: 0px 10px 8px 10px" class="pagetitle">Struts 2
Portlet Tutorial</div>
+
+ <div class="greynavbar" align="right" style="padding: 2px 10px;
margin: 0px;">
+ <a
href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=71458">
+ <img
src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif"
+ height="16" width="16" border="0" align="absmiddle"
title="Edit Page"></a>
+ <a
href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=71458">Edit
Page</a>
+
+ <a
href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">
+ <img
src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif"
+ height="16" width="16" border="0" align="absmiddle"
title="Browse Space"></a>
+ <a
href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse
Space</a>
+
+ <a
href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=71458">
+ <img
src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif"
+ height="16" width="16" border="0" align="absmiddle"
title="Add Page"></a>
+ <a
href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=71458">Add
Page</a>
+
+ <a
href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=71458">
+ <img
src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif"
+ height="16" width="16" border="0" align="absmiddle"
title="Add News"></a>
+ <a
href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=71458">Add
News</a>
+ </div>
+ </div>
+
+ <div class="pagecontent">
+ <div class="wiki-content">
+ <div id="ConfluenceContent"><h1><a shape="rect"
name="Struts2PortletTutorial-Struts2PortletTutorialCreatingasimpleBookmarkPortlet"></a>Struts
2 Portlet Tutorial - Creating a simple Bookmark Portlet</h1>
+
+<div class="panelMacro"><table class="noteMacro"><colgroup span="1"><col
span="1" width="24"><col span="1"></colgroup><tr><td colspan="1" rowspan="1"
valign="top"><img align="middle"
src="https://cwiki.apache.org/confluence/images/icons/emoticons/warning.gif"
width="16" height="16" alt="" border="0"></td><td colspan="1"
rowspan="1"><b>Work in progress</b><br clear="none">Using version
2.1.1-SNAPSHOT of the portlet plugin</td></tr></table></div>
+
+<div class="panelMacro"><table class="infoMacro"><colgroup span="1"><col
span="1" width="24"><col span="1"></colgroup><tr><td colspan="1" rowspan="1"
valign="top"><img align="middle"
src="https://cwiki.apache.org/confluence/images/icons/emoticons/information.gif"
width="16" height="16" alt="" border="0"></td><td colspan="1"
rowspan="1"><b>Note that this tutorial assumes that you're familiar with basic
Struts 2 web application programming.</b><br clear="none">If you have not used
Struts 2 before, please check out some of the other Struts 2 tutorials
first.</td></tr></table></div>
+
+<h2><a shape="rect"
name="Struts2PortletTutorial-Preparations"></a>Preparations</h2>
+<p>In this tutorial we will use eclipse as our IDE. If you do not have
Eclipse, you can download it from <a shape="rect" class="external-link"
href="http://www.eclipse.org" rel="nofollow">http://www.eclipse.org</a>. </p>
+
+<p>The project itself will be set up using Maven 2. Maven 2 is available from
<a shape="rect" class="external-link"
href="http://maven.apache.org">http://maven.apache.org</a>.</p>
+
+<p>If you have not used the maven-eclipse-plugin before, you need to set up
the Eclipse workspace with a variable that points to the Maven 2 repository. To
do this, type </p><div class="code panel" style="border-width: 1px;"><div
class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[mvn
-Declipse.workspace=<path-to-eclipse-workspace>
eclipse:add-maven-repo]]></script>
+</div></div>
+
+<h2><a shape="rect"
name="Struts2PortletTutorial-Creatingtheproject"></a>Creating the project</h2>
+<p>We'll use Maven 2 with the Struts 2 Portlet Archetype to create a skeleton
project for our portlet application. From the command line, issue the
command:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeContent
panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[mvn archetype:create
-DarchetypeGroupId=org.apache.struts
-DarchetypeArtifactId=struts2-archetype-portlet
-DarchetypeVersion=2.1.1-SNAPSHOT -DartifactId=bookmark-portlet
+ -DgroupId=com.mycompany
-DremoteRepositories=http://people.apache.org/repo/m2-snapshot-repository]]></script>
+</div></div>
+
+<p>This will set up the maven 2 structure for us and also set up the basic
configuration needed to create a Struts 2 portlet. The archetype creates a
sample HelloWorld portlet that shows off some of the basic principles of Struts
2 portlet programming. To test the set up, type </p><div class="code panel"
style="border-width: 1px;"><div class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[mvn jetty:run -P pluto-embedded]]></script>
+</div></div> in a command prompt. Open a browser and point your browser to <a
shape="rect" class="external-link"
href="http://localhost:8080/bookmark-portlet/pluto/index.jsp"
rel="nofollow">http://localhost:8080/bookmark-portlet/pluto/index.jsp</a> and
play around.
+
+<h2><a shape="rect"
name="Struts2PortletTutorial-Lookingatthebasics"></a>Looking at the basics</h2>
+<p>To see how the basic HelloWorld example works, let's look at some of the
configuration files, starting with the JSR168 portlet descriptor</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/webapp/WEB-INF/portlet.xml</b></div><div class="codeContent
panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![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_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
+ id="bookmark-portlet">
+
+ <portlet id="HelloPortlet">
+ <description xml:lang="EN">Simple hello world
portlet</description>
+ <portlet-name>HelloPortlet</portlet-name>
+ <display-name xml:lang="EN">bookmark-portlet</display-name>
+
+
<portlet-class>org.apache.struts2.portlet.dispatcher.Jsr168Dispatcher</portlet-class>
+
+ <!-- The namespace for the actions configured for view mode -->
+ <init-param>
+ <name>viewNamespace</name>
+ <value>/view</value>
+ </init-param>
+
+ <!-- The default action to invoke in view mode. -->
+ <init-param>
+ <name>defaultViewAction</name>
+ <value>index</value>
+ </init-param>
+
+ <!-- The namespace for the actions configured for edit mode -->
+ <init-param>
+ <name>editNamespace</name>
+ <value>/edit</value>
+ </init-param>
+
+ <!-- The default action to invoke in edit mode. -->
+ <init-param>
+ <name>defaultEditAction</name>
+ <value>index!input</value>
+ </init-param>
+
+ <expiration-cache>0</expiration-cache>
+
+ <supports>
+ <mime-type>text/html</mime-type>
+ <portlet-mode>view</portlet-mode>
+ <portlet-mode>edit</portlet-mode>
+ </supports>
+
+ <supported-locale>en</supported-locale>
+
+ <portlet-info>
+ <title>HelloPortlet</title>
+ <short-title>HelloPortlet</short-title>
+ <keywords>struts 2,portlet,hello,world</keywords>
+ </portlet-info>
+ </portlet>
+</portlet-app>
+]]></script>
+</div></div>
+
+<p>The important parts to notice are the <em>portlet-class</em> and
<em>init-param</em> elements. The <em>portlet-class</em> element is always
<b><em>org.apache.struts2.portlet.dispatcher.Jsr168Dispatcher</em></b> (or a
subclass, if you have added some custom functionality). This is the portlet
that acts as the dispatcher for the Struts 2 framework, and translates incoming
user interaction to action requests that Struts 2 understands. The init-params
<em>viewNamespace</em>, <em>defaultViewAction</em>, <em>editNamespace</em> and
<em>defaultEditAction</em> set up some defaults for the dispatcher when the
portlet encounters a portlet mode without a specific action. Here, we set up
the <em>view</em> portlet mode to map to the <em>/view</em> action namespace,
and the <em>edit</em> portlet mode to map to the <em>/edit</em> action
namespace. We also specify that the default actions for the mentioned portlet
modes are <em>index</em> and <em>index!input</em> respectively. We will
recognize t
hese namespaces in the next file:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/resources/struts.xml</b></div><div class="codeContent
panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE struts PUBLIC
+ "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
+ "http://struts.apache.org/dtds/struts-2.0.dtd">
+
+<struts>
+ <package name="default" extends="struts-portlet-default"
namespace="/view">
+ <action name="index" class="com.mycompany.HelloAction">
+ <result>/WEB-INF/jsp/view/index.jsp</result>
+ </action>
+ </package>
+
+ <package name="edit" extends="struts-portlet-default"
namespace="/edit">
+ <action name="index" class="com.mycompany.UpdateNameAction">
+ <result type="redirectAction">
+ <param name="actionName">index</param>
+ <param name="portletMode">view</param>
+ </result>
+ <result
name="input">/WEB-INF/jsp/edit/index.jsp</result>
+ </action>
+ </package>
+</struts>
+]]></script>
+</div></div>
+
+<p>As we can see, the actions for the <em>view</em> portlet mode is in the
<em>default</em> package, with <em>/view</em> as namespace, and the actions for
the <em>edit</em> portlet mode is in the <em>edit</em> package, with
<em>/edit</em> as namespace.</p>
+
+<h2><a shape="rect"
name="Struts2PortletTutorial-ImporttheprojectintoEclipse"></a>Import the
project into Eclipse</h2>
+<p>Now let's import the project into Eclipse. First, type </p><div class="code
panel" style="border-width: 1px;"><div class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[mvn eclipse:eclipse -P
pluto-embedded]]></script>
+</div></div><br clear="none">
+Then start Eclipse (if you have not already done so), and import the project
using "File -> Import -> General -> Existing Projects into Workspace".
Browse to the folder where you created the project and press finish. Your
portlet project should now be setup up with all dependencies in place.
+
+<h2><a shape="rect"
name="Struts2PortletTutorial-CreatingtheBookmarkdomainobject"></a>Creating the
Bookmark domain object</h2>
+<p>To represent the bookmarks, we'll create a simple domain object. We'll keep
it really simple, so the Bookmark object will only have a <em>name</em> and a
<em>url</em> property:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/java/com/mycompany/domain/Bookmark.java</b></div><div
class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+public class Bookmark {
+ private String name;
+ private String url;
+
+ public Bookmark(String name, String url) {
+ this.name = name;
+ this.url = url;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+}
+]]></script>
+</div></div>
+
+<h2><a shape="rect" name="Struts2PortletTutorial-Addingbookmarks"></a>Adding
bookmarks</h2>
+<p>Adding bookmarks is an operation that logically belongs to the
<em>edit</em> portlet mode. So we'll create a simple action for this purpose,
and configure it in the <em>edit</em> configuration package. In normal Struts 2
fashion, we'll create an action object with the properties we need:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/java/com/mycompany/AddBookmark.java</b></div><div
class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+public class AddBookmarkAction extends DefaultActionSupport {
+
+ private String name;
+ private String url;
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ @Override
+ public String execute() throws Exception {
+ return SUCCESS;
+ }
+}
+]]></script>
+</div></div>
+
+<p>And in struts.xml, remove the existing configuration for the edit package
and add an entry for the action:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width: 1px;"><b>struts.xml</b></div><div
class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<package name="edit" extends="struts-portlet-default" namespace="/edit">
+
+ <action name="index" class="com.mycompany.AddBookmarkAction">
+ <result name="input">/WEB-INF/jsp/edit/index.jsp</result>
+ </action>
+
+</package>
+]]></script>
+</div></div>
+
+<p>Let's create the input form so we have something to display. The form is
really simple, with a label and a text field for each of the properties in the
<em>Bookmark</em> domain object:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/webapp/WEB-INF/jsp/edit/index.jsp</b></div><div
class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<%@ taglib prefix="s" uri="/struts-tags" %>
+
+<h2>Manage bookmarks</h2>
+
+<s:form action="index">
+ <table>
+ <s:textfield name="name" label="Name"/>
+ <s:textfield name="url" label="URL"/>
+ <s:submit value="Add"/>
+ </table>
+</s:form>
+]]></script>
+</div></div>
+
+<p>The textfields maps to the property names we have defined in
<em>AddBookmarkAction</em>. Before we continue, let's check that everything is
configured correctly and check that our portlet can be run. In a command
prompt, change into the directory where you have created the project and issue
the command <em>mvn jetty:run -P pluto-embedded</em>. Then open <a shape="rect"
class="external-link"
href="http://localhost:8080/bookmark-portlet/pluto/index.jsp"
rel="nofollow">http://localhost:8080/bookmark-portlet/pluto/index.jsp</a> and
click on the <em>edit</em> portlet window control. If everything is set up
correctly, you should see a form like this:</p>
+
+<p><span class="image-wrap" style=""><img
src="struts-2-portlet-tutorial.data/AddBookmarkForm.jpg" style="border: 0px
solid black"></span></p>
+
+<p>If you try to submit data in the form, it will obviously not work since we
have not implemented any logic to add bookmarks yet. That will be our next
task. Since we'll need a PortletPreferences reference, we'll have the action
implement the <em>PortletPreferencesAware</em> interface that will instruct
Struts 2 to inject this into our action, without the need for us to look it up
manually. When we have the reference to the <em>PortletPreferences</em> object,
we'll implement logic to store the bookmark (or rather the bookmark's
properties, since we can only store Strings in the preferences object):</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/java/com/mycompany/AddBookmarkAction.java</b></div><div
class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+public class AddBookmarkAction extends DefaultActionSupport implements
PortletPreferencesAware {
+
+ private String name;
+ private String url;
+
+ private PortletPreferences portletPreferences;
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public void setPortletPreferences(PortletPreferences portletPreferences) {
+ this.portletPreferences = portletPreferences;
+ }
+
+ @Override
+ public String execute() throws Exception {
+ portletPreferences.setValue(name, url);
+ portletPreferences.store();
+ return SUCCESS;
+ }
+}
+]]></script>
+</div></div>
+
+<p>After the bookmark has been stored, we'll just redirect back to the input
form:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/resources/struts.xml</b></div><div class="codeContent
panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<package name="edit" extends="struts-portlet-default" namespace="/edit">
+
+ <action name="index" class="com.mycompany.AddBookmarkAction">
+ <result type="redirectAction">
+ <param name="actionName">index!input</param>
+ </result>
+ <result name="input">/WEB-INF/jsp/edit/index.jsp</result>
+ </action>
+
+</package>
+]]></script>
+</div></div>
+
+<p>We use a <em>redirectAction</em> result type to redirect back to the input
form in proper PRG (Post - Redirect - Get) manner.</p>
+
+<p>Now we can add some bookmarks. We don't get much feedback though, so let's
proceed...</p>
+
+<h2><a shape="rect"
name="Struts2PortletTutorial-Listingthebookmarks"></a>Listing the bookmarks</h2>
+
+<p>The bookmarks will be listed in the <em>view</em> portlet mode, so we'll
create a <em>ListBookmarksAction</em> and configure it in the default
package:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/java/com/mycompany/ListBookmarksAction.java</b></div><div
class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+public class ListBookmarksAction extends DefaultActionSupport implements
PortletPreferencesAware {
+ private List<Bookmark> bookmarks = new ArrayList<Bookmark>();
+ private PortletPreferences portletPreferences;
+
+ public List<Bookmark> getBookmarks() {
+ return bookmarks;
+ }
+
+ public void setPortletPreferences(PortletPreferences portletPreferences) {
+ this.portletPreferences = portletPreferences;
+ }
+
+ @Override
+ public String execute() throws Exception {
+ // For simplicity, we'll assume that only bookmarks are stored in the
preferences.
+ Map<String, String[]> preferencesMap = portletPreferences.getMap();
+ for(Map.Entry<String, String[]> entry : preferencesMap.entrySet())
{
+ bookmarks.add(new Bookmark(entry.getKey(), entry.getValue()[0]));
+ }
+ return SUCCESS;
+ }
+}
+]]></script>
+</div></div>
+
+<p>Again we use the <em>PortletPreferencesAware</em> to get the
<em>PortletPreferences</em> injected in our action. Then we just get all the
values from the preferences and add them as a <em>Bookmark</em> instance in an
<em>ArrayList</em>.</p>
+
+<p>Obviously, we'll need a jsp to view the list of bookmarks:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/webapp/WEB-INF/jsp/view/index.jsp</b></div><div
class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<%@ taglib prefix="s" uri="/struts-tags" %>
+
+<strong>Bookmarks</strong>
+<p>
+ <table>
+ <s:iterator value="%{bookmarks}" var="bookmark">
+ <tr>
+ <td><s:property value="%{name}"/></td>
+ <td><a href="<s:property value="%{url}"/>"
target="_blank"><s:property value="%{url}"/></a></td>
+ </tr>
+ </s:iterator>
+ </table>
+</p>
+]]></script>
+</div></div>
+
+<p>In the JSP, we just iterate over the list of Bookmarks and print the
properties in the iterator loop. </p>
+
+<p>In struts.xml, remove the <em>default</em> package, and add this
instead:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/resources/struts.xml</b></div><div class="codeContent
panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<package name="view" extends="struts-portlet-default" namespace="/view">
+ <action name="index" class="com.mycompany.ListBookmarksAction">
+ <result>/WEB-INF/jsp/view/index.jsp</result>
+ </action>
+</package>
+]]></script>
+</div></div>
+
+<p>When you're ready, go back to a command prompt and start the server again
(<em>mvn jetty:run -P pluto-embedded</em>), open a browser and start adding
some bookmarks. When you go back to <em>view</em> mode after adding a few,
you'll see the bookmarks listed:</p>
+
+<p><span class="image-wrap" style=""><img
src="struts-2-portlet-tutorial.data/ListBookmarks.jpg" style="border: 0px solid
black"></span></p>
+
+<h2><a shape="rect"
name="Struts2PortletTutorial-Preparingforbookmarkmanagement"></a>Preparing for
bookmark management</h2>
+
+<p>It would be nice to be able to manage the list of bookmarks, so we'll add
delete and edit functionality. All modifications will happen in the
<em>edit</em> portlet mode. We'll start by displaying the list of bookmarks in
the <em>edit</em> mode as well. The plan is to extend this list to add a
<em>delete</em> and an <em>edit</em> link to modify the bookmark entries. We'll
do it really simple and just copy the code from the <em>index.jsp</em> for view
into the index.jsp for <em>edit</em> and add the links in a new table
column:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/webapp/WEB-INF/jsp/edit/index.jsp</b></div><div
class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<%@ taglib prefix="s" uri="/struts-tags" %>
+
+<h2>Manage bookmarks</h2>
+
+<p>
+ <table>
+ <s:iterator value="%{bookmarks}" var="bookmark">
+ <s:url action="editBookmark!input" id="editUrl">
+ <s:param name="oldName" value="%{name}"/>
+ </s:url>
+ <s:url action="deleteBookmark" portletUrlType="action"
id="deleteUrl">
+ <s:param name="bookmarkName" value="%{name}"/>
+ </s:url>
+ <tr>
+ <td><s:property value="%{name}"/></td>
+ <td><a href="<s:property value="%{url}"/>"
target="_blank"><s:property value="%{url}"/></a></td>
+ <td><a href="<s:property
value="%{editUrl}"/>">Edit</a></td>
+ <td><a href="<s:property
value="%{deleteUrl}"/>">Delete</a></td>
+ </tr>
+ </s:iterator>
+ </table>
+</p>
+
+<s:form action="addBookmark">
+ <table>
+ <s:textfield name="name" label="Name"/>
+ <s:textfield name="url" label="URL"/>
+ <s:submit value="Add"/>
+ </table>
+</s:form>
+]]></script>
+</div></div>
+
+<p>For the <em>delete</em> url we need to specify that it is a portlet action
url since portlet preferences cannot be changed in the render phase. We also
need to change our configuration a bit since we'll use this page as index page
for <em>edit</em> mode, and not only as the input form for the
<em>AddBookmarkAction</em>:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/resources/struts.xml</b></div><div class="codeContent
panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<package name="edit" extends="struts-portlet-default" namespace="/edit">
+
+ <action name="index" class="com.mycompany.ListBookmarksAction">
+ <result>/WEB-INF/jsp/edit/index.jsp</result>
+ </action>
+
+ <action name="addBookmark" class="com.mycompany.AddBookmarkAction">
+ <result type="redirectAction">
+ <param name="actionName">index</param>
+ </result>
+ </action>
+
+</package>
+]]></script>
+</div></div>
+
+<p>Here we have added the <em>ListBookmarksAction</em> as the <em>index</em>
action, which will display the bookmark list with the input form. When the form
is submitted, it will invoke the <em>addBookmark</em> action, and upon success,
control is redirected back to the <em>index</em> action. With this new
structure, we'll also need to updated the portlet descriptor to use
<em>index</em> instead of <em>index!input</em> as the default action for
<em>edit</em> mode:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/webapp/WEB-INF/portlet.xml</b></div><div class="codeContent
panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<!-- The default action to invoke in edit mode. -->
+<init-param>
+ <name>defaultEditAction</name>
+ <value>index</value>
+</init-param>
+]]></script>
+</div></div>
+
+<p>Now you can (re)start the server and see how it works. This is how it looks
in <em>edit</em> mode after adding a few entries:</p>
+
+<p><span class="image-wrap" style=""><img
src="struts-2-portlet-tutorial.data/ListBookmarksInEditMode.jpg" style="border:
0px solid black"></span></p>
+
+<h2><a shape="rect"
name="Struts2PortletTutorial-Deletingbookmarks"></a>Deleting bookmarks</h2>
+
+<p>Let's create the action that handles deletion of bookmarks. It's pretty
simple. As with our other actions, we need to get a reference to the
<em>PortletPreferences</em> and simply remove the bookmark values from it:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/java/com/mycompany/DeleteBookmarkAction.java</b></div><div
class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+public class DeleteBookmarkAction extends DefaultActionSupport implements
PortletPreferencesAware{
+
+ private String bookmarkName;
+
+ private PortletPreferences portletPreferences;
+
+ public void setBookmarkName(String bookmarkName) {
+ this.bookmarkName = bookmarkName;
+ }
+
+ public void setPortletPreferences(PortletPreferences portletPreferences) {
+ this.portletPreferences = portletPreferences;
+ }
+
+ @Override
+ public String execute() throws Exception {
+ portletPreferences.reset(bookmarkName);
+ portletPreferences.store();
+ return SUCCESS;
+ }
+
+}
+]]></script>
+</div></div>
+
+<p>Pretty simple and straight forward. Next, add a configuration entry for the
action in the <em>edit</em> package:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/resources/struts.xml</b></div><div class="codeContent
panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<action name="deleteBookmark" class="com.mycompany.DeleteBookmarkAction">
+ <result type="redirectAction">
+ <param name="actionName">index</param>
+ </result>
+</action>
+]]></script>
+</div></div>
+
+<p>After a bookmark has been deleted, we redirect back to the <em>index</em>
action. Now you should be able to click the <em>Delete</em> link to remove
individual entries.</p>
+
+<h2><a shape="rect" name="Struts2PortletTutorial-Editingbookmarks"></a>Editing
bookmarks</h2>
+
+<p>The final step is to edit bookmark entries. When the user clicks the
<em>edit</em> link, the portlet will display a new page with an input form and
the bookmark values already filled in the text fields. We'll start by creating
the jsp file:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/webapp/WEB-INF/jsp/edit.jsp</b></div><div class="codeContent
panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<%@ taglib prefix="s" uri="/struts-tags" %>
+
+<h2>Edit bookmark</h2>
+
+<s:form action="editBookmark">
+ <input type="hidden" name="oldName" value="<s:property
value="%{oldName}"/>"/>
+ <table>
+ <s:textfield name="name" label="Name" value="%{oldName}"/>
+ <s:textfield name="url" label="URL"/>
+ <s:submit value="Update"/>
+ </table>
+</s:form>
+]]></script>
+</div></div>
+
+<p>The <em>oldName</em> hidden field keeps track of which bookmark is beeing
edited, since the name is also our id to the entry beeing edited. The actual
update of the bookmark will be a "delete and add a new entry":</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/java/com/mycompany/EditBookmarkAction.java</b></div><div
class="codeContent panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+public class EditBookmarkAction extends DefaultActionSupport implements
PortletPreferencesAware, Preparable, ParameterAware {
+
+ private String oldName;
+ private String name;
+ private String url;
+
+ private PortletPreferences portletPreferences;
+ private Map<String, String[]> parameters;
+
+ public String getOldName() {
+ return oldName;
+ }
+
+ public void setOldName(String oldName) {
+ this.oldName = oldName;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setPortletPreferences(PortletPreferences portletPreferences) {
+ this.portletPreferences = portletPreferences;
+ }
+
+ public void setParameters(Map<String, String[]> parameters) {
+ this.parameters = parameters;
+ }
+
+ public void prepare() throws Exception {
+ // Since the prepare interceptor is run before the parameter
interceptor,
+ // we have to get the parameter "manually".
+ this.oldName = parameters.get("oldName")[0];
+ this.url = portletPreferences.getValue(oldName, null);
+ }
+
+ public String execute() throws Exception {
+ // The modification is handled as remove/add
+ portletPreferences.reset(oldName);
+ portletPreferences.setValue(name, url);
+ portletPreferences.store();
+ return SUCCESS;
+ }
+}
+]]></script>
+</div></div>
+
+<p>There's a couple of new things here, but nothing unfamiliar if you have
worked with Struts 2 before. We use the <em>Preparable</em> interface to
pre-populate the vaules in the edit form, and we use the
<em>ParameterAware</em> interface to get a reference to the request parameter
map. Other than that, the <em>execute</em> method simply resets the old value
for the bookmark and add it with the (possibly) new name.</p>
+
+<p>The last thing we need to do is to add the configuration in the
<em>edit</em> package for the new action:</p>
+
+<div class="code panel" style="border-width: 1px;"><div class="codeHeader
panelHeader" style="border-bottom-width:
1px;"><b>src/main/resources/struts.xml</b></div><div class="codeContent
panelContent">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
+<action name="editBookmark" class="com.mycompany.EditBookmarkAction">
+ <result type="redirectAction">
+ <param name="actionName">index</param>
+ </result>
+ <result name="input">/WEB-INF/jsp/edit/edit.jsp</result>
+</action>
+]]></script>
+</div></div>
+
+<h2><a shape="rect" name="Struts2PortletTutorial-Summary"></a>Summary</h2>
+<p>Using Struts 2, we built a simple bookmark portlet utilizing the
<em>edit</em> portlet mode for management operations. The tutorial should have
given you a basic understanding of portlet development with Struts 2, and that
it is not very different from using Struts 2 in a regular web application. </p>
+
+<h2><a shape="rect" name="Struts2PortletTutorial-Notes"></a>Notes</h2>
+<p>Instead of using the Maven 2 Jetty plugin to run the tutorial, you can
check out the <em>JettyPlutoLauncher</em> which is included in the test
sources. Just launch it as a regular Java class in your IDE. And to debug, just
launch it in debug mode.</p>
+
+<h2><a shape="rect" name="Struts2PortletTutorial-Links"></a>Links</h2>
+<p><a shape="rect"
href="struts-2-portlet-tutorial.data/bookmark-portlet.zip?version=1&modificationDate=1199675399000">S2PLUGINS:Source
code for the tutorial</a><br clear="none">
+<a shape="rect" class="external-link"
href="http://jcp.org/aboutJava/communityprocess/final/jsr168/index.html"
rel="nofollow">JSR168 Specification</a><br clear="none">
+<a shape="rect" class="external-link"
href="http://struts.apache.org/2.x/docs/portlet-configuration.html">Struts 2
Portlet Configuration options</a><br clear="none">
+<a shape="rect" class="external-link" href="http://portletwork.blogspot.com"
rel="nofollow">Author's blog about portlet related development</a><br
clear="none">
+<a shape="rect" class="external-link"
href="http://struts.apache.org/2.x/docs/portlet-tutorial-webwork-22.html">Old
tutorial for WebWork 2</a></p></div>
+ </div>
+
+
+ </div>
+</div>
+<div class="footer">
+ Generated by CXF SiteExporter
+</div>
+</body>
+</html>
\ No newline at end of file
Added:
websites/production/struts/content/development/2.x/docs/struts-2-spring-2-jpa-ajax.data/quickstart.zip
==============================================================================
Binary file - no diff available.
Propchange:
websites/production/struts/content/development/2.x/docs/struts-2-spring-2-jpa-ajax.data/quickstart.zip
------------------------------------------------------------------------------
svn:mime-type = application/zip
Added:
websites/production/struts/content/development/2.x/docs/struts-2-spring-2-jpa-ajax.data/quickstart_maven.zip
==============================================================================
Binary file - no diff available.
Propchange:
websites/production/struts/content/development/2.x/docs/struts-2-spring-2-jpa-ajax.data/quickstart_maven.zip
------------------------------------------------------------------------------
svn:mime-type = application/zip
Added:
websites/production/struts/content/development/2.x/docs/struts-2-spring-2-jpa-ajax.data/quickstart_maven2.zip
==============================================================================
Binary file - no diff available.
Propchange:
websites/production/struts/content/development/2.x/docs/struts-2-spring-2-jpa-ajax.data/quickstart_maven2.zip
------------------------------------------------------------------------------
svn:mime-type = application/zip