CSV nach XML-Marshaler für Apache ServiceMix ESB

Das Einlesen und Verarbeiten von Tabellen im CSV Format kann Entwickler für Enterprise Service Bus Anwendungen vor ein Problem stellen. Dieser Artikel beschreibt eine einfache Lösung für den Apache ServiceMix.

Wer mit einem Enterprise Service Bus Nachrichten im Comma Seperated Values Format verarbeiten möchte steht vor einem Problem. Da ein JBI konformer ESB nur normalisierte Nachrichten mit einer XML Nutzlast akzeptiert. Eine Datei im CSV Format muss daher erst in XML umgewandelt werden, bevor sie den Bus betritt. Diese Aufgabe könnte eine spezieller Adapter, eine CSV Binding Komponente übernehmen. Beim ServiceMix ESB gibt es jedoch noch eine weitere Alternative. Die File Komponente, welche Dateien einliest kann die Normalisierung des Dateiinhaltes, d.H. die Umwandlung in das XML Format, an einen Marshaler delegieren. Dieser Artikel beschreibt einen solchen Marshaler und wie Sie diesen für Ihre eigenen Integrationsanwendungen einsetzen.

Der CSV2XML Marshaler

Der hier vorgestellte Open Source CSV2XML-Marshaler steht Ihnen im Quellcode, sowie in Form einer Binary Shared Library zur Verfügung. Der Marshaler kann in beliebigen kommerziellen und nicht- kommerziellen Projekten eingesetzt werden. Bitte beachten Sie die Lizenz am Ende des Artikels.

Voraussetzung

Apache ServiceMix Version 3.2.1 oder neuer.

Importieren der Shared Library in ServiceMix

Die Benötigten Bibliotheken für den Marshaler befinden sich im Archiv csv2xml-marshaler-1.0.zip. Dieses Archiv wird in das Verzeichnis hotdeploy der ServiceMix Engine kopiert. Anschließend steht die Bibliothek den einzelnen Komponenten zur Verfügung. Um auch von einer Service Unit aus Zugriff auf die Bibliothek zu bekommen, muss diese in den Classpath der SU eingebunden werden.

Einbinden des Marshalers in eine File-Service-Unit

Der Marshaler wird als Property in einem File-Poller angegeben. Hierfür wird in der Konfigurationsdatei xbean.xml der File-SU ein neues Bean deklariert. Das Bean verweist auf die Klasse des Marshalers und kann verschiedene Properties zur Konfiguration enthalten (siehe Abschnitt Properties). Zusätzlich muss die Shared Library des Marshalers in den Classpath aufgenommen werden.

<file:poller service="csv2xml:poller"
      endpoint="e1"
      targetService="csv2xml:sender"
      file="file:.\inbound">
      
  <property name="marshaler">
     <bean class="de.predic8.CSV2XMLMarshaler">
       <property name="delimiter" value=';' />
     </bean>
  </property> 
</file:poller>
<classpath>
  <library>csv2xml-marshaler</library>
</classpath>
Listing 1: Beispiel einer xbean.xml Konfiguration mit eingebundenem Marshaler

Properties

Dem Marshaler können folgende Properties zur Konfiguration übergeben werden:

Name Type Beschreibung Standardwert
Delimiter String Trennzeichen zwischen einzelnen Einträgen der csv Datei (Beispiel: 5;1.45;Milk) ;
firstLine Boolean Ist dieser Wert auf true gesetzt wird die erste Zeile der csv Datei zur Beschriftung der Zeilenelemente des generierten XML verwendet.
Beispiel: Aus folgender csv Datei quantity;price;good 5;1.45;Milk Wird diese XML Ausgabe generiert: <quantity>5</quantity> <price>1.45</price> <good>Milk</good>
true
containsDummyL Boolean Wird auf true gesetzt falls die csv Datei eine Dummyline (Beispiel: ;;;;;;;;;;;;) enthält false

Tabelle 1: Beschreibung der Properties des Marshalers

Funktionsweise des Marshalers

Das Tool basiert auf dem CSV nach XML Converter von OIO. Der Marshaler wird in eine File Service Unit eingebunden, bekommt dann den eingelesenen InputStream des File-Pollers übergeben und versucht diesen in generisches XML umzuwandeln. Konnte die Umwandlung erfolgreich abgeschlossen werden wird das erzeugte XML zurück gegeben und kann dann beispielsweise mit Hilfe der XSLT Komponente weiterverarbeitet werden. Wichtige Parameter, wie zum Beispiel die Angabe des Trennungszeichens zwischen einzelnen Einträgen der Datei, können über die Angabe von Properties konfiguriert werden. Bei der Ausgabe werden einzelne Zeilen der CSV Datei durch <row> Elemente voneinander getrennt. Am Ende dieses Artikels finden Sie als Beispiel eine vollständige Ausgabe einer umgewandelten CSV Datei.

Beispiel einer umgewandelten Datei

Nachfolgend wird an Hand eines einfachen CSV Datensatzes das Ergebnis der Umwandlung dargestellt. Die Properties wurden hierbei auf den Standardwerten belassen.

quantity;price;good
5;1.45;Milk
2;0.99;Butter
10;1.19;Muffin
Listing 2: Inhalt der CSV Datei
<?xml version="1.0" encoding="UTF-8"?>
<csvimport>
  <row>
    <quantity>5</quantity>
    <price>1.45</price>
    <good>Milk</good>
  </row>
  <row>
    <quantity>2</quantity>
    <price>0.99</price>
    <good>Butter</good>
  </row>
  <row>
    <quantity>10</quantity>
    <price>1.19</price>
    <good>Muffin</good>
  </row>
