Startseite > Techblog > Artikel von
jdi

Es kommt gelegentlich vor, dass bei Serveranwendungen die SSL-Zertifikate ausgetauscht werden. Insbesondere bei einem gleichzeitigen Austausch von CA-Zertifikaten (weil z.B. eine neue Sub-CA für die Signierung neuer Zertifikate verwendet wird) kann es dabei dazu kommen, dass eine Applikation, die als Client auf die Serveranwendung zugreift die Vertrauenskette des Serverzertifikates nicht mehr prüfen kann und dann z.B. in Java mit einer SSLHandShakeException aussteigt. Um hier Abhilfe zu schaffen, benötigt man die CA-Zertifikate, die bei SSL-Handshakes mitgeschickt werden. Um diese zu extrahieren bietet sich das Tool s_client der openssl-Bibliothek an.

Um beim Handshake die Zertifikate ausgeben zu lassen ruft man openssl folgendermaßen auf:

openssl s_client -connect targethost.domain.tld:443 -showcerts

damit liefert OpenSSL die im Handshake übermittelten Zertifikate im PEM-Format an die Standardausgabe. Mit dem folgenden kleinen Perl-Script certsplit.pl lassen sich diese in einzelne .pem-Dateien schreiben:

#!/usr/bin/perl -w
#
# take output from openssl s_client -showcerts and extract certificates
# as openssl-cert-$count.pem files
#
# (C) 2009 Jan Dittberner <jan.dittberner (at) communardo (dot) de>
#
use strict;

my $state = 0;
my $count = 0;
my $filename;
my $fh;

while () {
  if ($_ =~ /BEGIN CERT/) {
    open($fh, '>', "openssl-cert-$count.pem") or die $!;
    $count++;
    $state=1;
  }
  if ($state == 1) {
    print $fh $_;
  }
  if ($_ =~ /END CERT/) {
    close($fh) or die $!;
    $state=0;
  }
}

Das Ganze lässt sich über Pipes auch schön automatisieren:

echo -e "HEAD / HTTP/1.1\nHost: targethost.domain.tld\nConnection: Close\n\n"|openssl s_client -connect targethost.domain.tld:443 -showcerts | perl certsplit.pl

Anschließend liegen die Zertifikatsdateien als openssl-cert-#.pem (# ist die Reihenfolge in der die Zertifikate beim Handshake übermittelt werden) im aktuellen Verzeichnis vor.

Die PEM-Dateien können dann z.B. mit

openssl x509 -in openssl-cert-0.pem -noout -text

genauer inspiziert werden. Die CA-Zertifikate können dann z.B. mit dem keytool des JDK in den trusted Keystore importiert werden:

cd $JAVA_HOME/jre/lib/security
keytool -importcert -trustcacerts -keystore cacerts -storepass changeit -alias ALIAS -file ZERTFIKAT.pem

wobei ZERTIFIKAT, ALIAS und bei einem ordentlich gepflegten System auch das bei -storepass angegebene Passwort durch passende Werte zu ersetzen sind.

ACHTUNG: Dieser Vorgang ist nur dann sinnvoll, wenn man wirklich sicher sein kann, dass die Zertifikate wirklich von einem vertrauenswürdigen System kommen, ansonsten kann man damit natürlich auch einem potentiellen Angreifer sein Vertrauen aussprechen.

Kommentar Feed Trackback URL
jdi

In einem aktuellen Kundenprojekt hatten wir die Anforderung eine Message-Queue zu implementieren, die neben dem reinen Queuing eine garantierte Zustellung zum Zielsystem gewährleisten sollte. Es musste sichergestellt werden, dass auch bei Nichtverfügbarkeit des Zielsystems keine Nachrichten verloren gehen.

