<?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>Mersoft Corporation Blog &#187; xml parser</title>
	<atom:link href="http://blog.mersoft.com/tag/xml-parser/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.mersoft.com</link>
	<description>Achieve, Compete, and Evolve</description>
	<lastBuildDate>Wed, 07 Sep 2011 15:13:56 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Struts2 Rest Webservice</title>
		<link>http://blog.mersoft.com/2009/09/08/struts2-rest-webservice/</link>
		<comments>http://blog.mersoft.com/2009/09/08/struts2-rest-webservice/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 14:10:52 +0000</pubDate>
		<dc:creator>Mandi Zinn</dc:creator>
				<category><![CDATA[Java/Java Frameworks]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[rest web service]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[struts 2]]></category>
		<category><![CDATA[struts 2 rest plugin]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[xml parser]]></category>

		<guid isPermaLink="false">http://blog.mersoft.com/?p=242</guid>
		<description><![CDATA[I started out trying to create a rest webservice for a project I&#8217;m working on with Mersoft. After a little bit of research, I discovered Apache has a rest plugin that enables Struts 2 to perform as a rest webservice.
I followed the documentation at http://struts.apache.org/2.x/docs/rest-plugin.html and created my rest webservice. However, I came across a [...]]]></description>
			<content:encoded><![CDATA[<p>I started out trying to create a rest webservice for a project I&#8217;m working on with <a title="Mersoft Corporation" href="http://www.mersoft.com">Mersoft</a>. After a little bit of research, I discovered Apache has a rest plugin that enables Struts 2 to perform as a rest webservice.</p>
<p>I followed the documentation at http://struts.apache.org/2.x/docs/rest-plugin.html and created my rest webservice. However, I came across a couple of issues that I could not find any documentation as to how to address. The first of these issues is that the documentation says that the rest plugin supports xml, json, and xhtml. I downloaded the rest example&#8217;s source jar and tore it apart, but there was nothing to address the xhtml. Next I installed the pre-compiled war and to my amazement, the xhtml worked. After I tore apart the war, I discovered what is required for the xhtml (I have that documented <a href="#xhtml">here</a>)</p>
<p>The second issue I came across was that I didn&#8217;t like how the xml was being displayed (instead of using just the object name as the xml tag, it included the package name). How to customize the xml display is documented <a href="#xml">here</a>.</p>
<p>The last struggle I had was that I wanted to use Spring to inject classes into my controllers. I searched online and found other developers asking how to do this, but could find nothing on how to actually do this. How to use Spring for the controllers is documented <a href="#spring">here</a>.</p>
<p>I am writing this blog to document what I did to create a rest webservice and to share what I did to resolve the issues I had.</p>
<p><strong>Creating a Rest Webservice</strong></p>
<p>To create a rest webservice, Apache created a rest plugin that works with Struts 2. This plugin was written with the intent of being used with the struts 2 convention plugin.</p>
<p>These are the only dependencies needing to be added to a Struts2 project:</p>
<pre>&lt;dependency&gt;
   &lt;groupId&gt;org.apache.struts&lt;/groupId&gt;
   &lt;artifactId&gt;struts2-rest-plugin&lt;/artifactId&gt;
   &lt;version&gt;${struts.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
   &lt;groupId&gt;org.apache.struts&lt;/groupId&gt;
   &lt;artifactId&gt;struts2-convention-plugin&lt;/artifactId&gt;
   &lt;version&gt;${struts.version}&lt;/version&gt;
&lt;/dependency&gt;</pre>
<p>The web.xml must use the StrutsPrepareAndExecuteFilter for the struts 2 convention plugin (this Filter can also be used with other struts 2 applications as long as the application doesn&#8217;t need another filter that has to access the action&#8217;s context information). The web.xml should look like the following:</p>
<pre>&lt;web-app id="WebApp_9" version="2.4"
   xmlns="http://java.sun.com/xml/ns/j2ee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"&gt;

   &lt;filter&gt;
      &lt;filter-name&gt;action2&lt;/filter-name&gt;
      &lt;filter-class&gt;org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter&lt;/filter-class&gt;
   &lt;/filter&gt;

   &lt;filter-mapping&gt;
      &lt;filter-name&gt;action2&lt;/filter-name&gt;
      &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
   &lt;/filter-mapping&gt;

&lt;/web-app&gt;</pre>
<p>With the convention plugin, the only thing required in struts.xml is any changes in configuration needed for the convention plugin. If the web service is written without the convention plugin, you would just have to define each controller in the struts.xml (the same way an action is defined). The convention plugin just makes this defining process unnecessary.</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
   "http://struts.apache.org/dtds/struts-2.0.dtd"&gt;

&lt;struts&gt;

   &lt;!-- The struts rest plugin allows you to define the paths used for the webservice.
   If you have groupings of controllers and you want users to access the controllers based on the groupings, you can do this in the following way:
      1. create a package for each grouping (i.e. com.mersoft.test.group1, com.mersoft.test.group2)
      2. set the struts.convention.package.locators as the last package name before the groupings (i.e. "test")
      3. access the rest webservice by {application base}/{group name}/{controller name} (i.e. {application base}/group1/controller1, {application base}/group2/controller2)
   If you want all controllers accessed from the application base:
      1. put all the controllers in the same package (i.e. com.mersoft.controller).
      2. set the struts.convention.package.locators as the last package name (i.e. "controller")
     3. access the rest webservice by {application base}/{controller name} (i.e.  {application base}/controller1)
   --&gt;
   &lt;constant name="struts.convention.package.locators" value="[PACKAGE TO LOOK FOR CONTROLLERS]"/&gt;  &lt;!-- The convention plugin defaults this to "action,actions,struts,struts2" --&gt;
   &lt;constant name="struts.convention.action.suffix" value="Controller"/&gt;  &lt;!-- The convention plugin defaults this to "Action" --&gt;
   &lt;constant name="struts.convention.action.mapAllMatches" value="true"/&gt;   &lt;!-- The convention plugin defaults this to "false" --&gt;
   &lt;constant name="struts.convention.default.parent.package" value="rest-default"/&gt;  &lt;!-- The convention plugin defaults this to "convention-default". The "rest-default" is defined by the struts2 rest plugin --&gt;
&lt;/struts&gt;</pre>
<p>The objects being passed through the rest webservice need to be defined. These are just POJOs. Here&#8217;s an example:</p>
<pre>package com.mersoft.web.model;

public class TestObject {

   private String id;
   private String someString;
   private long someLong;
   private String anotherString;

   public String getId() {
      return id;
   }
   public void setId(String id) {
      this.id = id;
   }
   public String getSomeString() {
      return someString;
   }
   public void setSomeString(String someString) {
      this.someString = someString;
   }
   public long getSomeLong() {
      return someLong;
   }
   public void setSomeLong(long someLong) {
      this.someLong = someLong;
   }
   public String getAnotherString() {
      return anotherString;
   }
   public void setAnotherString(String anotherString) {
      this.anotherString = anotherString;
   }
}</pre>
<p>The rest webservice uses &#8220;controllers&#8221; for data manipulation. The controllers must implement ModelDriven&lt;T&gt;. In my example below I added the Validateable interface and the ValidationAwareSupport extension. This allows the controller to be validated prior to any executions.</p>
<p><strong>NOTE:</strong> The Controller name must not use camel casing. (i.e. use TestinstanceController instead of TestInstanceController).</p>
<pre>package com.mersoft.web.controller;

import org.apache.struts2.rest.DefaultHttpHeaders;
import org.apache.struts2.rest.HttpHeaders;

import com.mersoft.web.model.TestObject;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Validateable;
import com.opensymphony.xwork2.ValidationAwareSupport;

public class TestController extends ValidationAwareSupport implements ModelDriven&lt;TestObject&gt;, Validateable{
   /**
   *
   */
   private static final long serialVersionUID = -1045170916847707617L;

   private TestObject testObject = new TestObject();

   private String id;

   public TestController() {
      super();
   }

   public TestObject getModel() {
      //TODO: populate test object
      return testObject;
   }

   // GET /test/1
   public HttpHeaders show() {
      return new DefaultHttpHeaders("show");
   }

   // GET /test
   public HttpHeaders index() {
      return new DefaultHttpHeaders("index");
   }

   // POST /test
   public HttpHeaders create() throws Exception {
      //TODO: creation action here

      return new DefaultHttpHeaders("success");
   }

   //PUT /test/1
   public String update() throws Exception {
      //TODO: update action here
      return "success";
   }

   // DELETE /test/1
   public String destroy() {
      //TODO: delete action here
      return "success";
   }

   public void validate() {
      // TODO add validation here

   }

   public String getId() {
      return id;
   }

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

}</pre>
<p>To access the webservice, you just need to make the request. (Look above at the type of request and the parameters that need to be passed to access each method.)</p>
<p>For xml requests, add .xml to the end of the url (i.e. Making a GET request to {application base}/test.xml will access the index method and return an xml response).<br />
For json requests, add .json to the end of the url (i.e. Making a GET request to {application base}/test.json will access the index method and return a json response).</p>
<p><strong>Adding custom methods</strong></p>
<p>The rest webservice plugin is designed to be flexible. If there&#8217;s actions you don&#8217;t want the user to be able to perform, you simply omit it from the controller. If there&#8217;s a special action that is not part of the standard actions, you just add the custom action to your controller:</p>
<pre>   public String test() {
      return "test";
   }</pre>
<p>To access the above action, make a GET request to {application base}/test/1/test.xml.</p>
<p><strong><a name="xhtml">Accessing the webservice via xhtml</a></strong></p>
<p>Out of the box, the rest webservice supports xhtml, however you must create the jsp pages the webservice must display to the user.</p>
<p>By default, the convention plugin expects these files in WEB-INF/content/ (this can be changed by adding &lt;constant name=&#8221;struts.convention.result.path&#8221; value=&#8221;/WEB-INF/{jsp directory}&#8221;/&gt; to struts.xml)   . The file names must be {controller name}-{request name}.jsp. For example, for the jsp corresponding to the show action in TestController, the file name should be test-show.jsp.</p>
<p><strong>NOTE:</strong> To display objects returned by the getModel() method, you just need to reference the object name within the model. (i.e. to display someString from the TestObject, you can reference it as ${someString} in the jsp)</p>
<p>For requests needing to be sent as a PUT or a DELETE, you can attach &#8220;?_method={REQUEST TYPE} to the end of the action method in the form and send the request as a post.</p>
<p><strong><a name="xml">Customizing xml response</a></strong></p>
<p>To make the xml cleaner, I wanted to display just the object name without the package the object is in. After doing a little bit of research, I discovered that the struts-rest plugin uses XStream. The latest version of XStream allows annotations to customize the xml. Since the struts-rest plugin doesn&#8217;t use the latest XStream, I created my own ContentTypeHandler using the latest XStream.</p>
<p>Be sure to add the XStream dependency to the classpath:</p>
<pre>&lt;dependency&gt;
   &lt;groupId&gt;com.thoughtworks.xstream&lt;/groupId&gt;
   &lt;artifactId&gt;xstream&lt;/artifactId&gt;
   &lt;version&gt;1.3.1&lt;/version&gt;
&lt;/dependency&gt;</pre>
<p>The ContentTypeHandler I created is very similar to that of the rest plugin&#8217;s XML content handler. The main difference is that I told XStream to process annotations.</p>
<p><strong>NOTE:</strong> This must implement org.apache.struts2.rest.handler.ContentTypeHandler to work with the struts rest plugin.</p>
<pre>package com.mersoft.rest.handler;

import java.io.IOException;
import java.io.Reader;
import java.io.Writer;

import org.apache.struts2.rest.handler.ContentTypeHandler;

import com.thoughtworks.xstream.XStream;

/**
* Handles XML content
*/
public class XStreamHandler implements ContentTypeHandler {

   public String fromObject(Object obj, String resultCode, Writer out) throws IOException {
      if (obj != null) {
         XStream xstream = new XStream();
         xstream.processAnnotations(obj.getClass());
         xstream.toXML(obj, out);
      }
      return null;
   }

   public void toObject(Reader in, Object target) {
      XStream xstream = new XStream();
      xstream.processAnnotations(target.getClass());
      xstream.fromXML(in, target);
   }

   public String getContentType() {
      return "application/xml";
   }

   public String getExtension() {
      return "xml";
   }
}</pre>
<p>To use the new content handler, I had to add the following line to my struts.xml:</p>
<pre>   &lt;bean type="org.apache.struts2.rest.handler.ContentTypeHandler" name="myXml" class="com.mersoft.rest.handler.XStreamHandler" /&gt;</pre>
<p>To tell the rest plugin to use my new content handler, I simply have to add the bean name to a struts.properties file:</p>
<pre>struts.rest.handlerOverride.xml=myXml</pre>
<p>Now I can use the XStream annotations. Here&#8217;s an example of how to use the annotations with the TestObject:</p>
<pre>package com.mersoft.web.model;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamOmitField;

@XStreamAlias("test")
public class TestObject {

   private String id;
   private String someString;

   @XStreamOmitField
   private long someLong;

   private String anotherString;
   ...</pre>
<p>For more on XStream&#8217;s annotations see <a href="http://xstream.codehaus.org/annotations-tutorial.html">http://xstream.codehaus.org/annotations-tutorial.html</a></p>
<p><strong><a name="spring">Using Spring Dependency Injection on the Controllers</a></strong></p>
<p>With the rest webservice I was creating, I wanted to spring inject my managers into my controllers. After searching on the web, I couldn&#8217;t find any answers on how to do this. Analyzing what I have accomplished so far, I realized that the controllers were no more than specialized actions. My biggest obstacle was discovering how to use the struts2 spring plugin with the struts2 convention plugin. The struts2 spring plugin pulls the &#8220;class&#8221; name from the struts.xml file. If the &#8220;class&#8221; name matches a bean definition, then the spring plugin pulls the bean. If it does not match a bean definition, then it pulls the class. After discovering this, it was pretty clear as to how to get this to work with the struts convention plugin.</p>
<p>First, I added the struts2 spring plugin dependency:</p>
<pre>&lt;dependency&gt;
   &lt;groupId&gt;org.apache.struts&lt;/groupId&gt;
   &lt;artifactId&gt;struts2-spring-plugin&lt;/artifactId&gt;
   &lt;version&gt;${struts.version}&lt;/version&gt;
&lt;/dependency&gt;</pre>
<p>As the standard struts2 spring plugin requires, we must configure it in web.xml by setting up the context path and including the context listener:</p>
<pre>   &lt;context-param&gt;
      &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
      &lt;param-value&gt;
         classpath:/applicationContext-resources.xml
         classpath:/applicationContext-dao.xml
         classpath*:/applicationContext.xml
      &lt;/param-value&gt;
   &lt;/context-param&gt;

   &lt;listener&gt;
      &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
   &lt;/listener&gt;</pre>
<p>The only thing left was to set up the applicationContext.xml. In order for the spring plugin to pull the beans based on this configuration, the bean id must match the bean class.</p>
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xsi:schemaLocation="
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"&gt;

   &lt;bean id="com.mersoft.web.controller.TestController" &gt;
      &lt;constructor-arg ref="testManager" /&gt;
   &lt;/bean&gt;
&lt;/beans&gt;</pre>
<p><strong> </strong></p>
<p><strong>NOTE:</strong> This will call the TestController constructor with the constructor containing the &#8220;testManager&#8221; class (i.e.: public TestController(TestManager testManager))</p>
<p>For more information on the struts2 spring plugin, you can see <a href="http://struts.apache.org/2.0.8/docs/spring-plugin.html">http://struts.apache.org/2.0.8/docs/spring-plugin.html</a></p>
<p>With this last issue resolved, I was able to do everything I wanted to do with my rest webservice. I hope this is helpful.</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.mersoft.com%2F2009%2F09%2F08%2Fstruts2-rest-webservice%2F&amp;linkname=Struts2%20Rest%20Webservice"><img src="http://blog.mersoft.com/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a>]]></content:encoded>
			<wfw:commentRss>http://blog.mersoft.com/2009/09/08/struts2-rest-webservice/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>

