<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Web2.0 Tutorials &#187; struts2.1</title>
	<atom:link href="http://www.zulutown.com/blog/tag/struts21/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.zulutown.com/blog</link>
	<description>All the Guides You Need to Become a Web2.0 Expert</description>
	<lastBuildDate>Mon, 13 Jul 2009 07:50:00 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>REST web application with Struts2.1 Rest and Convention plugins</title>
		<link>http://www.zulutown.com/blog/2009/01/28/rest-web-application-with-struts21-rest-and-convention-plugins/</link>
		<comments>http://www.zulutown.com/blog/2009/01/28/rest-web-application-with-struts21-rest-and-convention-plugins/#comments</comments>
		<pubDate>Wed, 28 Jan 2009 21:22:41 +0000</pubDate>
		<dc:creator>Zulutown Webmaster</dc:creator>
				<category><![CDATA[Rest]]></category>
		<category><![CDATA[Struts2]]></category>
		<category><![CDATA[controller]]></category>
		<category><![CDATA[convention]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[poster]]></category>
		<category><![CDATA[Struts]]></category>
		<category><![CDATA[struts2.1]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://www.zulutown.com/blog/?p=50</guid>
		<description><![CDATA[The sample application developed in this tutorial will handle a simple message system, where it&#8217;s possible to read, add and remove messages.
So, the basic bean will be defined in the Message class:
package com.zulutown.struts2.rest;

public class Message {
	private String id;
	private String text;
	private String author;

	public Message() {
		super();
	}

	public Message(String id, String text, String author) {
		super();
		this.id = id;
		this.text = text;
		this.author [...]]]></description>
			<content:encoded><![CDATA[<p>The sample application developed in this tutorial will handle a simple message system, where it&#8217;s possible to read, add and remove messages.<br />
So, the basic bean will be defined in the <code>Message</code> class:</p>
<pre>package com.zulutown.struts2.rest;

public class Message {
	private String id;
	private String text;
	private String author;

	public Message() {
		super();
	}

	public Message(String id, String text, String author) {
		super();
		this.id = id;
		this.text = text;
		this.author = author;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}

	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Message other = (Message) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}
}</pre>
<p>The message will be identified by the <code>id</code> property and will contain its <code>text</code> and its <code>author</code> in the other two class properties.</p>
<p>The next step is to setup a basic <em>business service</em> that will handle the basic operations on the messages: <em>find</em>, <em>save</em>, <em>remove</em> and so on. In a real world application this service would be a singleton that interacts with a database (through JDBC or JPA) but in this little demo the data model is just a very basic (and ugly) Map kept in a static property of the <code>Message</code> class.</p>
<pre>package com.zulutown.struts2.rest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MessageService {

	public static Map messages = new HashMap();
	private static int nextMessageId = 4;

	static {
		Message message1 = new Message("1", "hello", "john");
		Message message2 = new Message("2", "world", "ted");
		Message message3 = new Message("3", "rest", "sam");
		messages.put("1", message1);
		messages.put("2", message2);
		messages.put("3", message3);
	}

	public static List findAll() {
		return new ArrayList(messages.values());
	}

	public static Message find(String id) {
		return messages.get(id);
	}

	public static void save(Message message) {
		if (message.getId() == null) {
			String id = String.valueOf(nextMessageId);
			message.setId(id);
			nextMessageId++;
		}
		messages.put(message.getId(), message);
	}

	public static void remove(String id) {
		messages.remove(id);
	}
}</pre>
<p>In <code>messages</code> it is stored the data and the static initializer of the <code>MessageService</code> class will populate the data model with three messages.<br />
Then, some utility methods are provided: <code>findAll()</code> to retrieve all the messages, <code>find(String id)</code> to retrieve a message with a specific <code>id</code>, <code>save(Message message)</code> to add (or update) a message in the data model and, finally, a <code>remove</code> method to delete a specific message.</p>
<p>Until now, this tutorial is not related at all with Struts 2.1, but now it is required to add a &#8220;web layer&#8221; to the application, and the REST capabilities provided by Struts2 will be used.</p>
<p>The first task is to add to the Web application the <code>.jar</code> libraries of Struts2. Those files must be placed into <code>/WEB-INF/lib</code> (in WebContent) that is the standard location where a Java Web Application expects to find its dependencies.</p>
<p>Download from the Struts <a href="http://struts.apache.org/download.cgi">website</a> the archives with the libraries for Struts 2.1.x (currently the GA release is 2.1.6), unpack it, and copy &amp; paste the following jars in <code>/WEB-INF/lib/</code> of your project.</p>
<ul>
<li>commons-beanutils-1.7.0.jar</li>
<li>commons-collections-3.2.jar</li>
<li>commons-fileupload-1.2.1.jar</li>
<li>commons-io-1.3.2.jar</li>
<li>commons-lang-2.3.jar</li>
<li>commons-logging-1.0.4.jar</li>
<li>ezmorph-1.0.3.jar</li>
<li>freemarker-2.3.13.jar</li>
<li>json-lib-2.1.jar</li>
<li>ognl-2.6.11.jar</li>
<li>struts2-convention-plugin-2.1.6.jar</li>
<li>struts2-core-2.1.6.jar</li>
<li>struts2-rest-plugin-2.1.6.jar</li>
<li>xpp3_min-1.1.3.4.O.jar</li>
<li>xstream-1.2.2.jar</li>
<li>xwork-2.1.2.jar</li>
</ul>
<p>Two Struts2 plugins are used:</p>
<ul>
<li> Rest Plugin</li>
<li>Convention Plugin</li>
</ul>
<p>First of all create at the root of the <code>src</code> directory the <code>struts.xml</code> file:</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
    "http://struts.apache.org/dtds/struts-2.1.dtd"&gt;

&lt;struts&gt;
    &lt;constant name="struts.convention.package.locators" value="rest"/&gt;
    &lt;constant name="struts.convention.action.suffix" value="Controller"/&gt;
    &lt;constant name="struts.convention.action.mapAllMatches" value="true"/&gt;
    &lt;constant name="struts.convention.default.parent.package" value="rest-default"/&gt;
&lt;/struts&gt;</pre>
<p>Convention plugin makes possible to map classes and methods on automatically generated URLs. It is not required the manual &#8220;wiring&#8221; usually done in the <code>struts.xml</code> configuration file that, in this case, contains just a few lines of configuration.  The property <code>struts.convention.package.locators</code> defines the package name where the Convention plugin will look for Struts2 Actions and Controllers, then with <code>struts.convention.action.suffix</code> it is specified that just the classes with the <em>Controller</em> suffix will be automatically mapped.  The REST controller that&#8217;s going to be defined in the next step, will have the name <code>MessagesController</code> and will be contained in the package <code>com.zulutown.struts2.rest</code>, then it will match both the configurations described above.  Given this configuration, the list of the messages in XML format will be accessible through an HTTP GET method on <code>http://localhost:8080/Struts2-Rest/messages.xml</code>, and to obtain the JSON messages list, it&#8217;s enough to call the HTTP GET method on <code>http://localhost:8080/Struts2-Rest/messages.json</code>. Simple, isn&#8217;t?  Now, the simple code of the Controller class that will handle the REST requests:</p>
<pre>package com.zulutown.struts2.rest;

import java.util.Collection;
import org.apache.struts2.rest.DefaultHttpHeaders;
import org.apache.struts2.rest.HttpHeaders;
import com.opensymphony.xwork2.ModelDriven;

public class MessagesController implements ModelDriven&lt;Object&gt; {

	private static final long serialVersionUID = 89268916175477696L;
	private Message model = new Message();
	private String id;
	private Collection&lt;Message&gt; list;

	public HttpHeaders create() {
		MessageService.save(model);
		return new DefaultHttpHeaders("create");
	}

	public HttpHeaders destroy() {
		return new DefaultHttpHeaders("destroy");
	}

	public HttpHeaders show() {
		return new DefaultHttpHeaders("show").disableCaching();
	}

	public HttpHeaders update() {
		MessageService.save(model);
		return new DefaultHttpHeaders("update");
	}

	public HttpHeaders index() {
		list = MessageService.findAll();
		return new DefaultHttpHeaders("index").disableCaching();;
	}

	public Object getModel() {
		return (list != null ? list : model);
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		if (id != null) {
			this.model = MessageService.find(id);
		}
		this.id = id;
	}
}</pre>
<p>In the Struts2 REST plugin, the method name (in the the Controller class) identifies which kind of operation should be executed on specific HTTP requests.</p>
<p>HTTP GET method on <code>http://localhost:8080/Struts2-Rest/messages.xml</code> calls <code>index()</code> and provides the list of all the messages (in the <code>model</code> property of the controller).</p>
<p>The result is:</p>
<pre>&lt;list&gt;
  &lt;com.zulutown.struts2.rest.Message&gt;
    &lt;id&gt;3&lt;/id&gt;
    &lt;text&gt;rest&lt;/text&gt;
    &lt;author&gt;sam&lt;/author&gt;
  &lt;/com.zulutown.struts2.rest.Message&gt;
  &lt;com.zulutown.struts2.rest.Message&gt;
    &lt;id&gt;2&lt;/id&gt;
    &lt;text&gt;world&lt;/text&gt;
    &lt;author&gt;ted&lt;/author&gt;
  &lt;/com.zulutown.struts2.rest.Message&gt;
  &lt;com.zulutown.struts2.rest.Message&gt;
    &lt;id&gt;1&lt;/id&gt;
    &lt;text&gt;hello&lt;/text&gt;
    &lt;author&gt;john&lt;/author&gt;
  &lt;/com.zulutown.struts2.rest.Message&gt;
&lt;/list&gt;</pre>
<p>HTTP GET method on <code>http://localhost:8080/Struts2-Rest/messages/2.xml</code> calls <code>setId("2")</code> (that loads in the <code>model</code> property the Message identified by the provided <code>id</code>) then <code>show()</code>.</p>
<p>The result is:</p>
<pre>&lt;com.zulutown.struts2.rest.Message&gt;
  &lt;id&gt;2&lt;/id&gt;
  &lt;text&gt;world&lt;/text&gt;
  &lt;author&gt;ted&lt;/author&gt;
&lt;/com.zulutown.struts2.rest.Message&gt;</pre>
<p>The previous two methods are easy to call with the browser but, to test the other HTTP methods, it&#8217;s better to use the Firefox plugin <a href="http://code.google.com/p/poster-extension/">Poster</a>.</p>
<p>HTTP POST method on <code>http://localhost:8080/Struts2-Rest/messages.xml</code> injects into <code>model</code> a new message, then calls <code>create()</code> that persists it.</p>
<p>In the <em>poster</em> dialog box, the URL must be <code>http://localhost:8080/Struts2-Rest/messages.xml</code> with <code>POST</code> action. In <em>Content to Send</em> it&#8217;s required to insert the XML entity for the new message (without specifying its id, because it will be automatically generated by <code>MessageService</code>).</p>
<pre>  &lt;com.zulutown.struts2.rest.Message&gt;
    &lt;text&gt;new text&lt;/text&gt;
    &lt;author&gt;new author&lt;/author&gt;
  &lt;/com.zulutown.struts2.rest.Message&gt;</pre>
<div id="attachment_62" class="wp-caption alignnone" style="width: 490px"><img class="size-large wp-image-62" title="Rest - HTTP Post" src="http://www.zulutown.com/blog/wp-content/uploads/2009/01/poster-post-480x592.png" alt="Rest - HTTP Post" width="480" height="592" /><p class="wp-caption-text">Rest - HTTP Post</p></div>
<p>HTTP PUT method on <code>http://localhost:8080/Struts2-Rest/messages/2.xml</code> calls <code>setId("2")</code> (that causes the loading of the existing message with <code>id=2</code> in the <code>model</code> property) then, depending on which fields are specified in the XML, those message properties are modified and finally  a call to <code>update()</code> saves the updated message.</p>
<p>In the <em>poster</em> dialog box, the URL must be <code>http://localhost:8080/Struts2-Rest/messages/2.xml</code> with <code>PUT</code> action. In <em>Content to Send</em> it&#8217;s required to insert the XML entity for the fields to edit (the unspecified fields will keep the previous values).</p>
<pre>  &lt;com.zulutown.struts2.rest.Message&gt;
    &lt;text&gt;updated text&lt;/text&gt;
  &lt;/com.zulutown.struts2.rest.Message&gt;</pre>
<div id="attachment_63" class="wp-caption alignnone" style="width: 490px"><img class="size-large wp-image-63" title="Rest - HTTP Put" src="http://www.zulutown.com/blog/wp-content/uploads/2009/01/poster-put-480x592.png" alt="Rest - HTTP Put" width="480" height="592" /><p class="wp-caption-text">Rest - HTTP Put</p></div>
<p>After the POST and PUT calls, the data structure will look like this:</p>
<pre>&lt;list&gt;
  &lt;com.zulutown.struts2.rest.Message&gt;
    &lt;id&gt;3&lt;/id&gt;
    &lt;text&gt;rest&lt;/text&gt;
    &lt;author&gt;sam&lt;/author&gt;
  &lt;/com.zulutown.struts2.rest.Message&gt;
  &lt;com.zulutown.struts2.rest.Message&gt;
    &lt;id&gt;2&lt;/id&gt;
    &lt;text&gt;updated text&lt;/text&gt;
    &lt;author&gt;ted&lt;/author&gt;
  &lt;/com.zulutown.struts2.rest.Message&gt;
  &lt;com.zulutown.struts2.rest.Message&gt;
    &lt;id&gt;1&lt;/id&gt;
    &lt;text&gt;hello&lt;/text&gt;
    &lt;author&gt;john&lt;/author&gt;
  &lt;/com.zulutown.struts2.rest.Message&gt;
  &lt;com.zulutown.struts2.rest.Message&gt;
    &lt;id&gt;4&lt;/id&gt;
    &lt;text&gt;new text&lt;/text&gt;
    &lt;author&gt;new author&lt;/author&gt;
  &lt;/com.zulutown.struts2.rest.Message&gt;
&lt;/list&gt;</pre>
<p>In this tutorial all the URLs refer to <code>xml</code> content type, but it&#8217;s possible to use <code>json</code> just changing URLs from <code>messages.xml</code> to <code>messages.json</code> or <code>messages/2.xml</code> to <code>messages/2.json</code>.</p>
<p>I hope this tutorial has given a simple and easy introduction to the REST capabilities of Struts2.1. Please leave your comments and feedback.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zulutown.com/blog/2009/01/28/rest-web-application-with-struts21-rest-and-convention-plugins/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
	</channel>
</rss>
