Free Online Courses for Software Developers - MrBool
× Please, log in to give us a feedback. Click here to login
×

You must be logged to download. Click here to login

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

Mobile Application Integrations: XML on the server

In this article, I add an XML interface tailored for use by Android-based smartphones to an existing Java servlet web site.

Introduction

With smartphones and tablet computers rapidly become a common fixture of most business’s IT strategy, integration of mobile applications with existing server-side systems is now among the most common kinds of development project. With a variety of mobile platforms to cater for, it can be a daunting task, but by standardising on a single client platform the scope of the project can be managed. For Java developers, Android presents a tempting platform, as the system is based around familiar Java APIs. Unfortunately for the Java developer, Android is far from a complete implementation of Java, and resource constraints on devices (particularly lower-cost smartphones) often mean that familiar enterprise APIs cannot be easily adapted to use on the clients. By careful choice of technology, however, it is still possible to rapidly develop client applications using Android, and by choosing standard data transfer techniques (e.g. XML entities passed over HTTP requests) we can leave open the possibility of supporting other platforms without requiring modifications to the server side.

To familiarise yourself with the site and data, I recommend you read my previous articles during which it was developed, especially Framework-free patterns: Model View Controller, which describes the most recent changes to the site that are built upon by this article (other articles in the series have modified the site since, but those changes are tangential to the changes introduced here).

Selecting an XML library

Many developers would choose to dive straight into an XML development project by first designing an XML schema for the requests and responses and then implementing that schema using the XML APIs they are familiar with (typically either the Document Object Model or JAXB, the Java Architecture for XML Binding). In my experience, this is a mistake.

Android runs on a very constrained implementation of Java, and is missing several parts of the standard Java SE API. Unfortunately, this includes several components that are required for supporting JAXB. While these components can be added (or, as in the case of the lack of support for reflection on packages, their absence worked around), doing so inflates the size of an application using JAXB by several megabytes; in resource constrained smartphones this is often an unacceptable cost. The standard alternative would be to use the DOM, but developing applications using the DOM is much slower than using a data binding API.

Fortunately, there are several alternatives available, including an implementation of XML as an output transformation for the data-format agnostic Jackson library (originally written as a data binder for JSON, but offering a choice of several formats now) and the XML-specific SimpleXML framework. I have chosen to use the latter in this article, as it has the lower resource requirements of the two (Jackson, while smaller than JAXB, still consumes more than a megabyte of space in your .apk files, while SimpleXML only requires a few hundred kilobytes). It can be downloaded from http://simple.sourceforge.net/.

With the choice of SimpleXML made, now I work on designing my schema. I have delayed this until now because SimpleXML and Jackson both allow very simple configuration if I chose to work with their default behaviour but can become quite complicated to use if I chose to try to force them to work with an arbitrary schema. By designing my Java objects and working with the format that the library naturally produces when passed those objects, I can save myself a substantial headache later.

Implementing the server

While it would be possible to add XML-based interfaces to my existing servlets (e.g. by including a mechanism for switching between multiple view implementations in a Model-View-Controller architecture), for the sake of simplicity I have chosen to implement new servlets in a parallel structure. All of the application specific logic for my site has already been moved into my Model objects; the existing servlets merely serve as an interface between the external world of HTTP requests and the business-domain world seen through the eyes of my model objects, so the duplication of effort is actually relatively small compared to the extra complexity that would be introduced by adding such view switching logic, along with the possibility of needing to decode requests from multiple formats.

I start with the simplest servlet, which is also the main gateway into the site, and will provide the data required for the app’s startup activity, the list of customers. I’ve chosen to put my XML servlets into a separate package, so I can reuse the same class names as the HTML-interface servlets.

Listing 1: Listing customers in XML

 
public class CustomerList extends HttpServlet
{
	CustomerDAO customerDAO;
	Serializer persister;

	public void setCustomerDAO(CustomerDAO customerDAO)
	{
		this.customerDAO = customerDAO;
	}

