Startseite > Techblog > Artikel mit dem Tag: jee
nächste Seite
sdi

Das Bauen und Ausliefern von normalen und eigenständigen Java Anwendungen die nicht in einem Webcontainer oder Applikationserver laufen sollen kann sich als schwierig erweisen. Die größten Probleme beim Erzeugen der Releases sind dabei die folgenden Punkte:

  • es müssen die benötigten Bibliotheken aufgelöst und mit in des Release gepackt werden
  • die Java Applikation muss in den meisten Fällen auf dem Zielsystem als Dienst laufen (Deamon)
  • das Erstellen und Packen des Releases sollte automatisiert erfolgen

Das Maven 2 Plugin appassembler zielt auf diesen Anwendungsfall ab und ermöglicht

  • das automatisierte Erstellen von Skripten zur einfachen Ausführung der Applikation
  • das Erzeugen von Releases die es ermöglichen, die Java Anwendung als Dienst zu betreiben
  • die Erzeugung von Repositories die alle nötigen Bibliotheken für die Anwendung enthalten.

Die Konfiguration des Plugins ist aber leider nicht ganz so einfach da die Dokumentation eher schlecht ist und ich auch auf Bugs im Plugin selber gestoßen bin.

Im Folgenden ist  eine Konfiguration als Beispiel aufgelistet die eine Deamonapplikation erzeugt.  Um die Applikation als Dienst betreiben zu können wird vom Plugin  der weit verbreitete Java Service Wrapper eingesetzt.

Beispielkonfiguration

<plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>appassembler-maven-plugin</artifactId>
 <configuration>
   <repositoryLayout>flat</repositoryLayout>
   <includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
   <target>${project.build.directory}/appassembler</target>
     <daemons>
       <daemon>
         <id>daemon-app</id>
         <mainClass>de.communardo.appassembler.Launcher</mainClass>
         <commandLineArguments>
           <commandLineArgument>start</commandLineArgument>
         </commandLineArguments>
         <platforms>
           <platform>jsw</platform>
         </platforms>
         <jvmSettings>
           <extraArguments>
             <extraArgument>-server</extraArgument>
           </extraArguments>
           <initialMemorySize>64M</initialMemorySize>
           <maxMemorySize>512M</maxMemorySize>
           <systemProperties>
             <systemProperty>property=value</systemProperty>
           </systemProperties>
         </jvmSettings>
         <generatorConfigurations>
           <generatorConfiguration>
             <generator>jsw</generator>
             <includes>
               <include>linux-x86-32</include>
               <include>linux-x86-64</include>
             </includes>
             <configuration>
               <property>
                 <name>configuration.directory.in.classpath.first</name>
                 <value>conf</value>
               </property>
               <property>
                 <name>set.default.REPO_DIR</name>
                 <value>lib</value>
               </property>
               <property>
                 <name>wrapper.logfile</name>
                 <value>logs/wrapper.log</value>
               </property>
               <property>
                 <name>wrapper.logfile.maxsize</name>
                 <value>10m</value>
               </property>
               <property>
                 <name>wrapper.logfile.maxfiles</name>
                 <value>5</value>
               </property>
               <property>
                 <name>wrapper.console.title</name>
                 <value>appassembler application</value>
               </property>
               <property>
                 <name>run.as.user.envvar</name>
                 <value>root</value>
               </property>
               <property>
                 <name>wrapper.working.dir</name>
                 <value>d:\</value>
               </property>
               <property>
                 <name>set.default.APP_BASE</name>
                 <value>d:\</value>
               </property>
             </configuration>
           </generatorConfiguration>
         </generatorConfigurations>
       </daemon>
     </daemons>
   </configuration>
   <executions>
     <execution>
       <id>create-release</id>
       <goals>
         <goal>create-repository</goal>
         <goal>generate-daemons</goal>
       </goals>
       <configuration>
         <assembleDirectory>${project.build.directory}/appassembler/jsw/daemon-app</assembleDirectory>
         <repoPath>lib</repoPath>
       </configuration>
       <phase>package</phase>
     </execution>
   </executions>
</plugin>

Parameter

