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>