February 27th, 2007
Marshalling mit smooks - Erweiterung der javabeans-Cartridge
Für mein aktuellen JBoss-ESB-Projekt habe ich mir in den Kopf gesetzt eine eingehende XML-Datei in Entity-Beans zu transformieren. JBoss-ESB bietet das von Hause aus über die Integration des Smooks-Frameworks.
Kurz zur Erklärung: Smooks ist ein Framework zur generischen Verarbeitung von XML-Dateien, bzw. XML-Fragmenten. Die Verarbeitung ist einfach: In einer Mapping-datei wird für jeden XML-Pfad ein Handler definiert, der über das Visitor-Pattern irgendetwas ausführt. So kann für ein Element (oder einen Teilbaum) z.B. ein XSLT ausgeführt werden oder auch völlig individueller Java-Codeausgeführt werden.
Hier ein Beispiel aus der Mapping-Datei (smooks-res.xml):
<smooks-resource selector="ORDER"
useragent="from-type:text/xml:fullfillorder and
from:dvdstore:orderdispatchservice"
path="org.milyn.javabean.ProcessingPhaseBeanPopulator" >
<param name="beanId">ORDER</param>
<param name="beanClass">org.jboss.soa.esb.dvdstore.Order</param>
<param name="addToList">true</param>
</smooks-resource>
<smooks-resource selector="ORDER"
useragent="from-type:text/xml:fullfillorder and
from:dvdstore:orderdispatchservice"
path="org.milyn.javabean.ProcessingPhaseBeanPopulator" >
<param name="beanId">order</param>
<param name="attributeName">orderId</param>
</smooks-resource>
<!-- ... repeat for each attribute ... -->
In diesem Beispiel wird für jedes Element “ORDER” der ProcessingPhaseBeanPopulator “besucht”. Der ProcessingPhaseBeanPopulator wird vom smooks-Framework über eine sog. Cartridge mitgeliefert. Er hat die Aufgabe, aus dem element “ORDER” ein POJO, also eine Java-Klasse zu generieren. Attribute können zu Java-Properties gemappt werden und für Unterelemente können ebenfalls Visitors definiert werden, die beispielsweise wiederum Properties setzen. Sowie sogut. Das Problem ist bloss, dass bei “echten” Business-Daten die Datenstrukturen nicht so trivial sind, wie in dem vom ESB mitgelieferten Sample “quickstarts/transformXML2POJO“. Habe ich ein ORDER-Element mit 30 oder mehr Unterelementen, die die Properties der ORDER definieren, wird mein smooks-mappingfile recht umfangreich und vor allem sehr wartungsfeindlich.
Schön wäre eine Smooks-Cartridge, die die Unterlemente eines XML-Elements automatisch auf die Properties (genaugesagt auf die Setter) meines POJO Mappt. So kann mit minimaler Konfiguration eine ganze Reihe von umfangreichen XML-Strukturen auf POJOs transformiert werden, ohne tonnenweise quasi-redundanten Konfigurationscode zu erzeugen.
Hierzu habe ich die von smooks mitgelieferte javabeans-cartridge etwas modifiziert, so dass folgende Konfiguration möglich ist:
<smooks-resource selector="ORDER"
useragent="from-type:text/xml:fullfillorder and
from:dvdstore:orderdispatchservice"
path="org.milyn.javabean.MyProcessingPhaseBeanPopulator" >
<param name="beanId">order</param>
<param name="beanClass">org.jboss.soa.esb.dvdstore.Order</param>
<param name=”attributesFromChildren”>true</param>
</smooks-resource>
Damit das funktioniert, habe ich in der Klasse ProcessingPhaseBeanPopulator etwas Code ergänzt.
Zunächst das Einlesen der Konfiguration, die nun den Parameter “attributesFromChildren” unterstützen soll:
public void setConfiguration(SmooksResourceConfiguration config) {
// ... existing code
// START Added by om, form4
attributesFromChildren =
config.getBoolParameter("attributesFromChildren", false);
// END Added by om, form4
}
Und das Processing im eigentlichen Visitor:
public void visit(Element element, ContainerRequest request) {
Object bean = getBean(request);
// START Added by om, form4
if (attributesFromChildren) {
NodeList children = element.getElementsByTagName("*");
for (int i = 0; i < bean.getClass().getMethods().length; i++) {
Method method = bean.getClass().getMethods()[i];
if (method.getName().startsWith(”set”)) {
String attr = method.getName().replaceAll(”^set”, “”).toLowerCase();
for (int j = 0; j < children.getLength(); j++) {
Element child = (Element) children.item(j);
if (attr.equalsIgnoreCase(child.getNodeName())) {
try {
String val = DomUtils.getAllText(child, false);
method.invoke(bean, new Object[] { val });
} catch (Exception e) {
logger.error(e); // etwas ignorant…
}
break;
}
}
}
}
}
// END Added by om, form4
// … go on with original code …
}


2 Responses to “Marshalling mit smooks - Erweiterung der javabeans-Cartridge”
Hi there.
I came across your post here. I’m the developer behind Smooks.
You might find the newer version of the Javabean Cartridge (v0.3-SNAPSHOT) a lot easier to use. It’s been enhanced to support:
1. Binding specification for a whole bean class through a single resource configuration - verses a requiring 1 config per bean property.
2. More complex types. Everything was a String prior to v0.3.
3. Creation of proper Object Graphs. Pre v0.3 didn’t support this at all.
See the tutorials at http://milyn.codehaus.org/Tutorials. Of particular interest might be the “javabean-populator”, and “edi-to-java” examples.
I think this makes this cartridge a lot more useful now. I also plan adding a JPA option on this stuff - to support persisting of the beans to a DB via something like Hibernate.
Regards,
Tom.
May 31st, 2007 at 01:34
Sorry, I noticed that the blog software screwed up that link - it included the full-stop. Tutorials at http://milyn.codehaus.org/Tutorials
May 31st, 2007 at 01:36
Leave a Reply