mainClass Die auszuführende Klasse.
commandLineArguments Parameter die beim Aufruf mit übergeben werden sollen.
platforms Die Liste der Plattformen für die ein Release erzeugt werden soll, hier “jsw” (Java Service Wrapper).
jvmSettings Faßt Konfigurationsparameter für die Java VM zusammen wie z.B. Speichereinstellungen, zusätzliche System Properties die gesetzt werden sollen oder Parameter für den Aufruf der VM
includes Ermöglicht die optionale Definition der Zielumgebungen, hier linux 32 und 64 bit, kann auch weggelassen werden.
configuration.directory.in.classpath.first Legt fest, dass ein bestimmtes Verzeichnis mit in den Classpath der VM aufgenommen wird. Darin lassen sich gut Konfigurationsdateien ablegen die von der Applikation beim Betrieb gebraucht werden.
set.default.REPO_DIR Das Verzeichnis in denen sich die Bibliotheken befinden.
run.as.user.envvar Der Nutzer mit dem die Applikation ausgeführt werden soll, wichtig beim Betrieb in Linuxumgebungen.
wrapper.xxx Einstellungen für den Java Service Wrapper wie z.b. das Arbeitsverzeichnis, Anzahl der Logfiles usw.
assembleDirectory, repoPath Diese Parameter konfigurieren das Zielverzeichnis für das zu erstellende Repository. Leider wird bei den Standardwerten das Repository in einem anderen Verzeichnis erzeugt als der Java Service Wrapper, daher ist eine Anpassung nötig.
<goals>
<goal>create-repository</goal>
<goal>generate-daemons</goal>
</goals>
Erzeugt die definierten Deamons und ein Library Repository mit allen Abhängigkeiten des Projekts.

Kommentar Feed Trackback URL
sdi

Asynchrone Prozesse werden sehr häufig in Enterprise Applikationen eingesetzt um Abläufe zu beschleunigen. Um diese mit EJB 3.0 zu realisieren kam man um den Einsatz von Message Driven Beans und JMS nicht herum, da diese die einzige Möglichkeit darstellten asynchrone Aufrufe zu realisieren. Mit der Einführung von EJB 3.1 und der neuen Annotation @Asynchronous wird es nun möglich, Methoden direkt als asynchron zu deklarieren.

Was bedeutet das?

Bei einem Aufruf einer asynchronen Methode wird die Kontrolle sofort an den Client zurückgegeben, noch bevor der EJB Container den Aufruf an die Session Bean delegiert hat. Der Client ist somit nicht blockiert und kann mit der Ausführung fortfahren. (fire and forget Prinzip)

Wie werden Methoden als asynchron markiert?

Für die asynchrone Ausführung wurde die Annotation @Asynchronous eingeführt.

Die Annotation kann angewendet werden auf

  • eine Methode einer Beanklasse
  • eine Methode eines Local/Remote Interfaces
  • alle Methoden einer Klasse
  • alle Methoden eines Local/Remote Interfaces

Alternativ können Methoden auch per deployment Descriptor als asynchron definiert werden.

Welche Signatur haben asynchrone Methoden?

Der Rückgabewert asynchroner Methoden ist entweder void oder Future<V>, wobei V dem entsprechenden Rückgabetyp entspricht.

Beim Rückgabewert void darf die Methode keinerlei anwendungsspezifische Ausnahmen deklarieren.

Bei Rückgabe eines Futureobjektes hat der Client die Möglichkeit, das Ergebnis des Aufrufes abzufragen. Dabei kann es sich um ein reguläres Ergebnis oder um eine Ausnahme handeln.

Wie verhält es sich mit Transaktionen?

Bei Aufrufen von asynchronen Methoden ist zu beachten, dass der Transaktionskontext des Clients nicht übernommen wird.

  • Ist die Methode mit dem Transaktionsattribut REQUIRED markiert, wird immer eine neue Transaktion erzeugt. Sie verhält sich somit genauso als wenn sie mit REQUIRES_NEW markiert wäre.
  • Ist die Methode mit dem Transaktionsattribut MANDATORY markiert wird immer eine TransactionRequiredException Exception  erzeugt.
  • Ist die Methode mit dem Transaktionsattribut SUUPORTS markiert wird die Methode immer ohne Transaktion ausgeführt.

Mit der neuen Annotation wird es für den Entwickler einfacher asynchrone Prozesse zu realisieren. Er muss dafür nicht mehr auf JMS zurückgreifen und kann sich auf das Wesentliche konzentrieren.