Da keine zusätzlichen Kosten für Softwarelizenzen anfallen sollten und ich das Rad nicht neu erfinden wollte, habe ich nach einer Lösung im OpenSource-Bereich gesucht. Mit Apache ActiveMQ bin ich fündig geworden. Innerhalb der verteilten Applikation wurde Axis2 verwendet. Das Zielsystem ist per SOAP/HTTP zu erreichen, während ActiveMQ eine Message-Queue auf JMS-Basis darstellt.

Um das Queuing zu implementieren, war folgende Reihenfolge der Nachrichtenübermittlung erforderlich:

  • Webapplikation erzeugt SOAP-Nachrichten (mit Attachments) und verpackt diese in JMS-Nachrichten
  • JMS-Nachrichten werden von der Webapplikation in eine ActiveMQ-Queue geschrieben
  • Eine selbstentwickelte Komponente holt die SOAP-Nachrichten aus der Queue
  • die selbe Komponente baut HTTP-Verbindungen zum Zielsystem auf und schickt die SOAP-Nachrichten über die HTTP-Verbindung

Initial sah die Implementierung ziemlich trivial aus, allerdings ergaben sich im Projektverlauf einige Schwierigkeiten.

Axis2 Stubs mit Maven 1 erzeugen

Da es für Axis2 kein Maven 1 Plugin gibt, bin ich für die Generierung der Stubklassen auf Maven 2 ausgewichen und habe dies in unseren Maven 1 Buildprozess integriert.

WSDL-Beschreibung

Der Service wird durch folgende WSDL beschrieben:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
  xmlns:types="http://jdi.communardo.de/swatesttypes/2008-01"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:ref="http://ws-i.org/profiles/basic/1.1/xsd" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" targetNamespace="http://jdi.communardo.de/swatest/2008-1"
  xmlns:tns="http://jdi.communardo.de/swatest/2008-1">
  <wsdl:types>
    <xsd:schema targetNamespace="http://ws-i.org/profiles/basic/1.1/xsd"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:simpleType name="swaRef">
        <xsd:restriction base="xsd:anyURI" />
      </xsd:simpleType>
    </xsd:schema>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      xmlns:ref="http://ws-i.org/profiles/basic/1.1/xsd" targetNamespace="http://jdi.communardo.de/swatesttypes/2008-01">
      <xsd:import namespace="http://ws-i.org/profiles/basic/1.1/xsd" />
      <xsd:complexType name="swatestMessageType">
        <xsd:sequence>
          <xsd:element name="requestId" type="xsd:string" />
          <xsd:element name="clientNr" type="xsd:string" />
          <xsd:element name="formFields"
            type="types:formField" minOccurs="0" maxOccurs="unbounded" />
          <xsd:element name="attachmentForm" type="ref:swaRef"
            minOccurs="0" maxOccurs="1" />
          <xsd:element name="fileName" type="xsd:string" />
        </xsd:sequence>
      </xsd:complexType>
      <xsd:complexType name="formField">
        <xsd:all>
          <xsd:element name="name" type="xsd:string" />
          <xsd:element name="value" type="xsd:string" />
        </xsd:all>
      </xsd:complexType>
      <xsd:element name="newMessage" type="types:swatestMessageType" />
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="createNewMessageRequest">
    <wsdl:part name="newMessageRequest" element="types:newMessage" />
    <wsdl:part name="attachment" type="xsd:base64Binary" />
  </wsdl:message>
  <wsdl:portType name="swatestPortType">
    <wsdl:operation name="createNewMessage">
      <wsdl:input message="tns:createNewMessageRequest"></wsdl:input>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="swatestBinding" type="tns:swatestPortType">
    <soap:binding style="document"
      transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="createNewMessage">
      <soap:operation
        soapAction="http://jdi.communardo.de/swatest/2008-1/createNewMessage" />
      <wsdl:input>
        <mime:multipartRelated>
          <mime:part>
            <soap:body parts="newMessageRequest" use="literal" />
          </mime:part>
          <mime:part>
            <mime:content part="attachment" type="*/*" />
          </mime:part>
        </mime:multipartRelated>
      </wsdl:input>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="swatestService">
    <wsdl:port name="swatestPort" binding="tns:swatestBinding">
      <soap:address location="http://jdi.communardo.de/" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Der Service stellt eine Operation createNewMessage zur Verfügung, die ein Attachment nach dem SwA-Standard sowie ein paar andere Parameter erwartet.

Erzeugen der Typklassen und Stubs mit Maven 2

Für die Erzeugung der Axis2-Typklassen und -Stubklassen wird wie oben schon erwähnt Maven 2 eingesetzt. Für Maven 2 gibt es das axis2-wsdl2code-maven-plugin. Mit dem folgenden Maven 2 pom und mvn package können die Klassen aus der obigen WSDL generiert werden:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>de.communardo.jdi</groupId>
  <artifactId>techblog-wsgen</artifactId>
  <name>Techblog WSDL Axis2 Testprojekt</name>
  <version>1.0-SNAPSHOT</version>
  <description>Techblog WSDL Axis2 Testprojekt</description>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.axis2</groupId>
        <artifactId>axis2-wsdl2code-maven-plugin</artifactId>
        <version>1.4</version>
        <executions>
          <execution>
            <id>wsdl2codeSwA</id>
            <goals>
              <goal>wsdl2code</goal>
            </goals>
            <configuration>
              <packageName>de.communardo.jdi.swatest</packageName>
              <wsdlFile>${basedir}/src/main/wsdl/MySwA.wsdl</wsdlFile>
              <databindingName>adb</databindingName>
              <generateAllClasses>true</generateAllClasses>
              <generateServerSide>true</generateServerSide>
              <generateServerSideInterface>true</generateServerSideInterface>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>org.apache.axis2</groupId>
      <artifactId>axis2</artifactId>
      <version>1.4</version>
      <scope>provided</scope>
    </dependency>
    <!--AXIOM Dependencies-->
    <dependency>
      <groupId>org.apache.ws.commons.axiom</groupId>
      <artifactId>axiom-impl</artifactId>
      <version>1.2.7</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.ws.commons.axiom</groupId>
      <artifactId>axiom-api</artifactId>
      <version>1.2.7</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.ws.commons.axiom</groupId>
      <artifactId>axiom-dom</artifactId>
      <version>1.2.7</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.neethi</groupId>
      <artifactId>neethi</artifactId>
      <version>2.0.2</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.13</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>commons-httpclient</groupId>
      <artifactId>commons-httpclient</artifactId>
      <version>3.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>wsdl4j</groupId>
      <artifactId>wsdl4j</artifactId>
      <version>1.6.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.ws.commons.schema</groupId>
      <artifactId>XmlSchema</artifactId>
      <version>1.3.2</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>stax</groupId>
      <artifactId>stax-api</artifactId>
      <version>1.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.codehaus.woodstox</groupId>
      <artifactId>wstx-asl</artifactId>
      <version>3.2.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>backport-util-concurrent</groupId>
      <artifactId>backport-util-concurrent</artifactId>
      <version>2.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <version>1.3</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.1.1</version>
      <scope>provided</scope>
    </dependency>
    <!-- JMS Dependencies -->
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-core</artifactId>
      <version>5.1.0</version>
    </dependency>
  </dependencies>
</project>

Aufruf von Maven 2 aus dem Maven 1 Buildprozess

Da der Buildprozess in dem Projekt noch auf Maven 1 basiert und ich trotzdem nicht auf die Codegenerierung verzichten wollte, habe ich aus dem Maven 1 Buildprozess heraus Maven 2 aufgerufen. Dazu waren folgende Einträge in der Maven 1 project.xml und maven.xml erforderlich:

project.xml:

  ...
  <build>
    <defaultGoal>jdi:build</defaultGoal>
    <sourceDirectory>${basedir}/target/generated-sources/axis2/wsdl2code</sourceDirectory>
    <sourceDirectory>${basedir}/src/main/java</sourceDirectory>
  </build>
  ...

