<?xml version="1.0"?>
<rss version="2.0">
<channel>
  <title>The Kitchen in the Zoo - webservices tag</title>
  <link>http://blog.maxant.co.uk:80/pebble/tags/webservices/</link>
  <description>&lt;small&gt;A blog where Ant writes about anything he finds interesting! &lt;a href=&#039;http://www.linkedin.com/in/maxant&#039;&gt;&lt;font color=&#039;white&#039;&gt;Who is Ant?&lt;/font&gt;&lt;/a&gt;      &lt;a href=&#039;/pebble/pages/copyright.html&#039;&gt;&lt;font color=&#039;white&#039;&gt;Copyright 2005-2012 Ant Kutschera&lt;/font&gt;&lt;/a&gt;&lt;/small&gt;</description>
  <language>en</language>
  <copyright>Ant Kutschera</copyright>
  <lastBuildDate>Thu, 10 May 2012 20:07:00 GMT</lastBuildDate>
  <generator>Pebble (http://pebble.sourceforge.net)</generator>
  <docs>http://backend.userland.com/rss</docs>
  
  
  <item>
    <title>JAX-WS Payload Validation, and Websphere 7 Problems</title>
    <link>http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html</link>
    
      
        <description>
          &lt;p&gt;A WSDL file contains a reference to an XSD document which defines the data structures which can be sent to the service over SOAP.  In an XSD, you can define a Type for an element, or things like the elements cardinality, whether its optional or required, etc.&lt;br /&gt;
&lt;br /&gt;
When the web server hosting a web service is called, it receives a SOAP envelope which tells it which web service is being called.  It could (and you might expect it does) validate the body of the SOAP message against the XSD in the WSDL... but it doesn&#039;t.&lt;br /&gt;
&lt;br /&gt;
Is this bad? Well, most clients will be generated from the WSDL, so you can assume that the type safety is respected.  Saying that, it&#039;s not something the server can guarantee, so it needs to check that say a field that is supposed to contain a date, really does contain a date, and not some garbled text that is meant to be a date.  But more importantly, something which a client does not guarantee, is whether all required fields in the data structure are actually present.  To check this, you can validate incoming SOAP bodies against the XSD.&lt;br /&gt;
&lt;br /&gt;
The way to do this, is by using &amp;quot;Handlers&amp;quot;.  The &lt;a href=&#034;http://www.jcp.org/aboutJava/communityprocess/pfd/jsr224/index.html&#034; target=&#034;_blank&#034;&gt;JAX-WS specification&lt;/a&gt; defines two kinds, namely, SOAP Handlers and Logical Handlers.  The SOAP kind is useful for accessing the raw SOAP envelope, for example to log the actual SOAP message.  The logical kind is useful for accessing the payload as an XML document.  To configure a handler, you add the &lt;code&gt;HandlerChain&lt;/code&gt; annotation to your web service, passing it the name of the handler configuration file:&lt;/p&gt;
&lt;div style=&#034;border: thin none; overflow: auto; width: 525px; height: 300px; background-color: rgb(255, 255, 255);&#034;&gt;
&lt;pre&gt;
@WebService
@HandlerChain(file=&amp;quot;handler.xml&amp;quot;)
public class GislerService {

  private static final String FORMAT_DD_MMM_YYYY_HH_MM_SS = &amp;quot;dd. MMM yyyy HH:mm:ss&amp;quot;;

  @WebMethod
  public String formatDate(ObjectModel om){
    SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DD_MMM_YYYY_HH_MM_SS);
    return &amp;quot;Formatted, its &amp;quot; + sdf.format(om.date);
  }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
So, in order to validate a body against an XSD (i.e. to ensure that the &amp;quot;ObjectModel&amp;quot; instance in the above method is valid, before your method gets called by the WS framework), you use a logical handler to grab the payload as a &lt;code&gt;javax.xml.transform.Source&lt;/code&gt; and pass it to a &lt;code&gt;javax.xml.validation.Validator&lt;/code&gt; which you create using a &lt;code&gt;javax.xml.validation.SchemaFactory&lt;/code&gt; and &lt;code&gt;javax.xml.validation.Schema&lt;/code&gt;, based on the XSD from the WSDL.  If the validation is successful, you let your handler return &amp;quot;true&amp;quot;, otherwise you throw a &lt;code&gt;javax.xml.ws.WebServiceException&lt;/code&gt; passing it the validation exception&#039;s text, so that any client making an invalid call can work out why it&#039;s invalid.  It&#039;s something like this:&lt;/p&gt;
&lt;div style=&#034;border: thin none; overflow: auto; width: 525px; height: 300px; background-color: rgb(255, 255, 255);&#034;&gt;
&lt;pre&gt;
public class MyLogicalHandler implements LogicalHandler&lt;logicalmessagecontext&gt; {&lt;br /&gt;&lt;br /&gt;  private Validator validator;&lt;br /&gt;&lt;br /&gt;  public MyLogicalHandler(){&lt;br /&gt;    try{&lt;br /&gt;      long start = System.nanoTime();					&lt;br /&gt;      SchemaFactory schemaFac = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);&lt;br /&gt;      Schema schema = schemaFac.newSchema(new URL(&amp;quot;http://localhost:8084/Gisler/GislerServiceService?xsd=1&amp;quot;));&lt;br /&gt;      validator = schema.newValidator();&lt;br /&gt;      System.out.println(&amp;quot;created validator in &amp;quot; + ((System.nanoTime()-start)/1000000.0) + &amp;quot;ms&amp;quot;);&lt;br /&gt;    } catch (IOException e) {&lt;br /&gt;      e.printStackTrace();&lt;br /&gt;      throw new WebServiceException(e.getMessage());  //cant validate/initialise&lt;br /&gt;    } catch (SAXException e) {&lt;br /&gt;      e.printStackTrace();&lt;br /&gt;      throw new WebServiceException(e.getMessage());  //cant validate/initialise&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;  public boolean handleMessage(LogicalMessageContext context) {&lt;br /&gt;&lt;br /&gt;    if (((Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)).booleanValue()) {&lt;br /&gt;      return true; // only validate incoming messages&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    try{&lt;br /&gt;      LogicalMessage lm = context.getMessage();&lt;br /&gt;      Source payload = lm.getPayload();&lt;br /&gt;      validator.validate(payload);&lt;br /&gt;      System.out.println(&amp;quot;validated ok&amp;quot;);&lt;br /&gt;    }catch(SAXParseException e){&lt;br /&gt;      System.out.println(&amp;quot;validated failed: &amp;quot; + e.getMessage());&lt;br /&gt;      throw new WebServiceException(e.getMessage());  //invalid, so tell the caller!&lt;br /&gt;    } catch (SAXException e) {&lt;br /&gt;      e.printStackTrace();&lt;br /&gt;      throw new WebServiceException(e.getMessage());  //cant validate/initialise&lt;br /&gt;    } catch (IOException e) {&lt;br /&gt;      e.printStackTrace();&lt;br /&gt;      throw new WebServiceException(e.getMessage());  //cant validate/initialise&lt;br /&gt;    }&lt;br /&gt;		&lt;br /&gt;    return true;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/logicalmessagecontext&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
The &lt;a href=&#034;/pebble/files/Gisler.zip&#034;&gt;attached Eclipse Projects&lt;/a&gt; were tested using GlassFish v3 (Glassfish Tools Bundle for Eclipse 1.2), and they worked well.  To test required but missing elements, I wrote a JUnit test, which is in the client project.  To test badly formed dates, I captured the SOAP HTTP Requests from the JUnit using the Eclipse TCP/IP Monitor, and modified them before resending them, with an invalid date string.  Note that to make this work, you also need to modify the HTTP header&#039;s &amp;quot;content-length&amp;quot; using the monitor, otherwise you get some very strange errors, because the stream terminates early!  An alternative is to use a tool like SoapUI.&lt;br /&gt;
&lt;br /&gt;
Compared to Glassfish, Websphere didn&#039;t do so well - it has a nasty bit of functionality built in.  Validating using a handler works fine, until your first invalid request comes in.  Then, it still works, until another valid request is processed.  After that, it completely ignores invalid elements like dates, if they are marked as optional (which is the default!).  How come?  Well, that took a while to work out, but basically, it&#039;s optimising the incoming message by arguing that if an element is optional, and happens to be present but invalid, the invalid data can be thrown away, because it&#039;s... well, optional...  OK, I couldn&#039;t believe it either, but that&#039;s what it does, the SOAP handler that logs to System.out simply had the invalid element missing.  So a little searching around on the internet, and a little luck, and hey presto this &lt;a href=&#034;http://www-01.ibm.com/support/docview.wss?rs=180&amp;amp;uid=swg1PK95199&#034; target=&#034;_blank&#034;&gt;link&lt;/a&gt; which is a bug fix for Websphere 7 fix pack 9.  By setting the system property &amp;quot;jaxws.payload.highFidelity=true&amp;quot;, Websphere guarantees that the message passed to the handlers is exactly that which came over the wire. Tests showed that it indeed did fix the problem.&lt;br /&gt;
&lt;br /&gt;
So what does all this mean, in the grand scheme of SOAP things?  Well, when designing a service, you need to consider how important it is to have valid data.  If you allow optional fields which are strongly typed, such as dates or complex types, then you could have a problem.  Without adding a validating handler, it is possible that the caller could pass you optional but invalid data, and you wouldn&#039;t receive it in your web service, which is given a null reference, instead of invalid data!  If you don&#039;t work with optional data, then you could skip validation, and just let null pointer exceptions fly around, in cases where a caller has passed invalid required data.  By logging the incoming and outgoing communications, it makes it easier to debug such problems, but it is a little impolite to build a public interface which handles invalid requests like this.&lt;br /&gt;
&lt;br /&gt;
The last consideration is performance.  Creating a validator for a simple schema like in this demo only took around 20ms on my laptop.  The actual validation took less than a millisecond for a valid request, and just over a millisecond for an invalid response.  The reader is left to draw their own conclusions :-)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;copy; 2010 Ant Kutschera&lt;/p&gt;&lt;div class=&#034;tags&#034;&gt;&lt;span&gt;Social Bookmarks : &lt;/span&gt;&amp;nbsp;&lt;a href=&#034;http://slashdot.org/bookmark.pl?url=http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&amp;amp;title=JAX-WS+Payload+Validation%2C+and+Websphere+7+Problems&#034; target=&#034;_blank&#034; title=&#034;Add this post to Slash Dot&#034;&gt;&lt;img src=&#034;common/images/slashdot.png&#034; alt=&#034;Add this post to Slashdot&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://digg.com/submit?url=http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&amp;amp;title=JAX-WS+Payload+Validation%2C+and+Websphere+7+Problems&#034; target=&#034;_blank&#034; title=&#034;Digg this post&#034;&gt;&lt;img src=&#034;common/images/digg.png&#034; alt=&#034;Add this post to Digg&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://reddit.com/submit?url=http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&amp;amp;title=JAX-WS+Payload+Validation%2C+and+Websphere+7+Problems&#034; target=&#034;_blank&#034; title=&#034;Add this post to Reddit&#034;&gt;&lt;img src=&#034;common/images/reddit.png&#034; alt=&#034;Add this post to Reddit&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://del.icio.us/post?url=http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&amp;amp;title=JAX-WS+Payload+Validation%2C+and+Websphere+7+Problems&#034; target=&#034;_blank&#034; title=&#034;Save this post to Del.icio.us&#034;&gt;&lt;img src=&#034;common/images/delicious.png&#034; alt=&#034;Add this post to Delicious&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.stumbleupon.com/submit?url=http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&amp;amp;title=JAX-WS+Payload+Validation%2C+and+Websphere+7+Problems&#034; target=&#034;_blank&#034; title=&#034;Stumble this post&#034;&gt;&lt;img src=&#034;common/images/stumbleupon.png&#034; alt=&#034;Add this post to Stumble it&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.google.com/bookmarks/mark?op=edit&amp;amp;bkmk=http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&amp;amp;title=JAX-WS+Payload+Validation%2C+and+Websphere+7+Problems&#034; target=&#034;_blank&#034; title=&#034;Add this post to Google&#034;&gt;&lt;img src=&#034;common/images/google.png&#034; alt=&#034;Add this post to Google&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://technorati.com/faves?add=http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Technorati&#034;&gt;&lt;img src=&#034;common/images/technorati.png&#034; alt=&#034;Add this post to Technorati&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.bloglines.com/sub/http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Bloglines&#034;&gt;&lt;img src=&#034;common/images/bloglines.png&#034; alt=&#034;Add this post to Bloglines&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.facebook.com/share.php?u=http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Facebook&#034;&gt;&lt;img src=&#034;common/images/facebook.png&#034; alt=&#034;Add this post to Facebook&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.furl.net/storeIt.jsp?u=http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&amp;amp;t=JAX-WS+Payload+Validation%2C+and+Websphere+7+Problems&#034; target=&#034;_blank&#034; title=&#034;Add this post to Furl&#034;&gt;&lt;img src=&#034;common/images/furl.png&#034; alt=&#034;Add this post to Furl&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;https://favorites.live.com/quickadd.aspx?mkt=en-us&amp;amp;url=http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&amp;amp;title=JAX-WS+Payload+Validation%2C+and+Websphere+7+Problems&#034; target=&#034;_blank&#034; title=&#034;Add this post to Windows Live&#034;&gt;&lt;img src=&#034;common/images/windowslive.png&#034; alt=&#034;Add this post to Windows Live&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;amp;u=http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html&amp;amp;t=JAX-WS+Payload+Validation%2C+and+Websphere+7+Problems&#034; target=&#034;_blank&#034; title=&#034;Add this post to Yahoo!&#034;&gt;&lt;img src=&#034;common/images/yahoo.png&#034; alt=&#034;Add this post to Yahoo!&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&lt;/div&gt;
        </description>
      
      
    
    
    
    <comments>http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html#comments</comments>
    <guid isPermaLink="true">http://blog.maxant.co.uk:80/pebble/2010/09/09/1284065640000.html</guid>
    <pubDate>Thu, 09 Sep 2010 20:54:00 GMT</pubDate>
  </item>
  
  <item>
    <title>Professional enterprise JAX-WS in no time at all?</title>
    <link>http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html</link>
    
      
        <description>
          &lt;p&gt;My current client is talking about migrating to Java 1.6 and a Java EE 5 app server (we are currently still on 1.5 because our data center only supports an older app server). One reason for doing so is that this stack supports JAX-WS. Not knowing much about JAX-WS, I decided it was time to take a look. The Java API for XML Web Services (JAX-WS) is basically a specification of how to deploy and use web services in the latest Java runtime. My first question was &amp;quot;whats so good about it compared to Apache Axis 1.4&amp;quot;, which I&#039;ve used successfully plenty of times in the past. Not only does JAX-WS offer improved performance as its based on StAX (a more efficient streaming pull parser for XML), but its also a standard. Axis isn&#039;t a standard, even though it is extensively used. JAX-WS is partially part of Java SE 1.6 and the bits which are not part of it, namely the server side implementation, can be theoretically exchanged without breaking anything, because all implementations implement the given specs. So, no vendor lockin; and you get choice over implementations. What more could one ask for...&lt;br /&gt;
&lt;br /&gt;
So I went with what I knew, and downloaded Axis2 which is an implementation of JAX-WS among other things and started to migrate a simple web service which had run under Axis 1.4. But it wasn&#039;t as simple as I had hoped.&lt;br /&gt;
&lt;br /&gt;
The requirement was to create a web service based on an existing Java &amp;quot;service&amp;quot; class, which supports incoming and outgoing attachments, security, exception handling, complex data types, and integration with Spring.&lt;br /&gt;
&lt;br /&gt;
To turn an exsiting class into a web service in JAX-WS you simply add some annotations:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; @WebService(serviceName = &amp;quot;TestService&amp;quot;, portName=&amp;quot;Port&amp;quot;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public class TestService {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; .&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; .&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&lt;/code&gt; That is all you need to do in order to deploy it to your server, as a fully functioning web service - great! Every public method is exposed. If you download the Axis2 WAR and deploy that to your web container, when you start the web app, it searches the entire classpath of the webapp for classes with such annotations and automatically deploys them. The URL depends upon the servlet mappings which are in the webapps web.xml, but the Axis2 default is to deploy the AxisServlet to &amp;quot;/services&amp;quot; so your web service URL becomes:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://localhost:8089/services/TestService.Port&lt;br /&gt;
&lt;/code&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
You can view the WSDL under:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; http://localhost:8089/services/TestService.Port?wsdl&lt;br /&gt;
&lt;/code&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
But to turn this service into something more useful, there are several steps required... Firstly, lets add support for sessions. To get access to the session serverside, you need a web service &amp;quot;context&amp;quot;. Within the web service class (TestService in the download, see bottom), you can define a class attribute:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /** injected by container */&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; @Resource&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; private WebServiceContext context;&lt;br /&gt;
&lt;/code&gt; &lt;br /&gt;
If you give it the @Resource annotation, the container automatically injects an instance at runtime. There are lots of things you can do with this context, and to get the session, you do the following call:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MessageContext mc = context.getMessageContext();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; HttpServletRequest request = (HttpServletRequest)mc.get(MessageContext.SERVLET_REQUEST);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; HttpSession session = request.getSession();&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Since this is a standard HttpSession, you can use it just as you would in any web application. On the client (see later) you need to add a little information to the request context:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; map.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
See later on, where there is more information. In Axis 1.4, the servers message context is maintained across successive calls to the same session. In JAX-WS and Axis2, this is not the case, and just because you are within a session, setting a property on the message context does not mean its available on the next call in the same session. The only place to put session variables appears to be in the HTTPSession. Which does raise questions if you are running your service outside of HTTP, say over SMTP...&lt;br /&gt;
&lt;br /&gt;
Now that you have the message context, you can also handle attachments, which are particularly useful when handling binary data transfer over web services. Any attachments sent to a web service can be read off the context:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /**&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;* demonstrates how to handle incoming attachments.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;*/&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; private void handleAttachmentsInRequest(MessageContext mc) throws ApplicationException {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; AttachmentsAdapter aa = (AttachmentsAdapter) mc.get(MessageContext.INBOUND_MESSAGE_ATTACHMENTS);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; if(aa != null &amp;amp;&amp;amp; !aa.isEmpty()) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; for(String name : aa.keySet()){&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; DataHandler dh = aa.get(name);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; //... do something with this attachment... like forward it to someone using email...&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; orchestrationService.echo(&amp;quot;testws@maxant.co.uk&amp;quot;, dh.getDataSource());&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Equally, you can send attachments back to the client:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /**&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;* demonstrates returning attachments in the response.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;*/&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; private void setAttachmentOnResponse(MessageContext mc) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; @SuppressWarnings(&amp;quot;unchecked&amp;quot;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Map&amp;lt;String, DataHandler&amp;gt; attachments = (Map&amp;lt;String, DataHandler&amp;gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; mc.get(MessageContext.OUTBOUND_MESSAGE_ATTACHMENTS);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; //can be null, initialise if necessary&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; if(attachments == null){&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; attachments = new HashMap&amp;lt;String, DataHandler&amp;gt;();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; mc.put(MessageContext.OUTBOUND_MESSAGE_ATTACHMENTS, attachments);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; DataHandler dh = new DataHandler(&amp;quot;an attachment being returned from the client&amp;quot;, &amp;quot;text/plain&amp;quot;);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; attachments.put(&amp;quot;RETURN_FROM_SERVER&amp;quot;, dh); //provide a content ID, and the handler for the attachment&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&lt;/code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
The client code for this service is generated using the &amp;quot;wsimport.exe&amp;quot; tool which is included in JDK 1.6:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; wsimport.exe -d src -verbose -s src service.wsdl&lt;br /&gt;
&lt;/code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
where &amp;quot;service.wsdl&amp;quot; is a local file containing the WSDL definition of the service. You could provide a URL here too.&lt;br /&gt;
&lt;br /&gt;
The client then calls the service in a few simple lines of code:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; TestService_Service service = new TestService_Service();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; TestService proxy = service.getPort();&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; //add session support from the client side, see above&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Map&amp;lt;String, Object&amp;gt; map = ((BindingProvider)proxy).getRequestContext();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; map.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; //call the service remotely!&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Foo foo = proxy.getInfo(bar);&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
The first problems that I had, were exactly here. I was using JDK 1.6.0_10 and although its not the absolute newest version, it is the tenth release. I spent some time before finding that there was a bug and attachments were simply not sent over the wire to the server. Attachment returned from the server were sent over the wire, but the API had no access to them.&amp;nbsp; I worked this out by using the TCP/IP Monitor which is part of Eclipse 3.5 (maybe even earlier). With it you can make your client call a server called a monitor, which acts as a proxy, and logs the call, before forwarding it to the real server. Although the web services were running on port 8089, the client call was modified from that above, to call port 11350:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; String url = &amp;quot;http://localhost:11350/services/TestService.Port&amp;quot;;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; map.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url);&lt;br /&gt;
&lt;/code&gt;&amp;nbsp;&lt;br /&gt;
By opening the TCP/IP Monitor View in Eclipse and right clicking in the upper left pane, you can view the properties and add a new monitor for your server. Ensure the monitor has been started before running your client. Note that as soon as you add SSL, the monitor no longer works.&lt;br /&gt;
&lt;br /&gt;
Two things were required to solve my &amp;quot;attachments problem&amp;quot;. Firstly I started using JDK 1.6.0_14. This meant that attachments coming back from the server were visible. But one other thing was needed to ensure that the client actually sent the attachments to the server, namely a custom SOAP handler. A &amp;quot;simple&amp;quot; or &amp;quot;empty&amp;quot; soap handler was added to the service:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //add the soap handler to the service client&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; service.setHandlerResolver(new HandlerResolver() {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; @SuppressWarnings(&amp;quot;unchecked&amp;quot;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; public List&amp;lt;Handler&amp;gt; getHandlerChain(PortInfo portInfo) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;Handler&amp;gt; hs = new ArrayList&amp;lt;Handler&amp;gt;();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; //hs.add(handler);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; hs.add(new SimpleSOAPHandler());&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return hs;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
The SimpleSOAPHandler class itself looked like this:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /**&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;* a soap handler which works as a workaround to make inbound attachments work.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;* only works with java 1.6.0_14 and above.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;* its pretty much blank, but its really needed otherwise attachments are not sent&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;* by the client.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;*/&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; private static class SimpleSOAPHandler&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; implements javax.xml.ws.handler.soap.SOAPHandler&amp;lt;SOAPMessageContext&amp;gt; {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; public Set&amp;lt;QName&amp;gt; getHeaders() {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; //simply return non null&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Set&amp;lt;QName&amp;gt; qs = new TreeSet&amp;lt;QName&amp;gt;();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return qs;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; public boolean handleFault(SOAPMessageContext context) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; //simply return true to continue processing&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; };&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; public boolean handleMessage(SOAPMessageContext context) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; //simply return true to continue processing&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; public void close(MessageContext context) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
As you can see, all it does it pretty much nothing apart from acting positively and handling messages and faults successfully! But its presence ensured that attachments were indeed uploaded to the server. For JDK 1.6.0_10 where attachments in the response could not be read, a similar soap handler could also be used, since it is called every time an incoming or outgoing message is sent. The SOAPMessageContext gives access to the attachments. In the download for this blog entry (see bottom), there is an example of how to handle downloads for 1.6.0_10, but its a mess because you need to keep track of whether the message you are handling is a request or a response to the service.&lt;br /&gt;
&lt;br /&gt;
The fact that even with JDK 1.6.0_14 you still need the SOAP handler, when it does nothing, demonstrates that the reference implementation of JAX-WS is still buggy. There is absolutely no need for it, and it is a shame that its required because Sun normally delivers a much better quality of software which simply works out of the box, and does so logically without you needing to fiddle with workarounds.&lt;br /&gt;
&lt;br /&gt;
The next set of problems came as soon as I made my service slightly more complicated so that it received and sent complex data types (ie. not just int, String, etc. but object models). The client classes generated by wsimport.exe did not always contain fields from the object models...&lt;br /&gt;
&lt;br /&gt;
This was somewhat unfortunate but the solution is to start annotating those missing fields with JAX-Binding annotations so that wsimport generates them. JAX-WS only specifies the web service specs. The data which is passed over to the web service as parameters is handled by the Java API for XML Binding (JAX-B), and this provides its own annotations for telling it how to marshal, unmarshal (serialize) and generate classes. For any missing fields, simply add the following annotation:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /** &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;* simply an array of codePoints, to show that we can return&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;* complex structures from web services.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;*/&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; @XmlElement(name=&amp;quot;chars&amp;quot;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; protected List&amp;lt;Integer&amp;gt; chars = new ArrayList&amp;lt;Integer&amp;gt;();&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
What was unpleasant about this is that there is nothing special about this field (apart from it being a List, but in other examples that was not a problem) and I was only aware that it was not mapped, because the generated client API didn&#039;t let me access it! Furthermore, I had to add the name attribute of the annotation, otherwise I got errors about duplicate fields being mapped. It might have been acceptable if all fields had such annotations, but for example in the Foo class from which the above code snippet is taken, if I annotated the other field &amp;quot;answer&amp;quot;, then I got the following exception when requesting the WSDL from the server:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; 1 counts of IllegalAnnotationExceptions&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Class has two properties of the same name &amp;quot;answer&amp;quot;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
This error occurred regardless of whether I gave the &amp;quot;answer&amp;quot; field a named attribute with the correct name, an unnamed annotation or even one with a different name:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @XmlElement(name=&amp;quot;answer&amp;quot;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; private String answer;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; @XmlElement&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; private String answer;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; @XmlElement(name=&amp;quot;answer2&amp;quot;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; private String answer;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
All of the above failed. Compared to Axis 1.4 where these problems did not occur, this was frustrating. I had similar problems with exceptions (see shortly, regarding the fields in the fault bean). Again, this appears to be as very buggy, and generates unnecessary work for developers.&lt;br /&gt;
&lt;br /&gt;
Exception handling was the next feature that needed to be added, as it allows decent handling of business logic problems. In Axis 1.4 you simply added a throws clause to your service method and when you generated the client, the exception was mapped and the client could catch the exception. The fact that the call was remote was virtually transparent. For lower level problems like network problems, there was the RemoteException class which you could catch to deal with such problems. In JAX-WS the exception handling mechanism has been changed. Web Service specs allow for errors to be handled client side by receiving web faults in the response, as opposed to exceptions. The response to a web service call has a header, a fault and a body. If an exception is thrown, it is mapped to a fault. In JAX-WS this is no longer that transparent, and an exception class uses a &amp;quot;fault bean&amp;quot;. The exception is what is thrown, but the bean is a class holding the information about that exception, like a custom internationalised message, or a unique error code. When defining the exception, you use an annotation to state which bean class to use:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @WebFault(&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; name=&amp;quot;AppExceptionWebFault&amp;quot;,&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; faultBean=&amp;quot;uk.co.maxant.testws.webservices.ApplicationExceptionFaultBean&amp;quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; )&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public class ApplicationException extends Exception {&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
The bean class itself is nothing special:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public class ApplicationExceptionFaultBean implements Serializable {&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; private static final long serialVersionUID = 1L;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; //doesnt work without this annotation!&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; @XmlElement(name=&amp;quot;msg&amp;quot;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; private String msg;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; /** required by jax-ws */&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; public ApplicationExceptionFaultBean(){&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; public ApplicationExceptionFaultBean(String msg){&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; this.msg = msg;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; public String getMsg(){&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return msg;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Note how the bean class, as well as the exception, and indeed anything which is sent over the wire, has a default constructor. In the bean, the fields which are to be marshalled are also annotated using JAX-B annotations.&lt;br /&gt;
&lt;br /&gt;
As far as integrating with Spring, there is nothing too complicated. Spring was configured to auto-wire the internal services. A Service Locator was written which loads and caches the application context. Finally a Dependency Resolver was written which uses reflection to inject service beans from Spring into fields in the web service. Since the web service runs outside of the transaction and security context of Spring, it is important that the web service delegate all calls to a fa&amp;ccedil;ade inside Spring. In the example which you can download, this fa&amp;ccedil;ade is the orchestration service, which typically would define transaction demarcation, security requirements, and delegate to lower level calls within other Spring services. There is much more information about this in the upcoming white paper on GWT (Google Web Toolkit), available at http://www.maxant.co.uk/whitepapers.jsp. Additionally I made reuse of the maxant Spring Security extension, available at http://www.maxant.co.uk/tools.jsp. Spring itself also contains an implementation of JAX-WS and can also be configured to load the application context at runtime. Although I did not investigate this here, it may be more useful than the dependency resolver / service locator used in this example.&lt;br /&gt;
&lt;br /&gt;
The final hurdle to overcome in the simple requirements listed at the start of this blog posting, which is now getting rather long because of all the problems I encountered, was security.&lt;br /&gt;
&lt;br /&gt;
Any professional enterprise service needs to consider security. There are typically three important facets, namely encryption to ensure the message is not readable by unauthorized eyes; authentication to ensure the caller is who they say they are; and authorization to ensure the caller is allowed to use the functionality on offer by the service. While standards like WS-Security cover these facets, it is simpler just to use existing mechanisms for all three. Not only that, but with all the problems I had encountered so far, I didn&#039;t want additional headaches trying to integrate message-level security when there are simpler ways. Because we are running our service inside a Java EE web container, why not simply use SSL to encrypt transmissions, and simple basic authentication to check the user and their roles? JAX-WS clients generated by the wsimport.exe tool allow you to set the URL to the web service so that it goes over SSL for encryption, as well as provide security credentials to authenticate/authorize:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; String url = &amp;quot;https://localhost:8444/services/TestService.Port&amp;quot;;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; .&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; .&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; map.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; .&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; .&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; //login info&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; map.put(BindingProvider.USERNAME_PROPERTY, &amp;quot;andy@maxant.co.uk&amp;quot;);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; map.put(BindingProvider.PASSWORD_PROPERTY, &amp;quot;asdf&amp;quot;);&lt;br /&gt;
&lt;/code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
When the call to the server is made, these properties are passed into the HTTP header:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; POST /services/TestService.Port HTTP/1.1&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Authorization: Basic YW5keUBtYXhhbnQuY28udWs6YXNkZg==&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
The server can then authenticate using a realm, so long as the relevant security constraints are set in the webapps web.xml:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;security-constraint&amp;gt; &amp;lt;!-- allows only authorized users to have access, and forces HTTPS --&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;display-name&amp;gt;SecureServices&amp;lt;/display-name&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;web-resource-collection&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;web-resource-name&amp;gt;SecureServices&amp;lt;/web-resource-name&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;url-pattern&amp;gt;/services/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/web-resource-collection&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;auth-constraint&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;role-name&amp;gt;registered&amp;lt;/role-name&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/auth-constraint&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;user-data-constraint&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;transport-guarantee&amp;gt;CONFIDENTIAL&amp;lt;/transport-guarantee&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/user-data-constraint&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/security-constraint&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;login-config&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;auth-method&amp;gt;BASIC&amp;lt;/auth-method&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/login-config&amp;gt;&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;security-role&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;role-name&amp;gt;registered&amp;lt;/role-name&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/security-role&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Well that&#039;s the theory, but there were a number of complications. Firstly, notice in the HTTP header shown above that the Basic Authentication token has the key &amp;quot;Authorization&amp;quot;, with a capital &amp;quot;A&amp;quot;. Now take a quick look at the Tomcat 5.5.9 code:&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; MessageBytes authorization = &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; request.getCoyoteRequest().getMimeHeaders()&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; .getValue(&amp;quot;authorization&amp;quot;);&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
It searches for the header with a lower case key... The internet RfC specifies that the keys are case insensitive, so this is actually a bug in Tomcat. But this is the first time I have ever come across this problem. Using Eclipse&#039;s TCP/IP Monitor, you can repeateldy retest this bug as well as change the key to lowercase to work around it. But since the web service client is entirely generated, my only solution was to try upgrading Tomcat. Instead of researching which version fixed the bug, I simply took the latest version, 6.0.20. The authenticators in this latest version also work a little differently, so only authenticate against URLs which define a security constaint. Older versions of Tomcat authenticate any time the HTTP header contains the basic authentication key. This was just something else which made this little project into a much bigger one.&lt;br /&gt;
&lt;br /&gt;
The next problem with security related to the requirement to authenticate. The web service client which is generated needs the WSDL at runtime in order to initiate, probably because it does so using a dynamic proxy. This is also different from Axis 1.4. The problem is that the WSDL document is serverside, and inaccessible unless you specify the username/password. But the client already fails when you create the proxy, so before you have access to the message context into which to add security properties. Basically said, you need to put the WSDL some place else, so that the client can access it without the username/password. The easiest way is to just download it and save it, but that has its own problems becuase the XSD is imported into the WSDL via a reference:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsd:import namespace=&amp;quot;http://webservices.testws.maxant.co.uk/&amp;quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; schemaLocation=&amp;quot;TestService.Port?xsd=TestService_schema1.xsd&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&lt;/code&gt;This was changed to:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;xsd:import namespace=&amp;quot;http://webservices.testws.maxant.co.uk/&amp;quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; schemaLocation=&amp;quot;testwsmaxantcouk.services.TestService.Port.xsd&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
where the WSDL and XSD files were located in the project root folder:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; testwsmaxantcouk.services.TestService.Port.wsdl&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; testwsmaxantcouk.services.TestService.Port.xsd&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
The WSDL location is then passed to the service constructor:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QName serviceName = new QName(&amp;quot;http://webservices.testws.maxant.co.uk/&amp;quot;, &amp;quot;TestService&amp;quot;);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; String wsdlFile = &amp;quot;file:///testwsmaxantcouk.services.TestService.Port.wsdl&amp;quot;;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; URL wsdlLoc = new URL(wsdlFile);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; TestService_Service service = new TestService_Service(wsdlLoc , serviceName);&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
This works fine, but these are all manual steps which are in my view completely unnecessary! Surely someone on the JAX-WS team at Sun thought this through at some stage? Apparently not. Alternatively there are very good reasons for this, but I have not found them published anywhere...&lt;br /&gt;
&lt;br /&gt;
I attempted to automate the process of downloading the WSDL and XSD, by creating an Apache Ant script. The idea was to use the &amp;quot;get&amp;quot; task which you can use with a username and password to download a secured file to a local file. The final problem I faced with security relates to SSL and this automated build. Since I was testing against a self certified SSL certificate, ie. one which was not signed by a Certificate Authority (CA), I had to install the certificate in the trust store so that I avoided &amp;quot;PKIX&amp;quot; errors, whereby Java throws an exception because it does not trust the unsigned certificate. To do this, download the security certificate with your browser by examining it and exporting it. Once you have it in a local file, install it into the following store:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; %JAVA_HOME%\jre\lib\security\cacerts&lt;br /&gt;
&lt;/code&gt; &lt;br /&gt;
This is your JREs trust store, as opposed to the key store located at:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; %user.home%/.keystore&lt;br /&gt;
&lt;/code&gt; &lt;br /&gt;
The keystore is what holds private data, trusted client certificates, or indeed the certificates which your server provides to clients in order to open an SSL connection. The truststore is where you tell your JRE which certificates to trust. To import the certificate to the trust store, so that Java stops throwing exceptions when trying to connect to a server it does not trust, run this command:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; keytool -keystore %trustStore% -import -file fileExportedFromBrowser&lt;br /&gt;
&lt;/code&gt; &lt;br /&gt;
It asks you if you are sure, to which you respond yes! The truststore password, if you have never changed it is &amp;quot;changeit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you use a different truststore than the default one, or indeed keystore, you can set it up via System properties:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -Djavax.net.ssl.trustStore=someTrustStore&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; -Djavax.net.ssl.trustStorePassword=somePassword&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; -Djavax.net.ssl.keyStore=someKeyStore&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; -Djavax.net.ssl.keyStorePassword=someOtherPassword&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
In fact, I didn&#039;t get as far as fully automating the WSDL download because I still had issues whereby Java needs a HostVerifier. This problem came about because SSL is based on IP Address, and I was developing against the domain &amp;quot;testwsmaxantcouk&amp;quot; which was mapped to localhost IP address 127.0.0.1 in my hosts file. Java tries to verify that the requested domain name matches the IP adderss, I think using a reverse DNS lookup, which of course fails in my case because the IP address maps to more than one domain name. &lt;br /&gt;
&lt;br /&gt;
So as you can see by the length of this blog entry, implementing JAX-WS is by far not as simple if you need to create a professional web service using any of the following:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;exceptions&lt;/li&gt;
    &lt;li&gt;security&lt;/li&gt;
    &lt;li&gt;complex data types / structures&lt;/li&gt;
    &lt;li&gt;attachments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;
As such, I would advise you to create some stringent proof of concepts if you need to migrate to this technology set and check your constraints on which versions of Java, application server and JAX-WS implementation you are allowed to use, perhaps because of enterprise architecture requiring common platforms for all your applications.&lt;br /&gt;
&lt;br /&gt;
The Eclipse project, all libraries and source code created as part of blog project can be downloaded &lt;a href=&#034;http://www.maxant.co.uk/tools.jsp&#034;&gt;here&lt;/a&gt;.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&amp;copy; Ant Kutschera 2009&lt;br /&gt;
&lt;br /&gt;
Some references:&lt;br /&gt;
&lt;br /&gt;
http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/keytool.html&lt;br /&gt;
&lt;br /&gt;
http://mail-archives.apache.org/mod_mbox/tomcat-users/200910.mbox/%3C2185441d0910021517w201a497fo83625c30062f7355@mail.gmail.com%3E&lt;br /&gt;
&lt;br /&gt;
http://java.sun.com/developer/EJTechTips/2006/tt0527.html&lt;/p&gt;&lt;div class=&#034;tags&#034;&gt;&lt;span&gt;Social Bookmarks : &lt;/span&gt;&amp;nbsp;&lt;a href=&#034;http://slashdot.org/bookmark.pl?url=http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&amp;amp;title=Professional+enterprise+JAX-WS+in+no+time+at+all%3F&#034; target=&#034;_blank&#034; title=&#034;Add this post to Slash Dot&#034;&gt;&lt;img src=&#034;common/images/slashdot.png&#034; alt=&#034;Add this post to Slashdot&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://digg.com/submit?url=http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&amp;amp;title=Professional+enterprise+JAX-WS+in+no+time+at+all%3F&#034; target=&#034;_blank&#034; title=&#034;Digg this post&#034;&gt;&lt;img src=&#034;common/images/digg.png&#034; alt=&#034;Add this post to Digg&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://reddit.com/submit?url=http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&amp;amp;title=Professional+enterprise+JAX-WS+in+no+time+at+all%3F&#034; target=&#034;_blank&#034; title=&#034;Add this post to Reddit&#034;&gt;&lt;img src=&#034;common/images/reddit.png&#034; alt=&#034;Add this post to Reddit&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://del.icio.us/post?url=http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&amp;amp;title=Professional+enterprise+JAX-WS+in+no+time+at+all%3F&#034; target=&#034;_blank&#034; title=&#034;Save this post to Del.icio.us&#034;&gt;&lt;img src=&#034;common/images/delicious.png&#034; alt=&#034;Add this post to Delicious&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.stumbleupon.com/submit?url=http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&amp;amp;title=Professional+enterprise+JAX-WS+in+no+time+at+all%3F&#034; target=&#034;_blank&#034; title=&#034;Stumble this post&#034;&gt;&lt;img src=&#034;common/images/stumbleupon.png&#034; alt=&#034;Add this post to Stumble it&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.google.com/bookmarks/mark?op=edit&amp;amp;bkmk=http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&amp;amp;title=Professional+enterprise+JAX-WS+in+no+time+at+all%3F&#034; target=&#034;_blank&#034; title=&#034;Add this post to Google&#034;&gt;&lt;img src=&#034;common/images/google.png&#034; alt=&#034;Add this post to Google&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://technorati.com/faves?add=http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Technorati&#034;&gt;&lt;img src=&#034;common/images/technorati.png&#034; alt=&#034;Add this post to Technorati&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.bloglines.com/sub/http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Bloglines&#034;&gt;&lt;img src=&#034;common/images/bloglines.png&#034; alt=&#034;Add this post to Bloglines&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.facebook.com/share.php?u=http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Facebook&#034;&gt;&lt;img src=&#034;common/images/facebook.png&#034; alt=&#034;Add this post to Facebook&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.furl.net/storeIt.jsp?u=http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&amp;amp;t=Professional+enterprise+JAX-WS+in+no+time+at+all%3F&#034; target=&#034;_blank&#034; title=&#034;Add this post to Furl&#034;&gt;&lt;img src=&#034;common/images/furl.png&#034; alt=&#034;Add this post to Furl&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;https://favorites.live.com/quickadd.aspx?mkt=en-us&amp;amp;url=http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&amp;amp;title=Professional+enterprise+JAX-WS+in+no+time+at+all%3F&#034; target=&#034;_blank&#034; title=&#034;Add this post to Windows Live&#034;&gt;&lt;img src=&#034;common/images/windowslive.png&#034; alt=&#034;Add this post to Windows Live&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;amp;u=http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html&amp;amp;t=Professional+enterprise+JAX-WS+in+no+time+at+all%3F&#034; target=&#034;_blank&#034; title=&#034;Add this post to Yahoo!&#034;&gt;&lt;img src=&#034;common/images/yahoo.png&#034; alt=&#034;Add this post to Yahoo!&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&lt;/div&gt;
        </description>
      
      
    
    
    
    <comments>http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html#comments</comments>
    <guid isPermaLink="true">http://blog.maxant.co.uk:80/pebble/2009/12/22/1261517160000.html</guid>
    <pubDate>Tue, 22 Dec 2009 21:26:00 GMT</pubDate>
  </item>
  
  <item>
    <title>Simple Web Services</title>
    <link>http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html</link>
    
      
        <description>
          &lt;p&gt;UPDATED: Something like Hessian - &lt;a href=&#034;http://hessian.caucho.com/&#034;&gt;http://hessian.caucho.com/&lt;/a&gt;&amp;nbsp;- would have been exactly what I was looking for to send binary data over HTTP.&lt;/p&gt;
&lt;p&gt;I recently had the need to send an object model from an applet back to the server. The model was rather complex and what might have been normal in the office, would have been to marshal the data into an XML document and send it to a SOAP interface.&lt;br /&gt;
&lt;br /&gt;
But that&#039;s rather excessive and would take quite some time to develop (think generating XML definitions, JAXB, generating a web service and some WSDL, then the web service clients, yawn, yawn).&lt;br /&gt;
&lt;br /&gt;
So I had a quick think about what I wanted to achieve.&lt;br /&gt;
&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;I wanted some data to be sent from the client to the server.&lt;/li&gt;
    &lt;li&gt;I wanted to develop it quickly too (so no time for research and the trials of software selection).&lt;/li&gt;
    &lt;li&gt;It had to be HTTP friendly as well, since I am paranoid about opening ports on my public servers.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;br /&gt;
So I wondered about serialising the model and sending it to a simple servlet where it could be stored into a database as a BLOB. If necessary (which was later to become the case) I would also be able to deserialise the model server side and extract some data from it.&lt;br /&gt;
&lt;br /&gt;
The only problem I faced was whether I could send binary data (the serialised data) over an HTTP request? To be on the safe side, and to avoid worrying about things like MIME types, I took the serialised data as a byte array and transcoded it into a delimited string of numbers. Each byte has a value from 0 to 255. The delimiter I chose was an arbitrarily chosen pipe character, |&lt;/p&gt;
&lt;p&gt;UPDATE: I could have used some kind of UUEncoding to convert from 8 bit to 7 bit to ensure it would go across HTTP. Didn&#039;t think of that at the time though!&lt;br /&gt;
&lt;br /&gt;
Two quick encode/decode methods later, implemented in a handy helper class and I was up and running.&lt;br /&gt;
&lt;br /&gt;
What I had not thought of, was the fact on the client side any number of Java Virtual Machines (JVM) could be serialising the data. What I mean here is that any version of a JVM (above 1.3, which I specified as the minimum requirement for the applet to ensure the largest number of users would not require a JRE install / upgrade) could be in action client side. Server side I don&#039;t even have the latest version of Java, so I was suddenly reliant on serialisation being both forward and backward compatible between Java versions. However, having tested with 1.3, 1.4, 1.5 and 1.6 it all seems to work. The clients serialise the model, send it to the server where its deserialised and later request other models which are serialised server side and deserialised client side. It all seems to work error free so far! &lt;br /&gt;
&lt;br /&gt;
What I have basically implemented is a very quick &lt;a target=&#034;_blank&#034; href=&#034;http://en.wikipedia.org/wiki/Representational_State_Transfer&#034;&gt;REST&lt;/a&gt; server. Instead of using something like &lt;a target=&#034;_blank&#034; href=&#034;http://en.wikipedia.org/wiki/Json&#034;&gt;JSON&lt;/a&gt; or &lt;a target=&#034;_blank&#034; href=&#034;http://en.wikipedia.org/wiki/Xml&#034;&gt;XML&lt;/a&gt; to send the data I just used an HTTP friendly version of a serialised model, otherwise known as a string.&lt;br /&gt;
&lt;br /&gt;
One advantage I have over things like XML and JSON is that I don&#039;t require any libraries to handle the data (which reduces the applet download / start time). Another advantage is that the data is verified against its data structure, which is not the case in JSON (where there is no schema definition) and which is not guaranteed in XML (where the data does not have to be checked against data type / schema definitions during binding/unmarshalling).&lt;br /&gt;
&lt;br /&gt;
What&#039;s the disadvantage? Well its huge. The data is not platform independent! I am limited to having both a Java client and server. Luckily Java is platform independent, but that doesn&#039;t really solve the problem, does it.&lt;br /&gt;
&lt;br /&gt;
The lesson here is the same lesson being taught with other REST paradigms, namely that you don&#039;t need to go the whole hog and implement an XML / SOAP stack in order to implement an RPC Service. KISS - &amp;quot;Keep it Simple Stupid&amp;quot;.&lt;/p&gt;&lt;div class=&#034;tags&#034;&gt;&lt;span&gt;Social Bookmarks : &lt;/span&gt;&amp;nbsp;&lt;a href=&#034;http://slashdot.org/bookmark.pl?url=http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&amp;amp;title=Simple+Web+Services&#034; target=&#034;_blank&#034; title=&#034;Add this post to Slash Dot&#034;&gt;&lt;img src=&#034;common/images/slashdot.png&#034; alt=&#034;Add this post to Slashdot&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://digg.com/submit?url=http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&amp;amp;title=Simple+Web+Services&#034; target=&#034;_blank&#034; title=&#034;Digg this post&#034;&gt;&lt;img src=&#034;common/images/digg.png&#034; alt=&#034;Add this post to Digg&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://reddit.com/submit?url=http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&amp;amp;title=Simple+Web+Services&#034; target=&#034;_blank&#034; title=&#034;Add this post to Reddit&#034;&gt;&lt;img src=&#034;common/images/reddit.png&#034; alt=&#034;Add this post to Reddit&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://del.icio.us/post?url=http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&amp;amp;title=Simple+Web+Services&#034; target=&#034;_blank&#034; title=&#034;Save this post to Del.icio.us&#034;&gt;&lt;img src=&#034;common/images/delicious.png&#034; alt=&#034;Add this post to Delicious&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.stumbleupon.com/submit?url=http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&amp;amp;title=Simple+Web+Services&#034; target=&#034;_blank&#034; title=&#034;Stumble this post&#034;&gt;&lt;img src=&#034;common/images/stumbleupon.png&#034; alt=&#034;Add this post to Stumble it&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.google.com/bookmarks/mark?op=edit&amp;amp;bkmk=http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&amp;amp;title=Simple+Web+Services&#034; target=&#034;_blank&#034; title=&#034;Add this post to Google&#034;&gt;&lt;img src=&#034;common/images/google.png&#034; alt=&#034;Add this post to Google&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://technorati.com/faves?add=http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Technorati&#034;&gt;&lt;img src=&#034;common/images/technorati.png&#034; alt=&#034;Add this post to Technorati&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.bloglines.com/sub/http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Bloglines&#034;&gt;&lt;img src=&#034;common/images/bloglines.png&#034; alt=&#034;Add this post to Bloglines&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.facebook.com/share.php?u=http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&#034; target=&#034;_blank&#034; title=&#034;Add this post to Facebook&#034;&gt;&lt;img src=&#034;common/images/facebook.png&#034; alt=&#034;Add this post to Facebook&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://www.furl.net/storeIt.jsp?u=http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&amp;amp;t=Simple+Web+Services&#034; target=&#034;_blank&#034; title=&#034;Add this post to Furl&#034;&gt;&lt;img src=&#034;common/images/furl.png&#034; alt=&#034;Add this post to Furl&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;https://favorites.live.com/quickadd.aspx?mkt=en-us&amp;amp;url=http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&amp;amp;title=Simple+Web+Services&#034; target=&#034;_blank&#034; title=&#034;Add this post to Windows Live&#034;&gt;&lt;img src=&#034;common/images/windowslive.png&#034; alt=&#034;Add this post to Windows Live&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href=&#034;http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;amp;u=http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html&amp;amp;t=Simple+Web+Services&#034; target=&#034;_blank&#034; title=&#034;Add this post to Yahoo!&#034;&gt;&lt;img src=&#034;common/images/yahoo.png&#034; alt=&#034;Add this post to Yahoo!&#034; border=&#034;0&#034; /&gt;&lt;/a&gt;&lt;/div&gt;
        </description>
      
      
    
    
    
    <comments>http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html#comments</comments>
    <guid isPermaLink="true">http://blog.maxant.co.uk:80/pebble/2007/12/01/1196542920000.html</guid>
    <pubDate>Sat, 01 Dec 2007 21:02:00 GMT</pubDate>
  </item>
  
  </channel>
</rss>