Kommentar Feed Trackback URL
tre

Die nunmehr Achte Veranstaltung der Java User Group Saxony stand am 10.9.2009 unter dem Motto EJB 3.1. Wir konnten gemeinsam mit unseren Sponsoren (unser Dank gilt der planConnect GmbH und der Communardo Software GmbH) Adam Bien mit seinem Vortrag „Extreme Lightweight Architectures (XLAs :-) ) mit Java EE 6 und insbesondere EJB 3.1“ für die JUG gewinnen. Knapp 100 Besucher waren gespannt auf  den Referenten des Abends, der extra für uns aus München  in die sächsische Landeshauptstadt gekommen war. Adam Bien ist Consultant, Entwickler und Architekt,  Java Champion, Expert Group Member  für  Java EE 6, EJB 3.1, Time and Date und JPA 2.0 sowie Autor zahlreicher Bücher rund um das Thema Java Architekturen.

In seinem Vortrag hat er mit einigen typischen Vorurteilen gegenüber EJBs, die noch aus den Tagen vor EJB 3.0 stammen, aufgeräumt. Sowohl mit theoretischen Mitteln als auch anhand von Codebeispielen wurden z.B. die folgenden Aussagen widerlegt:

  • EJBs sind schwergewichtig
  • EJBs sind schwer zu testen
  • EJBs sind nicht portierbar
  • EJBs sind nicht erweiterbar
  • EJBs sind langsam
  • EJBs skalieren nicht
  • EJBs sind zu komplex
  • EJBs sind nur schwer in Web Frameworks zu integrieren
  • EJBs sind schwer zu konfigurieren
  • EJBs sind schwer zu migrieren
  • EJBs lassen sich nur schwer entwickeln

Fazit des ersten Teils: Mit EJB 3.0 und 3.1 sind diese Aussagen nicht mehr zutreffend. Die Ursachen für komplizierte EJB Konstrukte sind im Overengineering der Architektur zu suchen.

Im zweiten Teil seines Vortrages hat Adam Bien seine Vorstellungen einer zweckmäßigen Architektur vorgestellt und mit zahlreichen Pattern unterlegt.  Trotz aller Vereinfachungen auf technischer Seite gilt weiterhin der Leitsatz: Keep it simple. Auch in der Softwarearchitektur sind Wahrscheinlichkeiten abzuwägen. Benötige ich tatsächlich noch einen zusätzlichen Layer um zwei Softwarekomponenten zu entkoppeln? Gibt es bereits Anforderungen die diesen Aufwand rechtfertigen oder werden nur bisher unbekannte Anwendungsfälle mit geringer Realisierungswahrscheinlichkeit betrachtet? Das Ziel sollte verständlicher und leichtgewichtiger Code sein der sich genau aus diesem Grund  ohne großen Aufwand erweitern lässt und das tägliche Arbeiten nicht behindert.

Die Folien zum Vortrag sind wie immer auf den Seiten der Java User Group Saxony zu finden. Damit kann sich jeder selbst ein Bild von den Argumenten machen und die Codebeispiele studieren.

Das 9. Treffen der JUG Saxony wird bereits vorbereitet. Wir würden uns freuen auch Sie demnächst begrüßen zu dürfen.

Die nunmehr Achte Veranstaltung der Java User Group Saxony stand am 10.9.2009 unter dem Motto EJB 3.1. Wir konnten gemeinsam mit unseren Sponsoren (unser Dank gilt der planConnect GmbH und der Communardo Software GmbH) Adam Bien mit seinem Vortrag „Extreme Lightweight Architectures (XLAs :-) ) mit Java EE 6 und insbesondere EJB 3.1“ für die JUG gewinnen. Knapp 100 Besucher waren gespannt auf den Referenten des Abends, der extra für uns aus München in die sächsische Landeshauptstadt gekommen ist. Adam Bien ist Consultant, Entwickler und Architekt, Java Champion, Expert Group Member für Java EE 6, EJB 3.1, Time and Date und JPA 2.0 sowie Autor zahlreicher Bücher rund um das Thema Java Architekturen.

In seinem Vortrag hat er mit einigen typischen Vorurteilen gegenüber EJBs, die noch aus den Tagen vor EJB 3.0 stammen, aufgeräumt. Sowohl mit theoretischen Mittel als auch anhand von Codebeispielen wurden z.B. die folgenden Aussagen widerlegt:

· EJBs sind schwergewichtig

· EJBs sind schwer zu testen

· EJBs sind nicht portierbar

· EJBs sind nicht erweiterbar

· EJBs sind langsam

· EJBs skalieren nicht

· EJBs sind zu komplex

· EJBs sind nur schwer in Web Frameworks zu integrieren

· EJBs sind schwer zu konfigurieren

· EJBs sind schwer zu migrieren

· EJBs lassen sich nur schwer entwickeln

Fazit des ersten Teils: Mit EJB 3.0 und 3.1 sind diese Aussagen nicht mehr zutreffend. Die Ursachen für komplizierte EJB Konstrukte sind im Overengineering der Architektur zu suchen.

Im zweiten Teil seines Vortrages hat Adam Bien seine Vorstellungen einer zweckmäßigen Architektur vorgestellt und mit zahlreichen Pattern unterlegt. Trotz aller Vereinfachungen auf technischer Seite gilt weiterhin der Leitsatz: Keep it simple. Auch in der Softwarearchitektur sind Wahrscheinlichkeiten abzuwägen. Benötige ich tatsächlich noch einen zusätzlichen Layer um zwei Softwarekomponenten zu entkoppeln? Gibt es bereits Anforderungen die diesen Aufwand rechtfertigen oder werden nur bisher unbekannte Anwendungsfälle mit geringer Realisierungswahrscheinlichkeit betrachtet? Das Ziel sollte verständlicher und leichtgewichtiger Code sein der sich genau aus diesem Grund ohne großen Aufwand erweitern lässt und das tägliche Arbeiten nicht behindert.

Die Folien zum Vortrag sind wie immer auf den Seiten der Java User Group Saxony zu finden. Damit kann sich jeder selbst ein Bild von den Argumenten machen und die Codebeispiele studieren.

Das 9. Treffen der JUG Saxony wird bereits vorbereitet. Wir würden uns freuen auch Sie demnächst begrüßen zu dürfen.

Kommentar Feed Trackback URL
tis

Vor einer Woche war es soweit. Die Tore der diesmal von Frank Anke (Saxonia Systems) gesponsorten 6. Java User Group in Sachsen öffneten sich und Eberhard Wolff von SpringSource konnte der bisher größten Teilnehmerschar der JUG Saxony (www.jugsaxony.org) das neue Produkt SpringSource dm Server vorstellen.

Vorstellung dm Server

Vorstellung dm Server

dm Server
In der Veranstaltung betonte Eberhard Wolff die Vorteile des dm Servers, die vor allem durch den Einsatz von OSGI in der Möglichkeit liegen, Applikationsmodule zur Laufzeit des Servers zu starten, zu stoppen und auszuwechseln. Durch den modularen Aufbau von Applikationen im dm Server ist es möglich, Teile der Applikation auszutauschen, nicht wie bisher üblich die gesamte Webapplikation selbst. Der dm Server selbst enthält dabei für den Einsatz in Enterprise Applikationen bereits Lösungen für Probleme, die im Einsatz von OSGI autreten können. Ein Beispiel dafür ist die Nutzung von Log4J in mehreren Modulen oder der Einsatz von Hibernate als Datasource.

Durch die Integration des Tomcat WebServers dürfte auch die Migration bestehender Applikationen ein Kinderspiel werden. Stufenweise ist es möglich, im ersten Schritt die in der Webapplikation vorhandenen Bibliotheken als OSGI Bundles zu nutzen und aus dem Deployment der WebApplikation zu entfernen. Durch diesen Schritt hat man bereits die Möglichkeit, Bibliotheken auszutauschen, ohne den Server neu starten zu müssen. SpringSource bietet zu diesem Zweck bereits ein Bundle Repository an, das OSGI-fähige OpenSource Bibliotheken aus dem Umfeld von Java und Spring enthält. Im zweiten Schritt lohnt es sich für solche Webapplikationen durch ein Refactoring geeignete Module herauszulösen und als OSGI Bundles zu deployen. Die Modularität der Applikationen und damit deren Wartbarkeit dürfte sich so wesentlich verbessern.

