Skip to content

Archive

Tag: web service

Abstract

About two years ago, I published an article about Exposing the Functionality implemented in Stateless Session Beans (EJB 2.1) using Web Services. J2EE 1.4 times are over and the new version of the Java Enterprise framework, called Java Enterprise Edition 5 (JavaEE 5, or simply JEE) has emerged. In this article the same business scenario is repeated in the new framework.

Requirements

Before we dive into code examples, some software is required. The good news about the software is, that it also evolved over time. Here is what we use:

  • Sun’s Java 6 SDK
  • JBoss AS 5.1.0 GA for JDK6
  • Eclipse Galileo 3.5.1 for JEE development

continue reading…

Introduction

During some work executed for the proposal to the NFC Congress 2008, we introduced a scenario for using the NFC-enabled Nokia 6131 in the industrial environment. The selected use case records some NFC data and uses the Internet to transmit it to the cental server. During the prototype construction, we decided to use Google Maps as a framework for location-based display of gathered information. The server has been constructed based on J2EE EJBs and exposes its functionality using SOAP-based document-literal Web Serives, as described in one of the privious posts.

Nokia 6131 NFC

The Nokia 6131 NFC is first NFC-enabled mobile phone. NFC stands for Near-Field-Communication – a new evolving wireless technology to interact with RFID tags. It is strongly supported and pushed by several big players. This results in several conferences around this subject all around the world.
The NFC in Java is specified in JSR 257. In addition to that, 6131 seems to support several other JSRs, also including JSR 172 for Web Services. After having a closer look on the offered API, it cames out, that only the XML-parser part of JSR 172 is supported.

Sending SOAP Requests without JSR 172

In order to set the requests to a Web Service from a mobile phone, that does not supprt Web Service JSR 172, a manual creation of request is needed. This results in something like:

public abstract class SoapHandler extends DefaultHandler {

    public static final String SOAP_BEGIN = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:q0=\"http://www.techjava.de/2008/nfc/visualizer/types\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Body>";
    public static final String SOAP_END = "</soapenv:Body></soapenv:Envelope>";

    private StringBuffer reqBuf = new StringBuffer(); // Buffer that holds the request message


    ...
    public SoapHandler(String message) {
        reqBuf.append(message);
    }

    public int doHttpRequest(String url, String soapAction) throws IOException {

        reqBuf.insert(0, SOAP_BEGIN);
        reqBuf.append(SOAP_END);

        HttpConnection httpConn = (HttpConnection) Connector.open(url);
        httpConn.setRequestMethod(HttpConnection.POST);
        httpConn.setRequestProperty("SOAPAction", soapAction);
        httpConn.setRequestProperty("Content-Length", Integer.toString(reqBuf.length()));

        OutputStream os = httpConn.openOutputStream();
     
        os.write(reqBuf.toString().getBytes());
        os.close(); // Request is sent when output-stream is closed
        return httpConn.getResponseCode();
    }

...
}

If you execute the code above, the 6131 device send a HTTP request using Content-Type plain/text, that is automatically inserted and changes the case of “SOAPAction” to lower. As long as JBoss 4.0.5 GA used in this experiment supports only Content-Types application/soap+xml and text/xml (as it should according to the specification), it throws a SOAP Exception:

javax.xml.soap.SOAPException: Unsupported content type: text/plain
        at org.jboss.ws.soap.MessageFactoryImpl.createMessageInternal(MessageFactoryImpl.java:138)
        at org.jboss.ws.soap.MessageFactoryImpl.createMessage(MessageFactoryImpl.java:87)
        at org.jboss.ws.server.ServiceEndpoint.handleRequest(ServiceEndpoint.java:190)
        at org.jboss.ws.server.ServiceEndpointManager.processSOAPRequest(ServiceEndpointManager.java:355)
        at org.jboss.ws.server.StandardEndpointServlet.doPost(StandardEndpointServlet.java:115)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.jboss.ws.server.StandardEndpointServlet.service(StandardEndpointServlet.java:76)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:810)
        ...

The MIME Content-Type can easily be set on any HTTP connection:

        httpConn.setRequestProperty("Content-Type", "application/soap+xml");

This works well in the NFC Nokia simulator, part of the Nokia SDK, but breaks down executed from the device. It seems to be a bug in the implementation, or an intended feature of Nokia limiting the usage of the phone for business applications, but the HTTP-Request contains a duplicate Content-Type entry valued by the “application/soap+xml”. Playing around with the implementation, we found that it put any Content-Type header twice into the request. Decompiling and analyzing of simulator code does not helped at all. Since we don’t know how to get and patch sources of J2ME port to Nokia 6131, I decided to apply a workaround.

Server tolerance

JBoss reacts to this fact of a duplicate Content-Type header by throwing a SOAPFaultException.

javax.xml.rpc.soap.SOAPFaultException: Could not parse content type:javax.mail.internet.ParseException: Expected ';', got ","
        at org.jboss.ws.jaxrpc.SOAPFaultExceptionHelper.exceptionToFaultMessage(SOAPFaultExceptionHelper.java:194)
        at org.jboss.ws.server.ServiceEndpoint.handleRequest(ServiceEndpoint.java:223)
        at org.jboss.ws.server.ServiceEndpointManager.processSOAPRequest(ServiceEndpointManager.java:355)
        at org.jboss.ws.server.StandardEndpointServlet.doPost(StandardEndpointServlet.java:115)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.jboss.ws.server.StandardEndpointServlet.service(StandardEndpointServlet.java:76)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:810)
        ...

We followed the stacktrace, and identified the class that causes the Execption. It is org.jboss.ws.soap.MessageFactoryImpl located in JBOSS_DEPLOY /jbossws14.sar/jbossws14-core.jar. After some source code alanysis, we found several problems in the implementation:

private static ContentType getContentType(MimeHeaders headers) throws SOAPException
{
	ContentType contentType = null;
	try
	{
		String type[] = headers.getHeader("Content-Type");
		if (type != null)
		{
			contentType = new ContentType(type[0]);
		} else
		{
			contentType = new ContentType("text/xml");
		}
		return contentType;
	} catch (ParseException e)
	{
		String message = (new JBossStringBuilder()).append("Could not parse content type:").append(e).toString();
		throw new SOAPException(message);
	}
}

First of all, we would expect that the array length is proven, before the first element is accessed. Secondly, if multiple same headers are present in the request, their values are combined using a comma resulting in:

application/soap+xml; charset=utf-8, application/soap+xml; charset=utf-8

This combination could make sence if you put multiple Content-Lang headers in your request, but not for Content-Type. So we fixed the implementation by following code, taking only the first Content-Type value from the list, if present:

...
String type[] = headers.getHeader("Content-Type");
if (type != null && type.length != 0)
{
	int index = type[0].indexOf(',');
	String correctedType = (index != -1) ? type[0].substring(0, index) : type[0];
	
	contentType = new ContentType(correctedType);
} else
{
	contentType = new ContentType("text/xml");
}
return contentType;
...

Summary

Even if Nokia 6131 NFC offers some functionality for the developer, it does not provide the best platform for use case try-outs. Especially, the lack of supported standard (like full JSR 172) and a low-end OS (Symbian 40-Series), and some bugs / features in implementation of connectivity will lead to problems in prototype implementations of use cases…