	public void setPersister(Serializer persister)
	{
		this.persister = persister;
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException
	{
		resp.setContentType("text/xml");
		try
		{
			persister.write(Result.customers(customerDAO.getAll()),
					resp.getWriter());
		} 
		catch (Exception e)
		{
			throw new ServletException("Error sending list of customers", e);
		}
	}
}

The CustomerDAO and Serializer objects will be supplied by Spring; CustomerDAO was already configured in previous articles, but the Serializer is new. Serializer is an interface defined by the SimpleXML framework; it is implemented by a class called Persister:

Listing 2: Creating the Persister

 
	<bean id="persister" class="org.simpleframework.xml.core.Persister" />
 

Handling the request is very simple. We tell the response that we will be producing XML output, fetch the list of customers from the customerDAO object, and send it to the persister object to produce XML. But before we do this, I have chosen to wrap all of my responses in a Result object. The reason for this is a restriction of the SimpleXML framework: we have to tell it what type of object we’re expecting when we read data out of an XML document; it cannot return different types depending on context. The Result object therefore can be used to encapsulate different possible outcomes: success with no further data, an error message, or a list of domain objects. It looks like this:

Listing 3: Result class

@Root(name="result")
public class Result
{
	@Attribute(required=true)
	private boolean success;
	
	@Attribute(required=false)
	private String error;
	
	@ElementList(inline=true, entry="customer", type=Customer.class, required=false)
	private List<Customer> customers;
	
	@ElementList(inline=true, entry="account", type=Account.class, required=false)
	private List<Account> accounts;
}

The annotations are defined by SimpleXML; with @Root I tell the framework that this object will serve as the root node of an XML document and tell it what tag name to use. The success and error fields are mapped to attributes of this root node, while customers and accounts are mapped to lists of XML elements (with tag name “customer” or “account” respectively). By specifying “inline=true” for these lists, I tell the framework not to wrap the lists inside an additional element. I also tell the framework whether each element or attribute is required or not; it will check when binding a document to objects whether these constraints have been met or not, and raise an exception if they are violated.

For convenience, I also define static methods to build Result objects with various combinations of fields filled in, for example:

Listing 4: Creating a result with the customer list

 
	public static Result customers (List<Customer> customers)
	{
		Result result = new Result ();
		result.success = true;
		result.customers = customers;
		return result;
	}

We also need to add similar annotations to the ones in the Result class on the fields of the model objects. We must also ensure that all of our model classes have default constructors. Unfortunately, this means we cannot use final fields to enforce immutability of data items that must change (e.g. the identifiers of records). Instead, I recommend making such fields private and not exposing public setters for them where possible. Here, for example, is the annotated Customer class:

Listing 5: Customer class annotated for XML binding

 
@Root (name="customer")
public class Customer
{
	@Attribute(required=true)
	private int id;
	@Attribute(required=true)
	private String name;

	public Customer ()
	{
		id = -1;
	}

	… methods unchanged from previous implementation …
}

Servlets that accept input from the user can be implemented in one of two different ways. The easiest way is to accept data in URL parameters, the same way you would if it were supplied in an HTML “GET” mode form or embedded in an HTML link. In my site I have used this technique when listing the accounts associated with a particular customer:

Listing 6: Listing a customer’s accounts

 
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException
	{
		resp.setContentType("text/xml");
		try
		{
			Customer customer = customerDAO.get(
						Integer.parseInt(req.getParameter("customer")));
			if (customer == null)
			{
				persister.write(Result.error("Customer not found"),
						resp.getWriter());
				return;
			}
			persister.write(Result.accounts(customer.getAccounts(accountDAO)),
					resp.getWriter());
		} 
		catch (Exception e)
		{
			throw new ServletException("Error sending account list", e);
		}
	}

The alternative is accepting an XML-encoded object that is passed as the entity in a POST request. This has the disadvantage that it makes testing harder (we cannot simply point a browser at the required URL to see what the result looks like), but the resulting code is so much simpler that it is hard to justify not working this way:

Listing 7: Creating a new customer

 
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
		throws ServletException, IOException
	{
		resp.setContentType ("text/xml");
		try
		{
			Customer customer = persister.read (Customer.class, req.getInputStream ());
			customer.validate ();
			customerDAO.create (customer);
			persister.write (Result.success (), resp.getWriter ());
		}
		catch (Exception e)
		{
			try
			{
				persister.write (Result.error("Failed to create customer: " + 
					e.toString()), resp.getWriter ());
			}
			catch (Exception nestedError)
			{
				throw new ServletException(nestedError);
			}
		}
	}

Because I’m expecting possible exceptions here (customer.validate() throws an IllegalArgumentException if the validation fails), I catch exceptions and report their text by encoding it as the error field of a Result object. Only failures to send error messages should cause exceptions to be thrown up to the servlet container.

This is all for this article. See you next time.

Also read:



My main area of specialization is Java and J2EE. I have worked on many international projects like Recorders,Websites,Crawlers etc.Also i am an Oracle Certified java professional as well as DB2 certified

What did you think of this post?
Services
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually – in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits – in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login