• No se han encontrado resultados

TÍTOL VII. REGULACIÓ DEL SÒL URBANITZABLE

CAPITOL PRIMER. REGULACIÓ DE LES ZONES DE SÒL URBANITZABLE

When you’re working with integration tools, you’re often working with XML. XML pro- vides a standard format for exchanging information between systems. However, work- ing with XML directly from Java is a bit cumbersome. In our integration logic, we want to work with standard Java objects, but we still need a generic format that can be sent between the various components. Many open source libraries are available that allow you to easily transform a Java object to XML and back again, such as Java Architecture for XML Binding (JAXB) and Service Data Objects (SDOs).

For this book we chose JiBX, an open source framework. Using JiBX you can create a mapping definition that provides the necessary functionality to map from XML mes- sages to your existing Java objects and back again. The main reason why we chose this framework is its flexibility. You can easily reuse your existing Java classes and have full control of how the Java classes are mapped to XML, and vice versa.

Using JiBX together with Mule and ServiceMix will allow us to keep using Java objects inside our Java code instead of having to work with XML. In this section, we show you how JiBX works, and also how you can integrate JiBX into Mule and Service- Mix to provide easy mapping from and to XML.

DEFINING JIBX MAPPINGCONFIGURATIONS

To get JiBX to work, you need to create a mapping definition. This definition tells

JiBX how an XML message is mapped to a Java object. In this definition file, you specify the name of the element in the XML message and then specify the name of the field in the Java object it needs to be mapped to. Let’s map the following XML message:

<person> <firstname>John</firstname> <lastname>Doe</lastname> <city>Amsterdam</city> <country>The Netherlands</country> </person>

Of course, this is a simple XML message, but it’s a good one to start with. This XML

