Dienstag, 28 Oktober 2008

A simple ActiveMQ example

A small class to get started with ActiveMQ. Inspired by the examples contained in the ActiveMQ download.

MyFirstActiveMqQueue.java

   1:/*
   2: * Small class to get started with ActiveMQ. Inspired by the examples contained in the
   3: * ActiveMQ download. Gisbert Amm, 2008-10-28
   4: */
   5:package de.gisbertamm.activemqstart;
   6:
   7:import javax.jms.JMSException;
   8:import org.apache.activemq.ActiveMQConnectionFactory;
   9:import org.apache.activemq.broker.BrokerService;
  10:import javax.jms.Connection;
  11:import javax.jms.DeliveryMode;
  12:import javax.jms.Destination;
  13:import javax.jms.ExceptionListener;
  14:import javax.jms.Message;
  15:import javax.jms.MessageConsumer;
  16:import javax.jms.MessageListener;
  17:import javax.jms.MessageProducer;
  18:import javax.jms.Session;
  19:import javax.jms.TextMessage;
  20:import org.apache.activemq.ActiveMQConnection;
  21:
  22:/**
  23: *
  24: * @author gisbert.amm
  25: */
  26:public class MyFirstActiveMqQueue {
  27:
  28:    private static ActiveMQConnectionFactory connectionFactory;
  29:    private static Connection connection;
  30:    private static Session session;
  31:    private static Destination destination;
  32:    private static boolean transacted = false;
  33:
  34:    public static void main(String[] args) throws Exception {
  35:        BrokerService broker = new BrokerService();
  36:        broker.setUseJmx(true);
  37:        broker.addConnector("tcp://localhost:61616");
  38:        broker.start();
  39:
  40:        setUp();
  41:        createProducerAndSendAMessage();
  42:        System.out.println("Simulating a huge network delay :)");
  43:        Thread.sleep(4000);
  44:        createConsumerAndReceiveAMessage();
  45:
  46:        //TODO: Find out how to get rid of the exceptions thrown when stopping the broker
  47:        broker.stop();
  48:    }
  49:
  50:    private static void setUp() throws JMSException {
  51:        connectionFactory = new ActiveMQConnectionFactory(
  52:                ActiveMQConnection.DEFAULT_USER,
  53:                ActiveMQConnection.DEFAULT_PASSWORD,
  54:                ActiveMQConnection.DEFAULT_BROKER_URL);
  55:        connection = connectionFactory.createConnection();
  56:        connection.start();
  57:        session = connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE);
  58:        destination = session.createQueue("mmy first active mq queue");
  59:    }
  60:
  61:    private static void createProducerAndSendAMessage() throws JMSException {
  62:        MessageProducer producer = session.createProducer(destination);
  63:        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
  64:        TextMessage message = session.createTextMessage("Hello World!");
  65:        System.out.println("Sending message: " + message.getText());
  66:        producer.send(message);
  67:    }
  68:
  69:    private static void createConsumerAndReceiveAMessage() throws JMSException, InterruptedException {
  70:        connection = connectionFactory.createConnection();
  71:        connection.start();
  72:        MessageConsumer consumer = session.createConsumer(destination);
  73:        MyConsumer myConsumer = new MyConsumer();
  74:        connection.setExceptionListener(myConsumer);
  75:        consumer.setMessageListener(myConsumer);
  76:    }
  77:
  78:    private static class MyConsumer implements MessageListener, ExceptionListener {
  79:
  80:        synchronized public void onException(JMSException ex) {
  81:            System.out.println("JMS Exception occured.  Shutting down client.");
  82:            System.exit(1);
  83:        }
  84:
  85:        public void onMessage(Message message) {
  86:            if (message instanceof TextMessage) {
  87:                TextMessage textMessage = (TextMessage) message;
  88:                try {
  89:                    System.out.println("Received message: " + textMessage.getText());
  90:                } catch (JMSException ex) {
  91:                    System.out.println("Error reading message: " + ex);
  92:                }
  93:            } else  {
  94:                System.out.println("Received: " + message);
  95:            }
  96:        }
  97:    }
  98:}