Ausblick
Neben der funktionalen Vorstellung des Servers, der die Brücke zwischen der Technologie OSGI und dem WebFramework Spring schließt, überzeugten auch die Themen, die in die Entwicklung des dmServers 2.0 eingeflossen sind. Hier sind vor allem die Integration des Applikationsgedanken über Plan Files in den OSGI  Container oder das Clonen von Bibliotheken zu nennen, mit dem der gleichzeitige Betrieb von Bibliotheken mit unterschiedlichen Abhängigkeiten möglich wird. Eberhard Wolff regte auch am Beispiel des Werkzeuges Bundlor, dass für das Management der Abhängigkeiten und die Erzeugung von OSGI Manifesten genutzt werden kann, den Austausch und Feedback über den Blog von SpringSource an.

Fazit
Zusammenfassend kann man sagen, dass das Konzept des dm Servers überzeugend vorgestellt wurde. Alle, die bisher den Tomcat Webserver einsetzen, können mit geringen Migrationsaufwänden auf den dm Server wechseln und schrittweise die Vorteile ausnutzen. Auch in neuen Projekten sollte der Einsatz des dm Servers erwogen werden, da die Möglichkeiten zur Modularisierung von Applikationen erheblich verbessert werden.

In diesem Sinne: Viel Spass beim Ausprobieren. Jeder ist natürich herzlich willkommen, seine Erfahrungen hier als Kommentar zu posten.

Übrigens: Der Spring Source dm Server steht ab sofort in der Version 2.0 M1 zum Download zur Verfügung.

Kommentar Feed Trackback URL
ast

Durch JCA (J2EE Connection Architekture) können externe Systeme, wie z.B. Enterprise Information Syteme, an einen J2EE Application Server angebunden werden. JCA bietet ein flexibles Framework an, welches es erlaubt, unterschiedliche Kommunikationswege, wie z.B. Message Queueing oder Files anzubinden. Bei der Kommunikation mit externen Systemen wird zwischen der Inbound- und Outbound-Kommunikation unterschieden. In dem folgenden Beispiel soll eine Inbound-Kommunikation zwischen einem MQ Manager und einem Application Server erfolgen. Dabei soll ein MessageDriven Bean beim Eingang einer neuen Message angesprochen werden.

247-1

Der Inbound Resource Adapter besteht aus den Komponenten:

  • MQResourceAdapter
  • MQEndpointConsumer
  • MQWorkConsumer
  • MQActivationSpec
  • ra.xml

Im JCA Deploymentdiscriptor ra.xml wird der ResourceAdapter, der MessageListener und die ActivationSpec Klasse angegeben. Zusätzlich können Parameter wie, z.B. der Name des Queue-Managers oder der Host angegeben werden. Als Beispiel hier ein Auszug aus der ra.xml:

ramxl_image

Die Klasse MQActivationSpec wird zur Übertragung von Konfigurationen an den ResourcenAdapter benötigt (Auszug):

mqactivationspec

In der Klasse MQWorkConsumer findet die eigentliche Arbeit statt. Es wird die Verbindung durch den EndpointConsumer zum MQServer aufgebaut und in einem Thread wird periodisch (polling) nach neuen Messages in der Queue gesucht. Wird eine Nachricht gefunden, wird diese an die MethodeonMessage des MessageDrivenBean übergeben. Beispiel das Thread der Work-Klasse:

run_thread

Die Methode zur Übergabe der empfangenen Nachricht an onMessage des MessageDrivenBean sieht wie folgt aus:

onmessage_uebergabe

Die MessageDrivenBean Klasse, die die Verarbeitung der eingegangenen Nachricht übernimmt, muss das Interface MessageListener implementieren und im EJB Deploymentdescriptor eingetragen werden.

MQResourceAdapter ist die Implementierung des ResourceAdapters. Diese Klasse reagiert auf Lifecycle Ereignisse des Application Servers und sorgt für die Instanziierung, Start und Stop des Listeners.

mqresourceadapter

Der eigene ResourceAdapter muss in den DeploymentDescriptor des jeweiligen Applicationserver eingetragen werden. In diesem Beispiel sieht der Eintrag so aus:

ejb_jar

Der Ablauf einer Instanziierung eines Resource Adapters sieht in einem Sequenzdiagram, welches in der ConnectorArchitecture Specification zu finden ist, wie folgt aus:

240-1

 

Links zum Thema:

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
tre

Am 13./14.9.2008 fand erstmals die Berlin.jar an der FHTW Berlin statt. Die Java Konferenz wurde durch die Java User Group Berlin Brandenburg sehr gut organisiert. Verteilt über beide Konferenztage gab es in fünf parallelen Tracks zahlreiche interessante Vorträge, sowie HandsOn Sessions und Workshops für die mehr als 250 Besucher. Einige Redner sind bereits von anderen Konferenzen bekannt. So gab Eberhard Wolff gleich zu Beginn Einblick in das Lösungsangebot von SpringSource, der Firma hinter dem Spring Framework. Im Anschluss gab Torsten Fink einen Überblick über die JBoss/SOA-Plattform mit allerlei Verweisen auf den Einsatz in der Praxis. Nachdem am Grillstand für das leibliche Wohl gesorgt wurde, brachte Alexander Greif anhand einer im Rahmen seines Vortrages erstellten Anwendung den Zuhörern die Funktionsweise der Grails Plattform näher. Abgerundet wurde der Tag durch Oliver Böhms Vortrag zu aspektorientierter Softwareentwicklung. Dabei wurde der Frage „Gibt es ein Leben nach Java und OO?“ nachgegangen. Mein Fazit: Aspektorientierte Programmierung ist eine sinnvolle Ergänzung (!) zur objektorientierten Entwicklung, aber sicher kein grundsätzlich neuer Ansatz. Den Weg in die Praxis hat sie schon seit längerer Zeit gefunden, wie z.B. das Spring Framework beweist.

Leider waren damit der erste Konferenztag und unser Besuch der Berlin.jar schon vorbei. Am Tag zwei haben wir u.a. die Vorträge der ubigrate GmbH (Drahtwanderung: WIIr machen den NäXTen Schritt) und der buschmais GbR (Integrationsmuster am Beispiel von Apache Camel, Paradigmenhochzeit: Felix und ServiceMix in trauter Zweisamkeit vereint, Modellierung statischer Domänenmodelle mit Xtext) verpasst, aber vielleicht gibt es ja schon bald ein Wiedersehen bei der JUG Saxony ;-)

Dieses wird es auf alle Fälle im kommenden Jahr bei der zweiten Ausgabe der Berlin.jar geben.

Kommentar Feed Trackback URL
tre

Auch die zweite Veranstaltung der Java User Group Saxony kann als voller Erfolg bezeichnet werden. Shaun Smith, Project Lead des EclipseLink Projektes und Produktmanager für Oracle TopLink, gab am 09.07.2008 einen Überblick über die Features und die Funktionsweise von EclipseLink.

Die Firma ubigrate hat diese Veranstaltung an der Informatik Fakultät der TU-Dresden in Zusammenarbeit mit dem JUG Saxony Team für die hiesige User Group organisiert und somit mehr als 50 Teilnehmern einen informativen und unterhaltsamen Abend ermöglicht.

Shaun Smith ging während seines Vortrages detailliert auf die Java Persistence API und die Referenzimplementierung EclipseLink ein. Dabei ist insbesondere die Vielseitigkeit des Frameworks hervorzuheben. Neben Objekt-Relationalem Mapping (ORM) stellt es Funktionen zum Objekt-XML Mapping (in Version 1.0 noch nicht 100% JAXB 2.0 kompatibel) sowie Unterstützung für Service Data Objects (SDO) 2.1 zur Verfügung. Sollte dies noch nicht genügen kann EclipseLink leicht um weitere Mapping Ziele erweitert werden wie Shaun Smith anhand eines JSON Beispiels demonstriert hat.

Neben der Vorstellung von technischen Details und der ein oder anderen Anekdote aus dem Projektgeschäft (wer sich dafür interessiert sollte die kommenden JUG Veranstaltungen nicht verpassen ;-) ) wurden auch die verschiedenen Mappings und das Zusammenspiel mit den Eclipse Dali JPA Tools im Rahmen von Live Demonstrationen vorgeführt.

Am Tag unserer Veranstaltung wurde EclipseLink 1.0 veröffentlicht und somit für den Produktiveinsatz freigegeben. Einen genaueren Blick ist es auf alle Fälle wert.