message has a Java class equivalent: public class Person {

private String firstName; private String lastName; private String city; private String country; // getters and setters }

To map the person XML message to the Person Java class and back again, we need to create a JiBX mapping file (see listing 3.7).

<binding>

<mapping name="person" class="org.demo.Person">

Listing 3.7 JiBX mapping file of the person XML message to a Person Java class

B

<value name="firstname" field="firstName" /> <value name="lastname" field="lastName" /> <value name="city" field="city" />

<value name="country" field="country" /> </mapping>

</binding>

In the JiBX mapping file you define the root element name of the XML message (person in this case) and the Java class we want to map it to

C

. Notice that there is a binding root element

B

, which is used by JiBX to represent the start of the mapping definitions. The next part involves defining the mapping between the message child elements and the properties of the Java class

D

. We do this by specifying the name of the XML element (e.g., firstname), and then in the field property we can specify the corresponding Java property (e.g., firstName). Figure 3.2 shows the mapping of a value from an XML file to a property in a Java object.

The example shown in figure 3.2 is the most basic JiBX mapping. We show you a cou- ple more binding options that will allow you to map most Java objects to XML, and vice versa. Let’s start once again by showing you the XML message that we want to map in the following code snippet:

<person> <firstname>John</firstname> <lastname>Doe</lastname> <address> <city>Amsterdam</city> <country>The Netherlands</country> </address> </person>

The corresponding Java object is shown in this code snippet: public class Person {

private String firstName; private String lastName; private Address address; }

public class Address { private String city; private String country }

D

As you can see, we can’t map the XML message to a single Java object. Part of the XML

message, the address elements, has to be mapped to a separate Java class. We can do this by introducing a structure element, as listing 3.8 shows.

<binding>

<mapping name="person" class="org.demo.Person"> <value name="firstname" field="firstName" /> <value name="lastname" field="lastName" /> <structure name="address" field="address" class="org.demo.Address"> <value name="city" field="city" />

<value name="country" field="country" /> </structure>

</mapping> </binding>

In listing 3.8 we define a structure that maps the address element to the Java prop- erty in the Person class with the same name

B

. We also specify that the structure element be mapped to the Java class Address. This way, we can easily map an element in an XML message to a Java class other than the root element (in this example, the Person class). Inside the structure element, the same mappings we showed earlier are configured to map the address XML elements to the properties in the Address Java class, such as the country element

C

.

Figure 3.3 illustrates how the previous mapping file maps the structure to the Java object.

Now that you understand the structure definition of JiBX, you should be able to map complex XML messages to corresponding Java objects. However, we haven’t dis- cussed the use of namespaces yet.

Listing 3.8 JiBX mapping example with a structure definition

B

C

Figure 3.3 An example that shows how JiBX maps a structure element to a Java class

XML namespaces are used to uniquely identify a certain XML element, and you’ll see these in most real-world XML usage. If you want to map an XML message that uses namespaces, you must configure these namespaces in the JiBX binding file. For our example, we use the same Java objects as we did in the previous example. But this time, we change the XML to use a namespace definition:

<ps:person xmlns:ps="http://demo/persons" xmlns:ad="http://demo/address"> <ps:firstname>Jos</ps:firstname> <ps:lastname>Dirksen</ps:lastname> <ad:address> <ad:city>Eindhoven</ad:city> <ad:country>The Netherlands</ad:country> </ad:address> </ps:person>

We add two namespaces to the person XML message: one for the person-specific ele- ments, which uses the “ps” prefix, and one for the address-specific elements, which uses the “ad” prefix. We need to make some small changes to the binding file to sup- port this (see listing 3.9).

<binding>

<mapping name="person" class="org.demo.Person"> <namespace uri="http://demo/persons" default="elements"/>

<value name="firstname" field="firstName" /> <value name="lastname" field="lastName" /> <structure name="address" field="address" class="org.demo.Address">

<namespace uri="http://demo/address" default="elements"/> <value name="city" field="city" /> <value name="country" field="country" /> </structure>

</mapping> </binding>

With the changes we made to the binding file compared to the one in listing 3.8, JiBX

is now configured to look for the person element and its child elements, in the http://demo/persons namespace, and the address elements and its child elements should be in the http://demo/address namespace.

USING JIBX TOTRANSFORM XML MESSAGESINTO JAVA

In the previous section you learned how to configure the mappings between Java objects and XML messages with JiBX, but we haven’t shown you how to use these mappings. First you need to run the binding compiler, which will use the binding definition and compile it into your class files. In other words, your class files will be enriched with the information required to marshal XML objects to Java and back again.

Listing 3.9 An example of a JiBX binding file with namespaces

Defines person namespace

Defines address namespace

Running this binding compiler isn’t difficult. You have two options. The first is to run the binding compiler directly:

java -jar jibx-bind.jar yourbinding.xml

Remember that if you choose this approach you have to ensure that all the classes you’re binding to (and superclasses as well) are on the classpath.

The second option is the one we use in this book. You can use an Ant task to run the binding compiler directly from your build file. To be able to run the binding com- piler within an Ant build file, first create a new Ant task definition:

<!-- JiBX binding compiler task definition -->

<taskdef name="bind" classname="org.jibx.binding.ant.CompileTask" classpath="${jibx-lib}/jibx-bind.jar"/>

The JiBX task definition tells Ant which JiBX class should be executed to run the bind- ing compiler and configures the classpath. With the JiBX task definition in place, we can define a bind configuration within an Ant target:

<!-- Run JiBX binding compiler -->

<bind verbose="true" load="true" binding="binding.xml"> <classpath>

<pathelement path="classes"/>

<pathelement location="${jibx-lib}/jibx-run.jar"/> </classpath>

</bind>

Once you’ve run the binding compiler, you’re ready to use the bindings from your application. The binding compiler processes the binding file and creates Java classes to execute the XML marshaling at runtime.

When we use JiBX in the examples in this book, you don’t have to worry too much about running the JiBX binding compiler. The build files used to run and compile the examples in this book already use the previously shown JiBX Ant tasks.

Using JiBX from your application code is easy. Let’s first see how to use JiBX to mar- shal a Java object to an XML file:

StringWriter outWriter = new StringWriter();

IMarshallingContext ctx = BindingDirectory.getFactory(Person.class) .createMarshallingContext();

ctx.marshalDocument(person, "UTF-8", null, outWriter);

You first need to get an IMarshallingContext. With this context you can use the marshalDocument method on your object instance to write the XML output to a Writer implementation—for example, a StringWriter.

When you want to go from XML to Java, you must use similar steps. But instead of using an IMarshallingContext, you should use an IUnmarshallingContext, as you can see in the following code snippet:

IUnmarshallingContext ctx = BindingDirectory.getFactory(Person.class) .createUnmarshallingContext();

You’ve now seen how to configure binding files for JiBX, how to run the binding com- piler, and how to invoke the JiBX bindings from Java. So if you want to use JiBX from your application code, you can use the code snippets we showed you to do so. In the next section, you’ll learn how to use JiBX together with ServiceMix and Mule.

USING JIBX WITH MULEAND SERVICEMIX

JiBX is used in this book whenever a transformation is required from XML to Java or the other way around. In most examples, we send the data as XML between the various components. ServiceMix requires this, and it’s generally considered good practice. Mule doesn’t have any special requirements for the data sent between components; with Mule, you can just as easily send serialized Java objects between components.

When there is already existing business logic implemented or when new business logic has to be included, you usually don’t want to work with XML messages directly. From a developer perspective, it’s much simpler to develop against Java objects. So we need an easy mechanism to transform the Java objects to XML messages, and vice versa.

Mule provides an easy access point for this with the transformer concept. List- ing 3.10 shows an example of implementing a Java object–to-XML transformation step in Mule.

Canonical data format and normalized messages

It’s often a good practice to define a common format for the messages that are exchanged between the various components and services. This format is called a

canonical data format. You might wonder why this is useful; why not simply apply

a transformation between the formats and be done with it? Well, that approach works when you don’t have to integrate multiple applications. If you have two or three applications to integrate, it’s often not that hard to keep track of the differ- ent data format requirements of these applications. However, when the number of applications increases you have to write more and more transformations to keep all the applications talking to one another. If you add a new application and you use the canonical data format, you only need to write one transformation—the one from the canonical data format to the new application—instead of writing new transformations for all the applications that are already connected.

Note, though, that when using ServiceMix you don’t automatically have a canoni- cal data format. What you’ve got is a normalized message, which describes what the data that is sent over the line looks like—XML in the case of ServiceMix. A canonical data format goes one step further. It defines not only the type of the mes- sage, but also the format (and in the optimal case, the semantics as well). So if, say, we want to use a canonical data format, we also have to specify an XML Schema that exactly describes the XML format of the messages that we’re send- ing over the line. As an example, consider the Universal Business Language (UBL) standard. This standard defines a number of XML Schemas and messages that you can use when you’re working with orders, receipts, and invoices. You could choose to use UBL as the canonical data format you’re using for your integration solution.

public class ObjectToXML extends AbstractTransformer { protected Object doTransform(Object payload)

throws TransformerException { try {

StringWriter outWriter = new StringWriter();

IMarshallingContext ctx = BindingDirectory.getFactory( payload.getClass()).createMarshallingContext(); ctx.marshalDocument(payload, "UTF-8", null, outWriter); return outWriter.toString();

} catch (JiBXException e) {

throw new TransformerException(this, e); }

} }

In listing 3.10, we implement a transformer for Mule based on JiBX. In the previous examples we’ve shown how you can use JiBX to marshal an object to XML. We can use this functionality without any change in a Mule transformer

B

. When this trans- former receives the message payload

C

, it checks the class of the object and retrieves the specific marshaling context for that class

D

. Then the JiBX context marshals the Java object contents to an XML String representation.

Of course, we also must be able to create a Java object from an XML message when we receive a message in a service bean. The Mule transformer implementation for the

XML to Java marshaling is shown in listing 3.11.

public class XMLToObject extends AbstractTransformer { private String targetClassName;

protected Object doTransform(Object xmldata) throws TransformerException {

try {

IUnmarshallingContext ctx = BindingDirectory .getFactory(Class.forName(targetClassName)) .createUnmarshallingContext(); return ctx.unmarshalDocument(new StringReader(xmldata)); } catch (Exception e) {

throw new TransformerException (this, e); }

}

public String getTargetClassName() { return targetClassName;

}

public void setTargetClassName(String targetClassName) { this.targetClassName = targetClassName;

} }

Listing 3.10 Implementation of the ObjectToXML transformer for Mule

Listing 3.11 Implementation of the XMLToObject transformer for Mule

B

C

D

B

C

D

The XMLToObject Mule transformer receives an XML String as input and transforms it into a Java object

c

. To be able to create the JiBX unmarshaling context

D

, we need to specify the class of the Java object we want to transform to

B

. This only works for objects for which we’ve created a mapping file and for which we’ve run the binding compiler.

Now that you’ve seen how to implement a Mule transformer based on JiBX to transform Java to XML and back again, let’s implement a similar transformer for ServiceMix.

For ServiceMix we need to provide a helper class to implement the transforma- tions. ServiceMix itself is JBI based, so all the data that’s sent between the components needs to be in line with the JBI specification—which means it has to be XML. So when we create our custom components for ServiceMix, we can use a helper class that han- dles the transformation for us. Let’s look at the servicemix-bean implementation that uses JiBX to marshal and unmarshal the XML messages (listing 3.12).

public class SimpleListenerBean

implements MessageExchangeListener { @Resource private DeliveryChannel channel;

public void onMessageExchange(MessageExchange exchange) throws MessagingException { if (exchange.getStatus() != ExchangeStatus.ACTIVE) return;

NormalizedMessage msg = exchange.getMessage("in"); try {

Person person = (Person)

JiBXUtil.unMarshalDocument(msg) .getContent(), Person.class); person.setName("John Doe"); exchange.getMessage("out").setContent(JiBXUtil. marshalDocument(person, "UTF-8")); MessageUtil.transferInToOut(exchange, exchange); channel.send(exchange); } catch (JiBXException e) { throw new MessagingException(

"Error transforming object to or from XML"); }

} }

