DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

The Latest Integration Topics

article thumbnail
How to Create a Java EE 6 Application with JSF 2, EJB 3.1, JPA, and NetBeans IDE 6.8
Develop a web-based app based on technologies in the JEE6 specs such as Enterprise Java Beans 3.1 and JPA with the help of NetBeans IDE 6.8.
December 29, 2009
by Christopher Lam
· 723,413 Views · 3 Likes
article thumbnail
A Groovy ride on Camel
Apache Camel is a routing and mediation engine which implements the Enterprise Integration Patterns. But don't let the words Enterprise Integration scare you off. Camel is designed to be really light weight and has a small footprint. It can be reused anywhere, whether in a servlet, in a Web services stack, inside a full ESB or a standalone messaging application. Camel makes it really simple to implement messaging application. So there are not many reasons why you could not use it in non-enterprise application. In fact, it is possible to use Camel as a tool, similar to the way you use scripting languages. For example, you could fire up the Camel Web Console and define a messaging application without write a single line of code. This article is a getting-started type of tutorial. As you might have guessed, I'm going to use Groovy as the programming language. And the programs in this article are intend to be ran with Groovysh, the Groovy Shell. Reasons: Groovy is concise, expressive and has less noice than Java. All programs in this article are just a couple dozen lines long and should be real easy to follow along. Using Groovysh allows the reader to interact with the application. I'm a Linux guy and am comfortable with VIM and working in command line. So bare with me. Putting the pieces together First, I'm going to write a simple program to make sure I'm able to talk to Camel in Groovy. I'm not using an IDE like Eclipse, nor creating a project, nor going to use any build tools like Maven. Any text editor will be sufficient. Save the following code to a file named CamelDemo.groovy (source download). import groovy.grape.Grape Grape.grab(group:"org.apache.camel", module:"camel-core", version:"2.0.0") class MyRouteBuilder extends org.apache.camel.builder.RouteBuilder { void configure() { from("direct://foo").to("mock://result") } } mrb = new MyRouteBuilder() ctx = new org.apache.camel.impl.DefaultCamelContext() ctx.addRoutes mrb ctx.start() p = ctx.createProducerTemplate() p.sendBody "direct:foo", "Camel Ride for beginner" e = ctx.getEndpoint("mock://result") ex = e.exchanges.first() println "INFO> ${ex}" This little program does a couple things: Imports the camel-core jar using Grape.grab() Defines a our custom RouteBuilder, which defines a simple route between a direct:foo and a mock:result enpoints. Instantiates the CamelContext, adds our custom RouteBuilder to it and starts Camel by ctx.start(). Tests the route by sending a message exchange using the producerTemplate obtained from the CamelContext Lookups the mock:result endpoint (ctx.getEndpoint("mock:result")) and dislays the first Exchange, which should contain the message we just sent. Now start the groovysh in a command window and load the program: $ groovysh groovy:000> load CamelDemo.groovy you should see a bunch of output and then the output from the script: INFO> Exchange[Message: Camel Ride for beginner] ===> null groovy:000> At this point, you can interact with the program via groovysh. For example the following shows a few things you can do. groovy:000> ctx.routes ===> [EventDrivenConsumerRoute[Endpoint[seda://foo] -> UnitOfWork(Channel[sendTo(Endpoint[mock://result])])]] groovy:000> ctx.components ===> {mock=org.apache.camel.component.mock.MockComponent@14f2bd7, seda=org.apache.camel.component.seda.SedaComponent@c759f5} groovy:000> ctx.endpoints ===> [Endpoint[seda://foo], Endpoint[mock://result]] groovy:000> ctx.endpoints[1].exchanges ===> [Exchange[Message: Camel Ride for beginner]] groovy:000> ctx.endpoints[1].exchanges[0].in.body ===> Camel Ride for beginner groovy:000> p.sendBody("seda:foo", "Camel Kicking") ===> null groovy:000> e.exchanges ===> [Exchange[Message: Camel Ride for beginner], Exchange[Message: Camel Kicking]] This is it for our first Groovy/Camel program. For the curious, you can actually modify the program and reload it without terminating and restarting groovysh. Camel Stock Quote This is a simple stock quote application. Initially, I planed to walk you thru the development steps, from adding a simple bean as a Processor to transforming it to a Multi-Channel, Multi-Data-Format service application. But after I've finished developing the program, it turns out that it is too simple to justify for such elaboration. To save your time and mine, I'm just going to show you the final version right here. Take a look at it, and if you can understand what it does, then may be you should skip the rest of this article :) Save the following code to a file named StockQuote.groovy (source download). import groovy.grape.Grape Grape.grab(group:"org.apache.camel", module:"camel-core", version:"2.0.0") Grape.grab(group:"org.apache.camel", module:"camel-jetty", version:"2.0.0") Grape.grab(group:"org.apache.camel", module:"camel-freemarker", version:"2.0.0") class QuoteServiceBean { public String usStock(String symbol) { "${symbol}: 123.50 US\$" } public String hkStock(String symbol) { "${symbol}: 90.55 HK\$" } } class MyRouteBuilder extends org.apache.camel.builder.RouteBuilder { void configure() { from("direct://quote").choice() .when(body().contains(".HK")).bean(QuoteServiceBean.class, "hkStock") .otherwise().bean(QuoteServiceBean.class, "usStock") .end().to("mock://result") from("direct://xmlquote").transform().xpath("//quote/@symbol", String.class).to("direct://quote") //curl -H "Content-Type: text/xml" http://localhost:8080/quote?symbol=IBM from('jetty:http://localhost:8080/quote').transform() .simple('').to("direct://xmlquote").choice() .when(header("Content-Type").isEqualTo("text/xml")).to("freemarker:xmlquote.ftl") .otherwise().to("freemarker:htmlquote.ftl") .end() } } ctx = new org.apache.camel.impl.DefaultCamelContext() mrb = new MyRouteBuilder() ctx.addRoutes mrb ctx.start() p = ctx.createProducerTemplate() //p.sendBody("direct:quote", "00005.HK") //p.sendBody("direct:xmlquote", "") //p.sendBody("direct:xmlquote", "") e = ctx.getEndpoint("mock://result") //e.exchanges.each { ex -> // println "INFO> in.body='${ex.in.body}'" //} OK, you are still here. It is assumed that: We have two market data providers, one for U.S. market and the other for Hong Kong market. An existing QuoteServiceBean class has been implemented as a POJO. It has two methods, usStock() and hkStock(). It is part of a legacy system, it works great, it hides the underlying details of interacting with the data providers. No one understands it and no one dares to modify it. We would like to use the existing QuoteServiceBean to provide a stock quote service that can be consume easily. i.e. Multi-Channel and Multi-Data-Format. Content Based Router and Message Translator from("direct://quote").choice() .when(body().contains(".HK")).bean(QuoteServiceBean.class, "hkStock") .otherwise().bean(QuoteServiceBean.class, "usStock") .end().to("mock://result") The first route (start at line 17) represented by the direct:quote endpoint. It routes the message according to the content of the body of the exchange, which it's assumed to contain the stock symbol. When the body of the exchange contains the string ".HK" the hkStock(String symbol) of QuoteServiceBean is called, otherwise the usStock(String symbol) of QuoteServiceBean is called. Notice that the route DSL almost reads like plain English! Let us try it out. First start groovysh, load the program and send two messages to the direct:quote endpoint: jack@localhost tmp]$ groovysh Groovy Shell (1.6.6, JVM: 1.6.0_11) groovy:000> load StockQuote.groovy .............. groovy:000> p.sendBody("direct:quote", "00001.HK") ===> null groovy:000> e.exchanges.last() ===> Exchange[Message: 00001.HK: 90.55 HK$] groovy:000> p.sendBody("direct:quote", "SUNW") ===> null groovy:000> e.exchanges.last() ===> Exchange[Message: SUNW: 123.50 US$] groovy:000> That is it, our simple content-based router successfully routes request to the corresponding processor methods. XML Quote Request, message Transform from("direct://xmlquote").transform().xpath("//quote/@symbol", String.class).to("direct://quote") This next route simply accepts requests in XML, transforms the request and chains it to direct://quote. With this, we've added the capability to accept requests in XML format! We are using XPath here to expression our transform. Check out the hosts of Expression Langauges supported by Camel. Let us try it out: groovy:000> p.sendBody("direct:xmlquote", "") ===> null groovy:000> e.exchanges.last() ===> Exchange[Message: GOOG: 123.50 US$] groovy:000> Multi-Channel, Multi-Data-Format Provisioning Grape.grab(group:"org.apache.camel", module:"camel-jetty", version:"2.0.0") Grape.grab(group:"org.apache.camel", module:"camel-freemarker", version:"2.0.0") // ........... lines removed for brevity ............. from('jetty:http://localhost:8080/quote').transform() .simple('').to("direct://xmlquote").choice() .when(header("Content-Type").isEqualTo("text/xml")).to("freemarker:xmlquote.ftl") .otherwise().to("freemarker:htmlquote.ftl") .end() Here we use the camel-jetty to expose an endpoint jetty:http://localhost:8080/quote to our quote service. Note that camel-jetty is not part of camel-core. That is why we have to grab it into our program. The HTTP request is translate into XML using simple expression. Note that the camel-jetty has kindly extracted the request parameters as well as the HTTP header and placed them on the Message header. So the request parameter symbol is access as ${header.symbol} in the expression. Next we simply chain the message exchange to the direct:xmlquote endpoint. The result from direct:xmlquote went thru another translation, which depends on the content-type of the orginating HTTP request. Here, I make use of the camel-freemarker to generate the desire output. So we need to create the two Freemarker templates: htmlquote.ftl ${body} xmlquote.ftl ${body} So let us see it in action, I'm going to use curl to make HTTP requests. Do this on another command window: [jack@localhost tmp]$ curl http://localhost:8080/quote?symbol=IBM IBM: 123.50 US$ [jack@localhost tmp]$ curl http://localhost:8080/quote?symbol=00001.HK 00001.HK: 90.55 HK$ [jack@localhost tmp]$ And to request XML content: [jack@localhost tmp]$ curl -H "Content-Type: text/xml" http://localhost:8080/quote?symbol=IBM IBM: 123.50 US$ [jack@localhost tmp]$ That's about it for our multi-channel/multi-data-format ser vice provision. Summary In this tutorial, I hoped to illustrate how Camel supports message passing paradigm style of application development. Camel provides all sort of components to help you build processing pipelines. All you need is to implement your business logic as simple POJOs and let Camel handle all the translating, routing, filtering, spliting and forwarding for you. Not shown in this tutorial is how to consume external resources and services from within a route. No sweat, it is just as easy. Camel integrates nicely with Spring as well as Guice, but works nicely on its own. It won't be in your way if you don't need DI support in your application. As they say: Keep the simple easy. Camel works nicely in a JBI environment like ServiceMix and OpenESB. Camel is OSGI-ready and tracks newly deployed bundles for Route definitions at runtime. So you can gear it all to way up to be part of an enterprise SOA infrastructure. Disclaimer, I'm not an experienced Camel user and still learning. Thank you for staying up with me.
December 3, 2009
by Jack Hung
· 26,100 Views
article thumbnail
Reload Your Plugins Without Restarting Eclipse
When you are developing Eclipse plugins, sometimes its annoying that the changes in the plugin.xml won't reflect immediately. You need to restart the target Eclipse to see the changes. This will be painful if you are playing with trial-n-error stuff like the menu urls. In this tip, I'll explain how to make Eclipse reread your plugin.xml without restarting the target. Create a plugin, launch as an Eclipse Application (you don't even need to Debug, just Run would do) Check the UI contributions of your plugin. Make the desired change in your plugin.xml. Right now, I've changed a Command's name; added a Command contribution to an existing menu; added a new view and made changes to an existing perspective In your target, open the Plug-ins Registry view and in the pull down menu, check the 'Show Advanced Operations' Right click your plugin and select Disable. Then right click again and select Enable. Since you have made changes to the current perspective by adding a view, you would be greeted with this Dialog. Say Yes. There you go. Now all the changes in the plugin.xml would reflect in the UI While this may not be applicable for all the changes you make in plugin.xml, this should cover up for most the changes From http://blog.eclipse-tips.com
December 2, 2009
by Prakash
· 13,413 Views
article thumbnail
How to Combine REST Services with EJB 3.1
Want to combine REST services using EJB 3.1? Learn how in this great tutorial.
December 1, 2009
by Milan Kuchtiak
· 138,432 Views · 1 Like
article thumbnail
Top Open Source ESB Projects
In today's software markets, open source technologies are giving commercial products some stiff competition. Enterprise Service Busses are no exception. Don Rippert, the chief technology officer at Accenture says, "ESBs are software products that allow you to create a business process with web services running on different platforms." Rippert believes an ESB is essential for achieveing the full potential of service-oriented architecture. In general, an ESB should provide flexibility built on a basis of standards. Jos Dirksen, an author of "Open Source ESBs in Action," said in a recent interview that today's top open source ESBs were "on par with commercial alternatives." Competition drives innovation, and this page has a list of the most competitive open source ESBs on the market. Here are the the forerunners among open source ESBs (in no particular order): JBoss ESB JBoss JBoss generally has mature components in its GA releases with no vendor-lockin characteristics. Their ESB leverages JEMStechnologies like the JBoss business rules engine for content-basedrouting and messaging. Content-based routing on the JBoss ESB can use Drools or XPath. The JBoss ESB supports XSLT and the Smookstransformation engine for XML and non-XML data formats. JBoss' ESBalso runs on the JBoss application server and features a pluggable architecture for swapping out ESBsubsystems. Apache ServiceMix Apache Apache ServiceMix 4 is OSGi based and a great option for integrating with an XML standards focussed landscape. Apache ServiceMix makes it very easy to hot-deploy new integration flows. Even the pluggable integration components are hot deployable. ServiceMix uses a JBI standard which provides a lot of components like JMS, BPEL, Web service, and Camel. The inclusion of Camel is a strong point for ServiceMix along with the Spring Framework, which is also supported. FUSE ESB is another great distribution of Apache ServiceMix. OpenESB Sun(Oracle) OpenESBhas an easy learning curve due to its solid integration with theGlassFish Application Server and Sun's popular IDE, NetBeans. TheNetbeans IDE provides countless integrated functions for administrationand development. The best thing about OpenESB is its toolset. OpenESB's tools include WSDL and schema editors, a JPI manager integrated into the service manager, and Antrunning in the background. Another tool is the Composite ApplicationService Assembly (CASA) editor, which gives you a graphical overview ofintegration applications. Many Java developers will love OpenESBbecause it comes straight from the home of Java. OpenESB is also OSGi based. MuleESB MuleSoft Mule is the most used open source integration platform. MuleESB's low cost along with easy configuration, expansion, and flexibility make it very popular. Java developers will find MuleESB easy to work with because it is Java centric. There’s also a powerful set of XML schemas in MuleESB. The creation of integration flows is very straightforward. MuleESB can have fairly complex integration flows up and running in minutes. It has many connectivity, routing, and transformation options right out of the box. WSO2 ESB WSO2 Other ESB products take a relatively heavyweight approach by using the JBI specification, but the relative newcomer, WSO2, takes a lightweight approach in its ESB. It does this by focusing on Web service standards for integration. The WSO2 ESB uses Apache Synapse, a nimble Web service mediation and routing engine that focuses on providing fast XML message processing. WSO2 takes advantage of Synapse's non-blocking http://s transport implementation over the Apache HttpComponents/NIO module. This allows the WSO2 ESB to handle thousands of parallel requests using a small amount of resources and threads. You can always expect great XML support from the WSO2 ESB because well-known XML expert James Clark is a company director at WSO2.
October 29, 2009
by Mitch Pronschinske
· 241,735 Views
article thumbnail
Integrating JBoss RESTEasy and Spring MVC
Building websites is a tough job. It's even tougher when you also have to support XML and JSON data services. Developers need to provide increasingly sophisticated AJAXy UIs. Marketing groups and other business units are becoming more savvy to the benefits of widgets and web APIs. If you're a Java developer who needs to implement those sexy features, you're likely going to accomplish that work with a dizzying variety of frameworks for web development, data access and business logic. The Spring Framework has a strong presence based on the premise of seamless (no pun intended) integration of all of those frameworks. The Spring framework integrates with a host of JEE standard technologies, such as EJBs and JSP. Spring MVC is a sub-project of the larger Spring Framework that has its own Controller API and also integrates other web development frameworks such as JSF, Struts and Tiles. While the Spring Framework also integrates with new JEE technologies as they develop, however, for a variety of reasons the Spring framework has not integrated with the tour de force JAX-RS standard which delivers an API for constructing RESTful services. There are six implementations of the JAX-RS standard, and each provides some level of integration with Spring. Most of those integrations work with the Spring framework proper, but don't take advantage of the benefits of Spring MVC. JBoss RESTEasy integrates with both the Spring Framework proper and also with the Spring MVC sub-project. In this article, we're going to explore how to use RESTEasy along with Spring MVC application. We'll deep dive into the internals of Spring MVC, we'll discuss JAX-RS and how they related to MVC web development. We'll also touch on quite a few technologies beyond Spring MVC and RESTEasy, including Jetty and maven. We're also going to discuss theoretical concepts relating to REST and Dependency Injection. This article has to cover quite a bit of ground and you'll be gaining quite a few tools you can use to develop complex web applications. If you follow this article, you'll be constructing an end-to-end web application, however, feel free to skim the article to find material that's relevant to you. REST and JAX-RS REST has been an increasingly trendy topic over the last three years. We as a development community have been looking at REST as an effective way to perform distributed programming and data-oriented services. In fact, the Java community's REST leaders got together and created a standard spec to standardize some RESTful ideas in JSR 311 - JAX-RS the Java API for XML and RESTful Services. The focus of JAX-RS was to create an API that Java developers could use to perform RESTful data exchanges. However, the Java community quickly saw the similarities between JAX-RS and MVC (Model View Control) infrastructures. James Strachan, a long time Java community member and open source contributor (to things like DOM4J, Groovy - he created the language, and recently the Apache Camel and CXF ESBs) suggested that JAX-RS as the one Java web framework to rule them all?. Jersey, the production ready JAX-RS reference implementation, has a built in JSP rendering mechanism. The RESTEasy community built a similar mechanism in HTMLEasy. The Jersey and and HTMLEasy approaches work well for simpler websites, but they don't solve some of the more complex needs of an application. If you want more complex functionality, you'll need a more sophisticated web-development platform, such as Spring MVC. A combination of Spring MVC and RESTEasy will have the following benefits compared to the simpler approaches: Session based objects Freedom of choice - chose the right tool for the job Spring MVC integrates with a whole bunch of MVC frameworks, including Spring MVC, Struts2 and now RESTEasy Spring MVC integrates with a whole bunch of View frameworks, including JSP, JSF, Tiles and much more Integrated AJAX components - the freedom of choice can make end-to-end AJAX calls a breeze, assuming you chose the appropriate framework More control over URL mapping This article tackles some more advanced topics. If you want some relevant background, we have a reference section at the end of this article. Before we take a look at code, let's take a more in depth view of Spring MVC. Spring MVC Spring MVC is broken down into three pluggable sub-systems: Handler Mapping - Map a URL to Spring Bean/Controller. Spring allows quite a few methods to perform this mapping. It can be based on the name of a Spring bean, it could be a URL to bean map, it could be based on an external configuration file or it could be based on annotations. Handler Mappings allow you to configure complex mappings without resorting to complex web.xml files. Handler Adapter - Invoke the Controller. Hander Adapters know what type of spring beans they can call and performs invocations on the types of beans it knows about. There are Handler Adapters for Spring MVC classic, spring @MVC, Struts, Struts2, Servlets, Wicket, Tapestry, DWR and more. View Mapping - Invoke the View. View Mappers know how to translate a logical view name produced by a Controller into a concrete View implementation. A name like "customers" may translate into any of the following technologies: JSP/JSTL, JSF, Velocity, FreeMarker, Struts Tiles, Tiles2, XSLT, Jasper Reports, XML, JSon, RSS, Atom, PDF, Excel, and more RESTEasy plugs into Spring MVC in all three sub-systems. JAX-RS Resources/Controllers are defined by annotations; therefore RESTEasy provides a ResteasyHandlerMapper that knows how to convert a URL to a RESTEasy managed JAX-RS controller method. Once RESTEasy determines which method to invoke, the ResteasyHandlerMapping performs the invocation. The invocation can either be an object, which invokes the default JAX-RS behavior which transforms the resulting Object to a Represetation such as XML or JSON. Additionally, you return a traditional Spring ModelAndView which can refer to a logical view name and a map of data to be rendered by the View. The default JAX-RS behavior creates a ResteasyView which uses JAX-RS's configurable MessageBodyReader and MessageBodyWriter transformation framework. RESTEasy can produce XML and JSON using JAXB, but can be configured to use other view technologies such as Jackson, which is a performant and flexible JSON provider, Flex AMF. This separation of Controller and View concepts allows you to mix and match your Controller and View technologies. RESTEasy Resources can call any Spring managed Views and other Controller technologies can be rendered by a ResteasyView. You can either use RESTEasy as your sole MVC framework, if it fits your needs, or you can augment an existing Controller infrastructure with data services provided by RESTEasy. Just as importantly, you can leverage all of the other functionality that Spring provides, such as DAO abstraction, transaction management and AOP. Your First SpringMVC/RESTEasy Application Before we start reviewing the project, let's review a quick checklist of items we will be reviewing. The project files fall into two categories: configuration and source code. All of the code that will be covered is available in the RESTEasy repository and can be downloaded (as a tar.gz file), or browsed. Here is a list of files that each category will require. Configuration Files: web.xml - servlet configuration with Spring MVC artifacts - Spring MVC's DispatcherServlet, and map to /contacts/* springmvc-servlet.xml - a Spring application context configuration with all of the Spring beans this project needs, including RESTEasy setup (one line) and JSP configuration pom.xml - maven 2 dependency configuration, including required repositories, RESTEasy dependencies and embedded Jetty setup Source Code: The code we're going to show you can be broken down into four layers: Controller - Controlling the flow between the HTTP request, the Model and the View ContactsResource.java - a RESTful Controller with JAX-RS annotations and some traditional HTML controller methods. It will be annotated with Spring's @Controller and @Autowired annotations as well. Model - the domain model and service objects in our case. In our case, we have 2 domain objects: Contact and Contacts; and 1 Service object: ContractService Contact.java - a JAXB domain object with contact information Contacts.java - a JAXB wrapper object that wraps a Contact List ContactService.java - a Map based repository of Contact instances View - How the domain model is transformed for consumer use. JAX-RS performs automated conversion to XML based on annotations on our domain model. We'll be using JSP for object to HTML conversion. contacts.jsp - a bare bones HTML view of our Contacts Test - JAX-RS provides quite a bit of functionality, we're writing quite a bit of code, and all of that is wrapped in quite a bit of configuration. This article will focus on testing our code, configuration and deployment in an automated JUnit test. ContractTest.java - a RESTEasy ReSTful Unit test for the ContractsResource functionality, embedded server included There's a lot of ground to cover, and we'll cover the most interesting pieces of the source first. Our first pass will cover the web.xml and springmvc-servlet.xml configuration files as well as the ContactsResource.java and ContactTest.java source files. Our second pass will cover the remaining topics. Core RESTEasy/Spring MVC artifacts web.xml Spring MVC's entry point is the DispatcherServlet. There are two parts in setting up the DispatcherServlet, the first is to map the servlet to the URL pattern which must follow the rules specified in Section 11.2 of Servlet API Specification. The next step is configure the behavior of the the servlet by providing the configuration file which we call 'springmvc-servlet.xml'. By default, DispatcherServlet looks for a configuration file at "WEB-INF/{servlet-name}-servlet.xml" to find it's configuration, but we're going to use a Spring configuration from the classpath so that the configuration can be reused later in our junit test case. springmvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springmvc-servlet.xml springmvc /contacts/* All requests will be forwarded to the Spring MVC DispatcherServlet. One can get much more sophisticated, but this is one of the simplest simplest web.xml you can create to integrate with Spring. Note that there isn't any reference here to a RESTEasy servlet. Other JAX-RS/Spring integrations require you to have an implementation specific Servlet to serve XML or JSon and a separate Spring MVC DispatcherServlet mapping to server HTML requests. RESTEasy integrates with DispatcherServlet to allow Spring MVC to direct the URL to either RESTEasy Resources or Spring MVC Controllers. Next, let's take a look at the Spring MVC configuration. springmvc-servlet.xml In our basic project, there are five things we need to do in the springmvc-servlet.xml file. Register the Spring namespace Register the package(s) to scan for Spring MVC annotations. Configure the context annotation processor. Import the springmvc-resteasy.xml configuration file which specifies the default RESTEasy/Spring MVC integration Spring beans. Configure the ViewResolver bean to configure the presentation layer to use JSP. Let's inspect the springmvc-servlet.xml file and focus on each of the above items. The springmvc-servlet.xml file itself is pretty short and shows off some of the features from Spring 2.5: Demystifying the Spring Configuration Spring allows for custom namespaces to reduce the verbosity of the configuration files. We make use of the namepsace by registering it in lines 3 and 4. Line 6 (component-scan) informs spring about which package(s) we want to scan and create the custom component object instances, such as controllers and service objects. We tell Spring about the packages we're interested in by using the custom namespace and set the base-package attribute with the packages we're interested in (org.jboss.resteasy.examples.springmvc ). Later on, you'll see that we're going to be using two Spring annotations that allow the Spring runtime to glean Dependency Management information directly from the object itself: @Controller and @Service. Line 7 (annotation-config) tells Spring that our application will be using annotations on how to configure the beans created by the (component-scan) operation of line 6. Spring looks for annotations such as Spring's @Autowired and @Required; JEE's @Resource; and JPA's @PersistenceContext and @PersistenceUnit to describe dependencies between bean instances. annotation-configSpring also looks for life-cycle annotations such as JSR 250's @PostConstruct and @PreDestroy. Our environment requires a dependency between our Controller and Service objects, and the annotation-config declaration will assist us to configure that relationship in Java code. Line 8 (import) is all the XML that is necessary to configure a RESTEasy environment in Spring MVC. The nice thing about the integration with RESTEasy is that most of the configuration is done for you within an embedded configuration file called springmvc-resteasy.xml. Lines 9-14 tell Spring how we intend to handle the rendering of our presentation layer. In our case, we want to use JSTL views that translate view names (such as "contact") to a JSP page found in the /WEB-INF/ directory (specifically /WEB-INF/contacts.jsp in our case). For more information about setting up Spring views, take a look at the spring documentation. Next, let's take a look at how you can mix and match Spring and JAX-RS annotations in a Controller/Resource. ContactsResource.java MVC Controllers control the flow between the Model and the View. Resource is REST's equivalent to Controllers, and we'll be using the term Resource and Controller interchangably. In our case, our resource handles requests to /contracts and /contracts/{id}. Our ContractsResource must perform quite a few functions on those two URL templates: Retrieve all Contacts - Display the results in either HTML, XML or JSon. For clarity, we'll break out the data oriented functionality (XML and JSon) from the user oriented functionality (HTML) into two distinct URLs - /contacts for HTML and /contacts/data for XML and JSon. REST allows a client to select which format it prefers to receive the data in through a process called Content Negotiation. Content Negotiation can happen through HTTP headers, URI or query parameters. Our ContractsResource will use different URIs to differentiate between data oriented and user views, and will use HTTP headers to differentiate between XML and JSon data views. Save a Contact - Create or Updating data is a pretty standard requirement. The Save a Contact functionality mirrors the Content Negotiation needs of Retrieve all Contacts. User oriented data exchange comes in the form of HTML form data, and data oriented exchange usually occurs in XML and JSon. These differing requirements require ContractResource to have two distinct JAX-RS Java methods; we'll also separate the URLs for clarity purposes. View a Contact - We'll create a single view for viewing a single contact that returns XML or JSon. We leave the user oriented view as an exercise for the reader. Here's another view of our requirements: Functionality URL Format Java Method User Oriented View All /contacts HTML viewAll() Data Oriented View All /contacts/data XML or JSon getAll() User Oriented Save /contacts/ Form data saveContactForm() Data Oriented Save /contacts/data XML or JSon saveContact() Data Oriented View Single /contacts/data/{lastName} XML or JSon get() Note that we mixed and matched HTML and data oriented functionality in this requirement. Now that we have our requirements in place, let's take a look at the ContactsResource code. There are quite a few new Spring and JAX-RS annotations which we'll explain right after the code: @Controller @Path(ContactsResource.CONTACTS_URL) public class ContactsResource { public static final String CONTACTS_URL = "/contacts"; @Autowired ContactService service; @GET @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Path("data") public Contacts getAll() { return service.getAll(); } @GET @Produces(MediaType.TEXT_HTML) public ModelAndView viewAll() { // forward to the "contacts" view, with a request attribute named // "contacts" that has all of the existing contacts return new ModelAndView("contacts", "contacts", service.getAll()); } @PUT @POST @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Path("data") public Response saveContact(@Context UriInfo uri, Contact contact) throws URISyntaxException { service.save(contact); URI newURI = UriBuilder.fromUri(uri.getPath()).path(contact.getLastName()).build(); return Response.created(newURI).build(); } @POST @PUT @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.TEXT_HTML) public ModelAndView saveContactForm(@Form Contact contact) throws URISyntaxException { service.save(contact); return viewAll(); } @GET @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Path("data/{lastName}") public Contact get(@PathParam("lastName") String lastName) { return service.getContact(lastName); } } This code is packed with annotations and Java code that's indicative of JAX-RS Resources and Spring applications. There is also a RESTEasy custom annotation. The Spring IoC annotations are well documented, but we are using them in unusual ways for our integration: @Controller tells the Spring runtime that it needs to create an instance of ContractsResource at startup time. Do you remember the component-scan directive that was used in the Spring configuration section? The combination of the directive and the annotation tell Spring that a singleton instance of ContractsResource must be created at startup. Spring has a more generic @Component, but the use of @Controller allows for more precise definition of bean usage and also allows for future upgrades that involve AoP to create more precise targeting. While @Controller is usually associated with Spring @MVC annotated controllers and not other Controller infrastructures, but even thought it's not a Spring MVC controller, we use it to tell Spring that this indeed is a Controller That association of @Controller to Spring MVC annotated controllers is a loose coupling in the Spring runtime. We'll use JAX-RS annotations to configure the handling of URL and HTTP handling behavior. You could theoretically add additional Spring @MVC annotations such as @RequestMapping (which is an equivalent of JAX-RS @Path) to our ContactsResource, if you really wanted to @Autowired tells the Spring runtime that instances of ContractResource require an instance of ContactService. We'll be coding the ContactService later in this article. You can take a look at the Spring reference documentation for more information about @Autowired and @Controller. The last Spring artifact that we use is ModelAndView: It is Spring MVC's encapsulation of which logical View to use and which Model variables should be passed into the View. In our case, we're going to create a Model variable called "contacts" that is a List of all Contact objects we have in the system. We're passing that variable to the a logical view named "contacts" which will map to "/WEB-INF/contacts.jsp" based on the Spring configuration that we previously discussed. The JAX-RS annotations are also well documented, but it's definitely worth while to give a brief overview: @Path tells the RESTEasy (or other JAX-RS environments) how to map URLs to java methods. Adding @Path at the class level tells, in our case "/contacts", indicates that all methods must be prefixed with that URL. The @Path value can either be a hard coded URL such as "/contacts" or it can be a URI template such as "data/{lastName}". You can even specify regular expressions for more sophisticated filtering in the URI template. @GET, @PUT and @POST are used in combination with @Path to indicate which specific HTTP methods are handled by individual Java methods @Produces and @Consumes are used to further filter how a request should be handled based on content negotiation based on the Accept and Content_Type HTTP header. JAX-RS provides a set of default mime type values in the MediaType class. @PathParam is a method parameter annotation that indicates how a URI template variable is mapped to a method parameter. There are quite a few other method parameter level annotations that you could use to map HTTP headers, cookies, query parameters and form parameters to member variables @Context is an interesting JAX-RS parameter that allows dependency injection of request level information such as HttpRequest, HttpResponse and UriInfo (which as you can probably guess encapsuldates information about the request URI). It's important to note that Spring by default manages beans such as ContactsResource as a singleton; if ContactsResource was a Prototype or Request scoped bean, you would be able to use the @Context annotation on member variables in addition to method variables. For more on Spring scoping see the Spring Framework documentation. The last annotation we need to talk about is @Form. It's a RESTEasy custom annotation that describes that a member variable encapsulates data from HTML forms. If you recall, we used the JAX-RS @FormParam annotation on our Contact domain object. @Form and @FormParam are used in concert to allow for better maintenance of form based processing systems. JAX-RS 2.0's stated goals include a more robust, uniform Form processing annotation system. The functionality to code ratio is pretty high because of all of the declarative coding conventions of these annotations. Now that we've discussed the most involved pieces of the puzzle, let's take a look at completing the project. Additional Artifacts pom.xml Our pom.xml includes dependency management, description of required Maven repositories, a description of which JDK we're going to use and a Jetty web server configuration. We'll cover the repository selection, the dependencies specific to RESTEasy and a jetty-maven integration External Repositories jboss jboss repo http://repository.jboss.org/maven2 scannotation http://scannotation.sf.net/maven2 java.net http://download.java.net/maven/1 legacy maven repo maven repo http://repo1.maven.org/maven2/ Project Dependencies Now that we've informed Maven which additional repositories are required, we can now include the dependencies the our sample project will require. The section of the pom.xml file, should include the following two dependencies for Spring and RESTEasy functionality - resteasy-spring and resteasy-jaxb-provider: org.jboss.resteasy resteasy-spring 1.2.RC1 org.jboss.resteasy resteasy-jaxb-provider 1.2.RC1 org.mortbay.jetty maven-jetty-plugin 6.1.15 test The resteasy-spring dependency includes the adapter that integrates RESTEasy into Spring's MVC and provides most the required Java dependencies for RESTEasy and Spring. It also contains Spring configuration needed within the embedded spring-resteasy.xml file that will be used in the Spring configuration section. The other RESTEasy dependency that's included, resteasy-jaxb-provider, contains classes that convert the payload into various formats before sending it to the client. The last dependency to focus on is the maven-jetty-plugin which allows us to easily startup our project in a Jetty webserver environment. Note: If you're follow the link above to the RESTEasy repository's version of pom.xml, you will have to modify the version of resteasy-spring and resteasy-jaxb-provider to the latest version that has been deployed, specifically 1.2.RC1 at the time this article was written. The RESTEasy repository contains a soon-to-be-deployed version number which will not work unless you build the entire RESTEasy project. Maven Jetty Plugin One last interesting item of pom.xml is the configuration of the Jetty web server resteasy-springMVC org.mortbay.jetty maven-jetty-plugin 6.1.15 / 2 ... This will allow us to startup Jetty against localhost:8080. You can learn more about the maven Jetty plugin and a variety of configuration options. Let's start with the domain model and move on to the service object. From there, we'll discuss the JAX-RS Resource/Controller. From there, we'll explore the unit test and finally we'll write the JSP View and start up our server. Contact.java Our DTO is going to be deceptively simple. It will perform a dual responsiblity of JAXB XML binding and Form parameter binding. Both sets of functionality will be configured through annotations and will be managed through JAXB and JAX-RS: import javax.ws.rs.FormParam; import javax.xml.bind.annotation.XmlRootElement; @XMLRootElement public class Contact { private String firstName, lastName; // default constructor for JAXB (also required by JPA/Hibernate if you use them) public Contact(){} // helper constructor for our Controller/Service operations public Contact(String firstName, String lastName){ this.firstName = firstName; this.lastName = lastName; } @FormParam("firstName") public void setFirstName(String firstName) { this.firstName = firstName; } public String getFirstName() { return firstName; } @FormParam("lastName") public void setLastName(String lastName) { this.lastName = lastName; } public String getLastName() { return lastName; } // equals and hasCode are added for the Map based Service object public boolean equals(Object other){ .. } public long hashCode(){ .. } } The annotation on the setters tells JAX-RS to bind any incoming form parameters to the appropriate setter. The @XMLRootElement annotation is enough to tell JAXB that the Contract object must be bound to getters and setters must be bound to an XML document that will look like: Richard Burton Contacts.java The Contacts class is a simple wrapper around a List of Contact instances: @XmlRootElement public class Contacts { private Collection contacts; public Contacts() { this.contacts = new ArrayList(); } public Contacts(Collection contacts) { this.contacts = contacts; } @XmlElement(name="contact") public Collection getContacts() { return contacts; } public void setContacts(Collection contact){ this.contacts = contact; } } Contacts has the @XmlRootElement, just like Contact. The @XmlRootElement annotation tells JAXB to transform objects of this type to an XML structure that has as its top level element. In addition, we've added the @XmlElement annotation to the getContacts() method. By default, JAXB renders all JavaBean elements and uses the JavaBean name as the element. JAXB handles Lists as special cases: all List elements are translated to XML elements using the JavaBean name. @XmlElement(name="contact") tells JAXB that we opted to override the default name ("contracts") in favor of our own name ("contract" - no 's'). The Contracts object will bind to XML that looks like: Richard Burton Solomon Duskis Now that we have our Domain model in place, let's start using it in our Service tier. ContactService.java Since the purpose of this article is JAX-RS centric, we're not going to create an elaborate service layer, but we'll add once since creating more robust Spring applications do require service or data access layers. If you're interested in seeing a RESTEasy/Spring application with database access, look here. Our ContractService performs simple in-memory storage of Contacts by last name: @Service public class ContactService { private Map contactMap = new ConcurrentHashMap(); public void save(Contact contact){ contactMap.put(contact.getLastName(), contact); } public Contact getContact(String lastName){ return contactMap.get(lastName); } public Contacts getAll() { return new Contacts(contactMap.values()); } } There are two items of interest that are noteworthy: Notice the use of Spring's @Service annotation. Do you remember the component-scan directive that was used in the Spring configuration section? The combination of the directive and the annotation tell Spring that a singleton instance of ContractService must be created at startup. Spring has a more generic @Component, but the use of @Service allows for more precise definition of bean usage and also allows for future upgrades that involve AoP to create more precise targeting. Notice the use of ConcurrentHashMap. It's a JDK 1.5 addition that adds performance in multi-threaded environments. It's an easy way to boost performance in distributed REST applications Next, let's take a look at the JSP that contacts.jsp We've explored the Model and Controller aspects of MVC. The last piece to the puzzle is the View. Most JAX-RS based interactions perform a more automated conversion of objects like our Contact to a data-oriented view, such as XML or JSon. Traditionally, Java EE MVC has been done with a more manual View management with languages such as JSP. Our JSP will take a Contracts instance created in ContractsResources.viewAll() and render it in basic HTML: Hello Contacts! Hello ${contact.firstName} ${contact.lastName} Save a contact, save the world: First Name: Last Name: This JSP loops over all contacts and adds links to their data-oriented View. It also creates a simple HTML form for creating a new Contact. While this JSP is simple, it will help us exercise three of our ContactsResource Controller: viewAll(), .saveContactForm(), and get(). It could also be a spring board for more complicated AJAX/JSon interaction, but that's beyond the scope of this article. The code and configuration is now complete, so let's run this project! Jetty Running Jetty is rather simple. You've seen most of the details of the pom.xml when we previously discussed it. Running jetty through maven involves running the following command: mvn jetty:run (If you haven't done so already, download the file as a tar ball, and change the pom.xml's version of the two RESTEasy dependencies to 1.2.RC1) That command will launch Jetty, and allow you to browse our project at http://localhost:8080/contacts. Add a few contacts, and view them either as a group at /contacts in HTML, as a group in XML at /contact/data, or individually as XML by following the links found at /contacts. Congratulations. You now have a running Spring MVC/RESTEasy application. We need one more thing to consider this application complete: a JUnit test. ContractTest.java RESTEasy provides a mechanism for easily launching a Spring MVC/RESTEasy application. RESTEasy also comes with a robust REST client framework. This article will cover bits and pieces of the test, but you can view the entire code in the RESTEasy SVN. To start, we're going to set up an interface that the RESTEasy client can use to create a client for our application. It consists of abstract methods annotated with JAX-RS annotations: @Path(ContactsResource.CONTACTS_URL) public interface ContactProxy { @Path("data") @POST @Consumes(MediaType.APPLICATION_XML) Response createContact(Contact contact); @GET @Produces(MediaType.APPLICATION_XML) Contact getContact(@ClientURI String uri); @GET String getString(@ClientURI String uri); } All methods on ContactProxy inherit the ContactsResource.CONTACTS_URL path ("/contacts") as the root URL, just like a server-side JAX-RS resource. This interface's has three methods: Create a contact - the createContact method maps to a POST to "/contacts/data". The method accepts a Contact object which will be converted to XML before it's sent to the server. The result is a JAX-RS Response object which contains the response status and headers. One of those headers includes the LOCATION of the new contact Get an XML Contact - Given a URL to a Contact, such as the URL returned by the createContact method's response's LOCATION header, GET an XML response and create a Contact object from it. Get a Response as a String - Given a URL, such as a Contact URL or anything else on the server, retrieve a String result. This interface will be used by RESTEasy to construct a concrete instance that uses the JAX-RS annotations to perform the actual HTTP calls. Next, let's create the embedded server and use RESTEasy to create that instance of a ContactProxy: private static ContactProxy proxy; private static TJWSEmbeddedSpringMVCServer server; public static final String host = "http://localhost:8080/"; @BeforeClass public static void setup() { server = new TJWSEmbeddedSpringMVCServer("classpath:springmvc-servlet.xml", 8080); server.start(); RegisterBuiltin.register(ResteasyProviderFactory.getInstance()); proxy = ProxyFactory.create(ContactProxy.class, host); } @AfterClass public static void end() { server.stop(); } JUnit invokes methods annotated by @BeforeClass before any test methods run. Methods annotated by @AfterClass are triggered by JUnit before after all test methods are complete. In our case, the setup method will instantiate a server that contains a SpringMVC Servlet on port 8080 that is configured by the same Spring XML configuration file we used in Jetty. It also invokes the two lines of code required to create a RESTEasy client. RegisterBuiltin sets up the RESTEasy run time, and must be run one time per client. ProxyFactory.create tells RESTEasy to read the annotations on the ContactProxy interface and to create a Java Proxy instance that knows how to perform the HTTP requests we'll need for our test: @Test public void testData() { Response response = proxy.createContact(new Contact("Solomon", "Duskis")); String duskisUri = (String) response.getMetadata().getFirst(HttpHeaderNames.LOCATION); Assert.assertTrue(duskisUri.endsWith(ContactsResource.CONTACTS_URL + "/data/Duskis")); Assert.assertEquals("Solomon", proxy.getContact(duskisUri).getFirstName()); ... } This test creates a new Contact, checks the server's response to make sure that the URL is consistent with the test's expectations. It then re-retrieves the Contact and confirms that the firstName is indeed what was sent sent in. While this is a pretty trivial looking test, it performs quite a bit of HTTP activity and business logic. Conclusion This article discussed quite a bit of philosophy and design considerations in building a RESTful web application with RESTEasy and Spring MVC. We also built an end to end application with RESTEasy, Spring MVC, Maven, Jetty and JUnit. Even though the content in this article was significant, the code presented here is relatively short compared to other Java alternatives. We touched on subjects like designing REST Applications, creating Spring applications, the RESTEasy client infrastructure and testing RESTful applications. Each of those subjects merit their own articles. There were also other subjects that we simply couldn't fit into this article (as long as it is), including JavaScript to the toolkit to allow closer integration between the browser and your RESTful application, integrating with Flex and more. The code presented in this article can serve as a spring board (again, no pun intended) for all of those ideas. About the Authors Solomon Duskis Solomon Duskis is a Senior Manager at SunGard Consulting Services. He's been developing for 22 years -- 12 years in professional capacity. He has experience in various industries such as Finance, Media, Insurance and Health. He contributes to Open Source projects such as JBoss Resteasy and the Spring framework. He is a published author of Spring Persistence - A Running Start, and the upcoming book Spring Persistence with Hibernate. Richard Burton Richard Burton is the co-founder of a small independent consulting firm called SmartCode LLC. He is an Open Source fanatic with over 10 years of experience in various industries such as Automotive, Insurance, Finance and fondly remembers the .com era. In his spare time, he contributes to Open Source projects such as SiteMesh 3, Struts 2, and more. Reference REST Roy Fielding's REST Thesis - Architectural Styles and the Design of Network-based Software Architectures(December 2000) Bill Burke's (August 2008 - DZone) How to GET a cup of coffee (October 2008 - InfoQ) Roy Fielding REST APIs Must Be Hypertext Driven (October 2008 - Untagled Roy's blog - take a look at the URI: roy.gbiv.com ) JAX-RS Bill Burke's (September 2008 - DZone) An overview of JAX-RS 1.0 Features James Strachan's JAX-RS as the one Java web framework to rule them all? (January 2009 - James' blog) RESTEasy RESTEasy project A blog about Spring + RESTEasy Getting Started with RESTEasy Spring Spring 2.5 reference Oh, just search google for "spring framework" Spring MVC Spring MVC Reference Spring MVC Step By Step Spring MVC Tutorial
October 15, 2009
by Solomon Duskis
· 141,356 Views · 1 Like
article thumbnail
Managing Eclipse RCP Launch Arguments
in my last post i discussed how to best manage run configurations for eclipse rcp applications . but there was one related topic i wanted to discuss in more detail, and that is how to manage launch arguments. what are launch arguments? launch arguments are arguments that are added to the command line when you execute your application. these arguments come in two flavors: program arguments – arguments that are eclipse-specific. for example, the -clean argument will clear the configuration area on startup. vm arguments – arguments that make sense to the java vm. for example, the -xmx argument allows you to set the maximum heap size for the vm. both of these argument types can be set on the arguments tab in the run configurations dialog. launch arguments and the target platform we oftentimes want to apply the same launch arguments to all of our run configurations, and one way to handle that is to specify them on your target platform . on the target platform preference page there is a section where you can add whatever arguments you wish. the arguments associated with a target platform will be added to run configurations generated from the manifest editor . they will not be added to configurations generated by the product configuration editor. also, because the manifest editor link does not regenerate a configuration each time, you will need to explicitly delete a configuration if you want to recreate it using new target platform arguments. launch arguments and products a second way to manage arguments is to add them using the launching tab of the product configuration editor. when you add arguments in this way, two things will happen: the arguments will be added to your run configurations if you launch using the link in the product configuration editor . because this link regenerates the run configuration each time, consistent use of the link guarantees that your configuration is in synch with your product definition. the arguments will also be added to your deployed application in the form of an ini file. this is a nice feature, but it means that you need to be careful when adding arguments that are only useful during development. for example, you may want to use -clean to clear the configuration area when you’re developing, but you probably do not want to ship this argument to your customers. launch arguments best practices my approach is to add arguments using the product configuration editor and to always launch my applications using the link in that editor. this guarantees that my run configurations are always in synch with my product definition. i also take care to not add arguments that would be detrimental to a deployed application. some, such as -consolelog, i consider harmless in a deployed app and i just leave those in. if for some reason i absolutely have to add an argument that should not be deployed, i usually clean it out of the ini file during the build process. it’s pretty rare for me to have to do this, though. from http://www.modumind.com
September 9, 2009
by Patrick Paulin
· 10,850 Views
article thumbnail
Spring Integration: A Hands-On Tutorial, Part 1
This tutorial is the first in a two-part series on Spring Integration. In this series we're going to build out a lead management system based on a message bus that we implement using Spring Integration. Our first tutorial will begin with a brief overview of Spring Integration and also just a bit about the lead management domain. After that we'll build our message bus. The second tutorial continues where the first leaves off and builds the rest of the bus. I’ve written the sample code for this tutorial as a Maven 2 project. I’m using Java 5, Spring Integration 1.0.3 and Spring 2.5.6. The code also works for Java 6. I've used Maven profiles to isolate the dependencies you’ll need if you’re running Java 5. The tutorials assume that you're comfortable with JEE, the core Spring framework and Maven 2. Also, Eclipse users may find the m2eclipse plug-in helpful. To complete the tutorial you'll need an IMAP account, and you'll also need access to an SMTP server. Let's begin with an overview of Spring Integration. A bird's eye view of Spring Integration Spring Integration is a framework for implementing a dynamically configurable service integration tier. The point of this tier is to orchestrate independent services into meaningful business solutions in a loosely-coupled fashion, which makes it easy to rearrange things in the face of changing business needs. The service integration tier sits just above the service tier as shown in figure 1. Following the book Enterprise Integration Patterns by Gregor Hohpe and Bobby Woolf (Addison-Wesley), Spring Integration adopts the well-known pipes and filters architectural style as its approach to building the service integration layer. Abstractly, filters are information-processing units (any type of processing—doesn’t have to be information filtering per se), and pipes are the conduits between filters. In the context of integration, the network we’re building is a messaging infrastructure—a so-called message bus—and the pipes and filters and called message channels and message endpoints, respectively. The network carries messages from one endpoint to another via channels, and the message is validated, routed, split, aggregated, resequenced, reformatted, transformed and so forth as the different endpoints process it. Figure 1. The service integration tier orchestrates the services below it. That should give you enough technical context to work through the tutorial. Let’s talk about the problem domain for our sample integration, which is enrollment lead management in an online university setting. Lead management overview In many industries, such as the mortgage industry and for-profit education, one important component of customer relationship management (CRM) is managing sales leads. This is a fertile area for enterprise integration because there are typically multiple systems that need to play nicely together in order to pull the whole thing off. Examples include front-end marketing/lead generation websites, external lead vendor systems, intake channels for submitted leads, lead databases, e-mail systems (e.g., to accept leads, to send confirmation e-mails), lead qualification systems, sales systems and potentially others. This tutorial and the next use Spring Integration to integrate several of systems of the kind just mentioned into an overall lead management capability for a hypothetical online university. Specifically we’ll integrate the following: • a CRM system that allows campus and call center staff to create leads directly, as they might do for walk-in or phone-in leads • a Request For Information (RFI) form on a lead generation ("lead gen") marketing website • a legacy e-mail based RFI channel • an external CRM that the international enrollment staff uses to process international leads • confirmation e-mails Figure 2 shows what it will look like when we’re done with both tutorials. For now focus on the big picture rather than the details. Figure 2. This is the lead management system we'll build. For this first tutorial we're simply going to establish the base staff interface, the (dummy) backend service that saves leads to a database, and confirmation e-mails. The second tutorial will deal with lead routing, web-based RFIs and e-mail-based RFIs. Let's dive in. We’ll begin with the basic lead creation page in the CRM and expand out from there. Building the core components [You can download the source code for this section of the tutorial here] We’re going to start by creating a lead creation HTML form for campus and call center staff. That way, if walk-in or phone-in leads express an interest, we can get them into the system. This is something that might appear as a part of a lead management module in a CRM system, as shown in figure 3. Figure 3. We'll build our lead management module with integration in mind from the beginning. Because we’re interested in the integration rather than the actual app features, we’re not really going to save the lead to the database. Instead we’ll just call a createLead() method against a local LeadService bean and leave it at that. But we will use Spring Integration to move the lead from the form to the service bean. Our first stop will be the domain model. DZone readers get 30% off Spring in Practice by Willie Wheeler and John Wheeler. Use code dzone30 when checking out with any version of the book at www.manning.com. Create the domain model We’ll need a domain object for leads, so listing 1 shows the one we’ll use. It’s not an industrial-strength representation, but it will do for the purposes of the tutorial. Listing 1. Lead.java, a basic domain object for leads. package crm.model;... other imports ...public class Lead { private static DateFormat dateFormat = new SimpleDateFormat(); private String firstName; private String middleInitial; private String lastName; private String address1; private String address2; ... other fields ... public Lead() { } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } ... other getters and setters, and a toString() method ...} There is nothing special happening here at all. So far the Lead class is just a bunch of getters and setters. You can see the full code listing in the download. If you thought that was underwhelming, just wait until you see the LeadServiceImpl service bean in listing 2. Listing 2. LeadServiceImpl.java, a dummy service bean. package crm.service;import java.util.logging.Logger;import org.springframework.stereotype.Service;import crm.model.Lead;@Service("leadService")public class LeadServiceImpl implements LeadService { private static Logger log = Logger.getLogger("global"); public void createLead(Lead lead) { log.info("Creating lead: " + lead); } This is just a dummy bean. In real life we’d save the lead to a database. The bean implements a basic LeadService interface that we've suppressed here, but it's available in the code download. Now that we have our domain model, let’s use Spring Integration to create a service integration tier above it. Create the service integration tier If you look back at figure 3, you’ll see that the CRM app pushes lead data to the service bean by way of a channel called newLeadChannel. While it’s possible for the CRM app to push messages onto the channel directly, it’s generally more desirable to keep the systems you’re integrating decoupled from the underlying messaging infrastructure, such as channels. That allows you to configure service orchestrations dynamically instead of having to go into the code. Spring Integration supports the Gateway pattern (described in the aforementioned Enterprise Integration Patterns book), which allows an application to push messages onto the message bus without knowing anything about the messaging infrastructure. Listing 3 shows how we do this. Listing 3. LeadGateway.java, a gateway offering access to the messaging system. package crm.integration.gateways;import org.springframework.integration.annotation.Gateway;import crm.model.Lead;public interface LeadGateway { @Gateway(requestChannel = "newLeadChannel") void createLead(Lead lead);} We are of course using the Spring Integration @Gateway annotation to map the method call to the newLeadChannel, but gateway clients don’t know that. Spring Integration will use this interface to create a dynamic proxy that accepts a Lead instance, wraps it with an org.springframework.integration.core.Message, and then pushes the Message onto the newLeadChannel. The Lead instance is the Message body, or payload, and Spring Integration wraps the Lead because only Messages are allowed on the bus. We need to wire up our message bus. Figure 4 shows how to do that with an application context configuration file. Listing 4. /WEB-INF/applicationContext-integration.xml message bus definition. The first thing to notice here is that we've made the Spring Integration namespace our default namespace instead of the standard beans namespace. The reason is that we're using this configuration file strictly for Spring Integration configuration, so we can save some keystrokes by selecting the appropriate namespace. This works pretty nicely for some of the other Spring projects as well, such as Spring Batch and Spring Security. In this configuration we've created the three messaging components that we saw in figure 3. First, we have an incoming lead gateway to allow applications to push leads onto the bus. We simply reference the interface from listing 3; Spring Integration takes care of the dynamic proxy. Next we create a publish/subscribe ("pub-sub") channel called newLeadChannel. This is the channel that the @Gateway annotation referenced in listing 3. A pub-sub channel can publish a message to multiple endpoints simultaneously. For now we have only one subscriber—a service activator—but we already know we're going to have others, so we may as well make this a pub-sub channel. The service activator is an endpoint that allows us to bring our LeadServiceImpl service bean onto the bus. We're injecting the newLeadChannel into the input end of the service activator. When a message appears on the newLeadChannel, the service activator will pass its Lead payload to the leadService bean's createLead() method. Stepping back, we've almost implemented the design described by figure 3. The only part that remains is the lead creation frontend, which we'll address right now. Create the web tier Our user interface for creating new leads will be a web-based form that we implement using Spring Web MVC. The idea is that enrollment staff at campuses or call centers might use such an interface to handle walk-in or phone-in traffic. Listing 5 shows our simple @Controller. Listing 5. LeadController.java, a @Controller to allow staff to create leads package crm.web;import java.util.Date;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import crm.integration.gateways.LeadGateway;import crm.model.Country;import crm.model.Lead;@Controllerpublic class LeadController { @Autowired private LeadGateway leadGateway; @RequestMapping(value = "/lead/form.html", method = RequestMethod.GET) public void getForm(Model model) { model.addAttribute(Country.getCountries()); model.addAttribute(new Lead()); } @RequestMapping(value = "/lead/form.html", method = RequestMethod.POST) public String postForm(Lead lead) { lead.setDateCreated(new Date()); leadGateway.createLead(lead); return "redirect:form.html?created=true"; } This isn't an industrial-strength controller as it doesn't do HTTP parameter whitelisting (for example, via an @InitBinder method) and form validation, both of which you would expect from a real implementation. But the main pieces from a Spring Integration perspective are here. We're autowiring the gateway into the @Controller, and we have methods for serving up the empty form and for processing the submitted form. The getForm() method references a Countries class that we've suppressed (it's in the code download); it just puts a list of countries on the model so the form can present a Country field to the staff member. The postForm() method invokes the createLead() method on the gateway. This will pass the Lead to the dynamic proxy LeadGateway implementation, which in turn will wrap the Lead with a Message and then place the Message on the newLeadChannel. There are a few other configuration files you will need to put in place, including web.xml, main-servlet.xml and applicationContext.xml. There's also a JSP for the web form. As none of these relates directly to Spring Integration, we won't treat them here. Please see the code download for details. With that, we've established a baseline system. To try it out, run mvn jetty:run against crm/pom.xml and point your browser at http://localhost:8080/crm/main/lead/form.html You should see a very basic-looking web form for entering lead information. Enter some user information (it doesn't matter what you enter—recall that we don't have any form validation) and press Submit. The console should report that LeadServiceImpl.createLead() created a lead. Congratulations! Even though we now have a working system, it isn't very interesting. From here on out (this tutorial and the next) we'll be adding some common features to make the lead management system more capable. Our first addition will be confirmation e-mails; the next tutorial will present further additions. Adding confirmation e-mails [The source for this section is available here] After an enrollment advisor (or some other staff member) creates a lead in the system, we want to send the lead an e-mail letting him know that that's happened. Actually—and this is a critical point—we really don't care how the lead was created. Anytime a lead appears on the newLeadChannel, we want to fire off a confirmation e-mail. I'm making the distinction because it points to an important aspect of the message bus: it allows us to control lead processing code centrally instead of having to chase it down in a bunch of different places. Right now there's only one way to create leads, but figure 2 revealed that we'll be adding others. No matter how many we add, they'll all result in sending a confirmation e-mail out to the lead. Figure 4 shows the new bit of plumbing we're going to add to our message bus. Figure 4. Send a confirmation e-mail when creating a lead. To do this, we're going to need to make a few changes to the configuration and code. POM changes First we need to update the POM. Here's a summary of the changes; see the code download for details: • Add a JavaMail dependency to the Jetty plug-in. • Add an org.springframework.context.support dependency. • Add a spring-integration-mail dependency. • Set the mail.version property. These changes will allow us to use JavaMail. Expose JavaMail sessions through JNDI We'll also need to add a /WEB-INF/jetty-env.xml configuration to make our JavaMail sessions available via JNDI. Once again, see the code download for details. I've included a /WEB-INF/jetty-env.xml.sample configuration for your convenience. As mentioned previously, you'll need access to an SMTP server. Besides creating jetty-env.xml, we'll need to update applicationContext.xml. Listing 6 shows the changes we need so we can use JavaMail and SMTP. Listing 6. /WEB-INF/applicationContext.xml changes supporting JavaMail and SMTP The changes expose JavaMail sessions as a JNDI resource. We've declared the jee namespace and its schema location, configured the JNDI lookup, and created a JavaMailSenderImpl bean that we'll use for sending mail. We won't need any domain model changes to generate confirmation e-mails. We will however need to create a bean to back our new transformer endpoint. Service integration tier changes First, recall from figure 4 that the newLeadChannel feeds into a LeadToEmailTransformer endpoint. This endpoint takes a lead as an input and generates a confirmation e-mail as an output, and the e-mail gets pipes out to an SMTP transport. In general, transformers transform given inputs into desired outputs. No surprises there. Figure 4 is slightly misleading since it's actually the POJO itself that we're going to call LeadToEmailTransformer; the endpoint is really just a bean adapter that the messaging infrastructure provides so we can place the POJO on the message bus. Listing 7 presents the LeadToEmailTransformer POJO. Listing 7. LeadToEmailTransformer.java, a POJO to generate confirmation e-mails package crm.integration.transformers;import java.util.Date;import java.util.logging.Logger;import org.springframework.integration.annotation.Transformer;import org.springframework.mail.MailMessage;import org.springframework.mail.SimpleMailMessage;import crm.model.Lead;public class LeadToEmailTransformer { private static Logger log = Logger.getLogger("global"); private String confFrom; private String confSubj; private String confText; ... getters and setters for the fields ... @Transformer public MailMessage transform(Lead lead) { log.info("Transforming lead to confirmation e-mail: " + lead); String leadFullName = lead.getFullName(); String leadEmail = lead.getEmail(); MailMessage msg = new SimpleMailMessage(); msg.setTo(leadFullName == null ? leadEmail : leadFullName + " <" + leadEmail + ">"); msg.setFrom(confFrom); msg.setSubject(confSubj); msg.setSentDate(new Date()); msg.setText(confText); log.info("Transformed lead to confirmation e-mail: " + msg); return msg; } Again, LeadToEmailTransformer is a POJO, so we use the @Transformer annotation to select the method that's performing the transformation. We use a Lead for the input and a MailMessage for the output, and perform a simple transformation in between. When defining backing beans for the various Spring Integration filters, it's possible to specify a Message as an input or an output. That is, if we want to deal with the messages themselves rather than their payloads, we can do that. (Don't confuse the MailMessage in listing 7 with a Spring Integration message; MailMessage represents an e-mail message, not a message bus message.) We might do that in cases where we want to read or manipulate message headers. In this tutorial we don't need to do that, so our backing beans just deal with payloads. Now we'll need to build out our message bus so that it looks like figure 4. We do this by updating applicationContext-integration.xml as shown in listing 8. Listing 8. /WEB-INF/applicationContext-integration.xml updates to support confirmation e-mails The property-placeholder configuration loads the various ${...} properties from a properties file; see /crm/src/main/resources/applicationContext.properties in the code download. You don't have to change anything in the properties file. The transformer configuration brings the LeadToEmailTransformer bean into the picture so it can transform Leads that appear on the newLeadChannel into MailMessages that it puts on the confEmailChannel. As a side note, the p namespace way of specifying bean properties doesn't seem to work here (I assume it's a bug: http://jira.springframework.org/browse/SPR-5990), so I just did it the more verbose way. The channel definition defines a point-to-point channel rather than a pub-sub channel. That means that only one endpoint can pull messages from the channel. Finally we have an outbound-channel-adapter that grabs MailMessages from the confEmailChannel and then sends them using the referenced mailSender, which we defined in listing 6. That's it for this section. We should have working confirmation e-mails. Restart your Jetty instance and go again to http://localhost:8080/crm/main/lead/form.html Fill it out and provide your real e-mail address in the e-mail field. A few moments after submitting the form you should receive a confirmation e-mail. If you don't see it, you might check your SMTP configuration in jetty-env.xml, or else check your spam folder. Summary In this tutorial we've taken our first steps toward developing an integrated lead management system. Though the current bus configuration is simple, we've already seen some key Spring Integration features, including • support for the Gateway pattern, allowing us to connect apps to the message bus without knowing about messages • point-to-point and pub-sub channels • service activators to allow us to place service beans on the bus • message transformers • outbound SMTP channel adapters to allow us to send e-mail The second tutorial will continue elaborating what we've developed here, demonstrating the use of several additional Spring Integration features, including • message routers (including content-based message routers) • outbound web service gateways for sending SOAP messages • inbound HTTP adapters for collecting HTML form data from external systems • inbound e-mail channel adapters (we'll use IMAP IDLE, though POP and IMAP are also possible) for processing incoming e-mails Enjoy, and stay tuned. Willie is a solutions architect with 12 years of Java development experience. He and his brother John are coauthors of the upcoming book Spring in Practice by Manning Publications (www.manning.com/wheeler/). Willie also publishes technical articles (including many on Spring) to wheelersoftware.com/articles/.
August 18, 2009
by Willie Wheeler
· 249,591 Views · 3 Likes
article thumbnail
JPA 2.0 Concurrency and Locking
Optimistic locking lets concurrent transactions process simultaneously, but detects and prevent collisions, this works best for applications where most concurrent transactions do not conflict. JPA Optimistic locking allows anyone to read and update an entity, however a version check is made upon commit and an exception is thrown if the version was updated in the database since the entity was read. In JPA for Optimistic locking you annotate an attribute with @Version as shown below: public class Employee { @ID int id; @Version int version; The Version attribute will be incremented with a successful commit. The Version attribute can be an int, short, long, or timestamp. This results in SQL like the following: “UPDATE Employee SET ..., version = version + 1 WHERE id = ? AND version = readVersion” The advantages of optimistic locking are that no database locks are held which can give better scalability. The disadvantages are that the user or application must refresh and retry failed updates. Optimistic Locking Example In the optimistic locking example below, 2 concurrent transactions are updating employee e1. The transaction on the left commits first causing the e1 version attribute to be incremented with the update. The transaction on the right throws an OptimisticLockException because the e1 version attribute is higher than when e1 was read, causing the transaction to roll back. Additional Locking with JPA Entity Locking APIs With JPA it is possible to lock an entity, this allows you to control when, where and which kind of locking to use. JPA 1.0 only supported Optimistic read or Optimistic write locking. JPA 2.0 supports Optimistic and Pessimistic locking, this is layered on top of @Version checking described above. JPA 2.0 LockMode values : OPTIMISTIC (JPA 1.0 READ): perform a version check on locked Entity before commit, throw an OptimisticLockException if Entity version mismatch. OPTIMISTIC_FORCE_INCREMENT (JPA 1.0 WRITE) perform a version check on locked Entity before commit, throw an OptimisticLockException if Entity version mismatch, force an increment to the version at the end of the transaction, even if the entity is not modified. PESSIMISTIC: lock the database row when reading PESSIMISTIC_FORCE_INCREMENT lock the database row when reading, force an increment to the version at the end of the transaction, even if the entity is not modified. There are multiple APIs to specify locking an Entity: EntityManager methods: lock, find, refresh Query methods: setLockMode NamedQuery annotation: lockMode element OPTIMISTIC (READ) LockMode Example In the optimistic locking example below, transaction1 on the left updates the department name for dep , which causes dep's version attribute to be incremented. Transaction2 on the right gives an employee a raise if he's in the "Eng" department. Version checking on the employee attribute would not throw an exception in this example since it was the dep Version attribute that was updated in transaction1. In this example the employee change should not commit if the department was changed after reading, so an OPTIMISTIC lock is used : em.lock(dep, OPTIMISTIC). This will cause a version check on the dep Entity before committing transaction2 which will throw an OptimisticLockException because the dep version attribute is higher than when dep was read, causing the transaction to roll back. OPTIMISTIC_FORCE_INCREMENT (write) LockMode Example In the OPTIMISTIC_FORCE_INCREMENT locking example below, transaction2 on the right wants to be sure that the dep name does not change during the transaction, so transaction2 locks the dep Entity em.lock(dep, OPTIMISTIC_FORCE_INCREMENT) and then calls em.flush() which causes dep's version attribute to be incremented in the database. This will cause any parallel updates to dep to throw an OptimisticLockException and roll back. In transaction1 on the left at commit time when the dep version attribute is checked and found to be stale, an OptimisticLockException is thrown Pessimistic Concurrency Pessimistic concurrency locks the database row when data is read, this is the equivalent of a (SELECT . . . FOR UPDATE [NOWAIT]) . Pessimistic locking ensures that transactions do not update the same entity at the same time, which can simplify application code, but it limits concurrent access to the data which can cause bad scalability and may cause deadlocks. Pessimistic locking is better for applications with a higher risk of contention among concurrent transactions. The examples below show: reading an entity and then locking it later reading an entity with a lock reading an entity, then later refreshing it with a lock The Trade-offs are the longer you hold the lock the greater the risks of bad scalability and deadlocks. The later you lock the greater the risk of stale data, which can then cause an optimistic lock exception, if the entity was updated after reading but before locking. The right locking approach depends on your application: what is the risk of risk of contention among concurrent transactions? What are the requirements for scalability? What are the requirements for user re-trying on failure? For More Information: Preventing Non-Repeatable Reads in JPA Using EclipseLink Java Persistence API 2.0: What's New ? What's New and Exciting in JPA 2.0 Beginning Java™ EE 6 Platform with GlassFish™ 3 Pro EJB 3: Java Persistence API (JPA 1.0)
August 3, 2009
by Carol McDonald
· 51,575 Views · 1 Like
article thumbnail
Introduction to the Open eHealth Integration Platform
The Open eHealth Integration Platform (IPF) is an extension of the Apache Camel routing and mediation engine and comes with comprehensive support for message processing and connecting information systems in the healthcare sector. It is available under the Apache License version 2.0. IPF and Camel both focus on a domain-specific language (DSL) to implement and combine Enterprise Integration Patterns (EIPs) in integration solutions. IPF leverages the Groovy programming language for application development and for extending the Apache Camel DSL. One example of a healthcare-related use case of IPF is the implementation of interfaces for transactions specified in IHE profiles. The use of IPF to implement actor interfaces for the IHE PIX and PDQ profiles was tested successfully at the 2009 Connect-a-thon. The actual actors were proprietary systems that were IHE-enabled via IPF-based integration solutions. It is important to note that usage of IPF is not just limited to the healthcare domain. It can also be used to build integration solutions for several other domains. However, this article will focus primarily on the healthcare-specific features of IPF. Riding the Camel IPF is built on top of the Apache Camel routing and mediation engine. This section deals briefly with the concepts behind Camel. For a more detailed overview, read Jonathan Anstey's excellent introductory article Apache Camel: Integration Nirvana. Apache Camel is about Enterprise Integration Patterns (EIPs). EIPs have previously been described by Gregor Hohpe and Bobby Woolf in their book Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions. They represent experiences of integration architects and can be used as building blocks for designing integration solutions. These patterns were published as recommendations without implying a concrete implementation. This is where Apache Camel comes in. Camel was created to provide implementations for EIPs. With Apache Camel, integration solutions are developed by combining integration patterns using a domain-specific language (DSL). In addition to EIP implementations, Camel also provides more than 60 components for connecting to a great variety of transports and APIs. The four major concepts in Camel are components, endpoints, processors and the domain-specific language (DSL). Components provide connectivity to other systems. From components, endpoints are created for sending and receiving messages. Endpoints are uniquely identified by their URIs. Processors are used to route and transform messages between endpoints. To wire endpoints and processors together, Camel provides a DSL for Java. Consider a simple example: from("jms:queue:validated") .filter().xpath("/person[@name='Martin']") .to("http://www.example.com/camel"); In this route definition, messages are read from a JMS queue (identified by the jms:queue:validated endpoint URI) and sent through a filter. The filter criterion is an XPath predicate. Any message that passes the filter will be POSTed to the http://www.example.com/camel endpoint. Camel also supports a Spring-based XML configuration for creating message processing routes (not shown here). Riding IPF Any feature provided by Camel can be used in combination with any other features provided by IPF. IPF makes its features available via extensions to the Camel DSL. These extensions have been implemented via Groovy meta-programming. For these extensions to be used in an IPF application, route definitions must be written in Groovy. Here is an example of a route definition that uses IPF's DSL extensions: from('file:input') // read HL7 message from file .unmarshal().ghl7() // create HL7 message object .validate().ghl7() // validate HL7 message object .filter {exchange -> // filter message using criteria defined by closure def msg = exchange.in.body // use exchange.in.body to access HL7 message object msg.PID[8].value == 'F' // use HL7 DSL to access and compare PID-8 field value } .to('http://...') // send message to destination (via HTTP In this route, an HL7 message is read from a file, validated and then filtered based on the value of the 8th field in the PID segment. To obtain this field value, the filter closure uses IPF's HL7 DSL. This DSL is explained in detail in the next section. If the message passes the filter it is forwarded to its destination via HTTP. The route definition uses the DSL elements from, unmarshal, filter and to from Camel directly, all other DSL elements are extensions provided by IPF, including the use of closures for filter criteria. IPF DSL extensions can be used as if they are native Camel DSL elements. Furthermore, the DSL used in applications is not just limited to the DSL provided by Camel and IPF. Application-specific DSL extensions can also be written using IPF's DSL extension mechanism. This mechanism also supports modularization of DSL definitions. Any component can contribute its own DSL extensions. Consequently, the scope of the overall DSL depends on which components were deployed for the application. Inside an OSGi environment, IPF can even automatically detect and activate DSL extensions provided by different bundles. The following sections will explore the healthcare-specific features of IPF in greater detail. For a detailed description of all IPF features consult the IPF reference documentation. For a more hands-on guide on how to write IPF applications, the IPF tutorials are a good starting point. HL7 message processing HL7 (Health Level 7) is an ANSI-accredited standards developing organization (SDO) in the healthcare sector. Among other standards it focuses on developing messaging standards for the clinical and administrative domain. This standard is often referred to as the HL7 messaging standard. There are several versions of this standard. HL7 version 2.x is widely used, the most recent update was version 2.6 in 2007. It differs significantly from the XML-based HL7 version 3. The following subsections focus on IPF's support for HL7 version 2.x. Support for HL7 version 3 is currently under development. IPF uses the open source HAPI library as its basis for HL7 version 2 message processing. HL7 version 2 at a glance HL7 version 2 messages have a hierarchical structure and are organized into groups, segments, fields and datatypes which can also repeat. Message elements are referenced by their path within the hierarchy (see navigation syntax in the following figure). HL7 DSL The core of IPF's HL7 message processing capabilities is the HL7 DSL. This is a domain-specific language for accessing and manipulating HL7 version 2 messages. The IPF library that implements this DSL (modules-hl7dsl) can also be used standalone (i.e. independent from other IPF components) in any Groovy application. Seamless integration into the IPF DSL is provided as well. The following examples presume a certain degree of familiarity with HL7 version 2 message structures and terms. Constructing messages The entry point to the HL7 DSL is IPF's MessageAdapter. To create a MessageAdapter instance from an HL7 file we use the load method from the MessageAdapters utility class. import org.openehealth.ipf.modules.hl7dsl.MessageAdapter import org.openehealth.ipf.modules.hl7dsl.MessageAdapters MessageAdapter message = MessageAdapters.load('ADT-A01.hl7') This loads the HL7 file ADT-A01.hl7 from the classpath. Accessing message content The following example obtains the PID segment contained in the PATIENT group which itself is contained in the first repetition of the repeatable PATIENT_RESULT group. // repeating elements are indexed from 0 to n def segment = message.PATIENT_RESULT(0).PATIENT.PID The function call operator () is used to refer to an element in a repetition. The element index is passed as argument. Obtaining fields is similar to obtaining groups and segments except that fields are often referred to by index rather than by name. To obtain the MSH-3 field from a message we can write: // fields are indexed from 1 to n def composite = message.MSH[3] If the field is a composite we access the second component with: // components of a composite field are indexed from 1 to n def primitive = message.MSH[3][2] or, equivalently, def primitive = message.MSH.sendingApplication.universalIDType As shown above, navigation is also possible using field names instead of indices. Care must be taken, because along with the change of internal message structures, individual field names change between HL7 versions, even when they refer to the same position of the field in a segment. If the version of the HL7 message is not known in advance, it is better to use the more concise index notation. Fields may also repeat. To obtain a given element of a repeating field the function call operator () is used, just like with groups and segments. In the next example we obtain the first element of the repeating NK1-5 field. Because NK1 is a repeating segment, the function call operator is used on segment-level, too. def field = message.NK1(0)[5](0) def fieldList = message.NK1(0)[5]() Omitting the repetition index returns a list of repeating elements. Omitting the function call operator, the first repetition of a group, segment or field is assumed. This is called smart navigation: assert message.NK1(0)[5](0)[1].value == message.NK1[5](0)[1].value assert message.NK1(0)[5](0)[1].value == message.NK1[5][1].value assert message.PATIENT_RESULT(0).PATIENT.PID[5][1] == message.PATIENT_RESULT.PATIENT.PID[5][1] If a component is omitted, the first component or subcomponent of a composite is assumed assert message.NK1(0)[5](0)[1].value == message.NK1[5].value assert message.NK1(0)[5](1)[1].value == message.NK1[5](1).value assert message.NK1(0)[2][1][1].value == message.NK1[2].value Using smart navigation, the expressions are usually shorter and less error-prone. Moreover, in many cases the same expression can be used for different HL7 versions, making the DSL more portable. Modifying message content A segment of one message can be assigned the segment value of another message using the assigment operator (=). The following example copies the EVN segment from message2 to message1. message1.EVN = message2.EVN To change a field value we navigate to that field (either by name or index, as shown above) and assign it a string or another field value. def msh = message.MSH def nk1 = message.NK1(0) msh[5] = nk1[4][4] msh[5] = 'abc' Composite fields may also be changed by assigning other composite fields. In the following example we copy the composite NK1(0)[4] field from message2 to message1. message1.NK1(0)[4] = message2.NK1(0)[4] Externalizing messages The left-shift operator (<<) appends the string-represenation of a MessageAdapter object to a writer. In the following example, we write an HL7 message to System.out. MessageAdapter message = ... System.out << message To obtain the string-representation directly, we can use the MessageAdapter.toString() method. MessageAdapter message = ... def rendered = message.toString() Usage in route definitions This section shows a few examples how to combine the HL7 DSL with IPF's route definition DSL. The unmarshal().ghl7() extension should be used to create a MessageAdapter object from an external HL7 message representation. The created MessageAdapter object can then be used in subsequent processors. from('file:input') .unmarshal().ghl7() .process {exchange -> MessageAdapter message = exchange.in.body ... } ... The reverse operation marshal().ghl7() marshals a MessageAdapter object into a stream. This is often needed for transmitting HL7 messages over a variety of transports such as JMS, for example. from('file:input') .unmarshal().ghl7() ... .marshal().ghl7() .to(jms:queue:validated) Another usage example is content-based routing. In the following example a message is routed to different destinations depending on the content of the MSH[4] field. Here we use closures in combination with Camel's when DSL element for implementing routing rules. The it variable inside closures represents a message exchange. from(...) .unmarshal().ghl7() ... .choice() .when { it.in.body.MSH[4].value == 'ABC' } .to(...) .when { it.in.body.MSH[4].value == 'DEF' } .to(...) .otherwise() .to(...) HL7 validation IPF also adds support for specifying validation rules in a way that is easy to write and simple to understand. It facilitates the definition of custom validation rules by providing a dedicated validation DSL. Like the HL7 DSL, the validation DSL can also be used standalone but also integrates well into the IPF DSL for defining message processing routes. The IPF component that implements HL7 validation is modules-hl7. Validation rules are defined by extending the ValidationContextBuilder class of IPF. The validation rules DSL is provided by the RuleBuilder class. The following example defines a subset of segments from the HL7 version 2.2 specification. package example import ca.uhn.hl7v2.validation.ValidationContext import org.openehealth.ipf.modules.hl7.validation.builder.RuleBuilder import org.openehealth.ipf.modules.hl7.validation.builder.ValidationContextBuilder class SampleRulesBuilder extends ValidationContextBuilder { RuleBuilder forContext(ValidationContext context) { new RuleBuilder(context) .forVersion('2.2') .message('ADT', 'A01').abstractSyntax( 'MSH', 'EVN', 'PID', [ { 'NK1' } ], 'PV1', [ { INSURANCE( 'IN1', [ 'IN2' ] , [ 'IN3' ] )}] ) } } The sequence and cardinality of groups and segments is defined in a syntax that is very closely related to the HL7 Abstract Message Syntax. The message must contain the segments MSH, EVN, PID and PV1; it may contain zero or more NK1 segments and it may contain a repeatable INSURANCE group. In a next step we configure our SampleRulesBuilder in a Spring application context along with a ValidationContextFactoryBean. The ValidationContextFactoryBean auto-detects any beans of type ValidationContextBuilder and adds their validation rules to a ValidationContext that is used in route definitions. The validate().ghl7() DSL extension, which we have already seen, can be configured with a custom validation profile using the profile() DSL extension. The validation context is looked up from the Spring application context via bean(ValidationContext.class). import ca.uhn.hl7v2.validation.ValidationContext import org.apache.camel.spring.SpringRouteBuilder class SampleRouteBuilder extends SpringRouteBuilder { void configure() { from(...) .unmarshal().ghl7() .validate().ghl7().profile(bean(ValidationContext.class)) ... .to(...) } } Code mapping HL7 message processing often involves mapping between code systems i.e. from one set of codes into a corresponding different set of codes. For example, HL7 version 2 and HL7 version 3 use different code systems for most coded values such as message type, gender, clinical encounter type, marital status codes, address and telecommunication use codes, just to mention a few. IPF defines a mapping service that provides the mapping logic. This may be a simple map but it can also be a facade to a remote mapping or terminology service. IPF's default mapping service implementation, the BidiMappingService, supports bidirectional mappings and reads custom mapping definitions from mapping files. An instance of the BidiMappingService can be created with the following bean definition. The mapping service references a mapping file example.map on the classpath. If there is more than one mapping file, a list can be provided via the mappingScripts property. Here is the content of example.map: mappings = { encounterType(['2.16.840.1.113883.12.4','2.16.840.1.113883.5.4'], E : 'EMER', I : 'IMP', O : 'AMB' ) } The example mapping file is a Groovy script and contains a single mapping with three entries for encounter type codes. Also defined are the ISO Object Identifiers (OIDs) for the key and value code systems. The mapping service can now be accessed either directly or via methods on java.lang.String. The String.map() method maps the codes on the left side to the right side. The identifier for the mapping can either be passed as argument assert 'E'.map('encounterType') == 'EMER' assert 'X'.map('encounterType') == null assert 'X'.map('encounterType', 'DEFAULT') == 'DEFAULT' or as part of a method name. assert 'E'.mapEncounterType() == 'EMER' assert 'X'.mapEncounterType() == null assert 'X'.mapEncounterType('DEFAULT') == 'DEFAULT' A dynamic dispatch is used to select the mapping definition from the method name. The method names must therefore correspond to the registered mappings. Mapping in the reverse direction is equally possible. assert 'EMER'.mapReverse('encounterType') == 'E' assert 'EMER'.mapReverseEncounterType() == 'E' Code systems are often associated with a globally unique identifier, usually in form of an OID. The identifier of both sides of a mapping can be obtained as follows. assert 'encounterType'.keySystem() == '2.16.840.1.113883.12.4' assert 'encounterType'.valueSystem() == '2.16.840.1.113883.5.4' Code mapping methods may also be used in combination with the HL7 DSL. MessageAdapter message = ... assert message.PV1.patientClass.value == 'I' assert message.PV1.patientClass.map('encounterType') == 'IMP' assert message.PV1.patientClass.mapEncounterType() == 'IMP' Response messages HL7 messaging often requires the return of an HL7 response message to the sender. With IPF, positive (ACK) or negative (NAK) acknowledgments to messages can be generated. Acknowledgments are in the same HL7 version as the original message and are populated with arguments to the ack() method. MessageAdapter message = ... def ack = message.ack() def nak1 = message.nak('Reason for failure') def nak2 = message.nak(new HL7Exception('Reason for failure', 204)) Generating acknowledgments is, however, only one special case of generating a response to an original message. For responses other than acknowledgements, a response message prototype can be created via the respond(eventType, triggerEvent) method. The MSH and MSA segments of the response message are then populated as required by the HL7 specification. def rsp = msg.respond('RSP','K21') // generates a RSP_K21 message More features So far, the main focus has been on HL7 message processing. IPF has many more features and services to support the development and the operation of production-quality integration solutions. Some of them are briefly described in the following list. A detailed description would far exceed the scope of this paper. For a complete overview refer to the IPF reference documentation. Core features. Collection of domain-neutral message processors and DSL extensions usable for general-purpose message processing including support for Groovy XML processing and support for using closures with Camel DSL elements. OSGi support. Support for running IPF and its services inside an OSGi environment and for the development of OSGi-ready IPF applications. Flow management. A service for monitoring and managing message flows through IPF applications. The flow manager also supports a replay of messages for e.g. recovery from failures. Large message support. Allows for memory-efficient processing of large messages. Event infrastructure. An infrastructure for publishing and consuming system and application events. Can be used e.g. for separating logging, audit or statistics concerns from application-specific route definitions. Can also be used to integrate with complex event processing (CEP) engines. Outlook Upcoming IPF releases will provide support for CDA (Clinical Document Architecture) and IHE (Integrating the Healthcare Enterprise). CDA is an XML-based document markup standard that specifies the structure and semantics of a clinical document for the purpose of exchange. IHE is an initiative of healthcare professionals and industry to improve the way computer systems in the healthcare sector share information. The goal of IPF is to make it as easy as possible for developers to implement the CDA, IHE (and other clinical) standards in their applications. Here are a few examples of what to expect in the next IPF release. CDA support IPF's CDA support will focus on building CDA documents using a domain-specific language. This DSL supports the creation of structurally correct CDA documents by enforcing CDA-relevant schema definitions but without dealing with low-level XML details. The DSL is implemented by a custom Groovy builder, the CDABuilder. In the following code snippet we use the CDABuilder to create a CDA document using CDA-specific terms such as clinicalDocument, code, title, recordTarget and so on. For printing the created document to stdout we use the left-shift (<<) operator. // Create a CDA builder CDABuilder builder = new CDABuilder() // Create a new CDA document def document = builder.build { clinicalDocument { id(root:'2.16.840.1.113883.19.4', extension:'c266') code( code:'11488-4', codeSystem:'2.16.840.1.113883.6.1', codeSystemName:'LOINC', displayName:'Consultation note' ) title('Good Health Clinic Consultation Note') recordTarget { patientRole { id { extension="12345" root="2.16.840.1.113883.19.5" } patient { name { given('John') family('Doe') } birthTime('19320924') } //... } //... } //... } //... } // Write document XML to stdout System.out << document CDA support will also include support for selected CDA profiles from IHE, HL7/ASTM and HITSP specifications, for example XPHR and CCD. Profile-specific CDA DSL extensions will enforce the constraints imposed by the profile specifications. As an example, predefined CDA sections could then be added without knowing their templateID-OIDs or their exact nested XML structure. DSL support for parsing, validating, transforming and rendering CDA documents will complete the feature set. IHE support IPF's IHE support is a framework for creating actor interfaces as specified in IHE profiles. Most likely, support for the XDS profile will be the first to come. XDS stands for Cross-Enterprise Document Sharing and deals with registration and distribution of, and access to clinical documents across health enterprises. Central to this profile are the actors document registry and document repository. A number of document management systems could in principle act as registry and/or repository in the XDS profile. Most of these, however, do not support the XDS actor interface specifications right out of the box. This is were IPF comes in. It helps developers to build IHE actor interfaces for existing information systems. Consider this example: from('ihe:xds.b:iti-41?port=8080') .process { exchange -> def document = exchange.in.body // do further document processing here ... } // communicate with your document management system .to('http://...') // notify about availability of new document .to('ihe:nav:iti-25:[email protected]') This route starts a server to receive documents according to the ITI-41 transaction of the XDS.b IHE profile. ITI-41 is the Provide and Register Document Set transaction in XDS.b. XDS.b requires documents to be transported via SOAP and ebXML standards. To free developers from having to deal with low-level SOAP/ebXML handling, these communication details are hidden inside an ihe component (eventually there may be more than one). Subsequent processors can access the transported document without having to deal with ITI-41 details. After processing, the incoming document is uploaded to a document management system and, finally, [email protected] is notified about the availability of a new document. Notifications are sent according to the IHE NAV profile where NAV stands for Notification of Document Availability. This example is of course oversimplified (for instance it does not address responses, etc) but it still gives an idea of the abstraction level on which IHE interfaces can be implemented for existing systems. Conclusion Apache Camel is a good answer to many of today's integration problems. It provides a DSL for implementing Enterprise Integration Patterns and offers developers a simple and efficient way to deal with the diversity of applications and transports in distributed systems. IPF brings the power of Apache Camel to the healtcare domain and makes healthcare IT standards usable by means of a domain-specific language that closely resembles the language of domain experts. The DSL extension mechanism permits the evolution of even more specialized healthcare DSLs. IPF's support for DSL modularization makes these DSLs and their implementing components reusable in different integration scenarios. Author Martin Krasser is a software architect and engineer working for InterComponentWare AG. He focuses on distributed systems, application integration and application security. Martin is the founder and project lead of the open source IPF project.
May 11, 2009
by Martin Krasser
· 46,286 Views · 2 Likes
article thumbnail
Enterprise Integration Patterns with Apache Camel Refcard Now Available!
Apache Camel is a powerful open source integration platform based on Enterprise Integration Patterns with Bean Integration. This Refcard provides you with eleven of the most essential patterns that anyone working with integration must know. This Refcard is targeted for software developers and enterprise architects, but anyone in the integration space can benefit as well. Download Now! About the Author: Claus Ibsen is a passionate open-source enthusiast who specializes in the integration space. As an engineer in the FuseSource Open Source Division he works full time on Apache Camel, FUSE Mediation Router (Apache Camel Enterprise) and related projects. Claus is very active in the Apache Camel and Fuse communities, writing blogs, twittering, assisting on the forums, irc channels and is driving the Apache Camel roadmap.
March 30, 2009
by Wei Ling Chen
· 5,039 Views
article thumbnail
Apache Camel: Integration Nirvana
Take any integration project and you have multiple applications talking over multiple transports on multiple platforms. As you can imagine, in large enterprise applications this can get complex very fast. Much of the complexity stems from two issues: 1. dealing with the specifics of applications and transports, and 2. coming up with good solutions to integration problems. Making your applications speak transports and APIs is relatively easy on its own. I'm sure everyone knows how to send JMS messages to their broker of choice; though it still requires in depth knowledge of the JMS specification, which many developers may not have. On top of that, what happens when you want to route that JMS message to another application? You then have to take care of mapping the JMS message to the application plus handle any new concepts related to the application. Add a dozen other applications into the mix and you've got quite a headache on your hands. Ignoring the mechanics of how to connect with multiple transports and APIs, we can focus on the high level design of how applications interact. Fortunately, most solutions to enterprise integration problems have been formalized already. Gregor Hohpe and Bobby Woolfe's book, Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions, boils down years of experience from enterprise architects into a set of sixty five Enterprise Integration Patterns (EIPs). This is great but we still have to hand code all parts of these patterns; these are not packaged solutions, only recommendations. Apache Camel was created with the intention of addressing these two issues. In this article I'll show you how it actually does this. What is Camel? Apache Camel is an open source Java framework that focuses on making integration easier and more accessible to developers. It does this by providing: • concrete implementations of all the widely used EIPs • connectivity to a great variety of transports and APIs • easy to use Domain Specific Language (DSL) to wire EIPs and transports together Figure 1 shows how these three items actually map to Camel concepts. To give you a good understanding of how Camel is organized, we will discuss Components, Endpoints, Processors, and the Domain Specific Language (DSL). There is of course a lot more going on here under the hood but we'll leave that for another discussion. Figure 1: High level view of Camel's architecture. Components are the extension point in Camel to add connectivity to other systems. The core of Camel is very small to keep dependencies low, promote embeddability, etc. and as a result contains only 12 essential components. There are over 60 components outside the core. To expose these systems to the rest of Camel, Components provide an Endpoint interface. By using URIs, you can send or receive messages on Endpoints in a uniform way. For instance, to receive messages from a JMS queue aQueue and send them to a file system directory "c:/tmp", you could use URIs like "jms:aQueue" and "file:c:\tmp". Processors are used to manipulate and mediate messages in between Endpoints. All of the EIPs are defined as Processors or sets of Processors. As of writing, Camel supports 41 patterns from the EIP book, 6 other integration patterns, and many other useful Processors. To wire Processors and Endpoints together, Camel defines a Java DSL. The term DSL is used a bit loosely here as it usually implies the involvement of a compiler or interpreter that can process keywords specific to a particular domain. In Camel, DSL means a fluent Java API that contains methods named like terms from the EIP book. Its best explained with an example from("jms:aQueue") .filter().xpath("/person[@name='Jon']") .to("file:c:\tmp"); Here we define a routing rule in a single Java statement that will consume messages from the "jms:aQueue" Endpoint, send them through a Message Filter Processor, which will then send on messages passing the XPath condition to the "file:c:\tmp" endpoint. Messages failing the condition will be dropped. You can also configure your routes in a XML-based Spring configuration file. This configuration file is a lot more verbose and less auto complete friendly than the Java DSL; many prefer it though because of its direct access to Spring concepts and no requirement for compilation after changes. Here is what the earlier example would look like in Spring: /person[@name='Jon'] These are the concepts that Camel was built upon. Since then many other interesting features have been added. Details of these are left up to the reader to investigate. To get you started, some of these include: • Pluggable data formats and type converters for easy message transformation between Artix Data Services, CSV, EDI, Flatpack, HL7, JAXB, JSON, XmlBeans, XStream, Zip, Camel-bindy, etc. • Pluggable languages to create expressions or predicates for use in the DSL. Some of these languages include: EL, JXPath, Mvel, OGNL, BeanShell, JavaScript, Groovy, Python, PHP, Ruby, SQL, XPath, XQuery, etc. • Support for the integration of beans and POJOs in various places in Camel. • Excellent support for testing distributed and asynchronous systems using a messaging approach • and much more... Example A motorcycle parts business, Rider Auto Parts, supplies parts to motorcycle manufacturers. Over the years they've changed the way they receive orders several times. Initially, orders were placed by uploading CSV files to an FTP server. The message format was later changed to XML. Currently they provide a web site to submit orders as XML messages over HTTP. All of these messages are converted to an internal POJO format before processing. Rider Auto Parts states to any new customers to use the web interface to place orders. However, because of existing agreements with customers, they must keep all the old message formats and interfaces up and running. Solution using EIPs Rider Auto Parts faces a pretty common problem; over years of operation businesses acquire software baggage in the form of transports/data formats that are popular at the time. Using patterns from the EIP book we can envision the solution as something like Figure 2. Figure 2: This shows the solution to Rider Auto Parts integration problem using notation from the Enterprise Integration Patterns book. So we have several patterns in use here. 1. There are two Message Endpoints; one for FTP connectivity and another for HTTP. 2. Messages from these endpoints are fed into the incomingOrderQueue Message Channel 3. The messages are consumed from the incomingOrderQueue and routed by a Content-Based Router to one of two Message Translators. As the EIP name implies, the routing destination depends on the content of the message. In this case we need to route based on whether the content is a CSV or XML file. 4. Both Message Translators convert the message content into a POJO, which is fed into the orderQueue Message Channel. The whole section that uses a Content-Based Router and several Message Translators is referred to as a Normalizer. This composite pattern has a unique graphic to depict it but was left out here in favor of its sub-patterns to make things clearer. Implementation using Camel As mentioned before, Camel has a small core set of components included by default. The rest of the components exist as separate modules. In applications that require many types of connectivity it is useful to figure out what Camel modules to include. Listing 1 shows the dependencies using Apache Maven for the Camel implementation of the Rider Auto Parts example. Of course, you don't need to use Apache Maven for dependencies - it is just the easiest way to rapidly add new dependencies to your applications. The list of dependencies includes support for core Camel, ActiveMQ, JAXB marshaling, CSV marshaling, and HTTP. To make the example easier to try out, I've opted to use the File endpoint instead of the FTP. If we were using the FTP endpoint we would need to add a dependency on the camel-ftp module as well. Listing 1: Maven dependencies for the Camel implementation org.apache.camel camel-core ${camel-version} org.apache.camel camel-spring ${camel-version} org.apache.activemq activemq-camel ${activemq-version} org.apache.camel camel-jaxb ${camel-version} org.apache.camel camel-csv ${camel-version} org.apache.camel camel-jetty ${camel-version} org.apache.activemq activemq-core ${activemq-version} org.apache.xbean xbean-spring ${xbean-spring-version} While it is perfectly legitimate to use Camel as a standalone Java application, it is often useful to embed it in a container. In this case, we will be loading Camel from Spring. The Spring beans XML file is shown in Listing 2. First we start an embedded Apache ActiveMQ broker and connect Camel to it. We also load up some helper beans that we will reference from the DSL. Finally, the camelContext element tells Camel to look for routes in the org.fusesource.camel package. Routes are Java classes that extend the RouteBuilder class in Camel. Listing 2: Spring XML file that configures an embedded ActiveMQ broker, several beans used in the Camel route, and initializes the Camel Context to search for routes in the org.fusesource.camel package. org.fusesource.camel The real meat of the Camel implementation lies in the OrderRouter class (shown in Listing 3). This class extends RouteBuilder, so it will be automatically picked up and loaded by Camel's runtime. Looking back at Figure 2, we need to receive orders from an FTP (substituted with File) and HTTP endpoint, formatted as shown in Listing 4. In the DSL we can specify these incoming endpoints with two from elements. Both from elements are connected to a to("jms:incomingOrderQueue") element, which will send the messages to a queue on the ActiveMQ broker. Listing 3: Route definitions for the example. The routing rules are specified using a fluent API, referred to as Camel's DSL. public class OrderRouter extends RouteBuilder { @Override public void configure() throws Exception { JaxbDataFormat jaxb = new JaxbDataFormat("org.fusesource.camel"); // Receive orders from two endpoints from("file:src/data?noop=true").to("jms:incomingOrderQueue"); from("jetty:http://localhost:8888/placeorder") .inOnly().to("jms:incomingOrderQueue") .transform().constant("OK"); // Do the normalization from("jms:incomingOrderQueue") .convertBodyTo(String.class) .choice() .when().method("orderHelper", "isXml") .unmarshal(jaxb) .to("jms:orderQueue") .when().method("orderHelper", "isCsv") .unmarshal().csv() .to("bean:normalizer") .to("jms:orderQueue"); } } In the case of the HTTP endpoint, there are a couple of extra things to mention. First off the HTTP client will be expecting a response from the application so we have to handle that. In Camel, we have full control over what the client gets back from the HTTP endpoint. Each response is determined by the last method in our current route definition (each Java statement is a route definition). In our case we use the transform method to set the response to the constant string "OK". Since we handle the response ourselves, we don’t want any response to come from the JMS incomingOrderQueue. To send to this queue in a fire-and-forget fashion we add the inOnly modifier. It is important to note at this point that when writing Camel DSL in a modern Java IDE, selection of the next processing step is easy because of auto complete. The auto complete feature basically gives you a list of processors (i.e. EIPs) to choose from at any point in your route. Since fluent APIs chain methods together, the only method you need to remember is the from; all other methods are shown via auto complete. Listing 4: Incoming message formats; XML on top, CSV below. "name", "amount" "brake pad", "2" The next section of DSL in Listing 3 specifies the Normalizer, complete with Content-Based Router and two Message Translators. First we specify that we want to consume messages from the incomingOrderQueue on the ActiveMQ broker. The content based routing of the messages is done with the choice and when methods. In our case, we want to send CSV messages to one Message Translator and XML messages to another. To check what type of message we have we will be using a simple Java bean shown in Listing 5. Of course, this is demonstration code only; for production cases you would want to add more thorough checking of content types. Listing 5: Java bean that contains helper methods to be used in the DSL. public class OrderHelper { public boolean isCsv(String body) { return !body.contains("> body) { List orderHeaders = body.get(0); List orderValues = body.get(1); return new Order(orderValues.get(0), Integer.parseInt(orderValues.get(1))); } } At this point, successfully normalized messages are sent to the orderQueue for processing by some other application at the Rider Auto Parts business. Conclusion In this article I've shown two common problems that an integration developer may face: dealing with the specifics of applications and transports, and coming up with good solutions to integration problems. The Apache Camel project provides a nice answer to both of these problems. As the example has shown, solving integration problems with Camel is straight forward and results in relatively concise code. In my opinion it is the closest thing to integration nirvana that we have today. Links Apache Camel – http://camel.apache.org FUSE Mediation Router (based on Apache Camel) – http://fusesource.com/products/enterprise-camel Enterprise Integration Patterns – http://www.enterpriseintegrationpatterns.com Jon’s Blog – http://janstey.blogspot.com Camel in Action book - http://www.manning.com/ibsen Article source code - http://repo.fusesource.com/maven2/org/fusesource/examples/rider-auto-example/1.0/rider-auto-example-1.0.zip Author Jonathan Anstey is a senior engineer working for Progress Software Corporation specializing in the enterprise integration space. Jon focuses mostly on Apache Camel and its Progress endorsed likeness, FUSE Mediation Router. He also works on the Apache ActiveMQ and Apache ServiceMix projects
March 23, 2009
by Jonathan Anstey
· 224,038 Views · 8 Likes
article thumbnail
Service Development Lifecycle Controls for Creating a Service Factory
The concept of a software factory describes a practical work-product approach to governing an efficient service factory - a software engineering-based approach to defining, developing, testing, deploying, and operating functional services and automated business processes. All services follow a similar lifecycle of analysis, followed by design, development, deployment, and ongoing management. Because the service creation process is repetitive, a production engineering approach to automating software development can be used. The Production Engineering method required a significant effort up front, creating a specialized production or assembly line that can then mass-produce the product efficiently and in quantity In effect, we are building a Services Factory: much of the purpose of SOA governance is to define how that factory can operate most effectively. In the following excerpt from the book "SOA Governance: Achieving and Sustaining Business and IT Agility" [REF-1] we will take a look specifically at service development lifecycle control points. This article authored by Clive Gee and Robert Laird and published in SOA Magazine on Feb 23, 2009 Introduction While most organizations have some form of a system development lifecycle (SDLC), the nature of creating shared services is best guided by an SDLC with sufficient governance control points to ensure quality of service. This article discusses and explains the key concepts of a governance control point, as applied specifically to the service development lifecycle. Service Development Lifecycle Control Points Most organizations already have some type of system development lifecycle (SDLC) and a methodology that is used to perform development, although we often see in practice a lack of enforcement of that approach across different business units, and even if a set of best practices, standards, policies, and patterns has been defined, they are not always enforced. Effectively enforcing best practices and a consistent SDLC provides a reasonable entry point for real governance, while not being a huge stretch from what is already being performed via the SDLC. At the same time, if the governance maturity level of the organization can be increased to the degree that it is able to govern the SDLC, the organization is then in a much better position to proceed to the next phase of the SOA governance cycle and create program and organization governance. The danger here for even initial attempts at SOA governance is that often some key individuals view the imposition of any process or governance as being something that might apply to other people but not to them personally. For them, it's an over-engineered, useless exercise that just gets in the way of meeting their own deadlines. So, many governance processes are simply bypassed, or they're followed in a less than an enthusiastic manner. The main reason for this is that governance is imposed from the outside and the execution is onerous. What would happen if governance were mostly automated, easy, and added value to the development process and actually helped with project deadlines? Would the skeptics be more willing to take the medicine if it genuinely eased their pain? To adequately govern the SDLC, there is a need to establish measurements, policy, standards, and control mechanisms to enable people to carry out their governance roles and responsibilities as efficiently as possible, without introducing overly bureaucratic procedures. Governance of the SDLC may be characterized by the sorts of decisions that need to be made at certain "control points" within the process of services development. A control point is a decision checkpoint that provides an opportunity to measure adherence to the established processes, whether you are on track to meet the targets and goals you have established, and then decide whether the way the processes are executed or managed needs adjusting. Knowing what decisions involved in the process are critical, when to make them, and understanding what measurements are needed to monitor those processes are all essential aspects of governance. Certain activities within a process may be associated with a control point. At the end of each identified activity, there is a control point at which the governance function decides whether the program is ready to move to the next activity. Each of these milestones is a control point. At its essence, the governance of the SDLC provides a way to identify control points and to define the governance rules. At each control point, it is necessary to identify the following: • The roles for who does what at the control point • The policies to be applied at the control point • Measurements at each control point that should be applied and collected for later governance vitality actions • The proof of compliance records to be created and archived A control point will be created where there is a demonstrated advantage weighing the standardization and efficiency provided versus the time, effort, and possible project delay. The control point enables SOA governance the opportunity to ascertain progress, to communicate this progress, to forecast efforts for subsequent phases of the SDLC based on scope and issues found, to review and report compliance, and to facilitate the injection of expertise and qualified review of the artifacts, process, or decisions made by the development team. Control points don't have to consist of huge formal meetings. Services and most automated business processes are smaller entities than projects, and there are many more of them. Therefore, the existing governance approach has to be streamlined or it might grind to a halt. We've found in practice that effective control point reviews can be made during regular - typically weekly - sessions of a subset of the SOA enablement. A real productivity aid in performing these control point reviews is the use of previously completed checklists, signed off by one or more senior professionals as certification that one or more tasks has been completed successfully, and that the service, process, or other work product is fit for purpose and ready in all respects for the next task in the development process. These checklists should be viewed as contracts between different experts in the service development process. The most important part of the checklist is the signature block to show who exercised approval authority; people tend to be careful about the quality of anything that carries their personal reputation with it. Another productivity aid is the use of automated tooling. As much of the governance control point as possible should be automated. This aids in better near real-time feedback to the developers and provides an easy method to recheck work that has been updated. In addition, human beings are busy and will tend to apply governance in an inconsistent manner. Machines are consistent but not usually as flexible as needed. The combination of the two provides an optimal governance mix. Let's look at the control points needed to govern a generic development lifecycle, at least at a high level. Figure 1 represents a "governance dashboard" monitoring a typical SDLC with an eye toward the key concepts and the points where they must be addressed by SOA governance. Figure 1: Software Development Lifecycle Governance Dashboard As mentioned previously, we need a streamlined process that can handle the large number of services and automated processes that we need to implement to have real impact on business agility and flexibility. However, that streamlined process must not sacrifice the quality of governance just because of the need for extra speed. That would be an unacceptable trade-off. Some organizations deal with highly regulated processes that have mission-critical or life-critical products and need to apply highly formal, auditable governance to manage the risks involved. Other organizations have processes with lower associated risks that can be more lightly regulated. We have found in practice that the same governance process can handle both these extremes perfectly well. If there is a need for stricter governance, it can be met with tighter policies at the control points together with more stringent policy enforcement and compliance measurement. If less-strict governance is more appropriate, the same process can be used with less restrictive policies, fewer audits, and lower levels of checklist signoff required. Even within a single organization, different processes may require different styles of governance. Some processes, such as service certification, require stricter governance than other processes, such as solution architecture. Different organizational cultures require different levels of autonomy in decision making. Good governance requires good judgment. First, let's update our Figure 1 with the location of these control points so that you have a visual representation in mind as you read their descriptions. Figure 2 shows where the control points occur in that development cycle. Figure 2: Software Development Lifecycle with SOA Control Points Here are descriptions of these control points. Business Requirements and Service Identification Control Point For an SOA approach, there is an emphasis on creating services that provide agility and reuse for the business. This first business requirements and service identification control point consists of a high-level review to determine that services are being identified in accordance with services selection and prioritization policies. This first business requirements and service identification control point should address the following types of questions: • Business goals. What are the business goals that the business seeks to attain and how do we measure the benefits or progress toward the business goals via key performance indicators (KPIs)? • Do the requirements as we currently understand them clearly support those goals, and do they align with an existing "business heat map"? • Are those requirements sufficiently understood and agreed to? Are they presented in a form such as use cases, business process models, sequence diagrams, or class diagrams that are consistent with the SOA development approach? • How do we provide traceability of the requirements so that we can ascertain that those requirements have been met during the development process? Have those requirements been entered into an enterprise-wide requirements and business rules catalog? Is there any conflict with existing entries in that catalog? • Which of those requirements could be translated into good candidate services, either because they represent functionality that may be needed by multiple consumers or that might be needed for process automation? Which requirements could be better supported by deploying applications, automated processes, or manual processes? • Where we have identified candidate services, have we identified potential consumers, and determined whether any of them have specific requirements that should be considered? • Given finite IT resources, what development priority should we assign? Is ownership of any new candidate IT asset defined, and is outline funding available for its development? Solution Architecture Control Point Different IT developers and groups, if left to make all design decisions on their own, would invariably use completely different platforms, coding languages, tools, styles, methods, and techniques. This variation adds cost and complexity to the ability of the business to make future changes, and makes future maintenance very hard and costly. Further, it reduces the reliability, stability, and interoperability of the organization's IT assets. We have seen this problem at many organizations that we have visited. Simply put, the purpose of the solution architecture control point is to prevent that expensive multiplicity of approaches from occurring ever again. Essentially, any proposed IT artifact that makes it past this control point is part of the IT build plan. For the area of solution architecture, the governance should control for a series of criteria the following: • Do the proposed standards, policies, and reference architectures - the solution architecture - identify the standards, policies, and design patterns to be followed in the service implementation? This will include reference architectures, platform standards for hardware, and software-usage standards. • Have any reusable assets been identified and assessed for suitability? Has the service sourcing policy been followed? • Have the nonfunctional requirements been identified and assessed? This includes the number of transactions per time unit, a busy hour analysis, the service performance required, presentation access to the service functionality, data managed by the service, space required for the installation of the service, and any dependency and configuration requirements. Governance must validate that all these are considered and addressed. • Governance must validate that all security policies are being considered and addressed. • Governance must validate that all legal and regulatory policies are considered and addressed. • By this stage in the development of IT assets such as services or automated processes, the technical IT staff involved should have a pretty good idea about the complexity of the tasks involved, and the probable level of resources required to complete development. Should development of the asset be confirmed, the scope reduced, or the asset abandoned? Service Specification Control Point A service specification should be created for each service whose development has been approved. Best practices for service design must integrate both an IT and business perspective for the design of the interface and the responsibilities of each service. Because the service specification is, in effect, the organization's face to business partners, customers, and other stakeholders, the service externals - those details of a service that are to be made public - become an important part of the overall business design. The design should take into account the requirements of all potential service consumers (within reason), and be created at a granularity that maximizes business value. For the area of service identification and specification, the governance should control for a series of criteria the following: • Does the service identified make sense, is at the right granularity, and is not duplicating an existing service? • Does the service specification follow all SOA standards and policies? • Does the service specification follow the messaging model? If not, should an exception be granted? Service Design Control Point After the service solution architecture has been turned over to the design team, a number of design elaboration decisions must be made. Collectively, these form the service internals - a set of design models, notes, and advice that will guide the service developers as they create and test the service code. For the area of service design, the governance should control for a series of criteria the following: • Has a service architect confirmed that the design should be able to meet the nonfunctional and functional requirements for this service? • Have the service designer and data architect agreed that the service can be made to conform to the signature (that is, inputs and outputs) described in the service externals? • If a service is wrapping an existing or planned application, are the necessary interfaces to that application well defined and stable (that is, won't change if a new version of that application is installed)? • Have the monitoring metrics (for example, usage, quality of service [QoS] levels) been established? • In the case of automated processes, have the monitoring requirements been defined and planned? • In the case of long-running automated processes, have all the necessary actions to handle recovery from process errors or technical failures been addressed? • Is the overall quality and level of completeness of the service specification package good enough that the service developers or process developers can complete development without further input? Service Build Control Point After the service design has been turned over to the service build team, a number of implementation decisions need to be made before development of the code or executable model. In the interests of consistency and quality, we strongly recommend the use of code walkthrough reviews, where peers (that is, other service developers or process developers) review the work in progress and offer constructive criticism. The service build control point is effectively the last of these code walkthroughs, and should be performed with slightly more formality than the others. Questions that should be addressed include the following: • Was the asset coded in accordance with the design? • Does the code follow the accepted coding standards? • Have all the associated artifacts (for example, load libraries, metadata files, resources) been defined to create a transportable build? Have the versions of each of those artifacts been checked to see that there are no version conflicts with services already in production? Service Test Control Point Service testing is different from testing complete IT solutions or applications. Because services and automated processes do not have their own user interface, it is not possible to perform user acceptance testing directly on services or automated processes. Code frameworks or specialized tools are needed to exhaustively test services and automated processes thoroughly to avoid uncovering problems during later formal user acceptance testing when the rest of the IT solution that uses those services or processes has been completed. SOA governance must ascertain that the services test is being performed in a manner conducive to a services approach, and that exhaustive functional and nonfunctional tests have been passed before releasing any SOA asset to production. The service test team must create and use the right service test environment with tools and data to affect a comprehensive test. This should include the following: • Using the optimum set of service test tools and frameworks. • The use of an automated build and test environment that can enable fast changes of the tested software and regression testing. This environment must closely resemble the production environment. • A load/stress test tool to test nonfunctional requirements, specification, creation, and loading of realistic but artificial test data. • A test management reporting tool to keep management apprised of the testing status. • Trace the test case to the original user requirements. Service Certification and Deployment Control Point The objectives of the deployment are to migrate the services to the production environment while minimizing client downtime and impact on the business. This process is subject to many errors if performed manually. It is vital that the correct version of the services be deployed and that any deployment binding with other services and applications be performed quickly and correctly. Areas for governance to validate include the following: • The use of a tool that automates the deployment and back-out process. • Final certification checks have been made against the services to verify compliance with all policies and standards and being able to demonstrate that what was tested matches not only the requirements but what was delivered, and that no corrective changes made during testing have invalidated other test results. • IT operations have completed acceptance testing and have formally accepted the asset, signifying their confidence in being able to operate it within the terms of the QoS specified for it. • The service registrar and business service champion have reviewed the service description in the service registry and approved it. Certification of a service or automated process is a formal "passing out" ceremony, and granting of certification should signify that the SOA enablement team is happy for their reputation to be associated with the performance of the new asset. Service Vitality Control Point Service vitality takes place periodically as part of SOA governance to check up on and update the governance processes, procedures, policies, and standards in reaction to the results of the real world. This involves examining any and all lessons learned in any of the SOA planning, program control, development, or operations activities. It also includes such things as comments and feedback from all stakeholders and an examination of any common patterns (for example, common exemption requests or common reasons for failure to pass one or more control points) that need remedial action. Metrics in the efforts required for each stage of the development process can show trends that indicate improvements or declines in their vitality. A formal service vitality control point review should be conducted every three to six months to determine whether the SOA transition remains on track, and whether the level and style of governance is optimal. Individual service or automated processes should be reviewed every 6 to 12 months. Usage data of all versions of each service can determine any "stale" versions that can be deprecated or deleted, and whether the deployment options taken and decisions on who should own and who should access each service are optimal. Conclusion We have focused in this extract on SOA Governance service development control points as a method to create a software engineering capability of a service factory. The factory is a production line for services. All services pass through a common, repeatable series of development, deployment and management steps. Quality and governance is built-in throughout the entire process. References [REF-1] "SOA Governance: Achieving and Sustaining Business and IT Agility" by William A. Brown, Robert G. Laird, Clive Gee, Tilak Mitra (IBM Press, ISBN 0137147465, Copyright 2009 by International Business Machines Corporation. All rights reserved.) This article was originally published in The SOA Magazine (www.soamag.com), a publication officially associated with "The Prentice Hall Service-Oriented Computing Series from Thomas Erl" (www.soabooks.com). Copyright ©SOA Systems Inc. (www.soasystems.com)
March 19, 2009
by Masoud Kalali
· 8,433 Views
article thumbnail
Camel Component For Amazon SQS
As its name implies Amazon Simple Queue Service (Amazon SQS) is a simplified version of a Messaging system. The great thing about it is its reliability and high scalability features. Amazon SQS makes it easy to build an automated workflow, working in close conjunction with the Amazon Elastic Compute Cloud (Amazon EC2) and the other AWS infrastructure web services. You can learn more about Amazon SQS here. The Problem My colleagues (Tom Purcell and Rod Biresch) and myself have been working on a demo application for Chariot Solutions' Emerging Technologies for the Enterprise conference and the need for a transport component to simplify the access of Amazon SQS arose. We have decided to use FUSE ESB(ServiceMix) 4 as the services integration platform for the demo application, and knowing that Apache Camel collaborates very well with ServiceMix, we decided to use it for the routing and transformation needs. Currently, neither ServiceMix, nor Camel provide a component to access Amazon SQS. Besides this limitation the remaining capabilities provided by these products still made it a great choice for the demo application. To learn more about the demo application, please visit Tom Purcell's blog. I also recommend attending to the Tom Purcell's presentation titled "Bus In the Cloulds" where he'll be speaking about Could Computing use cases and how Open Source Integration technologies can help resolve issues encountered while integrating with business partners. Another important part in production applications is management and monitoring. To learn more about how to monitor this application, please visit Rod Biresch's blog. A Solution Apache Camel makes it relatively easy to compose your own components, so the next logical step was to try to create one. Having seen Dave Kavanagh's Typica API in action and how easy it makes the communication with SQS, we decided to try and come up with such Camel component using this API as the back-bone. The Camel Amazon SQS Component The basic idea is to create a component that could be used in the following fashion: The above example shows a Camel route that sends data found in files placed in the data directory to a SQS queue named "dataQueue". In the to URI "sqs:sqsProducer?accessId=....", the protocol "sqs" will tell Camel what component to configure and attributes will be mapped the properties of either the Endpoint, or the Producer class. The documentation on writing Camel Components can be found here. Let's dive into the design of the Camel SQS component. The main steps for writing a Camel Component are: Write a POJO which implements the Component interface. The simplest approach is just to derive from DefaultComponent. In our case, the class SQSComponent was created. This class extends DefaultComponent. To support auto-discovery of your component add a file to META-INF/services/org/apache/camel/component/sqs where 'sqs' is the URI scheme for your component and any related endpoints created on the fly. The sqs file will contain the class attribute with the name of Class that implements the Component: class=com.chariotsolutions.soalab.camel.component.sqs.SQSComponent The Camel SQS Component is composed of the following artifacts: The SQSComponent Class This class serves as factory of Endpoints. When the component is being configured by Camel, the method of the createEndpoint is called. This method creates and configures the Endpoint (SQSEndpoint). The SQSEndpoint Class This class serves as a factory for Producers, Consumers, and Exchanges. After the SQSComponent.createEndpoint is execute, an instance of the class SQSEndoint is created. This class contains the properties used by the SQSConsumer class. These properties are: private String accessId; private String secretKey; private String queueName; This class extends ScheduledPollEndpoint and is used to create instances of the SQSProducer and SQSConsumer. The use of the ScheduledPollEndpoint is with the intention to use polling facilities it provides to query the SQS Queue at a specified time intervals. The SQSConsumer Class This class extends the ScheduledPollConsumer class to indicate that it will be excueted in poll intervals. The poll intervals are configured in the Component URI using the consumer.initialDelay and consumer.delay attributes like so: The poll() will be executed based on the configuration specified above.This method uses the Typica API to interact with the Amazon SQS Web services. If a message was found in the SQS Queue, it will e forward to the handleMessage. This method will set the message in a wrapper class called SQSObject, place it in the SQSExchange and send it flow of the route using the synchronous Processor by default. The attribute asyncProcess=true would cause it to use the AsyncProcess. The SQSProducer Class This class extends the DefaultProducer class. It processes the message coming from the Camel flow and sends it to the SQS queue, then it sets the assigned message id to the SQSObject, which is later added to the SQSExchange in case other components need it down the road. The SQSExchange Class This The base message exchange interface providing access to the request, response and fault instances. The SQSObject Class This is convenient POJO that wraps the payload and properties coming from the SQS Queue. Taking the Camel SQS Component For A Ride To see the Camel SQS Component in action, I created a small sample application. The sample application can be found in here. Here are the steps to build and run the application: If you haven't already done so, create an Amazon SQS account using the "Sign Up" button in this page. Extract the sample code to a directory of your choice. For example, /tmp/sqs-sample. You should see 2 directories in there, camel-sqs (camel sqs component) and camel-sqs-route (sample camel route). Navigate to the camel-sqs directory and build the code using: mvn clean install Navigate to the camel-sqs-route directory. Edit the file src/main/resources/aws.properties. Specify aws.accessId and aws.secretKey for your Amazon SQS account. Edit the file src/main/resources/META-INF/spring/camel-context.xml. Find the file endpoints and modify them to point to the directories of your choice. The File-In endpoint is where you would supply the data files to be sent to the SQS queue. The File-Out endpoint is the directory where the files containing the contents of the SQS queue will be placed on. Build the code using: mvn clean install Run the code using: mvn camel:run You should be able to place your sample text files directory pointed by the File-In endpoint. After a few seconds the output files will be placed in directory pointed by File-Out. Conclusion Amazon SQS combined with ServiceMix and Camel are a great platform for building your IaaS (Infrastructure as a Service) projects. Hopefully future versions of Apache Camel will include such component. The Camel CAMEL-1432 JIRA issue has been created for this reason.Happy Cloud Computing! Recommended Sites Tom Purcell's Blog Rod Biresch's Blog Amazon SQS FUSE ESB (ServiceMix) 4 Apache Camel Chariot Solutions
March 9, 2009
by Roberto Rojas
· 21,428 Views
article thumbnail
JAX-RPC client with Maven2
Recently I needed to make my Maven2 web project communicate with an old style RPC encoded web service. We run on GlassFish which comes with JAX-RPC RI built-in, so I was hoping to find a way to use it without having to bundle another runtime such as Axis into the project. Specifically I was looking for a way to make my build-script generate client stubs from a WSDL file in the project tree. I want the client stubs to use standardized JAX-RPC APIs which are serviced by the implementation provided by GlassFish. I found that the JAX-WS RI has a Maven2 plugin but not the JAX-RPC RI. I did a lot of googling, and posted messages in a few mailing lists. Surprisingly there is almost nobody using JAX-RPC on Maven2 projects because there are barely any examples online and nobody could answer my question. I'm surprised because there are a lot of legacy systems out there that developers need to integrate with, so I can't be the only one still needing JAX-RPC support. Some people suggested that I update the web service to modern RPC literal to make client-side development easier with JAX-WS, but that is not an option. Others suggested that I use Maven's antrun plugin to call out to an ant build script that does JAX-RPC work. Finally I found an all Maven solution that works for me: org.apache.axis axis 1.4 compile org.apache.axis axis-jaxrpc 1.4 compile commons-discovery commons-discovery 0.4 compile wsdl4j wsdl4j 1.6.2 compile org.codehaus.mojo axistools-maven-plugin 1.3 wsdl2java com.mycompany.service.client src/main/resources/META-INF/wsdl target/generated-sources/wsdl2java private MyServiceSEI getMyServicePort() throws ServiceException { MyServiceLocator locator = new MyServiceLocator(); MyServiceSEI port; Stub stub; port = locator.getMyServiceSEIPort(); // OPTIONALLY configure URL and HTTP BASIC authentication stub = (Stub) port; stub._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, "http://hostname/ContextRoot/ServicePort"); stub._setProperty(Stub.USERNAME_PROPERTY, "user"); stub._setProperty(Stub.PASSWORD_PROPERTY, "secret"); return port; } It works, but I think the client stubs are dependent on the Axis 1 runtime instead of using the GlassFish provided JAX-RPC runtime through the standardized JAX-RPC APIs. I've wasted enough time on this so I moved on. If you know a better way to do this, please let me know. No RESTful services rants please! I think SOAP and REST both have their uses depending on what you are doing. From my perspective, JAX-WS SOAP development is effortless and requires significantly less code than REST because I don't have to write the building/parsing code. After examining raw SOAP messages without extra WS-* headers added in, I decided that overhead is not a valid argument against SOAP. When you need more advanced features they are available to you without having to re-invent the wheel. I think most Java developers' negative impressions on SOAP comes from the JAX-RPC and Axis days, and because they haven't tried JAX-WS yet. From http://www.ryandelaplante.com/
March 9, 2009
by Ryan Developer
· 37,038 Views
article thumbnail
Integrate OpenOffice with Java without Installing OpenOffice
Until a few days ago, I've always needed to work with the rather cumbersome Office Bean and UNO Runtime when integrating OpenOffice into a Java application. I also had to configure a whole bunch of things to force OpenOffice to play nicely with the Java integration. Two days ago, however, I found out about ODF Toolkit. It seems to be a relatively new project, independent since last year some time, though I could be wrong. What's especially interesting is the ODFDOM: ''ODFDOM is an OpenDocument (ODF) framework. It's purpose is to provide an easy common way to create, access and manipulate ODF files, without requiring detailed knowledge of the ODF specification. It is designed to provide the ODF developer community an easy lightwork programming API, portable to any object-oriented language.'' Here's a snippet of it in action: public static void main(String[] args) { try { OdfDocument odfDoc = OdfDocument.loadDocument(new File("/home/geertjan/test.ods")); OdfFileDom odfContent = odfDoc.getContentDom(); XPath xpath = odfDoc.getXPath(); DTMNodeList nodeList = (DTMNodeList) xpath.evaluate("//table:table-row/table:table-cell[1]", odfContent, XPathConstants.NODESET); for (int i = 0; i < nodeList.getLength(); i++) { Node cell = nodeList.item(i); if (!cell.getTextContent().isEmpty()) { System.out.println(cell.getTextContent()); } } } catch (Exception ex) { //Handle... } } Let's assume that the 'test.ods' file above has this content: From the above, the code listing would print the following: Cuthbert Algernon Wilbert And, as a second example, here's me reading the first paragraph of an OpenOffice Text document: public static void main(String[] args) { try { OdfDocument odfDoc = OdfDocument.loadDocument(new File("/home/geertjan/chapter2.odt")); OdfFileDom odfContent = odfDoc.getContentDom(); XPath xpath = odfDoc.getXPath(); OdfParagraphElement para = (OdfParagraphElement) xpath.evaluate("//text:p[1]", odfContent, XPathConstants.NODE); System.out.println(para.getFirstChild().getNodeValue()); } catch (Exception ex) { //Handle... } } On my classpath I have "odfdom.jar" and "xerces-2.8.0.jar". I don't necessarily have OpenOffice installed, which means I can very easily process a whole bunch of spreadsheets (or other OpenOffice output) without (a) installing OpenOffice and (b) faster than I would otherwise do, since OpenOffice doesn't need to be started up, via the Office Bean or otherwise. In fact, Aljoscha Rittner from Sepix, who told me about this project and who is using it in his commercial applications, reports that his processing has sped up to a fraction of the original, also because he doesn't need to handle the situation where OpenOffice would crash randomly in the middle of long running processes, such as during the night when there's no human interaction for restarting it.
February 7, 2009
by Geertjan Wielenga
· 50,598 Views
article thumbnail
Creating a REST WCF Service From an Existing XSD Schema
A reader of my blog sent me an email asking the following question: “I have an XSD that I am required to use to export my company's data. How can I use that XSD and return data to them in a web method? I should be able to return a data set with the information formatted the way the XSD defines but I have no idea how to do that. Any ideas would save me a ton of time and grief!” Turns out this is a really good question, and I think one a lot of developers struggle with primarily because the majority of developers are scared of XSD schemas. Hopefully I can change that. An XML Schema is really simple and it is your friend. What is an XSD or Xml Schema Definition? An XML Schema describes the structure of an XML document. That’s it, see, it isn’t that hard after all! As a developer think of an XSD the same way you would when creating business rules to validate objects before storing them into a database. Some items in objects cannot be null, some can. Some need to have their data formatted (email address for example) and others need to not exceed certain lengths, etc. When dealing with an XML document, we need to apply the same type of rules and this is where the XSD comes in. Once we have an XSD to describe an XML document we can guarantee any XML data we receive conforms to these rules. Ok, enough intro, let’s get coding. The Schema In the case of the reader’s question, an XSD schema already existed. To save time, I’ve taken then general idea of the schema I was sent and slimmed it down for simplicity sakes. The schema represents an XML document that will contain job listings. Here is a view of the schema from the schema explorer in Visual Studio as well as the schema itself (again slimmed down). Once we have a schema defined like this we can generate code to be used for a service. We have a tool at our disposal that is available within the Visual Studio Command Prompt called XSD.exe. This executable does a lot of things but one thing it can do is generate code from an XML Schema Definition. When generating from the XSD file I was sent there was a problem with it. Here is the walk through of that story so you can follow along. When I first tried this on the reader’s original XSD I got an error: Warning: cannot generate classes because no top-level elements with complex type were found. What does this mean? Well, look at the screen shot of the XML Schema Explorer above. Do you see the <> green icons? Well those represent an XML Element. An element is a fancy name for an XML tag like: Bramar Let me roll this up and take another screen shot so you can start to see the problem (i have to hit my magic number of 12 screen shots anyway :) ). See the problem? There isn’t an element in this schema (no green <> thingy). What this means is we have a schema which just lists complex types of elements and enumerations. There isn’t any “xml” in this schema. The fix is simple though. Add an element to the schema. Now we have a green thingy icon which means this XSD contains at least one element. Basically think of the JobListing element as the root element. Now that we have an element we can generate a C# class file from this XSD: The code generated is about 350 lines so I’m not going to include it in the article. There are some nice things happening for us when the C# classes are generated using xsd.exe. For starters the enumerations in the XSD are turned into C# enumerations. The classes are marked serializable and they have the appropriate XML attributes on the properties to serialize these objects into XML. This is a good thing since it means we didn’t have to create it. Code generation is your friend. Now that we have C# objects we can serialize these to XML easily. The Service The first thing we need to do is create the WCF service. For this example I chose to create a WCF Service Application in Visual Studio 2008. After the project is initialized, the first thing we need to do is define the contract for the service. In other words, what is coming in and going back out. Since we have generated our code using the XSD utility we are going to use the XmlSerializer with our service. The reason is this will make sure our XML formatted the way we intended. While we are at it, I’ve made the service a RESTful type of service. Here is the contract. [ServiceContract] public interface IJobService { [OperationContract] [XmlSerializerFormat] [System.ServiceModel.Web.WebGet(UriTemplate="/jobs/{type}", RequestFormat=WebMessageFormat.Xml)] List GetJobListings(string type); } The contract above has one method GetJobListings(). This method has two additional attributes. One, the attribute to mark the method to serialize using the XmlSerializer and two the attribute to turn the method into a RESTful service. In other words our service can be accessed like this: http://localhost/service.svc/jobs/full-time Now that the contract is setup, we just need a class to implement this contract on. Here’s a quick and dirty implementation. public class Service1 : IJobService { #region IJobService Members public List GetJobListings(string type) { return GetJobs(); } private static List GetJobs() { var jobs = new List(); jobs.Add(new Job { JobType= JobType.parttime, Category = JobCategory.Banking, Benefits= "You are on your own.", Description="I did something" }); jobs.Add(new Job { JobType= JobType.fulltime, Category = JobCategory.Banking, Benefits= "You get something." }); jobs.Add(new Job { JobType= JobType.contractor, Category = JobCategory.Banking, Benefits= "Times are tuff, deal with it." }); jobs.Add(new Job { JobType= JobType.fulltime, Category = JobCategory.Banking, Benefits= "How does $700 billion sound?" }); return jobs; } #endregion } Now all we have left is to get this working is to configure WCF to support our RESTful implementation. In order to do this we are going to use the webHttpBinding. Here is the WCF configuration to implement our RESTful service. That’s it, we are all setup. Now all we have to do is launch the service and browse to the URL we outlined earlier to get our results. This may seem like a lot of steps but it really isn’t. I encourage you to take this example and play with it. You can download the solution below. Download Solution WcfService.zip
December 18, 2008
by Keith Elder
· 33,447 Views
article thumbnail
The Three Pillars of Continuous Integration
Continuous Integration commonly known as CI is a process that consists of continuously compiling, testing, inspecting, and deploying source code. In any typical CI environment, this means running a new build every time code changes within a version control repository. Martin Fowler describes CI as: A software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly. While CI is actually a process, the term Continuous Integration often is associated with three important tools in particular. As shown in the image the three pillars of CI are: 1. A version control repository like Subversion, or CVS. 2. A CI Server such as Hudson, or Cruise Control 3. An automated build process like Ant or Nant So, let’s look at each of these in detail: Version Control Repository: Version control repositories also known as SCM (source code management) play a crucial role in any software development environment. They also play a very important role for a successful CI process. The SCM is a central place for the team to store every needed artifact for the project. It is mandatory for the teams to put everything needed for a successful build into this repository. This includes the build scripts, property files, database scripts, all the libraries required to build the software and so on. The CI Server: For CI to function properly, we also need to have an automated process that monitors a version control repository and runs a build when any changes are detected. There are several CI servers available, both open source and commercial. Most of them are similar in their basic configuration and monitor a particular version control repository and run builds when any changes are detected. Some of the most commonly used open source CI servers are; Cruise Control, Continuum, and Hudson. Hudson is particularly interesting because of its ease of configuration and compelling plug-ins, which makes integration with test and static analysis tools much easier. Automated Build: The process of CI is about building software often, which is accomplished through the use of a build. A sturdy build strategy is by far the most important aspect of a successful CI process. In the absence of a solid build that does more than compile your code, CI withers. With automated builds, teams can reliably perform (in an automated fashion) otherwise manual tasks like compilation, testing, and even more interesting things like software inspection and deployment. Now that we have seen the important tools in our CI process, let’s see how a typical CI scenario looks like for a developer: CI server is configured to poll the version control repository continuously for changes. Developer commits code to the repository. CI server detects this change, and retrieves the latest code from the repository. This causes the CI server to invoke the build script with the given targets and options. If configured, CI Server will send out an e-mail to the specified recipients when a certain important event occurs. The CI server continues to poll for changes. Why is CI Important? This is one of the most frequently asked questions, and here are a few points to note about this powerful technique: Building software often greatly increases the likelihood that you will spot defects early, when they still are relatively manageable. Extends defect visibility. CI ensures that you have production ready software at every change. CI also ensures that you have reduced the risk of integration issues by building software at every change. CI server can also be configured to run continuous inspection which can assist the development team in finding potential bugs, bad programming practice, automatically check coding standards, and also provide valuable feedback on the quality of code being written. Over the past several months, I have assisted several companies in implementing CI. There was a little bit of resistance from the developers in the early stages when we implemented continuous feedback. But, never heard a single negative comment about this approach. If you already have a version control repository and automated builds, you are very close to the CI process. Download one of the open source CI servers, configure and setup a simple project. It should take less than an hour if you have automated build scripts. Start adding additional features like code inspections, generating reports, metrics, documentation and so on. Most important, send continuous feedback to your team. Give this process a try, you sure will be surprised to see how effective it is. And, as always share your thoughts, concerns or questions.
December 15, 2008
by Meera Subbarao
· 24,042 Views
article thumbnail
Eclipse Tip: Incremental Find or Find as You Type
Eclipse has many ways of doing things. Finding the way that suits you can be tricky. :-) The standard find dialog triggered by Crtl+F is, well, standard. But if you are a keyboard junkie then it kind of gets in the way. The other way of searching with in the current editor is Incremental Search. This is triggered by Crtl+J and has no GUI! Just press Ctrl+J and type the search text. Eclipse finds and highlights the next match as you type. You can use the Up or Down arrow key to jump to the next or previous match. I like this way... From http://www.vasanth.in/
November 25, 2008
by Vasanth Dharmaraj
· 20,168 Views · 1 Like
article thumbnail
Adding Color and Font preferences
You had that nice looking editors and views. You loved the button color and the geeky font. But your boss didn't. Solution? Put a preference so that the user can choose which ever he likes ;-) Ok. That may not be the real rationale, but for a valid reason, you wanted to have Color and Font preferences in the PreferencePage. The obvious answer for us (the plugin develoepers) would be to add ColorFieldEditor & FontFieldEditor in our existing PreferencePage. But its not obvious for the user to look into your plugins Preference Page for changing them. Eclipse already provides a PreferencePage for these customizations: Colors and Fonts page ( General->Appearance->Colors and Fonts ) Users might be looking into this place to change the colors & fonts. As you can see in the above image it categorizes the available preferences; gives a filter to search; provides space for description and preview; and a tool tip for the current value of the preference. This is much more than the *FieldEditor right? In this tip let us see how to add our preferences into that and access them. You need to extend the org.eclipse.ui.themes extension point for adding your content into this page. I would like to provide one category with one color preference and one font preference. The extension is: An example theme category Your description goes here Description for this font Guess all the elements are self explanatory - except for the value element. For colorDefinition the value element will be the COLOR_* constants defined in the SWT class. You can specify your custom colors thru comma separated RGB values like 125,245,96. For fontDefinition it would be fontname-style-height. Now our UI will look like: To get the values stored in the preferences, you need to use the IThemeManager: IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager(); ITheme currentTheme = themeManager.getCurrentTheme(); ColorRegistry colorRegistry = currentTheme.getColorRegistry(); Color color = colorRegistry.get("com.eclipse-tips.blog.preferences.colorDefinition"); FontRegistry fontRegistry = currentTheme.getFontRegistry(); Font font = fontRegistry.get("com.eclipse-tips.blog.preferences.fontDefinition"); Once you get the current theme, you can get the preferences stored by giving the appropriate ids defined in the plugin.xml What you have seen is just the tip of the iceberg. The themes extension point has much more functionalities (The Preview is one such example). I'll explain them later, but you can see the Extension Point description here. This is an extract from http://blog.eclipse-tips.com/2008/08/adding-color-and-font-preferences.html
October 15, 2008
by Prakash
· 13,927 Views
  • Previous
  • ...
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • Next
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook
×