Repository: camel
Updated Branches:
  refs/heads/master 5538801e5 -> 64d08a7e3


CAMEL-6955: camel-hl7 now supports netty4 also for mllp codec. Thanks to 
Christian Ohr for the patch.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/64d08a7e
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/64d08a7e
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/64d08a7e

Branch: refs/heads/master
Commit: 64d08a7e307c48e4bbaaa8b6f27155d65f8ab697
Parents: 5538801
Author: Claus Ibsen <davscl...@apache.org>
Authored: Thu Jan 8 19:29:18 2015 +0100
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Thu Jan 8 19:29:33 2015 +0100

----------------------------------------------------------------------
 components/camel-hl7/pom.xml                    |  12 +-
 .../camel/component/hl7/HL7DataFormat.java      |   5 +-
 .../camel/component/hl7/HL7MLLPCodec.java       |   4 +-
 .../camel/component/hl7/HL7MLLPConfig.java      |   2 +-
 ...HL7MLLPConfigAwareChannelHandlerFactory.java |  89 ++++++++
 .../component/hl7/HL7MLLPNettyDecoder.java      |  96 ++++++++
 .../hl7/HL7MLLPNettyDecoderFactory.java         |  30 +++
 .../component/hl7/HL7MLLPNettyEncoder.java      |  64 ++++++
 .../hl7/HL7MLLPNettyEncoderFactory.java         |  30 +++
 .../hl7/HL7MLLPNettyCodecBoundaryTest.java      |  84 +++++++
 .../HL7MLLPNettyCodecByteArrayRouteTest.java    | 221 +++++++++++++++++++
 .../hl7/HL7MLLPNettyCodecLongTest.java          |  88 ++++++++
 .../HL7MLLPNettyCodecStandAndEndBytesTest.java  | 123 +++++++++++
 .../component/hl7/HL7MLLPNettyCodecTest.java    | 116 ++++++++++
 .../camel/component/hl7/HL7NettyRouteTest.java  | 221 +++++++++++++++++++
 .../features/src/main/resources/features.xml    |   1 +
 16 files changed, 1178 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-hl7/pom.xml b/components/camel-hl7/pom.xml
index 4cbf7aa..6153c55 100644
--- a/components/camel-hl7/pom.xml
+++ b/components/camel-hl7/pom.xml
@@ -51,11 +51,20 @@
             <artifactId>hapi-base</artifactId>
             <version>${hapi-version}</version>
         </dependency>
+
+        <!-- for MLLP either use mina2 or camel-netty4 -->
         <dependency>
             <groupId>org.apache.mina</groupId>
             <artifactId>mina-core</artifactId>
             <version>${mina2-version}</version>
-        </dependency>      
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-netty4</artifactId>
+            <optional>true</optional>
+        </dependency>
 
         <!-- testing -->
         <dependency>
@@ -91,4 +100,5 @@
             <scope>test</scope>
         </dependency>
     </dependencies>
+
 </project>

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7DataFormat.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7DataFormat.java
 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7DataFormat.java
index 6f2abf8..d56e7ea 100644
--- 
a/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7DataFormat.java
+++ 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7DataFormat.java
@@ -140,8 +140,6 @@ public class HL7DataFormat extends ServiceSupport 
implements DataFormat {
         this.parser = parser;
     }
 