The SimpleListenerBean implementation contains the onMessageExchange method of the MessageExchangeListener interface

B

. The incoming message of the JBI mes- sage exchange is unmarshaled to a Person Java object, using a JiBX utility class that we discuss in listing 3.13. Then the name of the person is changed on the Java object and

Listing 3.12 The servicemix-bean implementation, using the JiBX framework

Implements MessageExchangeListener interface

B

Unmarshals XML to Java object Marshals Java object to XML

the object is marshaled to an XML message again. The XML message is a Source instance; in this example we use a StreamSource.

The SimpleListenerBean uses a JiBX utility class for the JiBX-specific functionality. Let’s look at the implementation of the JiBXUtil class in listing 3.13.

public static Object unMarshalDocument(Source source, Class targetClass) throws JiBXException {

Object result = null; try {

IUnmarshallingContext ctx = BindingDirectory .getFactory(targetClass)

.createUnmarshallingContext();

result = ctx.unmarshalDocument((InputStream) new ByteArrayInputStream(getBytes(source)), "UTF-8"); } catch (Exception e) {

throw new JiBXException("Error unmarshalling", e); }

return result; }

public static Source marshalDocument(Object src) throws JiBXException {

Source result = null; try {

ByteArrayOutputStream bOut = new ByteArrayOutputStream(); IMarshallingContext ctx = BindingDirectory.getFactory( src.getClass()).createMarshallingContext(); ctx.marshalDocument(src, "UTF-8", null, bOut); result = new StreamSource(

new ByteArrayInputStream(bOut.toByteArray())); } catch (Exception e) {

throw new JiBXException("Error marshalling", e); }

return result; }

The methods in listing 3.13 look much like the methods we’ve seen for Mule, only this time we use a java.xml.transform.Source object as our input and output for the JiBX methods. ServiceMix uses this class to represent the XML messages in a mes- sage exchange.

Well, that’s it for our discussion on JiBX. For Mule we’ve defined transformers that take care of transforming a message into and from XML, and for ServiceMix we created a helper class that can, for instance, be used with the servicemix-bean service engine.

The final technology we discuss is ActiveMQ, which provides us with asynchronous communication and reliable messaging capabilities.