maven.xml:

  ...
  <goal name="jdi:build"
      description="Installiert zip in lokale Repos"
      prereqs="jdiInternal:generate,jar:install">
  </goal>

  <!-- Ruft Maven 2 auf, um den Sourcecode zu generieren. -->
  <goal name="jdiInternal:generate">
      <ant:echo message="${os.name}" />
      <ant:exec executable="mvn.bat" os="Windows 2000, Windows XP" dir="${basedir}">
        <arg line="package" />
      </ant:exec>
      <ant:exec executable="mvn" os="Linux, SunOS, Unix" dir="${basedir}">
        <arg line="package" />
      </ant:exec>
  </goal>
  ...

Die Unterscheidung nach Betriebssystem ist leider nötig, da ant:exec unter Windows nicht die Dateiendung ergänzt, wie man dies von der Kommandozeile gewohnt ist.

Axis2 1.4 und JMS

Für Axis2 gibt es einen mitgelieferten JMS-Connector, allerdings stellte sich heraus, dass dieser für unsere Zwecke unbrauchbar war. Der Connector konnte weder mit unidirektionalen WebServices umgehen noch konnte er unsere SwA-Nachricht transportieren. Um trotzdem JMS nutzen zu können, habe ich die Stub-Klassen angepasst, so dass sie die Attachments korrekt im MessageContext integrieren und das eine eigene AXIOM-basierte JMS-Client-Implementierung die JMS-Nachrichten in der überschriebenen invoke(MessageContext)-Methode zusammenbaut. Im Gegensatz zum bei Axis2 mitgelieferten JMS-Connector wird dabei ein JMSByteMessage verwendet und die SwA-Serialisierung von Axis2 genutzt. Als Proof-of-Concept habe ich das Gleiche auch mit einer MTOM-Nachricht hinbekommen, dies wurde allerdings von dem WebService-Endpoint auf der Gegenseite nicht unterstützt.

Wichtig ist, dass der Stub folgendermaßen initialisiert wird:

JMSSwaTestStub stub = new JMSSwaTestStub(config, jmsEndpointUrl.toString());
stub._getServiceClient().getOptions().setUseSeparateListener(false);
stub._getServiceClient().getOptions().setProperty(Constants.Configuration.ENABLE_SWA, Constants.VALUE_TRUE);
stub._getServiceClient().getOptions().setProperty(Constants.Configuration.ENABLE_MTOM, Constants.VALUE_FALSE);

Das Attachment wird folgendermaßen in den MessageContext geschrieben:

    try {
      String contentId = _messageContext.addAttachment(attachmentData);
      SwaRef swaref = new SwaRef();
      swaref.setSwaRef(new URI("cid:" + contentId));
      newMessage5.getNewMessage().setAttachmentForm(swaref);
    } catch (MalformedURIException mue) {
      throw new AxisFault(mue.getLocalizedMessage(), mue);
    }

Die Verwendung einer ByteMessage wird folgendermaßen erzwungen:

    _messageContext.setProperty(JMSConstants.JMS_MESSAGE_TYPE, JMSConstants.JMS_BYTE_MESSAGE);

ActiveMQ-Überwachung

ActiveMQ bietet mehrere Möglichkeiten zur Überwachung der Queues dazu gehören

  • WebInterface
  • RSS- und Atom-Feeds
  • JMX

Per JMX lassen sich sehr leicht die Namen der Queues und ihr Füllstand überwachen. Bei Fehlern werden Nachrichten in eine spezielle Dead Letter Queue geschrieben. Zusätzlich haben wir für Applikationsfehler noch eine Error-Queue definiert, die der Konsument der JMS-Nachrichten genutzt hat, um auf Fehler von der HTTP/SOAP-Gegenstelle zu reagieren.

Fazit