-
-
     @Override
     protected void doStart() throws Exception {
         if (hapiContext == null) {
@@ -160,7 +158,6 @@ public class HL7DataFormat extends ServiceSupport 
implements DataFormat {
         // noop
     }
 
-
     /**
      * In HL7 the charset of the message can be set in MSH-18,
      * but you need to decode the input stream in order to be able to read 
MSH-18.
@@ -174,7 +171,7 @@ public class HL7DataFormat extends ServiceSupport 
implements DataFormat {
      * calling {@link 
org.apache.camel.util.IOHelper#getCharsetName(org.apache.camel.Exchange)}.
      *
      * @param b byte array
-     * @param exchange
+     * @param exchange the exchange
      * @return charset name
      */
     protected String guessCharsetName(byte[] b, Exchange exchange) {

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPCodec.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPCodec.java
 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPCodec.java
index 8472d03..c6a8c41 100644
--- 
a/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPCodec.java
+++ 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPCodec.java
@@ -42,8 +42,8 @@ import org.apache.mina.filter.codec.ProtocolEncoder;
  * any of the start and end markers, the encoder will add these, and stream 
the string as bytes.
  * <p/>
  * This codes supports charset encoding/decoding between bytes and String. The 
JVM platform default charset
- * is used, but the charset can be configued on this codec using the setter 
method.
- * The decoder will use the JVM platform default charset for decoding, but the 
charset can be configued on the this codec.
+ * is used, but the charset can be configured on this codec using the setter 
method.
+ * The decoder will use the JVM platform default charset for decoding, but the 
charset can be configured on the this codec.
  */
 public class HL7MLLPCodec implements ProtocolCodecFactory {
 

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPConfig.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPConfig.java
 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPConfig.java
index 4ec78d2..2d5abb2 100644
--- 
a/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPConfig.java
+++ 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPConfig.java
@@ -22,7 +22,7 @@ import ca.uhn.hl7v2.DefaultHapiContext;
 import ca.uhn.hl7v2.HapiContext;
 import ca.uhn.hl7v2.parser.Parser;
 
-class HL7MLLPConfig {
+public class HL7MLLPConfig {
 
     private Charset charset = Charset.defaultCharset();
 

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPConfigAwareChannelHandlerFactory.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPConfigAwareChannelHandlerFactory.java
 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPConfigAwareChannelHandlerFactory.java
new file mode 100644
index 0000000..2444c78
--- /dev/null
+++ 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPConfigAwareChannelHandlerFactory.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hl7;
+
+import java.nio.charset.Charset;
+
+import org.apache.camel.component.netty4.DefaultChannelHandlerFactory;
+
+/**
+ * Abstract helper for Netty decoder and encoder factory
+ */
+abstract class HL7MLLPConfigAwareChannelHandlerFactory extends 
DefaultChannelHandlerFactory {
+
+    protected final HL7MLLPConfig config;
+
+    public HL7MLLPConfigAwareChannelHandlerFactory() {
+        this(new HL7MLLPConfig());
+    }
+
+    public HL7MLLPConfigAwareChannelHandlerFactory(HL7MLLPConfig config) {
+        this.config = config;
+    }
+
+    public void setCharset(Charset charset) {
+        config.setCharset(charset);
+    }
+
+    public void setCharset(String charsetName) {
+        config.setCharset(Charset.forName(charsetName));
+    }
+
+    public Charset getCharset() {
+        return config.getCharset();
+    }
+
+    public boolean isConvertLFtoCR() {
+        return config.isConvertLFtoCR();
+    }
+
+    public void setConvertLFtoCR(boolean convertLFtoCR) {
+        config.setConvertLFtoCR(convertLFtoCR);
+    }
+
+    public char getStartByte() {
+        return config.getStartByte();
+    }
+
+    public void setStartByte(char startByte) {
+        config.setStartByte(startByte);
+    }
+
+    public char getEndByte1() {
+        return config.getEndByte1();
+    }
+
+    public void setEndByte1(char endByte1) {
+        config.setEndByte1(endByte1);
+    }
+
+    public char getEndByte2() {
+        return config.getEndByte2();
+    }
+
+    public void setEndByte2(char endByte2) {
+        config.setEndByte2(endByte2);
+    }
+
+    public boolean isProduceString() {
+        return config.isProduceString();
+    }
+
+    public void setProduceString(boolean apply) {
+        config.setProduceString(apply);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyDecoder.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyDecoder.java
 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyDecoder.java
new file mode 100644
index 0000000..4938cd5
--- /dev/null
+++ 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyDecoder.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hl7;
+
+import java.nio.charset.Charset;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.DecoderException;
+import io.netty.handler.codec.DelimiterBasedFrameDecoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * HL7 MLLP Decoder for Netty4
+ */
+class HL7MLLPNettyDecoder extends DelimiterBasedFrameDecoder {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(HL7MLLPNettyDecoder.class);
+    private static final int MAX_FRAME_LENGTH = Integer.MAX_VALUE;
+    private final HL7MLLPConfig config;
+
+    /**
+     * Creates a decoder instance using a default HL7MLLPConfig
+     */
+    public HL7MLLPNettyDecoder() {
+        this(new HL7MLLPConfig());
+    }
+
+    /**
+     * Creates a decoder instance
+     *
+     * @param config HL7MLLPConfig to be used for decoding
+     * @throws java.lang.NullPointerException is config is null
+     */
+    public HL7MLLPNettyDecoder(HL7MLLPConfig config) {
+        super(MAX_FRAME_LENGTH, true, Unpooled.copiedBuffer(
+                new char[]{config.getEndByte1(), config.getEndByte2()},
+                Charset.defaultCharset()));
+        this.config = config;
+    }
+
+    @Override
+    protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws 
Exception {
+        ByteBuf buf = (ByteBuf) super.decode(ctx, buffer);
+        if (buf != null) {
+            int pos = buf.bytesBefore((byte) config.getStartByte());
+            if (pos >= 0) {
+                ByteBuf msg = buf.readerIndex(pos + 1).slice();
+                LOG.debug("Message ends with length {}", msg.readableBytes());
+                return config.isProduceString() ? asString(msg) : 
asByteArray(msg);
+            } else {
+                throw new DecoderException("Did not find start byte " + (int) 
config.getStartByte());
+            }
+        }
+        // Message not complete yet - return null to be called again
+        LOG.debug("No complete messages yet at position {}", 
buffer.readableBytes());
+        return null;
+    }
+
+    private byte[] asByteArray(ByteBuf msg) {
+        byte[] bytes = new byte[msg.readableBytes()];
+        msg.getBytes(0, bytes);
+        if (config.isConvertLFtoCR()) {
+            for (int i = 0; i < bytes.length; i++) {
+                if (bytes[i] == (byte) '\n') {
+                    bytes[i] = (byte) '\r';
+                }
+            }
+        }
+        return bytes;
+    }
+
+    private String asString(ByteBuf msg) {
+        String s = msg.toString(config.getCharset());
+        if (config.isConvertLFtoCR()) {
+            return s.replace('\n', '\r');
+        }
+        return s;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyDecoderFactory.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyDecoderFactory.java
 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyDecoderFactory.java
new file mode 100644
index 0000000..168c19f
--- /dev/null
+++ 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyDecoderFactory.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hl7;
+
+import io.netty.channel.ChannelHandler;
+
+/**
+ * Netty MLLP Decoder factory
+ */
+public class HL7MLLPNettyDecoderFactory extends 
HL7MLLPConfigAwareChannelHandlerFactory {
+
+    @Override
+    public ChannelHandler newChannelHandler() {
+        return new HL7MLLPNettyDecoder(config);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyEncoder.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyEncoder.java
 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyEncoder.java
new file mode 100644
index 0000000..a661ccd
--- /dev/null
+++ 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyEncoder.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hl7;
+
+import ca.uhn.hl7v2.model.Message;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToByteEncoder;
+
+/**
+ * HL7 MLLP Encoder for Netty4
+ */
+class HL7MLLPNettyEncoder extends MessageToByteEncoder<Object> {
+
+    private final HL7MLLPConfig config;
+
+    public HL7MLLPNettyEncoder() {
+        this(new HL7MLLPConfig());
+    }
+
+    public HL7MLLPNettyEncoder(HL7MLLPConfig config) {
+        this.config = config;
+    }
+
+    @Override
+    protected void encode(ChannelHandlerContext channelHandlerContext, Object 
message, ByteBuf byteBuf) throws Exception {
+        if (message == null) {
+            throw new IllegalArgumentException("Message to be encoded is 
null");
+        } else if (message instanceof Exception) {
+            // we cannot handle exceptions
+            throw (Exception) message;
+        }
+
+        byte[] body;
+        if (message instanceof Message) {
+            body = ((Message) message).encode().getBytes(config.getCharset());
+        } else if (message instanceof String) {
+            body = ((String) message).getBytes(config.getCharset());
+        } else if (message instanceof byte[]) {
+            body = (byte[]) message;
+        } else {
+            throw new IllegalArgumentException("The message to encode is not a 
supported type: "
+                    + message.getClass().getCanonicalName());
+        }
+        byteBuf.writeByte(config.getStartByte());
+        byteBuf.writeBytes(body);
+        byteBuf.writeByte(config.getEndByte1());
+        byteBuf.writeByte(config.getEndByte2());
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyEncoderFactory.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyEncoderFactory.java
 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyEncoderFactory.java
new file mode 100644
index 0000000..e03de7d
--- /dev/null
+++ 
b/components/camel-hl7/src/main/java/org/apache/camel/component/hl7/HL7MLLPNettyEncoderFactory.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hl7;
+
+import io.netty.channel.ChannelHandler;
+
+/**
+ * Netty MLLP Encoder factory
+ */
+public class HL7MLLPNettyEncoderFactory extends 
HL7MLLPConfigAwareChannelHandlerFactory {
+
+    @Override
+    public ChannelHandler newChannelHandler() {
+        return new HL7MLLPNettyEncoder(config);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecBoundaryTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecBoundaryTest.java
 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecBoundaryTest.java
new file mode 100644
index 0000000..cfb6cd0
--- /dev/null
+++ 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecBoundaryTest.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hl7;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+import ca.uhn.hl7v2.model.v25.message.MDM_T02;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.util.IOHelper;
+import org.junit.Test;
+
+/**
+ * Test for situation where the two end bytes are split across different byte
+ * buffers.
+ */
+public class HL7MLLPNettyCodecBoundaryTest extends HL7TestSupport {
+
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndi = super.createRegistry();
+
+        // START SNIPPET: e1
+        HL7MLLPNettyDecoderFactory decoder = new HL7MLLPNettyDecoderFactory();
+        decoder.setCharset("iso-8859-1");
+        jndi.bind("hl7decoder", decoder);
+
+        HL7MLLPNettyEncoderFactory encoder = new HL7MLLPNettyEncoderFactory();
+        decoder.setCharset("iso-8859-1");
+        jndi.bind("hl7encoder", encoder);
+        // END SNIPPET: e1
+
+        return jndi;
+    }
+
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                from("netty4:tcp://127.0.0.1:" + getPort() + 
"?sync=true&decoder=#hl7decoder&encoder=#hl7encoder").process(new Processor() {
+                    public void process(Exchange exchange) throws Exception {
+                        // check presence of correct message type
+                        exchange.getIn().getBody(MDM_T02.class);
+                    }
+                }).to("mock:result");
+            }
+        };
+    }
+
+    @Test 
+    public void testSendHL7Message() throws Exception {
+        BufferedReader in = IOHelper.buffered(new 
InputStreamReader(getClass().getResourceAsStream("/mdm_t02-1022.txt")));
+        String line = "";
+        String message = "";
+        while (line != null) {
+            if ((line = in.readLine()) != null) {
+                message += line + "\r";
+            }
+        }
+        message = message.substring(0, message.length() - 1);
+        assertEquals(1022, message.length());
+        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
+        mockEndpoint.expectedMessageCount(1);
+        template.requestBody("netty4:tcp://127.0.0.1:" + getPort() + 
"?sync=true&decoder=#hl7decoder&encoder=#hl7encoder", message);
+        mockEndpoint.assertIsSatisfied();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecByteArrayRouteTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecByteArrayRouteTest.java
 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecByteArrayRouteTest.java
new file mode 100644
index 0000000..d49187e
--- /dev/null
+++ 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecByteArrayRouteTest.java
@@ -0,0 +1,221 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hl7;
+
+import ca.uhn.hl7v2.model.Message;
+import ca.uhn.hl7v2.model.v24.message.ADR_A19;
+import ca.uhn.hl7v2.model.v24.message.ADT_A01;
+import ca.uhn.hl7v2.model.v24.message.QRY_A19;
+import ca.uhn.hl7v2.model.v24.segment.MSA;
+import ca.uhn.hl7v2.model.v24.segment.MSH;
+import ca.uhn.hl7v2.model.v24.segment.PID;
+import ca.uhn.hl7v2.model.v24.segment.QRD;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.spi.DataFormat;
+import org.junit.Test;
+
+/**
+ * Unit test for HL7 routing where the netty4 endpoint passes on a byte array 
instead of a string
+ * and leaves charset interpretation to the dataformat.
+ */
+public class HL7MLLPNettyCodecByteArrayRouteTest extends HL7TestSupport {
+
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndi = super.createRegistry();
+
+        HL7MLLPNettyDecoderFactory decoder = new HL7MLLPNettyDecoderFactory();
+        decoder.setProduceString(false);
+        jndi.bind("hl7decoder", decoder);
+
+        HL7MLLPNettyEncoderFactory encoder = new HL7MLLPNettyEncoderFactory();
+        jndi.bind("hl7encoder", encoder);
+
+        MyHL7BusinessLogic logic = new MyHL7BusinessLogic();
+        jndi.bind("hl7service", logic);
+
+        return jndi;
+    }
+
+    @Test
+    public void testSendA19() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:a19");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(Message.class);
+
+        String line1 = 
"MSH|^~\\&|MYSENDER|MYSENDERAPP|MYCLIENT|MYCLIENTAPP|200612211200||QRY^A19|1234|P|2.4";
+        String line2 = 
"QRD|200612211200|R|I|GetPatient|||1^RD|0101701234|DEM||";
+
+        StringBuilder in = new StringBuilder();
+        in.append(line1);
+        in.append("\r");
+        in.append(line2);
+
+        String out = template.requestBody("netty4:tcp://127.0.0.1:" + 
getPort() + "?sync=true&encoder=#hl7encoder&decoder=#hl7decoder", 
in.toString(), String.class);
+
+        String[] lines = out.split("\r");
+        
assertEquals("MSH|^~\\&|MYSENDER||||200701011539||ADR^A19||||123|||||UNICODE 
UTF-8", lines[0]);
+        assertEquals("MSA|AA|123", lines[1]);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testSendA01() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:a01");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(Message.class);
+
+        String line1 = 
"MSH|^~\\&|MYSENDER|MYSENDERAPP|MYCLIENT|MYCLIENTAPP|200612211200||ADT^A01|123|P|2.4||||||UNICODE
 UTF-8";
+        String line2 = "PID|||123456||Döe^John";
+
+        StringBuilder in = new StringBuilder();
+        in.append(line1);
+        in.append("\r");
+        in.append(line2);
+
+        String out = template.requestBody("netty4:tcp://127.0.0.1:" + 
getPort() + "?sync=true&encoder=#hl7encoder&decoder=#hl7decoder", 
in.toString(), String.class);
+        String[] lines = out.split("\r");
+        
assertEquals("MSH|^~\\&|MYSENDER||||200701011539||ADT^A01||||123|||||UNICODE 
UTF-8", lines[0]);
+        assertEquals("PID|||123||Döe^John", lines[1]);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testSendUnknown() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:unknown");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(Message.class);
+
+        String line1 = 
"MSH|^~\\&|MYSENDER|MYSENDERAPP|MYCLIENT|MYCLIENTAPP|200612211200||ADT^A02|1234|P|2.4";
+        String line2 = "PID|||123456||Döe^John";
+
+        StringBuilder in = new StringBuilder();
+        in.append(line1);
+        in.append("\r");
+        in.append(line2);
+
+        template.requestBody("netty4:tcp://127.0.0.1:" + getPort() + 
"?sync=true&encoder=#hl7encoder&decoder=#hl7decoder", in.toString());
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                // START SNIPPET: e1
+                DataFormat hl7 = new HL7DataFormat();
+                // we setup or HL7 listener on port 8888 (using the hl7codec) 
and in sync mode so we can return a response
+                from("netty4:tcp://127.0.0.1:" + getPort() + 
"?sync=true&encoder=#hl7encoder&decoder=#hl7decoder")
+                    // we use the HL7 data format to unmarshal from HL7 stream 
to the HAPI Message model
+                    // this ensures that the camel message has been enriched 
with hl7 specific headers to
+                    // make the routing much easier (see below)
+                    .unmarshal(hl7)
+                    // using choice as the content base router
+                    .choice()
+                        // where we choose that A19 queries invoke the 
handleA19 method on our hl7service bean
+                        .when(header("CamelHL7TriggerEvent").isEqualTo("A19"))
+                            .beanRef("hl7service", "handleA19")
+                            .to("mock:a19")
+                        // and A01 should invoke the handleA01 method on our 
hl7service bean
+                        
.when(header("CamelHL7TriggerEvent").isEqualTo("A01")).to("mock:a01")
+                            .beanRef("hl7service", "handleA01")
+                            .to("mock:a19")
+                        // other types should go to mock:unknown
+                        .otherwise()
+                            .to("mock:unknown")
+                    // end choice block
+                    .end()
+                    // marshal response back
+                    .marshal(hl7);
+                // END SNIPPET: e1
+            }
+        };
+    }
+
+    public class MyHL7BusinessLogic {
+
+        // This is a plain POJO that has NO imports whatsoever on Apache Camel.
+        // its a plain POJO only importing the HAPI library so we can much 
easier work with the HL7 format.
+
+        public Message handleA19(Message msg) throws Exception {
+            // here you can have your business logic for A19 messages
+            assertTrue(msg instanceof QRY_A19);
+            // just return the same dummy response
+            return createADR19Message();
+        }
+
+        public Message handleA01(Message msg) throws Exception {
+            // here you can have your business logic for A01 messages
+            assertTrue(msg instanceof ADT_A01);
+            // just return the same dummy response
+            return 
createADT01Message(((ADT_A01)msg).getMSH().getMessageControlID().getValue());
+        }
+    }
+
+    private static Message createADR19Message() throws Exception {
+        ADR_A19 adr = new ADR_A19();
+
+        // Populate the MSH Segment
+        MSH mshSegment = adr.getMSH();
+        mshSegment.getFieldSeparator().setValue("|");
+        mshSegment.getEncodingCharacters().setValue("^~\\&");
+        
mshSegment.getDateTimeOfMessage().getTimeOfAnEvent().setValue("200701011539");
+        
mshSegment.getSendingApplication().getNamespaceID().setValue("MYSENDER");
+        mshSegment.getSequenceNumber().setValue("123");
+        mshSegment.getMessageType().getMessageType().setValue("ADR");
+        mshSegment.getMessageType().getTriggerEvent().setValue("A19");
+        mshSegment.getCharacterSet(0).setValue("UNICODE UTF-8");
+
+        // Populate the PID Segment
+        MSA msa = adr.getMSA();
+        msa.getAcknowledgementCode().setValue("AA");
+        msa.getMessageControlID().setValue("123");
+
+        QRD qrd = adr.getQRD();
+        qrd.getQueryDateTime().getTimeOfAnEvent().setValue("20080805120000");
+
+        return adr.getMessage();
+    }
+
+    private static Message createADT01Message(String msgId) throws Exception {
+        ADT_A01 adt = new ADT_A01();
+
+        // Populate the MSH Segment
+        MSH mshSegment = adt.getMSH();
+        mshSegment.getFieldSeparator().setValue("|");
+        mshSegment.getEncodingCharacters().setValue("^~\\&");
+        
mshSegment.getDateTimeOfMessage().getTimeOfAnEvent().setValue("200701011539");
+        
mshSegment.getSendingApplication().getNamespaceID().setValue("MYSENDER");
+        mshSegment.getSequenceNumber().setValue("123");
+        mshSegment.getMessageType().getMessageType().setValue("ADT");
+        mshSegment.getMessageType().getTriggerEvent().setValue("A01");
+        mshSegment.getCharacterSet(0).setValue("UNICODE UTF-8");
+
+        // Populate the PID Segment
+        PID pid = adt.getPID();
+        pid.getPatientName(0).getFamilyName().getSurname().setValue("Döe");
+        pid.getPatientName(0).getGivenName().setValue("John");
+        pid.getPatientIdentifierList(0).getID().setValue(msgId);
+
+        return adt;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecLongTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecLongTest.java
 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecLongTest.java
new file mode 100644
index 0000000..d6f49ba
--- /dev/null
+++ 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecLongTest.java
@@ -0,0 +1,88 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hl7;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+import ca.uhn.hl7v2.model.Message;
+import ca.uhn.hl7v2.model.v25.message.MDM_T02;
+import ca.uhn.hl7v2.model.v25.segment.MSH;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.util.IOHelper;
+import org.junit.Test;
+
+/**
+ * Unit test for the HL7MLLP Codec.
+ */
+public class HL7MLLPNettyCodecLongTest extends HL7TestSupport {
+
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndi = super.createRegistry();
+
+        // START SNIPPET: e1
+        HL7MLLPNettyDecoderFactory decoder = new HL7MLLPNettyDecoderFactory();
+        decoder.setCharset("iso-8859-1");
+        jndi.bind("hl7decoder", decoder);
+
+        HL7MLLPNettyEncoderFactory encoder = new HL7MLLPNettyEncoderFactory();
+        decoder.setCharset("iso-8859-1");
+        jndi.bind("hl7encoder", encoder);
+        // END SNIPPET: e1
+
+        return jndi;
+    }
+
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                from("netty4:tcp://127.0.0.1:" + getPort() + 
"?sync=true&encoder=#hl7encoder&decoder=#hl7decoder").process(new Processor() {
+                    public void process(Exchange exchange) throws Exception {
+                        assertEquals(70010, 
exchange.getIn().getBody(byte[].class).length);
+                        MDM_T02 input = 
(MDM_T02)exchange.getIn().getBody(Message.class);
+                        assertEquals("2.5", input.getVersion());
+                        MSH msh = input.getMSH();
+                        assertEquals("20071129144629", 
msh.getDateTimeOfMessage().getTime().getValue());
+                        exchange.getOut().setBody("some response");
+                    }
+                }).to("mock:result");
+            }
+        };
+    }
+
+    @Test
+    public void testSendHL7Message() throws Exception {
+        // START SNIPPET: e2
+        BufferedReader in = IOHelper.buffered(new 
InputStreamReader(getClass().getResourceAsStream("/mdm_t02.txt")));
+        String line = "";
+        String message = "";
+        while (line != null) {
+            if ((line = in.readLine()) != null) {
+                message += line + "\r";
+            }
+        }
+        message = message.substring(0, message.length() - 1);
+        assertEquals(70010, message.length());
+        String out = template.requestBody("netty4:tcp://127.0.0.1:" + 
getPort() + "?sync=true&encoder=#hl7encoder&decoder=#hl7decoder", message, 
String.class);
+        assertEquals("some response", out);
+        // END SNIPPET: e2
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecStandAndEndBytesTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecStandAndEndBytesTest.java
 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecStandAndEndBytesTest.java
new file mode 100644
index 0000000..17c4b1e
--- /dev/null
+++ 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecStandAndEndBytesTest.java
@@ -0,0 +1,123 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hl7;
+
+import ca.uhn.hl7v2.model.Message;
+import ca.uhn.hl7v2.model.v24.message.ADR_A19;
+import ca.uhn.hl7v2.model.v24.segment.MSA;
+import ca.uhn.hl7v2.model.v24.segment.MSH;
+import ca.uhn.hl7v2.model.v24.segment.QRD;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.JndiRegistry;
+import org.junit.Test;
+
+/**
+ * Unit test for the HL7MLLP Codec using different start and end bytes.
+ */
+public class HL7MLLPNettyCodecStandAndEndBytesTest extends HL7TestSupport {
+
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndi = super.createRegistry();
+
+        HL7MLLPNettyDecoderFactory decoder = new HL7MLLPNettyDecoderFactory();
+        decoder.setCharset("iso-8859-1");
+        // to test with different start and end bytes.
+        decoder.setStartByte('*');
+        decoder.setEndByte1('#');
+        decoder.setEndByte2('*');
+        decoder.setConvertLFtoCR(false);
+
+        jndi.bind("hl7decoder", decoder);
+
+        HL7MLLPNettyEncoderFactory encoder = new HL7MLLPNettyEncoderFactory();
+        encoder.setCharset("iso-8859-1");
+        // to test with different start and end bytes.
+        encoder.setStartByte('*');
+        encoder.setEndByte1('#');
+        encoder.setEndByte2('*');
+        encoder.setConvertLFtoCR(false);
+
+        jndi.bind("hl7encoder", encoder);
+
+        return jndi;
+    }
+
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                from("netty4:tcp://127.0.0.1:" + getPort() + 
"?sync=true&decoder=#hl7decoder&encoder=#hl7encoder")
+                    .process(new Processor() {
+                        public void process(Exchange exchange) throws 
Exception {
+                            Message input = 
exchange.getIn().getBody(Message.class);
+
+                            assertEquals("2.4", input.getVersion());
+                            QRD qrd = (QRD)input.get("QRD");
+                            assertEquals("0101701234", 
qrd.getWhoSubjectFilter(0).getIDNumber().getValue());
+
+                            Message response = createHL7AsMessage();
+                            exchange.getOut().setBody(response);
+                        }
+                    })
+                    .to("mock:result");
+            }
+        };
+    }
+
+    @Test
+    public void testSendHL7Message() throws Exception {
+        String line1 = 
"MSH|^~\\&|MYSENDER|MYRECEIVER|MYAPPLICATION||200612211200||QRY^A19|1234|P|2.4";
+        String line2 = 
"QRD|200612211200|R|I|GetPatient|||1^RD|0101701234|DEM||";
+
+        StringBuilder in = new StringBuilder();
+        in.append(line1);
+        in.append("\r");
+        in.append(line2);
+
+        String out = template.requestBody("netty4:tcp://127.0.0.1:" + 
getPort() + "?sync=true&decoder=#hl7decoder&encoder=#hl7encoder", 
in.toString(), String.class);
+
+        String[] lines = out.split("\r");
+        assertEquals("MSH|^~\\&|MYSENDER||||200701011539||ADR^A19||||123", 
lines[0]);
+        assertEquals("MSA|AA|123", lines[1]);
+    }
+
+    private static Message createHL7AsMessage() throws Exception {
+        ADR_A19 adr = new ADR_A19();
+
+        // Populate the MSH Segment
+        MSH mshSegment = adr.getMSH();
+        mshSegment.getFieldSeparator().setValue("|");
+        mshSegment.getEncodingCharacters().setValue("^~\\&");
+        
mshSegment.getDateTimeOfMessage().getTimeOfAnEvent().setValue("200701011539");
+        
mshSegment.getSendingApplication().getNamespaceID().setValue("MYSENDER");
+        mshSegment.getSequenceNumber().setValue("123");
+        mshSegment.getMessageType().getMessageType().setValue("ADR");
+        mshSegment.getMessageType().getTriggerEvent().setValue("A19");
+
+        // Populate the PID Segment
+        MSA msa = adr.getMSA();
+        msa.getAcknowledgementCode().setValue("AA");
+        msa.getMessageControlID().setValue("123");
+
+        QRD qrd = adr.getQRD();
+        qrd.getQueryDateTime().getTimeOfAnEvent().setValue("20080805120000");
+
+        return adr;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecTest.java
 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecTest.java
new file mode 100644
index 0000000..58838c5
--- /dev/null
+++ 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7MLLPNettyCodecTest.java
@@ -0,0 +1,116 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hl7;
+
+import ca.uhn.hl7v2.model.Message;
+import ca.uhn.hl7v2.model.v24.message.ADR_A19;
+import ca.uhn.hl7v2.model.v24.segment.MSA;
+import ca.uhn.hl7v2.model.v24.segment.MSH;
+import ca.uhn.hl7v2.model.v24.segment.QRD;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.JndiRegistry;
+import org.junit.Test;
+
+/**
+ * Unit test for the HL7MLLPNetty Codec.
+ */
+public class HL7MLLPNettyCodecTest extends HL7TestSupport {
+
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndi = super.createRegistry();
+
+        // START SNIPPET: e1
+        HL7MLLPNettyDecoderFactory decoder = new HL7MLLPNettyDecoderFactory();
+        decoder.setCharset("iso-8859-1");
+        decoder.setConvertLFtoCR(true);
+        jndi.bind("hl7decoder", decoder);
+
+        HL7MLLPNettyEncoderFactory encoder = new HL7MLLPNettyEncoderFactory();
+        decoder.setCharset("iso-8859-1");
+        decoder.setConvertLFtoCR(true);
+        jndi.bind("hl7encoder", encoder);
+        // END SNIPPET: e1
+
+        return jndi;
+    }
+
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                from("netty4:tcp://127.0.0.1:" + getPort() + 
"?sync=true&decoder=#hl7decoder&encoder=#hl7encoder")
+                    .process(new Processor() {
+                        public void process(Exchange exchange) throws 
Exception {
+                            Message input = 
exchange.getIn().getBody(Message.class);
+
+                            assertEquals("2.4", input.getVersion());
+                            QRD qrd = (QRD)input.get("QRD");
+                            assertEquals("0101701234", 
qrd.getWhoSubjectFilter(0).getIDNumber().getValue());
+
+                            Message response = createHL7AsMessage();
+                            exchange.getOut().setBody(response);
+                        }
+                    })
+                    .to("mock:result");
+            }
+        };
+    }
+
+    @Test
+    public void testSendHL7Message() throws Exception {
+        // START SNIPPET: e2
+        String line1 = 
"MSH|^~\\&|MYSENDER|MYRECEIVER|MYAPPLICATION||200612211200||QRY^A19|1234|P|2.4";
+        String line2 = 
"QRD|200612211200|R|I|GetPatient|||1^RD|0101701234|DEM||";
+
+        StringBuilder in = new StringBuilder();
+        in.append(line1);
+        in.append("\n");
+        in.append(line2);
+
+        String out = template.requestBody("netty4:tcp://127.0.0.1:" + 
getPort() + "?sync=true&decoder=#hl7decoder&encoder=#hl7encoder", 
in.toString(), String.class);
+        // END SNIPPET: e2
+
+        String[] lines = out.split("\r");
+        
assertEquals("MSH|^~\\&|MYSENDER||||200701011539||ADR^A19^ADR_A19|456|P|2.4", 
lines[0]);
+        assertEquals("MSA|AA|123", lines[1]);
+    }
+
+    // START SNIPPET: e3
+    private static Message createHL7AsMessage() throws Exception {
+        ADR_A19 adr = new ADR_A19();
+        adr.initQuickstart("ADR", "A19", "P");
+
+        // Populate the MSH Segment
+        MSH mshSegment = adr.getMSH();
+        
mshSegment.getDateTimeOfMessage().getTimeOfAnEvent().setValue("200701011539");
+        
mshSegment.getSendingApplication().getNamespaceID().setValue("MYSENDER");
+        mshSegment.getMessageControlID().setValue("456");
+
+        // Populate the PID Segment
+        MSA msa = adr.getMSA();
+        msa.getAcknowledgementCode().setValue("AA");
+        msa.getMessageControlID().setValue("123");
+
+        QRD qrd = adr.getQRD();
+        qrd.getQueryDateTime().getTimeOfAnEvent().setValue("20080805120000");
+
+        return adr;
+    }
+    // END SNIPPET: e3
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7NettyRouteTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7NettyRouteTest.java
 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7NettyRouteTest.java
new file mode 100644
index 0000000..a26ae41
--- /dev/null
+++ 
b/components/camel-hl7/src/test/java/org/apache/camel/component/hl7/HL7NettyRouteTest.java
@@ -0,0 +1,221 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.hl7;
+
+import ca.uhn.hl7v2.model.Message;
+import ca.uhn.hl7v2.model.v24.message.ADR_A19;
+import ca.uhn.hl7v2.model.v24.message.ADT_A01;
+import ca.uhn.hl7v2.model.v24.message.QRY_A19;
+import ca.uhn.hl7v2.model.v24.segment.MSA;
+import ca.uhn.hl7v2.model.v24.segment.MSH;
+import ca.uhn.hl7v2.model.v24.segment.PID;
+import ca.uhn.hl7v2.model.v24.segment.QRD;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.spi.DataFormat;
+import org.junit.Test;
+
+/**
+ * Unit test for HL7 routing.
+ */
+public class HL7NettyRouteTest extends HL7TestSupport {
+
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndi = super.createRegistry();
+
+        HL7MLLPNettyDecoderFactory decoder = new HL7MLLPNettyDecoderFactory();
+        decoder.setCharset("iso-8859-1");
+        jndi.bind("hl7decoder", decoder);
+
+        HL7MLLPNettyEncoderFactory encoder = new HL7MLLPNettyEncoderFactory();
+        decoder.setCharset("iso-8859-1");
+        jndi.bind("hl7encoder", encoder);
+
+        MyHL7BusinessLogic logic = new MyHL7BusinessLogic();
+        jndi.bind("hl7service", logic);
+
+        return jndi;
+    }
+
+    @Test
+    public void testSendA19() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:a19");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(Message.class);
+
+        String line1 = 
"MSH|^~\\&|MYSENDER|MYSENDERAPP|MYCLIENT|MYCLIENTAPP|200612211200||QRY^A19|1234|P|2.4";
+        String line2 = 
"QRD|200612211200|R|I|GetPatient|||1^RD|0101701234|DEM||";
+
+        StringBuilder in = new StringBuilder();
+        in.append(line1);
+        in.append("\r");
+        in.append(line2);
+
+        String out = template.requestBody("netty4:tcp://127.0.0.1:" + 
getPort() + "?sync=true&decoder=#hl7decoder&encoder=#hl7encoder", 
in.toString(), String.class);
+
+        String[] lines = out.split("\r");
+        assertEquals("MSH|^~\\&|MYSENDER||||200701011539||ADR^A19||||123", 
lines[0]);
+        assertEquals("MSA|AA|123", lines[1]);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testSendA01() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:a01");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(Message.class);
+
+        String line1 = 
"MSH|^~\\&|MYSENDER|MYSENDERAPP|MYCLIENT|MYCLIENTAPP|200612211200||ADT^A01|123|P|2.4";
+        String line2 = "PID|||123456||Doe^John";
+
+        StringBuilder in = new StringBuilder();
+        in.append(line1);
+        in.append("\r");
+        in.append(line2);
+
+        String out = template.requestBody("netty4:tcp://127.0.0.1:" + 
getPort() + "?sync=true&decoder=#hl7decoder&encoder=#hl7encoder", 
in.toString(), String.class);
+        String[] lines = out.split("\r");
+        assertEquals("MSH|^~\\&|MYSENDER||||200701011539||ADT^A01||||123", 
lines[0]);
+        assertEquals("PID|||123||Doe^John", lines[1]);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testSendUnknown() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:unknown");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(Message.class);
+
+        String line1 = 
"MSH|^~\\&|MYSENDER|MYSENDERAPP|MYCLIENT|MYCLIENTAPP|200612211200||ADT^A02|1234|P|2.4";
+        String line2 = "PID|||123456||Doe^John";
+
+        StringBuilder in = new StringBuilder();
+        in.append(line1);
+        in.append("\r");
+        in.append(line2);
+
+        template.requestBody("netty4:tcp://127.0.0.1:" + getPort() + 
"?sync=true&decoder=#hl7decoder&encoder=#hl7encoder", in.toString());
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                // START SNIPPET: e1
+                DataFormat hl7 = new HL7DataFormat();
+                // we setup or HL7 listener on port 8888 (using the hl7codec) 
and in sync mode so we can return a response
+                from("netty4:tcp://127.0.0.1:" + getPort() + 
"?sync=true&decoder=#hl7decoder&encoder=#hl7encoder")
+                    // we use the HL7 data format to unmarshal from HL7 stream 
to the HAPI Message model
+                    // this ensures that the camel message has been enriched 
with hl7 specific headers to
+                    // make the routing much easier (see below)
+                    .unmarshal(hl7)
+                    // using choice as the content base router
+                    .choice()
+                        // where we choose that A19 queries invoke the 
handleA19 method on our hl7service bean
+                        .when(header("CamelHL7TriggerEvent").isEqualTo("A19"))
+                            .beanRef("hl7service", "handleA19")
+                            .to("mock:a19")
+                        // and A01 should invoke the handleA01 method on our 
hl7service bean
+                        
.when(header("CamelHL7TriggerEvent").isEqualTo("A01")).to("mock:a01")
+                            .beanRef("hl7service", "handleA01")
+                            .to("mock:a19")
+                        // other types should go to mock:unknown
+                        .otherwise()
+                            .to("mock:unknown")
+                    // end choice block
+                    .end()
+                    // marshal response back
+                    .marshal(hl7);
+                // END SNIPPET: e1
+            }
+        };
+    }
+
+    // START SNIPPET: e2
+    public class MyHL7BusinessLogic {
+
+        // This is a plain POJO that has NO imports whatsoever on Apache Camel.
+        // its a plain POJO only importing the HAPI library so we can much 
easier work with the HL7 format.
+
+        public Message handleA19(Message msg) throws Exception {
+            // here you can have your business logic for A19 messages
+            assertTrue(msg instanceof QRY_A19);
+            // just return the same dummy response
+            return createADR19Message();
+        }
+
+        public Message handleA01(Message msg) throws Exception {
+            // here you can have your business logic for A01 messages
+            assertTrue(msg instanceof ADT_A01);
+            // just return the same dummy response
+            return 
createADT01Message(((ADT_A01)msg).getMSH().getMessageControlID().getValue());
+        }
+    }
+    // END SNIPPET: e2
+
+    private static Message createADR19Message() throws Exception {
+        ADR_A19 adr = new ADR_A19();
+
+        // Populate the MSH Segment
+        MSH mshSegment = adr.getMSH();
+        mshSegment.getFieldSeparator().setValue("|");
+        mshSegment.getEncodingCharacters().setValue("^~\\&");
+        
mshSegment.getDateTimeOfMessage().getTimeOfAnEvent().setValue("200701011539");
+        
mshSegment.getSendingApplication().getNamespaceID().setValue("MYSENDER");
+        mshSegment.getSequenceNumber().setValue("123");
+        mshSegment.getMessageType().getMessageType().setValue("ADR");
+        mshSegment.getMessageType().getTriggerEvent().setValue("A19");
+
+        // Populate the PID Segment
+        MSA msa = adr.getMSA();
+        msa.getAcknowledgementCode().setValue("AA");
+        msa.getMessageControlID().setValue("123");
+
+        QRD qrd = adr.getQRD();
+        qrd.getQueryDateTime().getTimeOfAnEvent().setValue("20080805120000");
+
+        return adr.getMessage();
+    }
+
+    private static Message createADT01Message(String msgId) throws Exception {
+        ADT_A01 adt = new ADT_A01();
+
+        // Populate the MSH Segment
+        MSH mshSegment = adt.getMSH();
+        mshSegment.getFieldSeparator().setValue("|");
+        mshSegment.getEncodingCharacters().setValue("^~\\&");
+        
mshSegment.getDateTimeOfMessage().getTimeOfAnEvent().setValue("200701011539");
+        
mshSegment.getSendingApplication().getNamespaceID().setValue("MYSENDER");
+        mshSegment.getSequenceNumber().setValue("123");
+        mshSegment.getMessageType().getMessageType().setValue("ADT");
+        mshSegment.getMessageType().getTriggerEvent().setValue("A01");
+
+        // Populate the PID Segment
+        PID pid = adt.getPID();
+        pid.getPatientName(0).getFamilyName().getSurname().setValue("Doe");
+        pid.getPatientName(0).getGivenName().setValue("John");
+        pid.getPatientIdentifierList(0).getID().setValue(msgId);
+
+        return adt;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/64d08a7e/platforms/karaf/features/src/main/resources/features.xml
----------------------------------------------------------------------
diff --git a/platforms/karaf/features/src/main/resources/features.xml 
b/platforms/karaf/features/src/main/resources/features.xml
index 91a835b..52666bc 100644
--- a/platforms/karaf/features/src/main/resources/features.xml
+++ b/platforms/karaf/features/src/main/resources/features.xml
@@ -637,6 +637,7 @@
   </feature>
   <feature name='camel-hl7' version='${project.version}' resolver='(obr)' 
start-level='50'>
     <feature version='${project.version}'>camel-core</feature>
+    <feature version='${project.version}'>camel-netty4</feature>
     <bundle 
dependency='true'>mvn:org.apache.mina/mina-core/${mina2-version}</bundle>
     <bundle 
dependency='true'>mvn:ca.uhn.hapi/hapi-osgi-base/${hapi-version}</bundle>
     <bundle>mvn:org.apache.camel/camel-hl7/${project.version}</bundle>

Reply via email to