</csvimport>
Listing 3: XML Ausgabe des Marshalers

Quellcode des Marshalers

/**
 * Dieser Code kann beliebig verwendet werden. Die Autoren übernehmen keine Garantie und keinerlei Haftung.
 *
 * @author Thomas Bayer, Marco Hippler
 * predic8 GmbH
 * http://www.predic8.de
 *
 */


package de.predic8;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.jbi.JBIException;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.messaging.MessagingException;
import javax.jbi.messaging.NormalizedMessage;

import org.apache.log4j.Logger;
import org.apache.servicemix.components.util.FileMarshaler;
import org.apache.servicemix.jbi.jaxp.BytesSource;
import org.apache.servicemix.jbi.util.StreamDataSource;
import org.xml.sax.ContentHandler;

import de.oio.util.xml.CSVReader;
import de.oio.util.xml.SAX2Writer;



public class CSV2XMLMarshaler implements FileMarshaler{

  private static final Logger log = Logger.getLogger(CSV2XMLMarshaler.class);
  private char delimiter=';';
  private boolean firstLine=true;
  private boolean containsDummyL=false;
  
  public String getOutputName(MessageExchange arg0, NormalizedMessage arg1)
      throws MessagingException {
    return null;
  }

  public void readMessage(MessageExchange arg0, NormalizedMessage out,
      InputStream in, String arg3) throws IOException, JBIException {
    StreamDataSource inputData=new StreamDataSource(in);
    ByteArrayOutputStream bStream=new ByteArrayOutputStream();
    ContentHandler contentHandler = new SAX2Writer(bStream);
    CSVReader reader = new CSVReader(inputData.getInputStream(), "Cp1252",  
contentHandler);
    reader.setDelimiter(delimiter);
    reader.setFirstLineAreColumnNames(firstLine);
    reader.setContainsDummyLine(containsDummyL);
    reader.parse();
    
    log.info("InputStream processed");
      
    out.setContent(new BytesSource(bStream.toByteArray()));
    
    
  }

  public void writeMessage(MessageExchange arg0, NormalizedMessage arg1,
      OutputStream arg2, String arg3) throws IOException, JBIException {
 
    
  }

   public void setDelimiter(char delimiter) {
    this.delimiter = delimiter;
  }

  public char getDelimiter() {
    return delimiter;
  }

  public void setFirstLine(boolean firstLine) {
    this.firstLine = firstLine;
  }

  public boolean isFirstLine() {
    return firstLine;
  }

  public void setContainsDummyL(boolean containsDummyL) {
    this.containsDummyL = containsDummyL;
  }

  public boolean isContainsDummyL() {
    return containsDummyL;
  }
}
Listing 4: Quellcode des CSV2XML-Marshaler

Das komplette Maven Projekt zum Erstellen des jar Archivs für das Hotdeployment in ServiceMix finden Sie hier.

Lizenz

Das Programm wird unentgeltlich der Allgemeinheit zur kommerziellen und nicht- kommerziellen Anwendung überlassen. predic8 weist jedoch ausdrücklich darauf hin, daß die Software möglicherweise noch fehlerhaft ist. Die Nutzung der Programme erfolgt auf eigenes Risiko des Anwenders.

Haftungsausschluss

DIE predic8 GmbH GARANTIERT NICHT DIE EIGNUNG DER SOFTWARE FÜR EINEN BESTIMMTEN ANWENDUNGSFALL ODER EINE BESTIMMTE HARDWAREKONFIGURATION. EBENSO ÜBERNIMMT SIE KEINERLEI GEWÄHR FÜR DIE KORREKTHEIT ODER QUALITÄT DER SOFTWARE. Predic8 IST UNTER KEINEN UMSTÄNDEN FÜR SCHÄDEN HAFTBAR ZU MACHEN DIE SICH AUS DER NUTZUNG DER VORLIEGENDEN SOFTWARE ERGEBEN KÖNNEN, UNGEACHTET DER SCHADENSURSACHE ODER DER GRUNDLAGE DES HAFTUNGSANSPRUCHS. DIES SCHLIEßT DEN VERLUST VON GESCHÄFTSGEWINNEN, DIE UNTERBRECHUNG DER GESCHÄFTLICHEN ABLÄUFEN, DEN VERLUST VON DATEN, SOWIE ALLE ÜBRIGEN MATERIELLEN, KOMMERZIELLEN UND IDEELLEN VERLUSTE UND DEREN FOLGESCHÄDEN EIN. DESWEITEREN IST predic8 NICHT FÜR DURCH EINE DRITTE PARTEI ERHOBENE RECHTSANSPRÜCHE HAFTBAR ZU MACHEN. DIES GILT SELBST DANN, WENN SIE ZUVOR AUSDRÜCKLICH AUF DIE MÖGLICHKEIT DERARTIGER SCHÄDEN ODER AUF PROGRAMMFEHLER HINGEWIESEN WURDEN.

Share

ESB Entwicklung mit JBI Schulung
Lernen Sie wie eine SOA mit ESB Technologie realisiert werden kann, sowie die Entwicklung von eigene Konnektoren und Komponenten mit dem JBI API.
ServiceMix Schulung
Erwerben Sie die notwendigen Kenntnisse, um selbst Integrationslösungen mit ServiceMix zu entwickeln.