Technorati Tags:

Posted by gisbert.amm at 12:07 AM in SOA

Montag, 29 September 2008

Pragmatische Visualisierung einer Architektur

Die einfachste und schnellste Methode ein bestehendes System zu visualisieren liegt in der Auswertung der Membervariablen jeglicher Klasse und die Erzeugung eines gerichteten Graphen. Natürlich werden hier Objekte die per Übergabe in Methoden verwendet werden nicht betrachtet sowie auch Singleton Klassen auf die man über die static Methoden zugreift. Aber wie gesagt, die Vorgehensweise verschafft einen ersten Einblick.

Das Resultat zum nachfolgenden Beispiel:

Dabei wird mit Hilfe von Reflection und Graphviz einem Tool zur grafischen Darstellung von Hierarchien und Netzwerken ein Architekturbild im gewünschten Format erzeugen. Graphviz eignet sich vor allem deswegen, weil ab einer gewissen größe eines System, das manuelle Layout nicht mehr einfach ist. Die Layoutalgorithmen von Graphviz können auch mehr als 100 oder 1000 Knoten noch immer transparent darstellen.

Folgende Vorgehensweise wird hier durchgeführt:

  1. Auslesen aller Klassen eines definierten Source-Verzeichnisses.
  2. Über eine Schleife werden alle MemberVariablen über die Methode
    classloader.loadClass(name).getDeclaredFields()
    ausgelesen.
  3. Jeder Schleifendurchlauf schreibt die Memeberbeziehung zu einer anderen Klasse in ein DOT-File (Graphvizformat)<./li>

Beispiel:
Drei Klassen, wobei jede die anderen kennt.
test2.java
   1:public class Class1 {
   2:    private Class2 class2;
   3:    private Class3 class3;
   4:}
   5:
   6:public class Class2 {
   7:    private Class1 class1;
   8:    private Class3 class3;
   9:}
  10:
  11:public class Class3 {
  12:    private Class2 class2;
  13:    private Class1 class1;
  14:}
Klasse, welche die Klassen ausliest und per Reflection die Beziehung zwischen diesen identifiziert sowie das DOT-File erezugt.
test2.java
   1:package org.developersblog.PragmaticVisualizeArchiteture;
   2:
   3:import java.io.File;
   4:import java.io.FileWriter;
   5:import java.io.IOException;
   6:import java.lang.reflect.Field;
   7:import java.util.ArrayList;
   8:import java.util.List;
   9:
  10:public class MemberExtractionAndDotGeneration {
  11:
  12:    public static void getClassNames(String prefix, 
  13:            List<String> classnames,
  14:            String dir) {
  15:        File dirFile = new File(dir);
  16:        for (File file : dirFile.listFiles()) {
  17:            if (file.isDirectory()) {
  18:                if (prefix.length() > 0) {
  19:                    getClassNames(prefix + "." + 
  20:                            file.getName(), 
  21:                            classnames,
  22:                            file.getAbsolutePath());
  23:                } else {
  24:                    getClassNames(file.getName(), classnames, 
  25:                            file.getAbsolutePath());
  26:                }
  27:            } else {
  28:                if (file.getName().endsWith(".java")) {
  29:                    if (prefix.length() > 0) {
  30:                        String name = prefix + "." + file.getName().
  31:                                replaceAll(".java", "");
  32:                        classnames.add(name);
  33:                    } else {
  34:                        String name = 
  35:                                file.getName().replaceAll(".java", "");
  36:                        classnames.add(name);
  37:                    }
  38:                }
  39:            }
  40:        }
  41:    }
  42:
  43:    /**
  44:     * @param args
  45:     * @throws ClassNotFoundException
  46:     * @throws SecurityException
  47:     * @throws IOException
  48:     */
  49:    public static void main(String[] args) throws SecurityException,
  50:            ClassNotFoundException, IOException {
  51:        FileWriter writer = new FileWriter(new File(
  52:                "/home/rafsob/Desktop/graph.dot"));
  53:        writer.write("digraph G {\r\nedge [len=2];\r\n");
  54:        ClassLoader cl = MemberExtractionAndDotGeneration.
  55:                class.getClassLoader();
  56:        List<String> classnames = new ArrayList<String>();
  57:        //Klassen aus dem src Verzeichnis holen
  58:        getClassNames("", classnames,
  59:          "/home/rafsob/Desktop/workspace/" +
  60:          "PragmaticVisualizeArchiteture/src/main/java");
  61:        //Klassenreferenzen identifizieren
  62:        for (String name : classnames) {
  63:            System.out.println("check class with name: " + name);
  64:            for (Field field : cl.loadClass(name).getDeclaredFields()) {
  65:                if (classnames.contains(field.getType().getCanonicalName()) && 
  66:                    !name.equals(field.getType().getCanonicalName())) {
  67:                    
  68:                    int lastFirst = name.lastIndexOf('.');
  69:                    int lastSecond = field.getType().
  70:                            getCanonicalName().lastIndexOf('.');
  71:                    //Knotenbeziehung in DOT defnieren
  72:                    writer.write(" \"" + name.substring(lastFirst + 1) + "\" -> \"" + 
  73:                            field.getType().getCanonicalName().
  74:                            substring(lastSecond + 1) + "\";\r\n");
  75:                }
  76:            }
  77:        }
  78:        writer.write("}");
  79:        writer.close();
  80:        //Neato für die Darstellung von Graphen starten
  81:        Process p = Runtime.getRuntime().exec(
  82:                "/usr/bin/neato " +
  83:                "-Tpng /home/rafsob/Desktop/graph.dot " +
  84:                "-o /home/rafsob/Desktop/graph.png");
  85:        System.out.println("end");
  86:    }
  87:}
  88:
  89:
Viele Grüße Rafael Sobek

Technorati Tags:

Posted by rafael.sobek at 2:59 PM in Architektur

Mittwoch, 17 September 2008

OSGI Embedded Container

Ich habe mich vor kurzem mit dem Thema OSGI-Einbindung des Felix- bzw. Equinoxcontainers beschäftigt. Anwendungsfelder können Applikationen sein, die sich gerade in der Refaktorisierungsphase Richtung OSGI-Komponentenapplikation befinden oder z.B. Servletapplikationen, die die Komponentenarchitektur in Form von OSGI-Bundles realisieren sollen.

Weiterhin könnte auch die Anforderung existieren, einen OSGI-Container per Trigger auf der Quellcode Ebene zu initialisieren.

Euqinox kann über die EclipseStarter-Klasse initilisiert werden (startup.jar), hier Beispielhaft:

test.java
   1:String args[] = { "-console", "2000" }; 
   2:BundleContext ctx = org.eclipse.core.runtime.adaptor.EclipseStarter.startup( args, null );
   3:Bundle b = ctx.installBundle("file://home/rafsob/bundlerepository/testbundle.jar");
   4:b.start();

Eine ausführliche Beschreibung der Einbettung des Felix OSGI Server's kann man auf der Apache Felix Seite finden Launching and Embedding Apache Felix.

Zusammenfassend kann ich sagen, dass die Einbettung des Equinoxservers kaum dokumentiert ist. Bzw. ich nicht die Richtige Stelle im Internet gefunden habe. :-)

Der Felixcontainer scheint mir hier einfacher und besser dokumentiert.

Viele Grüße
Rafael Sobek

Technorati Tags:

Posted by default at 10:17 PM in Uncategorized

Montag, 15 September 2008

Camel-Routen visualisieren

1. Neuesten Stand der Camel-Sourcen holen und bauen

Wir werden jetzt kleinere Features von Camel benutzen, die es im Release 1.4.0 noch nicht gibt (z.B. den Ablageort des Camel-Contextes zu konfigurieren). Deshalb ist es Zeit, die Camel-Sourcen auszuchecken und die aktuelle Version selbst zu bauen:

svn co https://svn.apache.org/repos/asf/activemq/camel/trunk camel
set MAVEN_OPTS=-Xmx512m -XX:MaxPermSize=128m
mvn install -Dtest=false

