Camel. Implementierung



Ähnliche Dokumente
Konfiguration VLAN's. Konfiguration VLAN's IACBOX.COM. Version Deutsch

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Konfiguration von Exchange 2000 zum versenden und empfangen von Mails & Lösung des SEND after POP Problems

Datensicherung. Beschreibung der Datensicherung

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang

Java: Vererbung. Teil 3: super()

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = Euro ergeben.

Session Beans & Servlet Integration. Ralf Gitzel ralf_gitzel@hotmail.de

BüroWARE Exchange Synchronisation Grundlagen und Voraussetzungen

ACHTUNG: Es können gpx-dateien und mit dem GP7 aufgezeichnete trc-dateien umgewandelt werden.

Anleitung über den Umgang mit Schildern

Wiederholung: Beginn

Tevalo Handbuch v 1.1 vom

Anleitung Grundsetup C3 Mail & SMS Gateway V

Er musste so eingerichtet werden, dass das D-Laufwerk auf das E-Laufwerk gespiegelt

Auszug aus JAX-WS Folien

Übung: Verwendung von Java-Threads

Einrichten eines Postfachs mit Outlook Express / Outlook bis Version 2000

VERWALTUNG. Postfächer, Autoresponder, Weiterleitungen, Aliases. Bachstraße 47, 3580 Mödring

Inhalt. 1 Einleitung AUTOMATISCHE DATENSICHERUNG AUF EINEN CLOUDSPEICHER

Anbindung des Onyx Editors an das Lernmanagementsystem OLAT Anwendungsdokumentation

Abamsoft Finos im Zusammenspiel mit shop to date von DATA BECKER

FTP-Server einrichten mit automatischem Datenupload für

FORUM HANDREICHUNG (STAND: AUGUST 2013)

Überprüfung der digital signierten E-Rechnung

Version Deutsch In diesem HOWTO wird beschrieben wie Sie Ihren Gästen die Anmeldung über eine SMS ermöglichen.

Arbeiten mit UMLed und Delphi

Schritt 1: Starten Sie Hidemyass, wählen Sie "IP: Port Proxies"

Anleitung zur Erstellung und Bearbeitung von Seiten in Typo3. Typo3. Anleitung. Wenpas Informatik

Abwesenheitsnotiz im Exchangeserver 2010

HOWTO Update von MRG1 auf MRG2 bei gleichzeitigem Update auf Magento CE 1.4 / Magento EE 1.8

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Monatstreff für Menschen ab 50 Temporäre Dateien / Browserverlauf löschen / Cookies

Das sogenannte Beamen ist auch in EEP möglich ohne das Zusatzprogramm Beamer. Zwar etwas umständlicher aber es funktioniert

E-Government Sondertransporte (SOTRA) Registrierung von Benutzerkennung

Es wird das Struts <html:option> Element erläutert und anhand von kleinen Beispielen der Umgang veranschaulicht.

Individuelle Formulare

Kommunikations-Management

Datenübernahme von HKO 5.9 zur. Advolux Kanzleisoftware

Tutorial -

Kommunikations-Parameter

Verarbeitung der Eingangsmeldungen in einem Callcenter

Einfügen von Bildern innerhalb eines Beitrages

Mail-Account Unimail mit der Einstellungen für Outlook Express 5.0

Bauteilattribute als Sachdaten anzeigen

Um ein solches Dokument zu erzeugen, muss eine Serienbriefvorlage in Word erstellt werden, das auf die von BüroWARE erstellte Datei zugreift.

Neue Funktionen im GUI für PC-DMIS V3.x 4.x Seite 1 von 8

1 topologisches Sortieren

EasyWk DAS Schwimmwettkampfprogramm

Das große ElterngeldPlus 1x1. Alles über das ElterngeldPlus. Wer kann ElterngeldPlus beantragen? ElterngeldPlus verstehen ein paar einleitende Fakten

Anleitung zur Verwendung der VVW-Word-Vorlagen

Folgende Einstellungen sind notwendig, damit die Kommunikation zwischen Server und Client funktioniert:

Artikel Schnittstelle über CSV

AZK 1- Freistil. Der Dialog "Arbeitszeitkonten" Grundsätzliches zum Dialog "Arbeitszeitkonten"

Leichte-Sprache-Bilder

Was ist PDF? Portable Document Format, von Adobe Systems entwickelt Multiplattformfähigkeit,

Virtual Channel installieren

AGROPLUS Buchhaltung. Daten-Server und Sicherheitskopie. Version vom b

Objektorientierte Programmierung. Kapitel 12: Interfaces

Software Engineering Interaktionsdiagramme

Verteilte Systeme: Übung 4

Lieber SPAMRobin -Kunde!

Anleitung zum erfassen von Last Minute Angeboten und Stellenangebote

mysql - Clients MySQL - Abfragen eine serverbasierenden Datenbank

Database Exchange Manager. Infinqa IT Solutions GmbH, Berlin Stralauer Allee Berlin Tel.:+49(0) Fax.:+49(0)

Installation der SAS Foundation Software auf Windows

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Suche schlecht beschriftete Bilder mit Eigenen Abfragen

SICHERN DER FAVORITEN

Arge Betriebsinformatik GmbH & Co.KG, CAP News 40, Februar CAP-News 40

inviu routes Installation und Erstellung einer ENAiKOON id

WordPress. Dokumentation

Beschreibung Regeln z.b. Abwesenheitsmeldung und Weiterleitung

Alle Schlüssel-Karten (blaue Rückseite) werden den Schlüssel-Farben nach sortiert und in vier getrennte Stapel mit der Bildseite nach oben gelegt.

