Browsing all articles tagged with Google App Engine
Feb
27

Building SOAP services on Google App Engine in Java: Part 1 – The Servlet

Background

Google App Engine (GAE) is an interesting platform that aims to allow for the development and hosting of Java, Python, and Go web applications.  The pricing scheme is particularly nice:  low-usage applications are hosted for free, pricing is solely dependent on resource usage (with the ability to set budgets and limits), and the minimum charge is only $2.10 per week.  No, I’m not affiliated with or being compensated by Google, but I do think this platform has some potential.

Google supplies a nice Eclipse plugin for use with the Google Web Toolkit and the App Engine, which allows for pretty easy construction of your standard web applications.  I’ve heard that it’s fairly easy to construct user interfaces, JSP pages, etc., but that’s not what we’re talking about here.

The Task

How can we build an application that uses the Google App Engine which uses SOAP for an API?  The primary problem (for me) is that one cannot use the Axis2 libraries (on the server side) due to permission issues, so things must be done a little more manually.

Google has an article covering the topic, but I wanted to do things slightly differently.  Specifically, I wanted to be able to create my service class in Java, generate the WSDL (with appropriately named fields in the XML types – not Parameter1,2,…), generate XML types which will be shared between the server and client projects, and to do it in such a way that I do not have to worry about keeping track of QNAMEs or other low-level details.

Requirements

For this project, I use:

• Eclipse for development, with the Eclipse plugin for GAE

• Axis2 for the client class (also for the java2wsdl and wsdl2java tools)

• JAXB for XML types (auto-generated by Axis2)

The Server

Overview of the Process

Here’s the logic flow for the server:

1. SOAP request arrives via Post into a HttpServlet.

2. HttpServlet builds a SOAPMessage for the request, and passes it to the SoapHandler class.

3. SoapHandler unmarshalls the XML message object, detects its type, and passes a specific application request to the ServiceAdapter class.

4. ServiceAdapter translates from the XML request message (in a safe fashion) to the Service method call.

5. Service method is run, business logic is performed, all the magic happens.

6. ServiceAdapter translates Service method response to XML response message.

7. SoapHandler builds SOAPMessage response (including catching thrown exceptions and turning them into SOAP Fault messages).

8. HttpServlet writes response to client.

All of that seems like a lot of work, but it’s pretty straightforward.  The best part?  I’ll give you the skeleton for all of this; there’s not much application-specific content in all of this.  The process for adding a method to your service class is: implement service class method, run Axis2 generators, modify/fix Axis2 client (the same every time, some auto-gen code must be changed), add 2 lines to SoapHandler, add an adaption method to SoapAdapter, and add a method to the client class.  It’s easier than it sounds.

Part 1 – The HttpServlet

Good news!  There’s no service specific code here.  I’ll just post the relevant parts of what I use:

public class SOAPServerServlet extends HttpServlet {
	public static final String URL = "http://ms4models.appspot.com/service";

	private static final Logger log = Logger
		.getLogger(SOAPServerServlet.class.getName());
	private static MessageFactory messageFactory;
	private static ServiceSOAPHandler soapHandler;

	static {
		try {
			messageFactory = MessageFactory.newInstance();
			soapHandler = new ServiceSOAPHandler();
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		log.info("SOAPAction: " + req.getHeader("SOAPAction"));
		log.entering("SOAPServerServlet", "doPost", new Object[] {
				req, resp });
		try {
			// Get all the headers from the HTTP request
			MimeHeaders headers = getHeaders(req);

			// Construct a SOAPMessage from the XML in the request body
			InputStream is = req.getInputStream();
			SOAPMessage soapRequest = messageFactory.createMessage(headers, is);

			ByteArrayOutputStream out = new ByteArrayOutputStream();
			soapRequest.writeTo(out);
			String strMsg = new String(out.toByteArray());

			log.finer("SOAP request: " + strMsg);

			// Handle soapReqest
			SOAPMessage soapResponse = soapHandler
					.handleSOAPRequest(soapRequest);

			// Write to HttpServeltResponse
			resp.setStatus(HttpServletResponse.SC_OK);
			resp.setContentType("text/xml;charset=\"utf-8\"");
			OutputStream os = resp.getOutputStream();
			soapResponse.writeTo(os);
			os.flush();
		} catch (SOAPException e) {
			throw new IOException("Exception while creating SOAP message.", e);
		}
		log.exiting("SOAPServerServlet", "doPost");
	}

	@SuppressWarnings("rawtypes")
	static MimeHeaders getHeaders(HttpServletRequest req) {
		Enumeration headerNames = req.getHeaderNames();
		MimeHeaders headers = new MimeHeaders();
		while (headerNames.hasMoreElements()) {
			String headerName = (String) headerNames.nextElement();
			String headerValue = req.getHeader(headerName);
			StringTokenizer values = new StringTokenizer(headerValue, ",");
			while (values.hasMoreTokens()) {
				headers.addHeader(headerName, values.nextToken().trim());
			}
		}
		return headers;
	}
}

Leave a comment if you have a question about what’s going on, I’ll not explain it for brevity’s sake (also: because I am lazy).

Coming Soon – Part 2

%d bloggers like this: