Cornelia's Weblog

my sporadically shared thoughts on, well, whatever is capturing my attention at the moment.

Posts Tagged ‘ECM’

Building Domain Specific RESTful Services with XML Technologies

Some colleagues and I have been very busy in the last months putting together a framework to do just that. Let me briefly back up a bit…One of the things that I’ve spent some time on in the last couple of years is the Content Management Interoperability Services (CMIS) standards development effort. One of the styles for exposing this set of services is through a RESTful interface. Through incremental improvements happening through the community development process the result is a pretty nice, and quite RESTful, interface. That said, Roy Fielding levied some pretty harsh criticisms toward it when it was first made public – the vast majority of which are now addressed. One issue from Roy’s list remains but is, frankly, something that CMIS didn’t intend to address, and that is the concern that the services exposed over a CMIS compliant repository do NOT expose the domain specific semantics in the resources. Roy is, of course, dead on on this, what CMIS exposes is the repository model, not your domain specific model. Yes, CMIS does provide a service where object types can be obtained by a client, but those details are not a part of the protocol, rather they are tunneled through the protocol. And, while CMIS resource representations do include hyperlinks between related resources, again the related resources are repository resources (i.e. this document is contained in this folder) not domain specific resources.This is an all too common pattern – we build interfaces that expose the repository models – and, of course, this is not at all without use as it does help consumers more rapidly build applications. Unfortunately, it has the unintended consequence of encouraging architectures where all of the domain specific details are all too often included far too far from the server. My boss calls this the “semantic gorp”, and in the best case it lands on an app server somewhere embedded in some services that in turn call the repository-model-centric services, but in the worst case it ends up far further away. This causes all sorts of headaches, which I’ll go into details on in subsequent posts… for now I’ll just call on your intuition to buy that point.(Okay, so that wasn’t entirely brief, but important context nonetheless.)In the deployment of ECM systems you go through a process where you design your domain specific artifacts, content types, lifecycles, etc. You then (ideally) configure the ECM to provide services for those domain specific entities. Wouldn’t it be cool if you got domain specific services as a result of that process? Now, don’t misunderstand, we haven’t built that (yet), but what we just published to the EMC Developer Network is a step in that direction.We have built a framework that allows for the development of domain specific RESTful services over a repository that supports xQuery. In particular, the implementation available for download operates over EMC Documentum xDB. Using the framework, all of the details of connecting to xDB are abstracted away from the developer, and he or she produces the RESTful services by

  1. “declaring” the resource model in Jax-RS annotated Java classes
  2. defining the uniform interface with more Jax-RS annotations (i.e. @GET, @PUT, @POST, @DELETE, etc.)
  3. producing an XQuery to interface each RESTful operation for each resource to the physical manifestation of that resource
  4. and binds it all together in a spring configuration file

In this first release of the framework we are mostly leveraging Jax-RS for REST features, which means that one of the most important features of RESTful interfaces, hyperlinking, is lacking. This will follow in version 2 of the framework in a few weeks.One of the primary drivers for this work was to simplify the development process for these services – if they are easy to build then we should see more domain specific services where otherwise, generic services might have been. This is already proving true in that we are leveraging the framework on several projects internally at EMC. The developers were able to concentrate on their resource models, representations and interactions rather than getting bogged down in the details on how to implement them. Sure, they still need to touch java code and spring configuration files, but it’s not a huge leap to see that tooling could shelter the developer from those details – we’re just focusing on the developer model, not the tooling(, for now?).The framework, including source code, plus a sample application leveraging the framework is available here. Also, for any of you that will be at EMC World in a few weeks, I am giving a talk on this framework – in the highly coveted last slot of the conference in the developer track (Thursday afternoon at 1PM). Hope to see you there.

Open eHealth IPF – Getting the HL7 Tutorial Running (in version 1.7 of the IPF)

The Open eHealth Integration Platform is pretty darn cool. In addition to enhancements that serve the healthcare domain, it also extends Camel with a great number of features that are of general value, including a Groovy based DSL that supports the likes of closures (!!) and more. I’m liking it.I’ve been looking at the available tutorials and didn’t get too, too far in before I hit a snag – in the third tutorial on the page, the HL7 Processing tutorial. The solution is very, very simple, and is given at the very end of this post, though finding the solution took me on a very instructive tour through the platform and a bunch of embedded packages. Fortunately, I had the benefit of time (the boys went to my son’s homecoming game last night) and absorbed a lot on the scenic route. Come along…Following the tutorial instructions to the letter resulted in an error when I tried to run it (unit testing run either from within eclipse or by running mvn test at the command line):SEVERE: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@3bfc47] to prepare test instance [org.openehealth.tutorial.SampleRouteTest@2f996f]java.lang.IllegalStateException: Failed to load ApplicationContextat org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:201)...[snip - a big stack trace with some cascading "Caused by:..." messages the last of which was the root cause]...Caused by: ca.uhn.hl7v2.HL7Exception: No map found for version 2.2. Only the following are available: [2.5, 2.3.1, 2.4, 2.6, 2.1, 2.5.1, 2.0D, 2.0, 2.3, 2.2]at ca.uhn.hl7v2.parser.Parser.getMessageStructureForEvent(Parser.java:352)...[snip - a bunch more stack trace]This error was getting thrown at bean instantiation time – the init method for the validationContext was failing. Of course, this error message is puzzling in two respects. First, most obviously, an error message that says “nothing available for x, only x, y and z are available” is rather contradictory. Second, when we look into the code for initialization of the validationContext we see that what we are doing is starting with a DefaultValidationContext and then we fill it in with the rules that are defined in the beans declared in the context.xml file. The DefaultValidationContext has a map, initially empty, from the HL7v2 versions (i.e. 2.1, 2.2, etc.) to the set of rules that apply to that version. Put that together with the error message above and we are easily mislead into thinking the system is complaining about some problem with the ruleMap in the DefaultValidationContext. Yes, mislead. This is NOT the map that is causing the problem.What happens at bean initialization time starts out exactly as I describe in the previous paragraph – the validationContext bean is instantiated and during initialization a DefaultValidationContext is created at the rules specified in the context.xml file are added. As the rules are added the forContext Groovy method is called, a RuleBuilder is instantiated and the forVersion method is called on it – that is, the rules are basically parsed (more on this in a moment). The rules in the defaultTypeRules are not a problem and are loaded without issue. The difference between these and myCustomRules, which are not loading, is that the custom rules we’ve defined are using the abstractSyntax method (those in the defaultTypeRules are specifying rules using different approaches).And here is the key…What happens when you define a rule using abstractSyntax is that the rule is validated against the abstractsyntax of the designated HL7 message version. That’s right, the IPF is doing a bunch of work here to make sure you’ve specified rules that are relevant against the version of HL7v2 that you are targeting. So, for example, if you tried to define a rule against an ADT_A25 message and you targeted it forVersion(’2.2′), you’re cool. If however you target it forVersion(’2.1′) then the rule itself won’t validate because version 2.1 only has ADT messages up through ADT_A24. And it even does validation into the message formats. This is a huge value add, it’s a point of model governance that I wasn’t necessarily expecting to have in IPF.So, back to the error message. The exception is thrown in ca.uhn.hl7v2.parser.Parser.getMessageStructureForEvent, the Parser does, indeed, contain a map from version numbers to messageStructures and the exception occurs because, indeed, there is no entry for version 2.2 (or any other version number for that matter). The question then is from where and when are they supposed to have been loaded. We don’t have to look too far, the Parser class includes a method called loadMessageStructures() and looking at the code in there we see:for (int i = 0; i < versions.length; i++) {   String resource = "ca/uhn/hl7v2/parser/eventmap/" + versions[i] + ".properties";   InputStream in = Parser.class.getClassLoader().getResourceAsStream(resource);   ...That is, for each version (the list is hardcoded in a class variable) load up the structure from a properties file with the right name. I knew then that this had to be a packaging issue, and, assuming the tutorial once worked as written, a result of some recent change. Digging through jars, this specifically had to do with HAPI libraries, and vaguely remembering seeing something about HAPI versions, here:

As of IPF 1.7-m3, the underlying HAPI library has been updated. The HL7 version-dependent classes have to be included separately.

was the solution.All that is to say that the only thing you need to do beyond what is described in the tutorial is add the following lines in the dependencies section of the pom.xml:<dependency>    <groupid>ca.uhn.hapi</groupid>    <artifactid>hapi-structures-v22</artifactid>    <version>0.6</version></dependency>