Archive for Java

WS-DuckTyping

One of the most popular features of languages such as Smalltalk, ObjectiveC, and Ruby is Duck typing. To quote Wikipedia:

[…] duck typing is a form of dynamic typing in which a variable’s value itself implicitly determines what the variable can do. This implies that an object is interchangeable with any other object that implements the same interface, regardless of whether the objects have a related inheritance hierarchy.[…]

The term is a reference to the duck test — “If it walks like a duck and quacks like a duck, it must be a duck”.

So what does this have to do with Web services? Well, duck typing is a great way to create graceful and interoperable Web services. Web services are about exchanging information, and as long as the information walks like a duck…

Here are my three tips to implement WS-Duck Typing:

Don’t validate incoming messages!

Not only is XSD-based validation slow, it also requires strict schema conformation from the other party, thus creating a strictly typed service. Such a service breaks Postel’s Law: be conservative in what you do; be liberal in what you accept from others.

If you really want to do validation, do it on server-side outgoing messages only. After all, you should adhere to your own schema. Also, Schematron is the exception to the rule, since it not based on grammars, but on finding tree patterns in the parsed document. Which brings us to:

Use XPath!

XPath is an excellent way to extract information from an XML document. Code written with XML API like DOM, SAX, or StAX is typically quite fragile when it comes to element ordering, nesting, or unexpected elements. And XML marshalling isn’t much better: some of these API’s throw exceptions in these cases.

Not with XPath. When using XPath, you don’t care whether the <lastName> element is the first or the second child of <person>; the /person/lastname expression grabs it anyway. And if if you really don’t know where to find the last name, you can always resort to //lastname, which finds it anywhere in the document.

In the past, XPath has dismissed as being too slow. With modern XPath libraries which support XPath pre-compilation, this is less of an issue.

Don’t create stubs or skeletons!

This is perhaps the most controversial tip. If you create client-side stubs or server-side skeletons in a strongly-typed language like Java, you throw away any option of being liberal about the XML messages. Instead, you have create a strongly-typed API that is strongly-coupled to the contract, and that passes or expects parameters of a certain kind. If they are of any other kind, or if they are simply not there, your code will never be invoked. Even if you didn’t need the parameter in the first place.

If you treat Web services like XML messaging, rather than RPC, you could have handled the message gracefully: let’s see if I can find the first name under the person element, and if it’s not there, I’ll try and find in anywhere in the document. Still not there? Perhaps it’s an older message: I’ll just apply this stylesheet, and see if I can find the first name then. Et cetera, et cetera.

Hopefully, these tips will help you create flexible, interoperable Web services that gracefully handle XML messages.

Quack!

Comments (25)

Nobody cares about your stack trace!

Some Web service stacks offer an option to send any server-side stack trace over to the client, as part of a <faultDetail/> block. Axis 1 does it, and it seems like the JAX-WS reference also offers this feature. Presumably, this makes it easier to debug the service from the client side.

Let me explain why I think that there is a big difference between a SOAP Fault and an exception, and why I don’t offer this feature in Spring-WS:

Let’s say I call a public Web service to get a stock quote. Instead of the result, I might get a SOAP Fault as a reponse, which means something went wrong. In SOAP 1.1, a Fault contains four elements, the first two of which are required:

  1. a code (a qualified name)
  2. a string
  3. an actor, and
  4. a detail (which can contain any number of xml elements)
A Java or .NET Exception, on the other hand, has just two elements:
  1. a string message, and
  2. a stack trace
Notice the difference between the two? Of course, you can use the exception message as the fault string, and you can create some kind mapping between the exception class and the code, but that’s your mapping. There is no standard, interoperable way to write stack traces in faults, mostly because stack traces can only be found in Java, but not in C, for instance. And Web services are all about interoperability.

Back to the stock quote: imagine the Web service is not written in Java, but in C, which means we cannot send any stack trace as part of the fault. So what do we send in order to facilitate debugging on the client side? Do we attach the core dump ;) ?

There’s a simple lesson here: it only makes sense to use Web service technology where the client isn’t interested to the language of the server. If you really want to see the stack trace on the client-side, use Java RMI. If you want to invoke a method on a class written in another language, use CORBA or Hessian. If you want to do XML messaging, use SOAP.

Comments (7)

The Quest for the Domain Expert

Compare the following quote from the EJB 1.1 specification:

The Application Assembler is a domain expert who composes applications that use enterprise Beans.

to this quote I found describing BPEL:

After the developer does the prep work, a domain expert pulls the services from a palette and connects them with lines that represent workflow.

Now, I’ve made quite a few EJB’s in my day, but I’ve never met an Application Assembler in my life. Somebody who took (existing) components and created new applications using them. Somehow, it all came down to us developers.

My burning question is: what has changed? Why would the domain expert want to compose services with BPEL/WS/SOA, when he didn’t want to with EJB?

Comments (3)

Domain Drivel

Computer science tells us there are three ways to represent data:

  1. Object graphs (i.e. Java or C#)
  2. Relational data (RBMS)
  3. Hierarchal data (XML or HTML)

During the years, we’ve found out about the Impedance Mismatches between these three representations. At first, it seems pretty easy to convert a row in a database to an object. However, things are not so easy as they seem.

And yet, conversion between these representations is all we do in a standard Web application! Data is generally stored in relational databases, and converted to Java or .NET objects using some kind of ORM tool. Next, we use the objects to invoke business logic, and finally, we display them on an HTML page. I find this very amusing, it makes me feel we are doing something wrong here.

Recently, though the influence of books like Domain Driven Design, it has become fashionable to think that a rich Domain Model is one of the most important things there is. Well, that might be the case for you as an OO developer, but for the Enterprise the database is much more important. It is not without reason that a large number of databases outlive the applications built around them. And for the user of your Web application the most important part is the HTML UI he or she is looking at. Finally, in this SOA day and age, the OO business logic is probably not the only business logic that is there. Your application is part of a team of services, the business logic on the mainframe is just as important!

Now, I’m not saying that a rich domain model is not important. I’m just saying that — as with any solution — it is not a silver bullet. Use it when it gives an advantage, but don’t swear by it. In the grand scheme of things, your precious OO model is not as important as you think it is.

Comments (6)

14compatibility.jar in Apple JDK 1.5

A while ago, I came across a weird issue while running the unit tests for Spring-WS. Some of my tests would run perfectly fine on both Windows and Linux, but would not run on Mac OS X.

After some investigation, I came across the /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/.compatibility/14compatibility.jar on my classpath. It contains the following:

    0 Mon Jan 16 14:21:08 CET 2006 META-INF/
    70 Mon Jan 16 14:21:08 CET 2006 META-INF/MANIFEST.MF
     0 Mon Jan 16 14:20:58 CET 2006 org/
     0 Mon Jan 16 14:20:58 CET 2006 org/apache/
     0 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/
     0 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/jaxp/
  1489 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/jaxp/DefaultValidationErrorHandler.class
   912 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/jaxp/DocumentBuilderFactoryImpl.class
  3494 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/jaxp/DocumentBuilderImpl.class
  1671 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/jaxp/SAXParserFactoryImpl.class
  2550 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/jaxp/SAXParserImpl.class
     0 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/
   895 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/AttributeDecl.class
   287 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/AttributesEx.class
  1557 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/AttributesExImpl.class
  1826 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/ContentModel.class
  1959 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/ContentModelState.class
   668 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/ElementDecl.class
   606 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/ElementValidator.class
   241 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/EndOfInputException.class
   306 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/EntityDecl.class
   933 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/ExternalEntity.class
 11395 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/InputEntity.class
   363 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/InternalEntity.class
   603 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/Parser2$1.class
   602 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/Parser2$2.class
   604 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/Parser2$3.class
  1105 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/Parser2$4.class
   542 Mon Jan 16 14:20:58 CET 2006 org/apache/crimson/parser/Parser2$Catalog.class
...

The Crimson XML parser! And the jar contains a version of Xalan as well.

No wonder my XML namespace tests failed: instead of using Xerces, which is part of JDK 1.5, it used Crimson! And the fact that the JAXP libraries in JDK 1.4 used the org.apache.* package makes it pretty hard to override them with your own version. Luckily, this was fixed in JDK 1.5, where Xerces was included in the com.sun.org.apache.xerces package.

I deleted the 14compatibility.jar, and the tests ran fine again. I have no idea what the goal of this jar is, but in my opinion, Apple should get rid of it. JDK 1.4 uses Crimson as a JAXP implementation, and JDK 1.5 uses Xerces. No need for a compatibility jar.

Comments (1)

« Previous entries · Next entries »