Das nächste Treffen der JUG Saxony ist für Oktober 2008 geplant. Das Thema lautet Rich Client Platform (RCP) Entwicklung mit Java.

Informationen zur kommenden Veranstaltung gibt es demnächst auf der Webseite der JUG Saxony unter http://www.jugsaxony.de. Die Folien zum EclipseLink Vortrag sind ebenfalls auf dieser Seite zu finden.

Einen Bericht zum Treffen in englischer Sprache gibt es im ubigrate Blog.

Kommentar Feed Trackback URL
tre

Am 03. April 2008 fand das erste Treffen und damit die Gründungsveranstaltung der Java User Group Saxony in den Räumen der Communardo Software GmbH statt. Diese Gruppe wurde auf Initiative von Torsten Rentsch (Communardo Software GmbH) und Falk Hartmann (ubigrate) Anfang 2008 ins Leben gerufen. Ziel ist es den Wissensaustausch im Java Umfeld zu fördern sowie Kontakte zwischen Firmen und wissenschaftlichen Einrichtungen zu knüpfen.

JUG Saxony Gründungsveranstaltung

Vor 43 interessierten Teilnehmern wurde die Model Driven Architecture (MDA) vorgestellt. Herr Professor Aßmann (Lehrstuhl Softwaretechnik der TU Dresden) gab eine konzeptionelle Einleitung zum Thema und betrachtete dabei insbesondere den Zusammenhang zwischen MDA und Component-based Software Engineering (CBSE) (Folien). Herr Torsten Lunze (Communardo Software GmbH) stellte mit seinem Vortrag (Folien) den Bezug zur Praxis anhand eines Beispiels aus dem Projektgeschäft her und erläuterte u.a. die Vor- und Nachteile von MDA beim Einsatz der Open Source Software AndroMDA. Beim anschließenden Buffet blieb Zeit Kontakte zu knüpfen und das Thema im Gespräch zu vertiefen.
Mindestens einmal pro Quartal wird nun eine Veranstaltung der JUG Saxony stattfinden. Das nächste Treffen ist am 9. Juli 2008 in den Räumen der TU Dresden geplant. Das Thema wird voraussichtlich EclipseLink (JPA 2.0 RI, JSR 317) sein.
Gern können Sie sich als Mitglied der JUG Saxony auf unserer Website http://www.jugsaxony.de registrieren. Für Anregungen und Wünsche sind wir stets offen.

Kommentar Feed Trackback URL
ast

Da es sich bei Axis2 um eine Neuentwicklung gegenüber der Vorgängerversion handelt, wurde ein komplett anderes Data Binding Konzept umgesetzt. Zum Einsatz kommen bestehende Lösungen wie:

die in Axis2 integriert werden. XMLBeans stammen ursprünglich von BEA Systems und wird von Apache weiterentwickelt. XMLBeans heben den Informationsgehalt eines XML-Infosets während der Verarbeitung auf, so dass Metadaten zur Verfügung stehen, die bspw. für eine Schema-Validierung genutzt werden können. Wenn XMLBeans als Data Binging genutzt werden sollen, muss “-d xmlbeans” als Parameter angegeben werden. (Defaultwert ist ADB):

WSDL2JAVA ... -d xmlbeans meine.wsdl

Das Framework generiert für jeden benutzerdefinierten Datentyp eine Interfaceklasse, mit der man bei der Entwicklung in Berührung kommt. Alle Interfaces erben von XMLObject und erhalten eine interne statische Inner Class “Factory” mit der eine Klasse des jeweiligen Types erzeugt werden kann. Beispiel zur Erzeugung eines Objektes vom Typ Kunde:

KundeDocument kundeDoc = KundeDocument.Factory.newInstance();

Ein XML-Document kann über die Methode “save” in ein XML-Format serialisiert werden. Mit “xmlText” wird ein String als XML zurückgegeben.

String kundeXml = kundeDoc.xmlText();

kundeDoc.save(new File("kundeDoc.xml"));

Andere Data Bindings bilden Datantypen wie bspw. xsd:String, xsd:Token, xsd:anyUrl oder xsd:Name auf String ab. XMLBeans bietet hierfür eigene Datentypen, um die unterschiedlichen Wertebereiche und semantischen Bedeutung zu behalten.

Kommentar Feed Trackback URL
nächste Seite

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