Der Einsatz von ActiveMQ als Message-Queuing Middleware hat sich für das Projekt gelohnt, auch wenn uns der schlechte JMS-Support in Axis2 einige Stolpersteine in den Weg gelegt hat.

ActiveMQ bietet auch eine ganze Reihe von Möglichkeiten, die wir im Rahmen des Projektes nicht ausschöpfen konnten. Interessant sind dabei z.B. die Konnektoren zu anderen Transportprotokollen als JMS, z.B. XMPP (Jabber), OpenWire und Stomp. Die Dokumentation auf der ActiveMQ Webseite (http://activemq.apache.org/) ist sehr umfangreich, aber insbesondere im Hinblick auf die Konfiguration nicht immer ganz aktuell und vollständig. Hier mussten wir gelegentlich einen Blick in den zum Glück verfügbaren Sourcecode werfen, um alles richtig zu konfigurieren.

Bei Axis2 sieht das Bild etwas getrübter aus. Für “normale” Einsatzgebiete wie reine HTTP/SOAP-WebServices ist die Unterstützung sehr gut, allerdings stößt man bei Attachments und insbesondere der Nutzung anderer Transportprotokolle, in unserem Fall JMS, schnell an Grenzen und Fehler und muss sich selbst helfen. Auch die Dokumentation auf der Projektwebseite (http://ws.apache.org/axis2/) ist recht lückenhaft. Axis2 hat allerdings eine große und aktive Entwicklercommunity, so dass zu hoffen ist, das sich diese Situation im Laufe der Zeit verbessert.

Kommentar Feed Trackback URL
jdi

Bei der Kommunikation über Java-RMI gibt es einen sehr hässlichen Fallstrick, für den ich hier eine Lösung beschreibe.

Artikel vollständig lesen »

Kommentar Feed Trackback URL
jdi

In einem existierenden Java2 1.4 Projekt sollen generierte XFire-Clientklassen verwendet werden. Der XFire-Codegenerator verwendet JAXB2 und ist damit auf einige Java2 5.0-Features wie Annotations angewiesen. Der Umstieg auf Java2 5.0 ist in dem Projekt keine Option und deshalb habe ich eine Möglichkeit gebraucht, die generierten Klassen mit Java2 1.4 zu verwenden.

Nach ein paar Recherchen habe ich mich für die Verwendung des freien Retrotranslator-Tools entschieden und eine Proof-Of-Concept-Implementierung realisiert. Retrotranslator kann sowohl zur Compile-Zeit als auch zur Laufzeit den Java2 5.0 Bytecode in Java2 1.4 Bytecode umwandeln. Für den eigenen Code habe ich mich für die Umwandlung zur Compilezeit entschieden und für verwendeten Code Dritter für die Umwandlung zur Laufzeit (Just in Time Compilierung).

Nun zur praktischen Umsetzung mit Maven2:

Das POM des Codegenerierungsprojektes sieht folgendermaßen aus:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>de.communardo.techblog</groupId>
  <artifactId>demoxfiregen</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Generierter XFire-Code fuer Communardo Techblog</name>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>xfire-maven-plugin</artifactId>
        <version>1.0-SNAPSHOT</version>
        <executions>
          <execution>
            <goals>
              <goal>wsgen</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <package>
            de.communardo.techblog.services
          </package>
          <profile />
          <binding />
          <outputDirectory>
            ${project.build.directory}/generated-sources/xfire
          </outputDirectory>
          <wsdls>
            <wsdl>
              ${basedir}/src/main/resources/TechblogDemoService.wsdl
            </wsdl>
          </wsdls>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>retrotranslator-maven-plugin</artifactId>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>translate-project</goal>
            </goals>
            <configuration>
              <classifier>jdk14</classifier>
              <attach>true</attach>
              <embed>net.sf.retrotranslator</embed>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.codehaus.xfire</groupId>
      <artifactId>xfire-jaxb2</artifactId>
      <version>1.2.5</version>
    </dependency>
  </dependencies>
</project>

Der erste Plugin-Aufruf setzt die Java-Version auf 1.5, der Zweite generiert den Java-Code aus einer WSDL und der dritte generiert in der package-Phase von Maven ein Java2 1.4 kompatibles JAR-Archiv mit dem Classifier jdk14. Mit

mvn install

wird alles gebaut und ins lokale Maven-Repository installiert.

Im Java2 1.4-Projekt wird das generierte JAR in den Dependencies so referenziert:

    <dependency>
      <groupId>de.communardo.techblog</groupId>
      <artifactId>demoxfiregen</artifactId>
      <version>1.0-SNAPSHOT</version>
      <classifier>jdk14</classifier>
    </dependency>

Um alle Abhängigkeiten, die von XFire und den JAXB2-Klassen benötigt werden zu erfüllen und den Retrotranslator Just-In-Time-Compiler (JIT) vefügbar zu machen, wurden noch folgende Dependencies in das Ziel-POM eingetragen:

    <dependency>
      <groupId>net.sf.retrotranslator</groupId>
      <artifactId>retrotranslator-transformer</artifactId>
      <version>1.2.1</version>
    </dependency>
    <dependency>
      <groupId>javax.xml.parsers</groupId>
      <artifactId>jaxp-api</artifactId>
      <version>1.4</version>
    </dependency>
    <dependency>
      <groupId>com.sun.org.apache</groupId>
      <artifactId>jaxp-ri</artifactId>
      <version>1.4</version>
    </dependency>
    <dependency>
      <groupId>xerces</groupId>
      <artifactId>xercesImpl</artifactId>
      <version>2.8.1</version>
    </dependency>

Damit das Ganze dann zur Laufzeit funktioniert muss beim Start der Applikation der Retrotranslator JIT genutzt werden, das geschieht in dem man die JVM-Kommandozeile folgendermaßen aufbaut:

java <JVM-Parameter> net.sf.retrotranslator.transformer.JITRetrotranslator <Main-Klasse> <Anwendungsparameter>

Kommentar Feed Trackback URL
jdi

Nach dem gestrigen Erfolg folgte heute eine Anforderung, die den Wechsel zu einem anderen Maven2-Plugin und einer neuen Mapping-Datei führte.

Die neue Anforderung war, dass Attribute aus der DTD auf andere Typen als String gemappt werden sollen. Da DTDs keine Typisierung wie XML-Schema kennen, muss dies mit einem Mapping-File geschehen. Das Maven2-Plugin aus dem gestrigen Artikel war leider mit dem Mapping der Attribute überfordert.

Jetzt wurde das Maven2-JAXB-Plugin von java.net verwendet, damit ändert sich die pom.xml folgendermaßen:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>de.mms-dresden</groupId>
  <artifactId>hsp-search-gen</artifactId>
  <name>Hilfe- und Support-Portal generierter Code fuer die Suche</name>
  <version>0.1-SNAPSHOT</version>
  <parent>
    <groupId>de.mms-dresden</groupId>
    <artifactId>hsp</artifactId>
    <version>0.1-SNAPSHOT</version>
  </parent>
  <description>Generierter Code fuer die Suche im Hilfeportal</description>
  <build>
    <plugins>
      <plugin>
        <groupId>org.jvnet.jaxb2.maven2</groupId>
        <artifactId>maven-jaxb2-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>generate</goal>
            </goals>
            <configuration>
              <generateDirectory>${project.build.directory}/generated-sources/jaxb</generateDirectory>
              <extension>true</extension>
              <schemaLanguage>DTD</schemaLanguage>
              <schemaIncludes>
                <schemaInclude>*.dtd</schemaInclude>
              </schemaIncludes>
              <bindingIncludes>
                <bindingInclude>*.jaxb</bindingInclude>
              </bindingIncludes>
              <verbose>true</verbose>
              <args>
                <arg>-Xinject-listener-code</arg>
              </args>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.jvnet.jaxb2-commons</groupId>
            <artifactId>property-listener-injector</artifactId>
            <version>1.0</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>

  <repositories>
    <repository>
      <id>maven2-repository.dev.java.net</id>
      <url>http://download.java.net/maven/2/</url>
    </repository>
  </repositories>

  <pluginRepositories>
    <pluginRepository>
      <id>maven2-repository.dev.java.net</id>
      <url>http://download.java.net/maven/2/</url>
    </pluginRepository>
  </pluginRepositories>

  <dependencies>
    <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
    </dependency>
  </dependencies>
</project>

Bei der Angabe der Repository-Pfade muss man aufpassen, weil die Angaben auf der Projektseite des Plugins inzwischen nicht mehr stimmen. Stattdessen mussten die Pfade aus der Repositoryseite von java.net verwendet werden.

Die Dependency-Versionen sind jetzt im Parent-POM definiert, entsprechen aber den Versionen aus dem gestrigen Beitrag.

Das Mapping mappt jetzt das Attribut HITCOUNT des Elements NAVIGATIONENTRY auf den Java-Typ int (genauer gesagt den Wrapper Integer um auch null-Werte darstellen zu können) und sieht jetzt folgendermaßen aus:

<?xml version="1.0" ?>
<!--
	The syntax of the binding file for DTD is defined in the JAXB EA.
	See vendorSchemaLangs.html for details.
-->
<xml-java-binding-schema xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
  xmlns:ci="http://jaxb.dev.java.net/plugin/listener-injector">

  <!-- specify the package name for the generated code -->
  <options package="de.mms_dresden.mip.hsp.base.services.search" />
  <xjc:serializable/>

  <element name="NAVIGATIONENTRY" type="class">
    <attribute name="HITCOUNT" convert="int" />
  </element>
</xml-java-binding-schema>

Kommentar Feed Trackback URL
jdi

Heute mussten aus einer existierenden DTD ein paar JAXB2-Binding-Klassen generiert werden. Nach einigem probieren ist dies mit folgender pom.xml und einem passenden Binding-File gelungen.

Hier die pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
>
  <modelVersion>4.0.0</modelVersion>
  <groupId>de.mms-dresden</groupId>
  <artifactId>hsp-search-gen</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <description>Generierter Code fuer die Suche im Hilfeportal</description>
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>jaxb2-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>xjc</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <schemaDirectory>${basedir}/src/main/dtd</schemaDirectory>
          <dtd>true</dtd>
          <xmlschema>false</xmlschema>
          <schemaFiles>FastSearchResult.dtd</schemaFiles>
          <strict>false</strict>
          <verbose>true</verbose>
          <explicitAnnotation>true</explicitAnnotation>
          <packageName>de.mms_dresden.mip.hsp.base.services.search</packageName>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>2.0</version>
    </dependency>
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-impl</artifactId>
      <version>2.0.3</version>
    </dependency>
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-xjc</artifactId>
      <version>2.0.3</version>
    </dependency>
  </dependencies>
</project>

und hier noch das passende File FastSearchResult.xjb:

<?xml version="1.0" encoding="UTF-8"?>
<xml-java-binding-schema>
<options package="de.mms_dresden.mip.hsp.base.services.search" />
<element name="SEGMENTS" type="class" root="true" />
</xml-java-binding-schema>

Die generierten Klassen landen damit in target/generated-sources/jaxb

Kommentar Feed Trackback URL
jdi

Als Ergänzung zu dem Beitrag “XFire-WebService-Client mit Maven2 generieren” möchte ich heute noch eine Implementierung für den Service vorstellen, damit man das Beispiel aus dem ersten Beitrag lokal nachvollziehen kann.

Die Implementierung benutzt den XFireServer, der auf Jetty basiert und damit recht leichtgewichtig ist. Bei Interesse werde ich in einem weiteren Beitrag noch die Integration mit Tomcat und Spring beschreiben.

Als Basis für dieses Beispiel dient die WSDL und der generierte Java-Code aus dem ersten Artikel. Die benötigten Dateien befinden sich in der Datei xfirefun-service.zip. Die Implementierung liefert angeforderte Dateien aus und benutzt die JaxbServiceFactory für die eigentliche Servicegenerierung.

Kommentar Feed Trackback URL
jdi

In einem aktuellen Projekt gab es die Erforderniss mehrere WebServices für ein Portal bereitzustellen. Da das Spring-Framework und Maven 2 zur Verfügung standen und ich mich etwas tiefergehend mit den Möglichkeiten des WebService-Frameworks XFire beschäftigen wollte, habe ich mich für eine Realisierung damit entschieden.

Heute stelle ich kurz vor, wie man mit Maven 2 und dem XFire-Plugin aus einer WSDL-Datei einen WebService-Client generieren und dann z.B. in einer Testklasse nutzen kann.

Zuerst benötigt man einmal eine WSDL-Beschreibung eines WebService, dafür stelle ich ein kleines Beispiel (xfirefun.wsdl) bereit, es kann aber prinzipiell eine beliebige valide WSDL-Datei genutzt werden.

Alle Dateien die zum Nachvollziehen dieser kurzen Anleitung benötigt werden, liegen in der Zip-Datei xfirefun.zip.

Für den Build mit Maven 2 das XFire-Maven-Plugin benötigt und konfiguriert. Der entsprechende Abschnitt in der pom.xml sieht folgendermaßen aus:

  ...
  <build>
    ...
    <plugins>
      ...
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>xfire-maven-plugin</artifactId>
        <version>1.0-SNAPSHOT</version>
        <executions>
          <execution>
            <goals>
              <goal>wsgen</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <package>de.communardo.ws.xfirefun</package>
          <profile></profile>
          <binding></binding>
          <outputDirectory>${project.build.directory}/generated-sources/client</outputDirectory>
          <wsdls>
            <wsdl>${basedir}/src/main/wsdl/xfirefun.wsdl</wsdl>
          </wsdls>
        </configuration>
      <plugin>
      ...
    </plugins>
    ...
  </build>
  ...

Wenn man nun mvn install aufruft, generiert Maven im Verzeichnis target/client die Webservice-Endpoint- und Datentypklassen. Die eine eigene Clientklasse (XfireFunClientTest.java) dann einfach folgendermaßen nutzen kann:

...
// Client erzeugen
FunClient client = new FunClient();
// Endpoint festlegen und SOAP-Proxy holen
Fun fun = client.getFun(endpoint);
// Request-Objekt erzeugen und befuellen
FunRequest request = new FunRequest();
request.setFileName(filename);
// Remotezugriff absetzen
try {
  FunResponse response = fun.getFile(request);
  FileOutputStream fos = new FileOutputStream(response.getFileName());
  fos.write(response.getData());
} catch (Exception e) {
  e.printStackTrace(System.err);
}
...

Kommentar Feed Trackback URL

Tag Cloud

Unsere Themen

Kommentare

  • SharePoint_Team: Rückblick zum Treffen der .NET Usergroup Dresden am 24.02.2010: im #Communardo #Techblog...
  • TorstenHu: Rückblick zum Treffen der .NET Usergroup Dresden am 24.02.2010: im #Communardo #Techblog...
  • SharePoint_Team: Neuer Blogpost zur #BastaCon im #Communardo #TechBlog: http://tinyurl.com/yjqyqpb This comment was...
  • SharePoint_Team: Nur noch etwa 1 Stunde, dann beginnt die .NET Usergroup… http://bit.ly/dxDoKg This comment was...
  • SharePoint_Team: RT @TorstenHu: ViS is waiting for an operation oder Warum Copy & Paste schlecht ist: #Communardo...

Twitter