(vgl. http://activemq.apache.org/camel/building.html)

Das dauert eine Weile. In der Zwischenzeit können wir unser Projekt anpassen.

2. POM anpassen

Zunächst zentralisieren wir die Camel-Versionsangabe an einer Stelle, damit wir bei der nächsten Versionsänderung nur diese anpassen müssen. Dazu fügen wir der POM auf Hauptebene diesen Eintrag hinzu:

property.xml

   1:<properties>
   2:        <camel.version>1.5-SNAPSHOT</camel.version>
   3:</properties>

Nun können wir alle Vorkommen der Camel-Versionsnummer durch eine Referenz auf diese Property (${camel.version}) ersetzen, im vi z.B. mittels
%s,1.4.0,${camel.version},g

Wir ergänzen folgende Dependency, damit das Maven Camel-Plugin den Spring-Kontext laden kann:

dependency.xml

   1:<dependency>
   2:        <groupId>org.apache.camel</groupId>
   3:        <artifactId>camel-spring</artifactId>
   4:        <version>${camel.version}</version>
   5:</dependency>
   6:

In den <build><plugins>-Abschnitt fügen wir diese Konfiguration ein:

plugin-eintrag-build.xml

   1:<plugin>
   2:        <groupId>org.apache.camel</groupId>
   3:        <artifactId>camel-maven-plugin</artifactId>
   4:        <version>${camel.version}</version>
   5:        <configuration>
   6:                <fileApplicationContextUri>src/main/webapp/WEB-INF/spring-context.xml</fileApplicationContextUri>
   7:        </configuration>
   8:</plugin>
   9:

Der Parameter <fileApplicationContextUri> ist einer der Gründe, warum Camel 1.5 benötigt wird (dieser Code wurde von den Camel-Entwicklern am 1. September 2008 eingebaut).

Außerdem fügen wir einen Reporting-Abschnitt ein:

plugin-eintrag-reporting.xml

   1:<reporting>
   2:        <plugins>
   3:                <plugin>
   4:                        <groupId>org.apache.camel</groupId>
   5:                        <artifactId>camel-maven-plugin</artifactId>
   6:                        <version>${camel.version}</version>
   7:                </plugin>
   8:        </plugins>
   9:</reporting>
  10:

Damit sind die Vorbereitungen abgeschlossen und wir können die Visualisierung der Route erstellen.

3. Visualisierung der Route mit GraphViz

Sobald Maven mit dem Kompilieren und Installieren von Camel 1.5-SNAPSHOT fertig ist, können wir mit mvn camel:dot eine graphische Repräsentation der Route erstellen. Dazu muss dot auf dem Rechner installiert sein (Doku dazu findet sich unter http://activemq.apache.org/camel/camel-maven-plugin.html und http://activemq.apache.org/camel/visualisation.html). Die graphische Darstellung der Route wird nach target/site/cameldoc generiert und sieht zunächst so aus:

Das ist weder sehr schön noch besonders praktikabel; aber da Camel GraphViz benutzt, kann man die Routen mit relativ wenig Aufwand nachbearbeiten. Die Datei target/site/cameldoc/routes.dot sieht etwa so aus:

routes.dot

   1:digraph CamelRoutes {
   2:
   3:node [style = "rounded,filled", fillcolor = yellow, fontname="Helvetica-Oblique"];
   4:
   5:subgraph cluster_0 {
   6:label = "Camel Routes";
   7:color = grey;
   8:style = "dashed";
   9:URL = "Camel Routes.html";
  10:
  11:
  12:node1 [
  13:label = "cxf:bean:helloEndpoint"
  14:tooltip = "cxf:bean:helloEndpoint"
  15:URL = "http://activemq.apache.org/camel/message-endpoint.html"
  16:];
  17:
  18:
  19:node2 [
  20:label = "Interceptor Ref"
  21:tooltip = "Interceptor Ref: Delegate(DeadLetterChannel[Delegate(TraceInterceptor[To[bean:myCamelProcessor]]), RecipientList[log:org.apache.camel.DeadLetterChannel?level=error], RedeliveryPolicy[maximumRedeliveries=5, initialRedeliveryDelay=1000, maximumRedeliveryDelay=60000, useExponentialBackOff=false, backOffMultiplier=2.0, useCollisionAvoidance=false, collisionAvoidanceFactor=0.15]])"
  22:URL = "http://activemq.apache.org/camel/interceptor-ref.html"
  23:shape = "box"
  24:];
  25:
  26:node1 -> node2 [
  27:];
  28:
  29:node3 [
  30:label = "bean:myCamelProcessor"
  31:tooltip = "bean:myCamelProcessor"
  32:URL = "http://activemq.apache.org/camel/message-endpoint.html"
  33:];
  34:
  35:node2 -> node3 [
  36:label = "Delegate(DeadLetterChannel[Delegate(TraceInterceptor[To[bean:myCamelProcessor]]), RecipientList[log:org.apache.camel.DeadLetterChannel?level=error], RedeliveryPolicy[maximumRedeliveries=5, initialRedeliveryDelay=1000, maximumRedeliveryDelay=60000, useExponentialBackOff=false, backOffMultiplier=2.0, useCollisionAvoidance=false, collisionAvoidanceFactor=0.15]])"
  37:];
  38:
  39:}
  40:
  41:}

Die Labels sind etwas geschwätzig; das läßt sich jedoch leicht ändern, indem man den Text großzügig kürzt. Außerdem kann man von http://activemq.apache.org/camel/images/eip/ die passenden Bildchen herunterladen und mit image = "<Pfad im Dateisystem> in die Grafik einarbeiten (GraphViz kann leider aktuell nicht mit HTTP-URLs umgehen). Die resultierende Datei sieht z.B. so aus:

routes.dot

   1:digraph CamelRoutes {
   2:
   3:node [fontname="Helvetica-Oblique", fontsize="10", fontcolor="red"];
   4:
   5:subgraph cluster_0 {
   6:label = "Camel Routes";
   7:color = grey;
   8:style = "dashed";
   9:URL = "Camel Routes.html";
  10:
  11:
  12:node1 [
  13:label = "cxf:bean:helloEndpoint"
  14:labelloc = "t"
  15:tooltip = "cxf:bean:helloEndpoint"
  16:URL = "http://activemq.apache.org/camel/message-endpoint.html"
  17:shape = "box"
  18:image = "images/MessageEndpointIcon.png"
  19:];
  20:
  21:
  22:node2 [
  23:label = "Interceptor Ref"
  24:tooltip = "TraceInterceptor"
  25:URL = "http://activemq.apache.org/camel/interceptor-ref.html"
  26:shape = "box"
  27:image = "images/WireTapIcon.png"
  28:];
  29:
  30:node1 -> node2 [
  31:label = "Logging"
  32:];
  33:
  34:node3 [
  35:label = "bean:myCamelProcessor"
  36:tooltip = "bean:myCamelProcessor"
  37:URL = "http://activemq.apache.org/camel/message-endpoint.html"
  38:shape = "box"
  39:image = "images/MessageTranslatorIcon.png"
  40:];
  41:
  42:node2 -> node3 [
  43:];
  44:
  45:}
  46:
  47:}

Und das Bildchen, das dabei herauskommt, kann sich schon eher sehen lassen.

Technorati Tags:

Posted by gisbert.amm at 9:16 PM in SOA

Freitag, 12 September 2008

SOAP Service Testing

Recently I looked for an easy and trivial way for testing webservices at junit tests. One way is the jetty servlet container which is runnable as ambedded server at java source code.

(1) First you have to define the content of your soap request. An example could be:

   1:<soapenv:Envelope 
   2:  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
   3:  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
   4:  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   5:  <soapenv:Body>
   6:    <ns1:sayHello soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://127.0.0.1:40406/hello">
   7:      <integer href="#id0"/>
   8:    </ns1:sayHello>
   9:    <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
  10:      xsi:type="xsd:long" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">Rafael</multiRef>
  11:  </soapenv:Body>
  12:</soapenv:Envelope>

(2) Equivalent Axis Service Call mechanism, that generates the soap content above:

JavaCall.java
   1:Call c = new Call(serviceURL + "/hello");
   2:c.addParameter("string", new QName("http://www.w3.org/2001/XMLSchema", "string"), ParameterMode.IN);
   3:c.setReturnType(new QName(serviceURL + "/Server", "string"));
   4:Object o = c.invoke(serviceURL + "/hello", "sayHello", new String[]{"Rafael"});
   5:String returnString = o.toString();

(3) Second you define the response soap content. An example could be:

soap-response.xml
   1:<?xml version="1.0" encoding="UTF-8"?>
   2:<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   3:        <soapenv:Body>
   4:                <ns1:sayHello soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://127.0.0.1:40406/hello">
   5:                        <hello href="#id0"/>
   6:                </ns1:sayHello>
   7:                <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">Server: Hello Rafael</multiRef>
   8:        </soapenv:Body>
   9:</soapenv:Envelope>

(4) Then you implement a simple servlet, which generated the expected response which generic content:

ServletTest.java
   1:public class SimpleServlet extends HttpServlet { 
   2:
   3:    public void doProcess (HttpServletRequest req, HttpServletResponse res)
   4:        throws ServletException, IOException {
   5:        ServletOutputStream out = res.getOutputStream();
   6:        res.setContentType("text/xml");
   7:        out.print("... response soap code snippet + generic code ...");
   8:        out.close();
   9:    }
  10:    
  11:    public void doGet (HttpServletRequest req, HttpServletResponse res)
  12:        throws ServletException, IOException {
  13:            doProcess(req, res);
  14:    }
  15:    
  16:    public void doPost (HttpServletRequest req, HttpServletResponse res)
  17:        throws ServletException, IOException {
  18:            doProcess(req, res);
  19:    }
  20:
  21:    public String getServletInfo() {
  22:        return "A simple servlet";
  23:    }
  24:}

(5) Last you have to implement the junit test:

UnitTest.java
   1:public class TestSoap {
   2:
   3:    @Test
   4:    public testSoap() throws Exception {
   5:        ServletTester tester = new ServletTester();
   6:        tester.setContextPath("/");
   7:        tester.addServlet(ServletTest.class, "/*");
   8:        String serviceURL = 
   9:            tester.createSocketConnector(true);
  10:        tester.start();
  11:        
  12:        String soapRequest = "... first snippet, which will generated from second java snippet ...";
  13:        
  14:        //second axis call snippet with the service url
  15:        
  16:        assertEquals("Server: Hello Rafael",response.getContent());
  17:    }
  18:} 

Regards Rafael Sobek

Technorati Tags:

Posted by rafael.sobek at 10:36 PM in SOA

Donnerstag, 11 September 2008

Zum Spring-CXF-Service Routing mit Apache Camel hinzufügen

Um zu dem neulich erstellten Spring-CXF-Service Routing per Apache Camel hinzuzufügen, sind folgende Schritte nötig:

1. POM anpassen

pom-schnipsel.xml

   1:
   2:<dependency>
   3:        <groupId>org.apache.camel</groupId>
   4:        <artifactId>camel-core</artifactId>
   5:        <version>1.4.0</version>
   6:</dependency>
   7:
   8:<dependency>
   9:        <groupId>org.apache.camel</groupId>
  10:        <artifactId>camel-cxf</artifactId>
  11:        <version>1.4.0</version>
  12:</dependency>

2. spring-context.xml anpassen

spring-config.xml

   1:<?xml version="1.0" encoding="UTF-8"?>
   2:<beans xmlns="http://www.springframework.org/schema/beans" 
   3:       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   4:       xmlns:cxf="http://activemq.apache.org/camel/schema/cxfEndpoint" 
   5:       xsi:schemaLocation="http://www.springframework.org/schema/beans 
   6:                           http://www.springframework.org/schema/beans/spring-beans.xsd 
   7:                           http://activemq.apache.org/camel/schema/cxfEndpoint 
   8:                           http://activemq.apache.org/camel/schema/cxfEndpoint/camel-cxf.xsd 
   9:                           http://activemq.apache.org/camel/schema/spring 
  10:                           http://activemq.apache.org/camel/schema/spring/camel-spring.xsd">
  11:                           
  12:        <import resource="classpath:META-INF/cxf/cxf.xml" />
  13:        <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
  14:        <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
  15:
  16:        <bean id="myCamelProcessor" class="org.developers.blog.MyCamelProcessor" />
  17:
  18:        <cxf:cxfEndpoint id="helloEndpoint" 
  19:                         serviceClass="org.developers.blog.ServiceExample" 
  20:                         address="/Hello" />
  21:
  22:        <camelContext id="test_context" 
  23:                      xmlns="http://activemq.apache.org/camel/schema/spring" 
  24:                      trace="true">
  25:                <route>
  26:                        <from uri="cxf:bean:helloEndpoint"/>
  27:                        <to uri="bean:myCamelProcessor"/>
  28:                </route>
  29:        </camelContext>
  30:</beans>

trace="true" ist notwendig, damit anschließend im Logfile auch etwas zu sehen ist.

3. Camel Processor implementieren

MyCamelProcessor.java

   1:package org.developers.blog;
   2:
   3:import java.util.List;
   4:import org.apache.camel.Exchange;
   5:import org.apache.camel.Processor;
   6:
   7:public class MyCamelProcessor implements Processor {
   8:        
   9:        public void process (Exchange exchange) {
  10:                String message = (String) exchange.getIn().getBody(List.class).get(0);
  11:                exchange.getOut().setBody("Hello was: " + message);
  12:        }
  13:}

4. Kompilieren und WAR deployen (z.B. in den Tomcat)

Wenn man den Service nun z.B. über die SoapUI aufruft, schreibt Camel so etwas nach catalina.out (natürlich alles in einer Zeile):

11.09.2008 22:47:47 org.apache.camel.processor.Logger process
INFO: ID-osiris/33225-1221173240660/2-0 -> to1 To[bean:myCamelProcessor]
InOut Properties:{CamelCauseException=null}
Headers:{javax.xml.ws.wsdl.port={http://my.org/ns/}ServiceExamplePort,
org.apache.cxf.service.model.MessageInfo=[MessageInfo INPUT{http://my.org/ns/}sayHello],
org.apache.cxf.message.Message.PROTOCOL_HEADERS={content-type=[text/xml;charset=UTF-8],
host=[localhost:8080],
soapaction=[""],
content-length=[275],
user-agent=[Jakarta Commons-HttpClient/3.0.1]},
operationNameSpace=http://my.org/ns/,
javax.xml.ws.wsdl.interface={http://my.org/ns/}IServiceExample,
HTTP.REQUEST=org.apache.catalina.connector.RequestFacade@16f2723, Accept=null,
org.apache.cxf.headers.Header.list=[],
org.apache.cxf.message.Message.BASE_PATH=/cxf-spring-example/Hello,
org.apache.cxf.message.Message.PATH_INFO=/cxf-spring-example/Hello,
operationName=sayHello,
javax.xml.ws.wsdl.service={http://my.org/ns/}ServiceExampleService,
org.apache.cxf.message.Message.HTTP_REQUEST_METHOD=POST,
org.apache.cxf.message.Message.ENCODING=UTF-8,
org.apache.cxf.message.Message.QUERY_STRING=null,
HTTP.RESPONSE=org.apache.catalina.connector.ResponseFacade@728743,
org.apache.cxf.security.SecurityContext=org.apache.cxf.transport.http.AbstractHTTPDestination$1@10e7233,
org.apache.cxf.async.post.response.dispatch=true,
javax.xml.ws.wsdl.operation={http://my.org/ns/}sayHello,
org.apache.cxf.message.MessageFIXED_PARAMETER_ORDER=false,
org.apache.cxf.transport.Destination=org.apache.cxf.transport.servlet.ServletDestination@13dd5ec,
javax.xml.ws.wsdl.description=/Hello?wsdl,
org.apache.cxf.service.model.BindingMessageInfo=org.apache.cxf.service.model.BindingMessageInfo@a77997,
Content-Type=text/xml;charset=UTF-8,
HTTP.CONTEXT=org.apache.catalina.core.ApplicationContextFacade@48a158} BodyType:org.apache.cxf.message.MessageContentsList Body:Du

Von CXF generierte WSDL

wsdl.xml