Mit einem Mausklick sind s aus ACT! heraus in Outlook geschrieben, die dann wiederum auf Wunsch in ACT! dokumentiert werden.

Wichtige Hinweise zu den neuen Orientierungshilfen der Architekten-/Objektplanerverträge

Erstellen einer in OWA (Outlook Web App)

Tapps mit XP-Mode unter Windows 7 64 bit (V2.0)

AUTOMATISCHE -ARCHIVIERUNG. 10/07/28 BMD Systemhaus GmbH, Steyr Vervielfältigung bedarf der ausdrücklichen Genehmigung durch BMD!

Einrichten eines POP-Mailkontos unter Thunderbird Mail DE:

Installationsanleitung Maschinenkonfiguration und PP s. Release: VISI 21 Autor: Anja Gerlach Datum: 18. Dezember 2012 Update: 18.

Abwesenheitsnotiz im Exchange Server 2010

1. Einschränkung für Mac-User ohne Office Dokumente hochladen, teilen und bearbeiten

L10N-Manager 3. Netzwerktreffen der Hochschulübersetzer/i nnen Mannheim 10. Mai 2016

Anwenderdokumentation PersoSim

infach Geld FBV Ihr Weg zum finanzellen Erfolg Florian Mock

Version smarter mobile(zu finden unter Einstellungen, Siehe Bild) : Gerät/Typ(z.B. Panasonic Toughbook, Ipad Air, Handy Samsung S1):

EJB Beispiel. JEE Vorlesung 10. Ralf Gitzel

> Mozilla Firefox 3. Browsereinstellungen optimieren. Übersicht. Stand Juli Seite. Inhalt. 1. Cache und Cookies löschen

Karten-Freischaltung mit dem UNLOCK MANAGER

SANDBOXIE konfigurieren

1. Einführung. 2. Archivierung alter Datensätze

Leitfaden zur Einrichtung za-mail mit IMAP auf dem iphone

Anleitung zur Daten zur Datensicherung und Datenrücksicherung. Datensicherung

Speicher in der Cloud

Proxy. Krishna Tateneni Übersetzer: Stefan Winter

Guide DynDNS und Portforwarding

Der lokale und verteilte Fall

SRH - Kurzinformation

Transkript:

Camel Apache Camel ist eine freie, regelbasierte Routing und Konvertierungsengine. Mit Apache Camel kann man Routing- und Konvertierungsregeln deklarativ in Java oder Scala basierend auf einer domänenspezifischen Sprache, oder mittels Spring basierter XML Konfiguration definieren. Diese Seite enthält Informationen wie Camel auf dem Service-Layer eingesetzt wird und wie man damit Web Services und Routes (Orchestrierung von anderen Services) umsetzen kann. Inhalt Implementierung Konfiguration Camel Komponenten ( components-camel.xml) Spring Komponenten ( components.xml) ActiveMQ Komponenten ( components-activemq.xml) Transaktions-Handling JMS Transaktions-Handling Backend Transaktions-Handling Exception-Handling Technische Exceptions Fachliche Exceptions RouteVariable-Handling JMS Selektoren Camel Proxies Known Issues Java DSL und nested Choice-Blocks Exception-Handling in Loop- und RecipientList-Blocks Type Converter und Recipient List Camel JAXB Problem Literatur Ressourcen Implementierung Für die Implementierung einer Camel Route wird eine domänenspezifischen Sprache eingesetzt, entweder die Java DSL oder die Spring DSL. Für die Realisierung der Services auf dem Service-Layer wird die Java-DSL eingesetzt, da es mit der Spring DSL in der Camel version 2.2 noch gewisse Einschränkungen gibt (siehe Known Issues). Wird Java DSL verwendet muss eine RouteBuilder-Klasse geschrieben werden welche von der abstrakten AbstractSpringRouteBuilder Klasse erbt. Nachfolgend ein Beispiel einer RouteBuilder-Klasse: package import import import public ch.visana.services.xxx.vyyy.impl; ch.visana.services.xxx.userinfoservice; ch.visana.services.xxx.to.objectfactory; ch.visana.util.camel.abstractspringroutebuilder; class xxxserviceroute extends AbstractSpringRouteBuilder { public void configureroute() throws Exception { fromcxfendpointwithexceptionhandling(xxxservice.class, ObjectFactory.class).to( } } Innerhalb der configureroute Methode können Messages von einem CXF Endpoint konsumiert und verarbeitet werden. Dabei können verschiedene fromcxfendpoint Methoden eingesetzt werden, die ein unterschiedliches Transaktions- und ExceptionHandling-Verhalten aufweisen. Nachfolgend eine Auflistung der verschiedenen Methoden mit ihren Eigenschaften: Methode fromcxfendpoint fromcxfendpointtransacted Eigenschaften Messages werden nicht transaktional vom JMS Endpoint konsumiert, es ist kein ExceptionHandling aktiviert Messages werden transaktional vom JMS Endpoint konsumiert, es ist kein ExceptionHandling aktiviert

fromcxfendpointwithexceptionhandling fromcxfendpointtransactedwithexceptionhandling Messages werden nicht transaktional vom JMS Endpoint konsumiert, das Default- ExceptionHandling ist aktiviert Messages werden transaktional vom JMS Endpoint konsumiert, das Default- ExceptionHandling ist aktiviert Konfiguration Um ein Web Service über Camel zur Verfügung zu stellen werden diverse Komponenten benötigt die im Spring Context konfiguriert werden. Grundsätzlich kann ein Web Service auf zwei Arten exponiert werden, über JMS oder über HTTP. Aktuell wird der Web Service immer über JMS zur Verfügung gestellt, optional kann auch noch der Weg über HTTP aktiviert werden. Der Weg nur über HTTP ist aktuell nicht möglich, sollte aber in Zukunft auch möglich sein. Für Testing-Zwecke kann der Web Service noch über HTTP mit anschliessendem JMS Transport exponiert. Damit wird erreicht dass Messages mit geringem Aufwand in die Message Queue gestellt werden können. Nachfolgend eine Übersicht über die verschiedenen Transportwege über die eine Camel Route aufgerufen werden kann. Wie bereits erwähnt werden alle Camel Komponenten wie CXF Endpoint, JMS Provider usw. im Spring Context definiert. Damit dieser Spring Context überschaubar und wartbar bleibt wurde die Konfiguration auf drei Files verteilt die anschliessend beschrieben werden. Camel Komponenten ( components-camel.xml) In diesem Konfigurations-File werden Camel Komponenten wie z.b. der Camel Context oder die CXF Endpoints definiert. Nachfolgend Auszüge aus einer Camel Konfiguration mit Testing CXF HTTP Endpoint, CXF HTTP Endpoint und CXF JMS Endpoint: Camel Context Es folgt ein Beispiel eines Camel Context für Camel Routes mit Java DSL: <camelcontext trace= "true" id= "ch.visana.services.xxx.vyyy.impl.camelcontext" > <routebuilder ref= "xxxserviceroute" /> </camelcontext> Die routebuilder Referenz zeigt dabei auf ein ServiceRoute Bean die im Konfigurations-File components.xml definiert wird (siehe Spring Komponenten). Default Route ( im AbstractSpringRouteBuilder.initFromRoute() ) from( direct:barcoderelation.v2.barcoderelationservice ).routeid( barcoderelation.v2.barcoderelationservice ) if(jaxbvalidation == true) {.process( new JaxbValidatorProcessor() ) } Service ROUTE im xxxroute.java Klasse Testing CXF HTTP Endpoint

<cxf:cxfendpoint address="http://0.0.0.0:${jetty.http.port}/test/xxx/vyyy/xxxservice" id= "xxx.vyyy.xxxservicetest" serviceclass= "ch.visana.services.xxx.vyyy.xxxservice" > <cxf:properties> <beans:entry key= "dataformat" value= "MESSAGE" /> </cxf:properties> </cxf:cxfendpoint> Hier ist zu beachten dass der Context Path den Teil /test enthält damit dieser Endpoint nicht plötzlich produktiv eingesetzt wird. Testing CXF HTTP Endpoint Route ( im AbstractSpringRouteBuilder.exposeAsTestCxfEndpoint() ) from( cxf:bean:barcoderelation.v2.barcoderelationservicetest ).routeid( barcoderelation.v2.barcoderelationservice.testroute ).onexception(throwable.class).maximumredeliveries(0).handled( false).end().process( new ServiceOperationProcessor()).to( activemq:queue:${environment}.barcoderelation.v2.barcoderelationservice?jmsmessagetype=bytes ); CXF HTTP Endpoint <cxf:cxfendpoint address="http://0.0.0.0:${jetty.http.port}/xxx/vyyy/xxxservice" id= "xxx.vyyy.xxxservice.cxf" serviceclass= "ch.visana.services.xxx.vyyy.xxxservice" > <cxf:ininterceptors> <beans:bean parent= "wss4jininterceptor" /> </cxf:ininterceptors> <cxf:properties> <beans:entry key= "dataformat" value= "POJO" /> </cxf:properties> </cxf:cxfendpoint> CXF HTTP Endpoint Route ( im AbstractSpringRouteBuilder.exposeAsCxfEndpoint() ) from( cxf:bean:barcoderelation.v2.barcoderelationservice.cxf ).routeid( barcoderelation.v2.barcoderelationservice.cxfroute ).setheader(routetransporthandler.transport_type, constant(routetransporthandler.soap_http_transport_type)).process(routetransporthandler).to( direct:barcoderelation.v2.barcoderelationservice ); CXF JMS Endpoint <cxf:cxfendpoint address="camel://activemq:queue:${environment}.xxx.vyyy.xxxservice" id= "xxx.vyyy.xxxservice" serviceclass= "ch.visana.services.xxx.vyyy.xxxservice" > <cxf:ininterceptors> <beans:bean parent= "wss4jininterceptor" /> </cxf:ininterceptors> <cxf:properties> <beans:entry key= "dataformat" value= "POJO" /> </cxf:properties> </cxf:cxfendpoint> CXF JMS Endpoint Route ( im AbstractSpringRouteBuilder.initFromRoute() )

from( cxf:bean:barcoderelation.v2.barcoderelationservice ).routeid( barcoderelation.v2.barcoderelationservice.activemqroute ).transacted().policy(springtransactionpolicy).setheader(routetransporthandler.transport_type, constant(routetransporthandler.soap_jms_transport_type)).process(routetransporthandler).to( direct:barcoderelation.v2.barcoderelationservice ); Damit im CXF JMS Endpoint die Notation camel://activemq:queue: verwendet werden kann muss noch der Camel Transport für CXF konfiguriert werden, dies geschieht mit folgendem XML-Fragment: <beans:bean class= "org.apache.camel.component.cxf.transport.cameltransportfactory" > <beans:property name= "bus" ref= "cxf" /> <beans:property name= "camelcontext" ref= "ch.visana.services.userinfo.v0.impl.camelcontext" /> <beans:property name= "transportids" > <beans:list> <beans:value> http://cxf.apache.org/transports/camel</beans:value> </beans:list> </beans:property> Camel Enpoint direkt von WSDL ohne Service Class Beispiel <cxf:cxfendpoint address="camel://activemq:queue:${environment}.vision.v1.visionservice" id="vision.v1.visionservice" wsdlurl="classpath:ch/visana/services/vision/v1/impl/wsdl/ivisionsoapvisana.wsdl" endpointname="s:ivisionsoapvisanaport" servicename="s:ivisionsoapvisanaservice" xmlns:s = "http://tempuri.org/" > <cxf:properties> <beans:entry key= "dataformat" value= "MESSAGE" /> </cxf:properties> </cxf:cxfendpoint> <cxf:cxfendpoint address="/vision/v1/visionservice" id="vision.v1.visionservice.cxf" wsdlurl="classpath:ch/visana/services/vision/v1/impl/wsdl/ivisionsoapvisana.wsdl" endpointname="s:ivisionsoapvisanaport" servicename="s:ivisionsoapvisanaservice" xmlns:s = "http://tempuri.org/" > <cxf:properties> <beans:entry key= "dataformat" value= "MESSAGE" /> </cxf:properties> </cxf:cxfendpoint> Spring Komponenten ( components.xml) In diesem Konfigurations-File werden allgemeine Komponenten wie z.b. die ServiceRoute Bean oder Dozer konfiguriert. Nachfolgend ein Beispiel wie die ServiceRoute Bean konfiguriert wird: <bean id= "xxxserviceroute" class= "ch.visana.services.xxx.vyyy.impl.xxxserviceroute" > <property name= "servicenamespace" value= "xxx.vyyy.xxxservice" /> <property name= "environment" value= "${environment}" /> <property name= "springtransactionpolicy" ref= "PROPAGATION_REQUIRES_NEW" /> <property name= "exposeaswebservice" value= "true" /> <property name= "exposeastestwebservice" value= "true" /> <property name= "errorredeliverypolicy" ref= "errorredeliverypolicy" /> </bean>

Falls das Default Redelivery Verhalten bei technischen Exceptions angepasst werden soll, kann das errorredeliverypolicy Property auf eine Redelivery Policy Bean mit den gewünschten Werten gesetzt werden (siehe Exception-Handling). Falls Messages transaktional von der Message Queue konsumiert werden sollen (siehe Implementierung), dann muss das springtransactionpolicy Property gesetzt sein (siehe Transaktions-Handling). Es stehen folgende Transaktions-Propagtions zur Verfügung: Transaktion-Propagation PROPAGATION_REQUIRES_NEW PROPAGATION_REQUIRED Eigenschaft Es wird immer eine neue Transaktion gestartet um die Message zu verarbeiten Falls keine Transaktion vorhanden wird eine neue gestartet, sonst wird die bestehende verwendet Die Transaktion-Propagation Beans sind bereits vordefiniert und können mit folgendem XML-Fragment importiert werden: <beans:import resource= "classpath:ch/visana/util/camel/spring/components.xml" /> Falls die Camel Route über HTTP exponiert werden soll muss das exposeaswebservice Property auf true gesetzt werden. Zudem wird dann im Konfigurations-File components-camel.xml eine CXF HTTP Endpoint Konfiguration benötigt. Das gleiche gilt für des exposeastestwebservice Property falls die Camel Route über den Test CXF Endpoint exponiert werden soll. ActiveMQ Komponenten ( components-activemq.xml) In diesem Konfigurations-File wird die Camel ActiveMQ Komponente und der JMS Message Broker ActiveMQ konfiguriert. Nachfolgend eine Auflistung der verschiedenen Konfigurationen: Camel ActiveMQ Komponente Mit der ActiveMQ Camel Komponente können JMS Message auf eine Queue oder Topic gesendet oder von dort konsumiert werden. <beans:bean id= "activemq" class= "org.apache.activemq.camel.component.activemqcomponent" > <beans:property name= "configuration" ref= "jmsconfig" /> In einer Camel Route kann die ActiveMQ Camel Komponente mit folgendem URI Format verwendet werden: activemq:[queue: topic:]destinationname JMS Konfiguration Mit der JMS Konfiguration können allgemeine JMS Einstellungen gesetzt werden. <beans:bean id= "jmsconfig" class= "org.apache.camel.component.jms.jmsconfiguration" > <beans:property name= "connectionfactory" ref= "pooledjmsconectionfactory"/> <beans:property name= "transactionmanager" ref= "jmstransactionmanager"/> <beans:property name= "transacted" value= "true"/> <beans:property name= "transactedinout" value= "true"/> <beans:property name= "concurrentconsumers" value= "10"/> <beans:property name= "usemessageidascorrelationid" value= "false" /> <beans:property name= "requesttimeout" value= "60000" /> <beans:property name= "preservemessageqos" value= "false" /> <beans:property name= "explicitqosenabled" value= "true" /> <beans:property name= "timetolive" value= "120000" /> Nachfolgend eine Beschreibung der wichtigsten Einstellungen: Property transacted transactedinout Beschreibung Wenn aktiviert transaktionale Verarbeitung der JMS Messages Wenn aktiviert transaktionale Verarbeitung der JMS Messages bei der Verwendung des InOut Exchange Patterns

concurrentconsumers usemessageidascorrelationid requesttimeout timetolive Anzahl Consumers die von einer JMS Destination Messages beziehen können Wenn aktiviert wird in der Response JMS Message die Message ID als Correlation ID verwendet - wird verwendet um den Request und den Response zu korrelieren (muss für aktueller Layer7 Setup deaktiviert sein, siehe Layer7 JMS Konfiguration) Timeout in Millisekunden bis die Response auf der Response Queue eintreffen muss, sollte kleiner als das HTTP Timeout auf dem Layer7 sein (siehe Layer7 HTTP Konfiguration) Anzahl Millisekunden wie lange eine JMS Message gültig ist bevor sie in die Dead Letter Queue gestellt wird, ist nur für ausgehende Message relevant, sprich Response JMS Messages - eingehende Messages verfallen nie Transaktions Manager <beans:bean id= "jmstransactionmanager" class= "org.springframework.jms.connection.jmstransactionmanager"> <beans:property name= "connectionfactory" ref= "pooledjmsconectionfactory"/> Connection Factories <beans:bean id= "poolejmsconectionfactory" class= "org.apache.activemq.pool.pooledconnectionfactory" destroy-method= "stop" > <beans:property name= "connectionfactory" ref= "jmsconnectionfactory"/> <beans:property name= "maxconnections" value= "10"/> <beans:bean id= "jmsconnectionfactory" class= "org.apache.activemq.activemqconnectionfactory" > <beans:property name= "brokerurl" value= "${activemq.brokerurl}" /> <beans:property name= "prefetchpolicy" ref= "prefetchpolicy" /> <beans:property name= "redeliverypolicy" ref= "redeliverypolicy" /> <beans:property name= "optimizeacknowledge" value= "true" /> Redelivery Policy Die Redelivery Policy wird verwendet falls bei der Verarbeitung einer JMS Message ein Fehler aufgetreten ist und der Fehler nicht behandelt werden konnte. Gründe dafür sind z.b. das der Fehler auf Stufe Camel nicht abgefangen wurde oder es liegt ein schwerwiegendes Problem mit der Infrastruktur vor. In diesem Fall kann das Default Redelivery Verhalten von ActiveMQ mit folgender Konfiguration überschrieben werden: <beans:bean id= "redeliverypolicy" class= "org.apache.activemq.redeliverypolicy" > <beans:property name= "maximumredeliveries" value= "1"/> <beans:property name= "initialredeliverydelay" value= "1000"/> Default Redelivery Verhalten von ActiveMQ: Property Default Wert maximumredeliveries 6 initialredeliverydelay 1000 Millisekunden bis nächster Versuch gestartet wird Prefetch Policy Die Prefetch Policy definiert wieviele JMS Messages aus einer JMS Destination in den Speicher geladen werden um die Verarbeitungsgeschwindikeit zu optimieren (optimaler Tradeoff zwischen Speicherplatz und Performance muss gefunden werden). Mit folgender Konfiguration kann das Default Prefetch Verhalten von ActiveMQ überschrieben werden:

<beans:bean id= "prefetchpolicy" class= "org.apache.activemq.activemqprefetchpolicy" > <beans:property name= "queueprefetch" value= "1000"/> <beans:property name= "topicprefetch" value= "32766"/> <beans:property name= "queuebrowserprefetch" value= "500"/> <beans:property name= "durabletopicprefetch" value= "100"/> <beans:property name= "optimizedurabletopicprefetch" value= "1000"/> <beans:property name= "inputstreamprefetch" value= "100"/> Bei Performance Probleme können mit diesen Werten Verbesserungen erzielt werden. Transaktions-Handling Das Camel Transaktions-Handling besteht aus zwei Teilen, dem JMS Transaktions-Handling von Camel welches mitgeliefert wird und dem Backend Transaktions-Handling für die Integration der Backend System der Visana wie Syrius oder LP. JMS Transaktions-Handling Das JMS Transaktions-Handling von Camel wurde bereits weiter oben kurz erwähnt und soll hier nochmals detaillierter erklärt werden. JMS Messages können transaktional oder nicht-transaktional verarbeitet werden. Sollen JMS Messages transaktional verarbeitet werden muss in der Camel ActiveMQ Konfiguration components-activemq.xml bei der JMS Konfiguration das Property transacted auf true gesetzt sein (siehe Konfiguration). Zudem muss die entsprechende Route als transaktional gekennzeichnet werden wie nachfolgendes Beispiel zeigt: from("activemq:queue:input).transacted().policy(springtransactionpolicy).to( Die nachfolgende Grafik visualisiert welche Komponenten die JMS Transaktion von Camel umfasst. Backend Transaktions-Handling Damit die Backend System der Visana transaktional in Camel Routes integriert werden können, wurde ein eigener Transaktions-Handler geschrieben ( RouteTransactionHandler). Mit diesen Transaktions-Handler können Transaktionen gestartet, comitted und zurückgerollt werden. Nachfolgend ein Beispiel einer Camel Route mit zwei Transaktionen: fromcxfendpointtransactedwithexceptionhandling(xxxservice.class, ObjectFactory.class).setHeader(RouteTransactionHandler.BEGIN_TRX, constant( "lptransactionmanager")).setheader(routetransactionhandler.begin_trx, constant( "syrtransactionmanager")).beanref("syrservice");.beanref("lpservice");.setheader(routetransactionhandler.commit_trx, constant( "syrtransactionmanager")).setheader(routetransactionhandler.commit_trx, constant( "lptransactionmanager"))

Die auf der Camel Route verwendeten Transaktions Managers müssen im OSGi Container vorhanden sein. Nachfolgend ein Auszug aus dem OSGi Konfigurations-File ( bundle-context.xml) das zeigt wie die Transaktions-Managers referenziert werden: <osgi:reference id= "syrtransactionmanager" bean-name= "ch.visana.access.syrius.syrtransactionmanager" interface= "org.springframework.transaction.platformtransactionmanager" /> <osgi:reference id= "lptransactionmanager" bean-name= "ch.visana.access.lp.lptransactionmanager" interface= "org.springframework.transaction.platformtransactionmanager" /> Damit die Transaktions-Managers verwendet werden können, müssen diese in ein RouteTransactionManagerPool Bean injected werden welches wiederum in das RouteTransactionHandler Bean injected wird. Nachfolgend ein Auszug aus dem Spring Konfigurations-File components.xml: <bean id= "routetransactionhandler" class= "ch.visana.util.camel.processor.routetransactionhandler" /> <bean id= "routetransactionmanagerpool" class= "ch.visana.util.camel.routetransactionmanagerpool" > <property name= "transactionmanagerpool" > <map> <entry key= "syrtransactionmanager" value-ref= "syrtransactionmanager" /> <entry key= "lptransactionmanager" value-ref= "lptransactionmanager" /> </map> </property> </bean> <bean id= "xxxserviceroute" class= "ch.visana.services.xxx.vyyy.impl.xxxserviceroute" autowire= "no" > <property name= "routetransactionhandler" ref= "routetransactionhandler" /> </bean> Vorsicht bei Lese-Operationen mit dem Syrius SAPI, dort werden teilweise Transaktionen benötigt. Wird eine SAPI Transaktion gestartet und wird anschliessend nie gebraucht kann die beim Commit zu einer Exception führen. Workaround: Transaktion auch nur dann starten wenn sie 100% gebraucht wird. Tritt in einer Camel Route ein Fehler auf dann werden alle offenen Backend-Transaktionen zurückgerollt Da der RouteTransactionHandler ein Interceptor ist darf dieser nie am Ende einer Camel Route definiert werden weil dieser sonst nicht aufgeruft wird. Falls man trotzdem am Ende einer Route eine Transacktion commiten mnöchte muss explizit der RouteTransactionHandler Prozessor aufgerufen werden: fromcxfendpointtransactedwithexceptionhandling(xxxservice.class, ObjectFactory.class).setHeader(RouteTransactionHandler.COMMIT_TRX, constant( "syrtransactionmanager")).process(routetransactionhandler); Exception-Handling Beim Camel Exception-Handling wird zwischen technischen Exceptions ( ), fachlichen Exceptions ( CamelTechnicalRuntimeException CamelBusinessRuntimeException) und unbekannten Exceptions (keine Kategorisierung möglich) unterschieden.

Falls ein Backend Transaktions-Handler eingesetzt wird dann werden bei einem Fehler auf der Camel Route alle offenen Transaktionen zurückgerollt. Technische Exceptions Bei technischen Exceptions (z.b. Backend-System nicht verfügbar) wird mit dem Redelivery-Verfahren mehrmals versucht die Message zu verarbeiten. Beim Erreichen der maximalen Anzahl Retries wird die orginale Request Message in die Dead Letter Queue weitergeleitet und dem Aufrufer ein SOAP-Fault zurückgegeben (siehe Abbildung oben). Das Redelivery-Verhalten kann bei der ServiceRoute Bean Definition (Konfigurations-File components.xml) mit Property errorredeliverypolicy definiert werden (siehe Konfiguration). Nachfolgend ein Beispiel einer Redelivery Policy und die Beschreibung der verschiedenen Properties: <bean id= "errorredeliverypolicy" class= "org.apache.camel.processor.redeliverypolicy" > <property name= "backoffmultiplier" value= "1.0" /> <property name= "maximumredeliveries" value= "10" /> <property name= "redeliverdelay" value= "1000" /> </bean> Zu beachten ist hier dass das Redelivery-Verhalten nur beim Transport mit JMS eingesetzt werden kann. Beim Transport über HTTP kann der Request nicht mehrmals verarbeitet werden da keine Transaktionalität vorhanden ist, technische Fehler werden sofort dem Aufrufer zurückgegeben analog fachlichen Fehler. Property Beschreibung backoffmultiplier Mit diesem Multiplikator wird das Redelivery Delay bei jedem Retry multipliziert, d.h bei einem backoffmultiplier von 1.5 und einem redeliverydelay von 1000 wird beim ersten Retry 1000 ms gewartet und beim zweiten Retry 1000 ms * 1.5 usw, das redeliverydelay berechnet sich somit mit folgender Formel: redeliverydelay * backoffmultiplier retrycount-1 maximumredeliveries redeliverdelay Anzahl Retries bevor die Message in die Dead Letter Queue gestellt wird Zeit die zwischen zwei Retries gewartet wird Fachliche Exceptions Bei einem fachlichen Fehler wird kein Redelivery durchgeführt weil in diesem Fall der Fehler durch Retries nicht behoben werden kann. Dem Aufrufer wird sofort ein SOAP-Fault mit entsprechender Fehlerbeschreibung zurückgegeben (siehe Abbildung oben): RouteVariable-Handling Der RouteVariableHandler ist ein Camel Prozessor und verantwortlich für das Setzen und Lesen von Body Nachrichten auf dem Camel Exchange. Der RouteVariableHandler ist ein Interceptor und wird vor jedem Aufruf eines Camel Schritts ( to(), process(), beanref() usw.) aufgerufen. Mit folgendem Beispiel kann der aktuelle Body mit Name 'var1' auf dem Exchange gesetzt werden:

fromcxfendpoint().setheader(routevariablehandler.set_variable, constant( "var1")) Folgendes Beispiel setzt auf der zuvor gespeicherten Variable 'var1' das Property 'attribute1' mit dem aktuellen Body: fromcxfendpoint().setheader(routevariablehandler.set_variable, constant( "var1.attribute1")) Folgendes Beispiel setzt die zuvor gespeicherte Variable 'var1' als Body auf dem Exchange: fromcxfendpoint().setheader(routevariablehandler.set_body, constant( "var1")) Folgendes Beispiel setzt alle Route Variablen auf den Body. Für das Halten der Route Variablen wird eine Instanz der Klasse RouteVariableHolder verwendet und auf dem Body des Exchanges gesetzt: fromcxfendpoint().setheader(routevariablehandler.set_body, constant(routevariablehandler.route_variables)) Da der RouteVariableHandler ein Interceptor ist darf dieser nie am Ende einer Camel Route definiert werden weil dieser sonst nicht aufgeruft wird. Falls man trotzdem am Ende einer Route eine Variable oder den Body setzen möchte muss explizit der RouteVariableHandler Prozessor aufgerufen werden: fromcxfendpoint().setheader(routevariablehandler.set_body, constant(routevariablehandler.route_variables)).process(routevariablehandler); JMS Selektoren In bestimmten Fällen möchte man nicht alle Message einer JMS Destination mit der gleichen Camel Route verarbeiten. Gründe dafür sind wenn eine Camel Route sehr komplex wird und nicht mehr wartbar ist oder wenn für eine bestimmte Operation spezielle Einstellungen notwendig sind (concurrentconsumers). In solchen Fällen bieten sich JMS Selektoren an die nur bestimmte JMS Message aus einer JMS Destination konsumieren. Um JMS Selektoren zu verwenden muss im Camel Konfiguratons-File components-camel.xml ein neuer CXF JMS Endpoint definiert werden. Zu beachten ist die Namenskonvention der Bean ID, dort wird neu nach dem Service Name zusätzlich der Selektor Name definiert z.b. die Operation. Nachfolgend ein Beispiel eines CXF JMS Endpoints mit JMS Selektor:

<cxf:cxfendpoint address="camel://activemq:queue:${environment}.xxx.vyyy.zzz?selector=operation%3d%27 <operationname> %27" id=" xxx.vyyy.xxxservice.zzz" serviceclass= "ch.visana.services.xxx.vyyy.xxxservice" > <cxf:ininterceptors> <beans:bean parent= "wss4jininterceptor" /> </cxf:ininterceptors> <cxf:properties> <beans:entry key= "dataformat" value= "POJO" /> </cxf:properties> </cxf:cxfendpoint> Das Property selector auf dem CXF JMS Endpoint muss das URL Encoding verwenden, d.h. ein '=' Zeichen muss kodiert werden. Nachfolgend eine Übersetzung von häufig benötigten Zeichen: Zeichen URL Encoding < %3C = %3D > %3E ' %27 Damit dieser JMS Selektor funktioniert muss das JMS Property Operation auf der JMS Message gesetzt sein. Das Setzen von JMS Properties wird beim Message Provider durchgeführt, also auf dem Layer7 (siehe Layer7). Für JMS Selektoren können neben den JMS Properties auch die JMS Headers verwendet werden. Als letzter Schritt muss bei der Camel Route Implementierung die entsprechende fromcxfendpoint Methode mit dem Selektor Name verwendet werden: fromcxfendpointtransactedwithexceptionhandling( "zzz", xxxservice.class, ObjectFactory.class).to( Camel Proxies Camel Routes sind verantwortlich für die Orchestrierung der verschiedenen Basis Services. Es kann vorkommen dass eine Camel Route auch wieder als Service in einer anderen Camel Route integriert werden soll. Um dies zu erreichen muss die zu integrierende Camel Route als OSGi Service verfügbar gemacht werden, dies erreicht man durch Verwendung von Camel Proxies.

Der Camel Proxy wird im Camel Konfigurations-File components-camel.xml konfiguriert: <camelcontext trace= "false" id= "ch.visana.services.partner.v2.impl.camelcontext" > <proxy id= "xxxservice" serviceinterface= "ch.visana.services.xxx.vyyy.xxxservice" serviceurl= "direct:xxx.vyyy.xxxservice"/> <routebuilder ref= "xxxserviceroute" /> </camelcontext> Beim Property serviceinterface wird das Interface angegeben, das über OSGi zur Verfügung gestellt werden soll. Das Property serviceurl definiert den Endpoint der Camel Route der über das OSGi Interface aufgerufen werden soll, entspricht dem Property sericenamespace des ServiceRoute Beans auf dem Spring Konfigurations-File components.xml mit vorangestelltem direct: Prefix. Dieser Camel Proxy muss jetzt noch im OSGi Konfigurations-File bundle-context.xml als OSGi Service definiert werden: <alias name= "xxxservice" alias= "ch.visana.services.xxx.vyyy.xxxservice"/> <osgi:service ref= "ch.visana.services.xxx.vyyy.xxxservice" interface= "ch.visana.services.xxx.vyyy.xxxservice" /> Dieser OSGi Service kann jetzt auf einer anderen Camel Route als OSGi Service integriert und aufgerufen werden, nachfolgend ein Auszug aus dem OSGi Konfigurations-File bundle-context.xml:

<osgi:reference id="xxxservice" bean-name="ch.visana.services.xxx.vyyy.xxxservice" interface= "ch.visana.services.xxx.vyyy.xxxservice" /> Camel Proxies sind mit Vorsicht einzusetzen! Bei der Verwendung von Camel Proxies und der Integration von Camel Routes in anderen Camel Routes muss das Exception- und Transaktions-Handling beachtet werden. Mit verschachtelten Camel Routes können auch verschachtelte Transaktionen entstehen was zu Schwierigkeiten führen kann (Rollback, Transaktion Propagation usw.). Auch dem Redelivery-Verhalten bei einer Exception muss besondere Beachtung geschenkt werden (Redelivery auf beiden Camel Routes oder nur auf der aufgerufenen Camel Route). Known Issues Java DSL und nested Choice-Blocks Bei Verwendung von verschachtelten Choice-Blocks oder andere Blocks (Loop, Try-Catch) wird am Ende eines Blocks nicht mehr die richtige Process Definition zurückgegeben. Nachfolgend ein Beispiel dieses Problems: fromcxfendpointtransacted(partnerpresentationservice.class, ObjectFactory.class).choice().when().choice().when().process();.end().process(); // Hier ist keine ChoiceDefinition vorhanden und die when Methode kann nicht gefunden werden.when().process(); Die Klasse AbstractSpringRouteBuilder stellt verschiedene Methoden zur Verfügung um dieses Problem zu umgehen: Methode saveroute Beschreibung Speichert die aktuell definiert Route in eine Variable castchoice Castet die gespeicherte Route und gibt eine ChoiceDefinition Instanz zurück castloop Castet die gespeicherte Route und gibt eine LoopDefintion zurück castrecipientlist Castet die gespeicherte Route und gibt eine RecipientListDefintion zurück casttry Castet die gespeicherte Route und gibt eine TryDefintion zurück castcatch Castet die gespeicherte Route und gibt eine CatchDefintion zurück Das Route Problem mit dem Choice-Block könnte somit wie folgt gelöst werden:

// Die Route wird bis zum Cast-Problem definiert und gespeichert saveroute(fromcxfendpointtransacted(partnerpresentationservice.class, ObjectFactory.class).choice().when().choice().when().process();.end().process()); // Die gespeicherte Route Definition wird in eine Choice Definition gecastet und die Route zu Ende definiert castchoice().when().process(); Exception-Handling in Loop- und RecipientList-Blocks Tritt in einem Loop- bzw. RecipientList-Block ein Fehler auf dann wird der vom OnExceptionProcessor generierte SOAP-Fault nicht als Response zurückgegeben sondern der eingehende Request. Mit einem speziellen Fault-Handler Bean kann dieses Problem gelöst werden. Zuerst muss im Spring Konfigurations-File components.xml die AOP Fault-Handler Bean definiert werden: <bean id= "aopfaulthandler" class= "ch.visana.util.camel.exception.aopfaulthandler" /> Dieser Fault-Handler muss anschliessend am Ende des Loop- bzw. RecpientList-Block mit AOP definiert werden:.aop().afterfinally("bean:aopfaulthandler").loop().process().end().end() Type Converter und Recipient List Bei Verwendung des RecipientList Integration Patterns müssen die Type Converter mit der @Converter Annotation versehen werden damit diese gefunden werden. Die Verwendung von Bean Binding (@Body Annotation) reicht für die Type Konvertierung nicht aus weil Camel trotz des richtigen Ziel-Types nochmals den Type Converter aufruft. Werden bei der RecipientList Type Converters mit der @Converter Annotation verwendet dann muss in der Liste der Recipients kein Endpoint dafür eingefügt werden, die benötigten Type Converters werden automatisch aufgerufen. Bei der Verwendung der @Converter Annotation und der Konfiguration mit dem File META-INF/services/org/apache/camel/TypeConverter muss beachtet werden, dass diese Type Converters für andere Bundles im OSGi Container sichtbar sind und aufgerufen werden. Grundsätzlich sollte diese Art der Type Converter Konfiguration nur für Type Konvertierung verwendet werden, die für alle Bundles gleich sind (z.b. String in ein anderen Type). Camel JAXB Problem Aufgetretenes Problem A) org.apache.camel.language.bean.runtimebeanexpressionexception: Failed to invoke method: istechnicalexception on null due to: org.apache.camel.camelexecutionexception: Exception occurred during execution on the exchange: Exchange[Message: ch.visana.services.lp.readlpinvoiceresponse@1da590d] B) com.sun.istack.saxexception2: A cycle is detected in the object graph. This will cause infinitely deep XML: ch.visana.business.lp.lpmessage@1d7c10b -> ch.visana.business.lp.lpprocessstep@13c421b -> ch.visana.business.lp.lpmessage@1d7c10b

Analyse Problem A) ist ein Folgefehler, allerdings ein merkwürdiger. Denn der einzige Ort, wo istechnicalexception aufgerufen wird, ist im OnExceptionHandler selbst und auch dies nur auf eine lokal erzeugte Instanz. Problem B) ist hartnäckiger. Die Meldung besagt, dass Zyklische Referenzen (Kind eines Vaters zeigt auf den Vater) bei der Transformation angetroffen wurden. Eine kurze Überprüfung des Modells unterstreicht diese Aussage. Weiteres Nachforschen bei JAXB zeigt auf, dass JAXB ein Problem mit zyklischen Referenzen hat; die Website Mapping cyclic references to XML zeigt die drei grundsätzlichen Verfahren zur Problemlösung auf. Das Verfahren mit den Annotationen erscheint am naheliegensten. Während der Beurteilung welche Lösungsvariante wohl die richtige ist, stellt sich auf einmal die Frage, wieso überhaupt dieses Response-Objekt nach XML transformiert wird. Die Lp-Objekte stammen vom Basis-Server, der Basis-Server wird lediglich Servicemix-intern verwendet, das Response-Objekt dürfte eigentlich nie nach aussen gelangen. Und eigentlich wird nur bei der Herausgabe nach Aussen transformiert. Weitere Analysen und Debugging-Sessions zeigen auf, dass die Transformation gleich nach dem Service-Aufruf auftritt; in der Route selbst sind dazu keine Anweisungen gegeben. Nach einer längeren Debug-Session ist es klar: Die Transformation wird vom Trace-Mechanismus der Camel-Kontext angeworfen um das Response-Objekt im Log ausgeben zu können. Behebung Entweder keine zyklischen Referenzen verwenden, diese mittels den gegebenen Jaxb-Möglichkeiten handhaben oder einfach den Trace ausschalten. Trace-Attribute auf dem Camel-Kontext auf false setzen: <camelcontext trace= " false " id= "ch.visana.services.lp.v1.impl.camelcontext" > Literatur Camel Manual G:\KE2\Literatur\CamelinAction.pdf Ressourcen Visio Grafiken