From a62a64bba35bbff602e8c728638b682f92d194d5 Mon Sep 17 00:00:00 2001 From: unixoid Date: Mon, 27 Oct 2014 00:45:41 +0100 Subject: [PATCH] #53: MLLP dispatching consumer --- .../ihe/hl7v2/AcceptanceCheckUtils.groovy | 110 ------- .../hl7v2/Hl7v2TransactionConfiguration.java | 161 ++++++++- .../intercept/AcceptanceInterceptorUtils.java | 15 +- .../ihe/hl7v2ws/AbstractHl7v2WebService.java | 6 +- .../org/apache/camel/component/mllp-dispatch | 12 + .../ihe/mllp/core/MllpAuditStrategy.java | 4 +- .../camel/ihe/mllp/core/MllpComponent.java | 175 ++-------- .../ihe/mllp/core/MllpDispatchComponent.java | 66 ++++ .../ihe/mllp/core/MllpDispatchEndpoint.java | 62 ++++ .../MllpDispatchEndpointConfiguration.java | 44 +++ .../camel/ihe/mllp/core/MllpEndpoint.java | 307 ++++-------------- .../mllp/core/MllpEndpointConfiguration.java | 127 ++++++++ .../mllp/core/MllpTransactionComponent.java | 58 ++++ .../mllp/core/MllpTransactionEndpoint.java | 181 +++++++++++ .../MllpTransactionEndpointConfiguration.java | 52 +++ .../intercept/AbstractMllpInterceptor.java | 9 +- .../mllp/core/intercept/AuditInterceptor.java | 2 +- .../mllp/core/intercept/MllpInterceptor.java | 5 +- .../consumer/ConsumerAuditInterceptor.java | 10 +- ...sumerAuthenticationFailureInterceptor.java | 6 +- .../ConsumerDispatchingInterceptor.java | 132 ++++++++ .../ConsumerInPayloadLoggerInterceptor.java | 3 +- ...rInteractiveResponseSenderInterceptor.java | 12 +- .../ConsumerOutPayloadLoggerInterceptor.java | 3 +- ...onsumerRequestDefragmenterInterceptor.java | 3 +- .../ConsumerStringProcessingInterceptor.java | 3 +- .../producer/ProducerAuditInterceptor.java | 10 +- .../ProducerInPayloadLoggerInterceptor.java | 3 +- ...nteractiveResponseReceiverInterceptor.java | 10 +- .../ProducerOutPayloadLoggerInterceptor.java | 3 +- .../ProducerRequestFragmenterInterceptor.java | 3 +- .../ProducerStringProcessingInterceptor.java | 3 +- .../camel/ihe/mllp/iti10/Iti10Component.java | 4 +- .../camel/ihe/mllp/iti21/Iti21Component.java | 4 +- .../camel/ihe/mllp/iti22/Iti22Component.java | 4 +- .../camel/ihe/mllp/iti64/Iti64Component.java | 4 +- .../camel/ihe/mllp/iti8/Iti8Component.java | 2 +- .../camel/ihe/mllp/iti9/Iti9Component.java | 4 +- .../core/ManagedMllpItiEndpointTest.groovy | 6 +- .../ihe/mllp/core/MllpTestContainer.groovy | 13 +- .../mllp/dispatch/DispatchRouteBuilder.groovy | 51 +++ .../ihe/mllp/dispatch/TestDispatch.groovy | 104 ++++++ .../mllp/core/mbean/SomeMllpItiComponent.java | 4 +- .../src/test/resources/dispatch/dispatch.xml | 64 ++++ 44 files changed, 1268 insertions(+), 596 deletions(-) delete mode 100644 platform-camel/ihe/hl7v2/src/main/groovy/org/openehealth/ipf/platform/camel/ihe/hl7v2/AcceptanceCheckUtils.groovy create mode 100644 platform-camel/ihe/mllp/META-INF/services/org/apache/camel/component/mllp-dispatch create mode 100644 platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchComponent.java create mode 100644 platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchEndpoint.java create mode 100644 platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchEndpointConfiguration.java create mode 100644 platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpEndpointConfiguration.java create mode 100644 platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionComponent.java create mode 100644 platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionEndpoint.java create mode 100644 platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionEndpointConfiguration.java create mode 100644 platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerDispatchingInterceptor.java create mode 100644 platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/dispatch/DispatchRouteBuilder.groovy create mode 100644 platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/dispatch/TestDispatch.groovy create mode 100644 platform-camel/ihe/mllp/src/test/resources/dispatch/dispatch.xml diff --git a/platform-camel/ihe/hl7v2/src/main/groovy/org/openehealth/ipf/platform/camel/ihe/hl7v2/AcceptanceCheckUtils.groovy b/platform-camel/ihe/hl7v2/src/main/groovy/org/openehealth/ipf/platform/camel/ihe/hl7v2/AcceptanceCheckUtils.groovy deleted file mode 100644 index 6ed687e9aa..0000000000 --- a/platform-camel/ihe/hl7v2/src/main/groovy/org/openehealth/ipf/platform/camel/ihe/hl7v2/AcceptanceCheckUtils.groovy +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2009 the original author or authors. - * - * Licensed 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.openehealth.ipf.platform.camel.ihe.hl7v2 - -import org.openehealth.ipf.modules.hl7dsl.MessageAdapter - - -/** - * Groovy subroutines for HL7 message acceptance checks. - * @author Dmytro Rud - */ -class AcceptanceCheckUtils { - - private AcceptanceCheckUtils() { - throw new IllegalStateException('Helper class, do not instantiate'); - } - - - /** - * Performs transaction-specific acceptance test of the given request message. - */ - static void checkRequestAcceptance( - MessageAdapter msg, - Hl7v2TransactionConfiguration config) throws Hl7v2AcceptanceException - { - checkMessageAcceptance(msg, config, 'Request') - } - - - /** - * Performs transaction-specific acceptance test of the given response message. - */ - static void checkResponseAcceptance( - MessageAdapter msg, - Hl7v2TransactionConfiguration config) throws Hl7v2AcceptanceException - { - checkMessageAcceptance(msg, config, 'Response') - - if( ! ['AA', 'AR', 'AE', 'CA', 'CR', 'CE'].contains(msg.MSA[1]?.value)) { - throw new Hl7v2AcceptanceException("Bad response: missing or invalid MSA segment") - } - } - - - /** - * Performs acceptance test of the given message. - * @param msg - * {@link MessageAdapter} representing the message. - * @param config - * transaction configuration. - * @param direction - * either 'Request' or 'Response'. - * @throws Hl7v2AcceptanceException - * when the message cannot be accepted. - */ - private static void checkMessageAcceptance( - MessageAdapter msg, - Hl7v2TransactionConfiguration config, - String direction) throws Hl7v2AcceptanceException - { - def version = msg.MSH[12].value - if(version != config.hl7Version) { - throw new Hl7v2AcceptanceException("Invalid HL7 version ${version}", 203) - } - - def msgType = msg.MSH[9][1].value - if( ! config."isSupported${direction}MessageType"(msgType)) { - throw new Hl7v2AcceptanceException("Invalid message type ${msgType}", 200) - } - - def triggerEvent = msg.MSH[9][2].value - if( ! config."isSupported${direction}TriggerEvent"(msgType, triggerEvent)) { - throw new Hl7v2AcceptanceException("Invalid trigger event ${triggerEvent}", 201) - } - - def structure = msg.MSH[9][3].value - if(structure) { - - // This may not work as the custom event map cannot be distinguished from the - // default one! This needs to be fixed for HAPI 2.1 - def event = "${msgType}_${triggerEvent}" - def expected = config.parser.getMessageStructureForEvent(event, version) - // TODO when upgrading to HAPI 2.1 remove the constant IF statements - if (event == 'QBP_ZV1') expected = 'QBP_Q21' - if (event == 'RSP_ZV2') expected = 'RSP_ZV2' - - // the expected structure must be equal to the actual one, - // but second components may be omitted in acknowledgements - if( ! ((structure == expected) || - (structure.startsWith('ACK') && expected.startsWith('ACK')))) - { - throw new Hl7v2AcceptanceException("Invalid structure map ${structure}", 204) - } - } - } - -} diff --git a/platform-camel/ihe/hl7v2/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2/Hl7v2TransactionConfiguration.java b/platform-camel/ihe/hl7v2/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2/Hl7v2TransactionConfiguration.java index 23821dbc0d..af1d53d435 100644 --- a/platform-camel/ihe/hl7v2/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2/Hl7v2TransactionConfiguration.java +++ b/platform-camel/ihe/hl7v2/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2/Hl7v2TransactionConfiguration.java @@ -15,14 +15,18 @@ */ package org.openehealth.ipf.platform.camel.ihe.hl7v2; +import ca.uhn.hl7v2.HL7Exception; +import ca.uhn.hl7v2.model.Message; +import ca.uhn.hl7v2.model.Segment; import ca.uhn.hl7v2.parser.Parser; +import ca.uhn.hl7v2.util.Terser; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; +import org.openehealth.ipf.modules.hl7dsl.MessageAdapter; import java.util.List; -import static org.apache.commons.lang3.ArrayUtils.INDEX_NOT_FOUND; -import static org.apache.commons.lang3.ArrayUtils.contains; -import static org.apache.commons.lang3.ArrayUtils.indexOf; +import static org.apache.commons.lang3.ArrayUtils.*; import static org.apache.commons.lang3.Validate.*; /** @@ -30,7 +34,7 @@ * @author Dmytro Rud */ public class Hl7v2TransactionConfiguration { - + private final String hl7Version; private final String sendingApplication; private final String sendingFacility; @@ -143,19 +147,19 @@ public Hl7v2TransactionConfiguration( /** - * Returns true when request messages - * of the given type belong to this transaction. + * Returns true when request messages + * of the given type belong to this transaction. */ - public boolean isSupportedRequestMessageType(String messageType) { + private boolean isSupportedRequestMessageType(String messageType) { return contains(allowedRequestMessageTypes, messageType); } - + /** * Returns true when the given trigger event * is valid for request messages of the given type. */ - public boolean isSupportedRequestTriggerEvent(String messageType, String triggerEvent) { + private boolean isSupportedRequestTriggerEvent(String messageType, String triggerEvent) { int index = indexOf(allowedRequestMessageTypes, messageType); if (index == INDEX_NOT_FOUND) { throw new IllegalArgumentException("Unknown message type " + messageType); @@ -170,7 +174,7 @@ public boolean isSupportedRequestTriggerEvent(String messageType, String trigger * of the given type belong to this transaction. * "ACK" is always supported. */ - public boolean isSupportedResponseMessageType(String messageType) { + private boolean isSupportedResponseMessageType(String messageType) { return "ACK".equals(messageType) || contains(allowedResponseMessageTypes, messageType); } @@ -180,7 +184,7 @@ public boolean isSupportedResponseMessageType(String messageType) { * is valid for response messages of the given type. * For "ACK" message type, every trigger event is considered valid. */ - public boolean isSupportedResponseTriggerEvent(String messageType, String triggerEvent) { + private boolean isSupportedResponseTriggerEvent(String messageType, String triggerEvent) { if("ACK".equals(messageType)) { return true; } @@ -245,8 +249,139 @@ public boolean isDataStartSegment(List segments, int index) { public boolean isFooterStartSegment(List segments, int index) { return false; } - - + + + /** + * Performs transaction-specific acceptance test of the given request message. + * @param messageAdapter + * IPF {@link MessageAdapter} object. + */ + public void checkRequestAcceptance(MessageAdapter messageAdapter) throws Hl7v2AcceptanceException { + Message message = messageAdapter.getHapiMessage(); + checkMessageAcceptance(message, true); + } + + + /** + * Performs transaction-specific acceptance test of the given response message. + * @param messageAdapter + * IPF {@link MessageAdapter} object. + */ + public void checkResponseAcceptance(MessageAdapter messageAdapter) throws Hl7v2AcceptanceException { + Message message = messageAdapter.getHapiMessage(); + checkMessageAcceptance(message, false); + + try { + if (! ArrayUtils.contains( + new String[] {"AA", "AR", "AE", "CA", "CR", "CE"}, + new Terser(message).get("MSA-1"))) + { + throw new Hl7v2AcceptanceException("Bad response: missing or invalid MSA segment", 101); + } + } catch (HL7Exception e) { + throw new Hl7v2AcceptanceException("Bad response: missing or invalid MSA segment", 207); + } + } + + + /** + * Performs acceptance test of the given message. + * @param message + * HAPI {@link Message} object. + * @param isRequest + * true iff the message is a request. + * @throws Hl7v2AcceptanceException + * when the message is not acceptable. + */ + public void checkMessageAcceptance( + Message message, + boolean isRequest) throws Hl7v2AcceptanceException + { + try { + Segment msh = (Segment) message.get("MSH"); + checkMessageAcceptance( + Terser.get(msh, 9, 0, 1, 1), + Terser.get(msh, 9, 0, 2, 1), + Terser.get(msh, 9, 0, 3, 1), + Terser.get(msh, 12, 0, 1, 1), + isRequest); + } catch (HL7Exception e) { + throw new Hl7v2AcceptanceException("Missing or invalid MSH segment", 207); + } + } + + + /** + * Performs acceptance test of the message with the given attributes. + * @param messageType + * value from MSH-9-1, can be empty or null. + * @param triggerEvent + * value from MSH-9-PAI2, can be empty or null. + * @param messageStructure + * value from MSH-9-3, can be empty or null. + * @param version + * value from MSH-12, can be empty or null. + * @param isRequest + * true iff the message under consideration is a request. + * @throws Hl7v2AcceptanceException + * when the message is not acceptable. + */ + public void checkMessageAcceptance( + String messageType, + String triggerEvent, + String messageStructure, + String version, + boolean isRequest) throws Hl7v2AcceptanceException + { + if (! hl7Version.equals(version)) { + throw new Hl7v2AcceptanceException("Invalid HL7 version " + version, 203); + } + + boolean messageTypeSupported = isRequest + ? isSupportedRequestMessageType(messageType) + : isSupportedResponseMessageType(messageType); + + if (! messageTypeSupported) { + throw new Hl7v2AcceptanceException("Invalid message type " + messageType, 200); + } + + boolean triggerEventSupported = isRequest + ? isSupportedRequestTriggerEvent(messageType, triggerEvent) + : isSupportedResponseTriggerEvent(messageType, triggerEvent); + + if(! triggerEventSupported) { + throw new Hl7v2AcceptanceException("Invalid trigger event " + triggerEvent, 201); + } + + if (! StringUtils.isEmpty(messageStructure)) { + // This may not work as the custom event map cannot be distinguished from the + // default one! This needs to be fixed for HAPI 2.1 + String event = messageType + "_" + triggerEvent; + String expectedMessageStructure; + try { + expectedMessageStructure = Parser.getMessageStructureForEvent(event, version); + } catch (HL7Exception e) { + throw new Hl7v2AcceptanceException("Acceptance check failed", 204); + } + + // TODO when upgrading to HAPI 2.1 remove the constant IF statements + if ("QBP_ZV1".equals(event)) { + expectedMessageStructure = "QBP_Q21"; + } else if ("RSP_ZV2".equals(event)) { + expectedMessageStructure = "RSP_ZV2"; + } + + // the expected structure must be equal to the actual one, + // but second components may be omitted in acknowledgements + boolean bothAreEqual = messageStructure.equals(expectedMessageStructure); + boolean bothAreAcks = (messageStructure.startsWith("ACK") && expectedMessageStructure.startsWith("ACK")); + if (! (bothAreEqual || bothAreAcks)) { + throw new Hl7v2AcceptanceException("Invalid message structure " + messageStructure, 207); + } + } + } + + // ----- automatically generated getters ----- public String getHl7Version() { diff --git a/platform-camel/ihe/hl7v2/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2/intercept/AcceptanceInterceptorUtils.java b/platform-camel/ihe/hl7v2/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2/intercept/AcceptanceInterceptorUtils.java index 9a54d98674..23ed2aeb9b 100644 --- a/platform-camel/ihe/hl7v2/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2/intercept/AcceptanceInterceptorUtils.java +++ b/platform-camel/ihe/hl7v2/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2/intercept/AcceptanceInterceptorUtils.java @@ -18,12 +18,11 @@ import org.apache.camel.Exchange; import org.openehealth.ipf.modules.hl7dsl.MessageAdapter; import org.openehealth.ipf.platform.camel.core.util.Exchanges; -import org.openehealth.ipf.platform.camel.ihe.hl7v2.AcceptanceCheckUtils; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2TransactionConfiguration; /** - * Generic functionality for HL7v2 acceptance checking - * interceptors, a kind of Visitor. + * Generic functionality for HL7v2 acceptance checking interceptors. * @author Dmytro Rud */ public class AcceptanceInterceptorUtils { @@ -41,9 +40,8 @@ public static void processRequest( Exchange exchange) throws Exception { // check input message - AcceptanceCheckUtils.checkRequestAcceptance( - exchange.getIn().getBody(MessageAdapter.class), - interceptor.getHl7v2TransactionConfiguration()); + Hl7v2TransactionConfiguration config = interceptor.getHl7v2TransactionConfiguration(); + config.checkRequestAcceptance(exchange.getIn().getBody(MessageAdapter.class)); // run the route interceptor.getWrappedProcessor().process(exchange); @@ -61,8 +59,7 @@ public static void processResponse( interceptor.getWrappedProcessor().process(exchange); // check output message - AcceptanceCheckUtils.checkResponseAcceptance( - Exchanges.resultMessage(exchange).getBody(MessageAdapter.class), - interceptor.getHl7v2TransactionConfiguration()); + Hl7v2TransactionConfiguration config = interceptor.getHl7v2TransactionConfiguration(); + config.checkResponseAcceptance(Exchanges.resultMessage(exchange).getBody(MessageAdapter.class)); } } diff --git a/platform-camel/ihe/hl7v2ws/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2ws/AbstractHl7v2WebService.java b/platform-camel/ihe/hl7v2ws/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2ws/AbstractHl7v2WebService.java index 2c56985318..d64ab87104 100644 --- a/platform-camel/ihe/hl7v2ws/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2ws/AbstractHl7v2WebService.java +++ b/platform-camel/ihe/hl7v2ws/src/main/java/org/openehealth/ipf/platform/camel/ihe/hl7v2ws/AbstractHl7v2WebService.java @@ -17,8 +17,6 @@ import static org.openehealth.ipf.commons.ihe.hl7v2ws.Utils.render; import static org.openehealth.ipf.platform.camel.core.util.Exchanges.resultMessage; -import static org.openehealth.ipf.platform.camel.ihe.hl7v2.AcceptanceCheckUtils.checkRequestAcceptance; -import static org.openehealth.ipf.platform.camel.ihe.hl7v2.AcceptanceCheckUtils.checkResponseAcceptance; import static org.apache.commons.lang3.StringUtils.trimToEmpty; import org.apache.camel.Exchange; @@ -71,7 +69,7 @@ protected String doProcess(String request) { MessageAdapter msg; try { msg = MessageAdapters.make(config.getParser(), trimToEmpty(request).replaceAll("\n", "\r\n")); - checkRequestAcceptance(msg, config); + config.checkRequestAcceptance(msg); } catch (Exception e) { LOG.error(formatErrMsg("Request not acceptable"), e); return render(nakFactory.createDefaultNak(e)); @@ -92,7 +90,7 @@ protected String doProcess(String request) { resultMessage(exchange), exchange.getProperty(Exchange.CHARSET_NAME, String.class), config.getParser()); - checkResponseAcceptance(msg, config); + config.checkResponseAcceptance(msg); return render(msg.getHapiMessage()); } catch (Exception e) { diff --git a/platform-camel/ihe/mllp/META-INF/services/org/apache/camel/component/mllp-dispatch b/platform-camel/ihe/mllp/META-INF/services/org/apache/camel/component/mllp-dispatch new file mode 100644 index 0000000000..62a2d3bc7d --- /dev/null +++ b/platform-camel/ihe/mllp/META-INF/services/org/apache/camel/component/mllp-dispatch @@ -0,0 +1,12 @@ +# Copyright 2014 the original author or authors. Licensed 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. + +# Camel registration for the mllp-dispatch component + +class=org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpDispatchComponent \ No newline at end of file diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpAuditStrategy.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpAuditStrategy.java index cb7903c64f..d0c8926d28 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpAuditStrategy.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpAuditStrategy.java @@ -99,9 +99,9 @@ abstract public void doAudit( * @param hostAddress * the address of the node that is responsible for the failure. */ - public void auditAuthenticationNodeFailure(String hostAddress) { + public static void auditAuthenticationNodeFailure(String hostAddress) { AuditorManager.getPIXManagerAuditor().auditNodeAuthenticationFailure( - true, null, getClass().getName(), null, hostAddress, null); + true, null, "IPF MLLP Component", null, hostAddress, null); } diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpComponent.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpComponent.java index 77d71219dd..7d521f30fb 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpComponent.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpComponent.java @@ -20,20 +20,12 @@ import org.apache.camel.component.hl7.HL7MLLPCodec; import org.apache.camel.component.mina2.Mina2Component; import org.apache.camel.component.mina2.Mina2Endpoint; -import org.apache.camel.spring.GenericBeansException; -import org.apache.camel.spring.SpringCamelContext; -import org.apache.commons.lang3.StringUtils; -import org.apache.mina.filter.codec.ProtocolCodecFactory; -import org.openehealth.ipf.commons.ihe.core.ClientAuthType; import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2ConfigurationHolder; import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2Interceptor; -import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2InterceptorFactory; import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerAdaptingInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.context.ApplicationContext; -import javax.net.ssl.SSLContext; import java.nio.charset.Charset; import java.util.Collections; import java.util.HashMap; @@ -42,34 +34,49 @@ /** - * Generic Camel component for IHE PIX/PDQ transactions. - * + * Generic Camel component for MLLP. * @author Dmytro Rud */ -public abstract class MllpComponent extends Mina2Component implements Hl7v2ConfigurationHolder { +public abstract class MllpComponent + extends Mina2Component implements Hl7v2ConfigurationHolder +{ private static final transient Logger LOG = LoggerFactory.getLogger(MllpComponent.class); public static final String ACK_TYPE_CODE_HEADER = ConsumerAdaptingInterceptor.ACK_TYPE_CODE_HEADER; private static final String DEFAULT_HL7_CODEC_FACTORY_BEAN_NAME = "#hl7codec"; - /** - * Default constructor. - */ protected MllpComponent() { super(); } - /** - * Camel context-based constructor. - * - * @param camelContext - */ protected MllpComponent(CamelContext camelContext) { super(camelContext); } + /** + * Creates a configuration object. + * @param parameters + * URL parameters. + * @return + * configuration object filled with values from the provided parameter map. + */ + protected abstract ConfigType createConfig(Map parameters) throws Exception; + + + /** + * Creates an endpoint object. + * @param wrappedEndpoint + * standard Camel MINA2 endpoint instance. + * @param config + * endpoint configuration. + * @return + * configured MLLP endpoint instance which wraps the MINA2 one. + */ + protected abstract MllpEndpoint createEndpoint(Mina2Endpoint wrappedEndpoint, ConfigType config); + + /** * Creates and configures the endpoint. */ @@ -79,49 +86,6 @@ protected Endpoint createEndpoint( String remaining, Map parameters) throws Exception { - // replace URL parts - int pos = uri.indexOf(":"); - uri = new StringBuilder(uri).replace(0, pos, "mina2:tcp").toString(); - remaining = "tcp://" + remaining; - - // extract & exclude parameters which cannot be handled by camel-mina - boolean audit = getAndRemoveParameter(parameters, "audit", boolean.class, true); - - boolean secure = getAndRemoveParameter(parameters, "secure", boolean.class, false); - ClientAuthType clientAuthType = getAndRemoveParameter(parameters, "clientAuth", - ClientAuthType.class, ClientAuthType.NONE); - String sslProtocolsString = getAndRemoveParameter(parameters, "sslProtocols", String.class, null); - String sslCiphersString = getAndRemoveParameter(parameters, "sslCiphers", String.class, null); - - boolean supportInteractiveContinuation = getAndRemoveParameter( - parameters, "supportInteractiveContinuation", boolean.class, false); - int interactiveContinuationDefaultThreshold = getAndRemoveParameter( - parameters, "interactiveContinuationDefaultThreshold", int.class, -1); // >= 1 data record - - boolean supportUnsolicitedFragmentation = getAndRemoveParameter( - parameters, "supportUnsolicitedFragmentation", boolean.class, false); - int unsolicitedFragmentationThreshold = getAndRemoveParameter( - parameters, "unsolicitedFragmentationThreshold", int.class, -1); // >= 3 segments - - boolean supportSegmentFragmentation = getAndRemoveParameter( - parameters, "supportSegmentFragmentation", boolean.class, false); - int segmentFragmentationThreshold = getAndRemoveParameter( - parameters, "segmentFragmentationThreshold", int.class, -1); // >= 5 characters - - InteractiveContinuationStorage interactiveContinuationStorage = - resolveAndRemoveReferenceParameter( - parameters, - "interactiveContinuationStorage", - InteractiveContinuationStorage.class); - - UnsolicitedFragmentationStorage unsolicitedFragmentationStorage = - resolveAndRemoveReferenceParameter( - parameters, - "unsolicitedFragmentationStorage", - UnsolicitedFragmentationStorage.class); - - boolean autoCancel = getAndRemoveParameter(parameters, "autoCancel", boolean.class, false); - // explicitly overwrite some standard camel-mina parameters if (parameters == Collections.EMPTY_MAP) { parameters = new HashMap(); @@ -129,88 +93,30 @@ protected Endpoint createEndpoint( parameters.put("sync", true); parameters.put("lazySessionCreation", true); parameters.put("transferExchange", false); - if( ! parameters.containsKey("codec")) { + if (! parameters.containsKey("codec")) { parameters.put("codec", DEFAULT_HL7_CODEC_FACTORY_BEAN_NAME); } + ConfigType config = createConfig(parameters); + // adopt character set configured for the HL7 codec - ProtocolCodecFactory codecFactory = getCamelContext().getRegistry().lookupByNameAndType( - extractBeanName((String) parameters.get("codec")), - ProtocolCodecFactory.class); Charset charset = null; try { - charset = ((HL7MLLPCodec) codecFactory).getCharset(); + charset = ((HL7MLLPCodec) config.getCodecFactory()).getCharset(); } catch(ClassCastException cce) { - LOG.error("Unsupported HL7 codec factory type " + codecFactory.getClass().getName()); + LOG.error("Unsupported HL7 codec factory type " + config.getCodecFactory().getClass().getName()); } - if(charset == null) { + if (charset == null) { charset = Charset.defaultCharset(); } parameters.put("encoding", charset.name()); // construct the endpoint - Endpoint endpoint = super.createEndpoint(uri, remaining, parameters); + Endpoint endpoint = super.createEndpoint(uri, "tcp://" + remaining, parameters); Mina2Endpoint minaEndpoint = (Mina2Endpoint) endpoint; - List customInterceptorsFactories = resolveAndRemoveReferenceListParameter( - parameters, "interceptorFactories", Hl7v2InterceptorFactory.class); - - SSLContext sslContext = secure ? resolveAndRemoveReferenceParameter( - parameters, - "sslContext", - SSLContext.class, - SSLContext.getDefault()) : null; - - String[] sslProtocols = sslProtocolsString != null ? sslProtocolsString.split(",") : null; - String[] sslCiphers = sslCiphersString != null ? sslCiphersString.split(",") : null; - // wrap and return - return new MllpEndpoint( - this, - minaEndpoint, - audit, - sslContext, - clientAuthType, - extractInterceptorBeanNames(parameters), - customInterceptorsFactories, - sslProtocols, - sslCiphers, - supportInteractiveContinuation, - supportUnsolicitedFragmentation, - supportSegmentFragmentation, - interactiveContinuationDefaultThreshold, - unsolicitedFragmentationThreshold, - segmentFragmentationThreshold, - interactiveContinuationStorage, - unsolicitedFragmentationStorage, - autoCancel); - } - - - private static String extractBeanName(String originalBeanName) { - return originalBeanName.startsWith("#") ? originalBeanName.substring(1) : originalBeanName; - } - - - private String[] extractInterceptorBeanNames(Map parameters) { - SpringCamelContext camelContext = (SpringCamelContext) getCamelContext(); - ApplicationContext applicationContext = camelContext.getApplicationContext(); - - String paramValue = getAndRemoveParameter(parameters, "interceptors", String.class); - if (StringUtils.isEmpty(paramValue)) { - return new String[0]; - } - - String[] beanNames = paramValue.split(","); - for (int i = 0; i < beanNames.length; ++i) { - beanNames[i] = extractBeanName(beanNames[i]); - if (! applicationContext.isPrototype(beanNames[i])) { - throw new GenericBeansException("Custom HL7v2 interceptor bean '" + - beanNames[i] + "' shall have scope=\"prototype\""); - } - } - - return beanNames; + return createEndpoint(minaEndpoint, config); } @@ -257,17 +163,4 @@ public List getAdditionalProducerInterceptors() { return Collections.emptyList(); } - - // ----- abstract methods ----- - - /** - * Returns server-side ATNA audit strategy. - */ - public abstract MllpAuditStrategy getServerAuditStrategy(); - - /** - * Returns client-side ATNA audit strategy. - */ - public abstract MllpAuditStrategy getClientAuditStrategy(); - } diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchComponent.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchComponent.java new file mode 100644 index 0000000000..8116053ed8 --- /dev/null +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchComponent.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed 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.openehealth.ipf.platform.camel.ihe.mllp.core; + +import org.apache.camel.component.mina2.Mina2Endpoint; +import org.openehealth.ipf.modules.hl7.parser.PipeParser; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2TransactionConfiguration; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.NakFactory; + +import java.util.Map; + +/** + * MLLP dispatching Camel component. + * @author Dmytro Rud + */ +public class MllpDispatchComponent extends MllpComponent { + public static final Hl7v2TransactionConfiguration CONFIGURATION = + new Hl7v2TransactionConfiguration( + "2.5", + "MLLP Dispatcher", + "IPF", + 207, + 207, + new String[] {"\0"}, // acceptance checking will be delegated (4x) + new String[] {"\0"}, + new String[] {"\0"}, + new String[] {"\0"}, + new boolean[] {false}, // audit trail (if any) will be delegated + new boolean[] {false}, // interactive continuation (if any) will be delegated + new PipeParser()); + + private static final NakFactory NAK_FACTORY = new NakFactory(CONFIGURATION); + + @Override + protected MllpDispatchEndpointConfiguration createConfig(Map parameters) throws Exception { + return new MllpDispatchEndpointConfiguration(this, parameters); + } + + @Override + protected MllpEndpoint createEndpoint(Mina2Endpoint wrappedEndpoint, MllpDispatchEndpointConfiguration config) { + return new MllpDispatchEndpoint(this, wrappedEndpoint, config); + } + + @Override + public Hl7v2TransactionConfiguration getHl7v2TransactionConfiguration() { + return CONFIGURATION; + } + + @Override + public NakFactory getNakFactory() { + return NAK_FACTORY; + } +} diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchEndpoint.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchEndpoint.java new file mode 100644 index 0000000000..b00c32f240 --- /dev/null +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchEndpoint.java @@ -0,0 +1,62 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed 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.openehealth.ipf.platform.camel.ihe.mllp.core; + +import org.apache.camel.component.mina2.Mina2Endpoint; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2Interceptor; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerMarshalInterceptor; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.consumer.ConsumerDispatchingInterceptor; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.consumer.ConsumerRequestDefragmenterInterceptor; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.consumer.ConsumerStringProcessingInterceptor; + +import java.util.ArrayList; +import java.util.List; + +/** + * MLLP dispatching Camel endpoint. + * @author Dmytro Rud + */ +public class MllpDispatchEndpoint extends MllpEndpoint { + + public MllpDispatchEndpoint( + MllpDispatchComponent mllpComponent, + Mina2Endpoint wrappedEndpoint, + MllpDispatchEndpointConfiguration config) + { + super(mllpComponent, wrappedEndpoint, config); + } + + + @Override + protected List createInitialConsumerInterceptorChain() { + List initialChain = new ArrayList(); + initialChain.add(new ConsumerStringProcessingInterceptor()); + if (isSupportUnsolicitedFragmentation()) { + initialChain.add(new ConsumerRequestDefragmenterInterceptor()); + } + initialChain.add(new ConsumerMarshalInterceptor()); + initialChain.add(new ConsumerDispatchingInterceptor(getCamelContext(), getConfig().getRoutes())); + + return initialChain; + } + + + @Override + protected List createInitialProducerInterceptorChain() { + throw new IllegalStateException("No producer support for MLLP dispatch endpoints."); + } + +} diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchEndpointConfiguration.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchEndpointConfiguration.java new file mode 100644 index 0000000000..966039fb54 --- /dev/null +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpDispatchEndpointConfiguration.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed 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.openehealth.ipf.platform.camel.ihe.mllp.core; + +import lombok.Getter; +import org.apache.camel.CamelException; + +import java.util.Map; + +import static org.apache.commons.lang3.StringUtils.stripToNull; + +/** + * Configuration of a dispatching MLLP endpoint. + * @author Dmytro Rud + */ +public class MllpDispatchEndpointConfiguration extends MllpEndpointConfiguration { + private static final long serialVersionUID = -2217584969904791989L; + + @Getter private final String[] routes; + + protected MllpDispatchEndpointConfiguration(MllpComponent component, Map parameters) throws Exception { + super(component, parameters); + + String routesString = stripToNull(component.getAndRemoveParameter(parameters, "routes", String.class)); + if (routesString == null) { + throw new CamelException("Endpoint URL parameter 'routes' must be not empty"); + } + routes = routesString.split("\\s*,\\s*"); + } + +} diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpEndpoint.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpEndpoint.java index be35653cb9..a1647aadfb 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpEndpoint.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpEndpoint.java @@ -15,6 +15,8 @@ */ package org.openehealth.ipf.platform.camel.ihe.mllp.core; +import lombok.AccessLevel; +import lombok.Getter; import org.apache.camel.*; import org.apache.camel.api.management.ManagedAttribute; import org.apache.camel.api.management.ManagedResource; @@ -35,19 +37,6 @@ import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2Interceptor; import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2InterceptorFactory; import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2InterceptorUtils; -import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerAdaptingInterceptor; -import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerRequestAcceptanceInterceptor; -import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerMarshalInterceptor; -import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerResponseAcceptanceInterceptor; -import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.producer.ProducerAdaptingInterceptor; -import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.producer.ProducerRequestAcceptanceInterceptor; -import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.producer.ProducerMarshalInterceptor; -import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.producer.ProducerResponseAcceptanceInterceptor; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.consumer.*; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.producer.ProducerAuditInterceptor; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.producer.ProducerMarshalAndInteractiveResponseReceiverInterceptor; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.producer.ProducerRequestFragmenterInterceptor; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.producer.ProducerStringProcessingInterceptor; import javax.net.ssl.SSLContext; import java.util.ArrayList; @@ -60,28 +49,17 @@ * @author Dmytro Rud */ @ManagedResource(description = "Managed IPF MLLP ITI Endpoint") -public class MllpEndpoint extends DefaultEndpoint implements Hl7v2ConfigurationHolder { - - private final MllpComponent mllpComponent; - private final Mina2Endpoint wrappedEndpoint; - private final boolean audit; - - private final SSLContext sslContext; - private final String[] customInterceptorBeans; - private final List customInterceptorFactories; - private final ClientAuthType clientAuthType; - private final String[] sslProtocols; - private final String[] sslCiphers; - - private final boolean supportInteractiveContinuation; - private final boolean supportUnsolicitedFragmentation; - private final boolean supportSegmentFragmentation; - private final int interactiveContinuationDefaultThreshold; - private final int unsolicitedFragmentationThreshold; - private final int segmentFragmentationThreshold; - private final InteractiveContinuationStorage interactiveContinuationStorage; - private final UnsolicitedFragmentationStorage unsolicitedFragmentationStorage; - private final boolean autoCancel; +public abstract class MllpEndpoint + < + ConfigType extends MllpEndpointConfiguration, + ComponentType extends MllpComponent + > + extends DefaultEndpoint implements Hl7v2ConfigurationHolder +{ + + @Getter(AccessLevel.PROTECTED) private final ConfigType config; + @Getter(AccessLevel.PROTECTED) private final ComponentType mllpComponent; + @Getter(AccessLevel.PROTECTED) private final Mina2Endpoint wrappedEndpoint; /** @@ -90,120 +68,39 @@ public class MllpEndpoint extends DefaultEndpoint im * MLLP Component instance which is creating this endpoint. * @param wrappedEndpoint * The original camel-mina endpoint instance. - * @param audit - * Whether ATNA auditing should be performed. - * @param sslContext - * the SSL context to use; {@code null} if secure communication is not used. - * @param clientAuthType - * type of desired client authentication (NONE/WANT/MUST). - * @param customInterceptorBeans - * names of interceptor beans defined in the endpoint URI. - * @param customInterceptorFactories - * names of interceptor factories defined in the endpoint URI. - * @param sslProtocols - * the protocols defined in the endpoint URI or {@code null} if none were specified. - * @param sslCiphers - * the ciphers defined in the endpoint URI or {@code null} if none were specified. - * @param supportInteractiveContinuation - * {@code true} when this endpoint should support interactive message continuation. - * @param supportUnsolicitedFragmentation - * {@code true} when this endpoint should support segment fragmentation. - * @param supportSegmentFragmentation - * {@code true} when this endpoint should support segment fragmentation. - * @param interactiveContinuationDefaultThreshold - * default consumer-side threshold for interactive response continuation. - * @param unsolicitedFragmentationThreshold - * producer-side threshold for unsolicited message fragmentation. - * @param segmentFragmentationThreshold - * threshold for segment fragmentation. - * @param interactiveContinuationStorage - * consumer-side storage for interactive message continuation. - * @param unsolicitedFragmentationStorage - * consumer-side storage for unsolicited message fragmentation. - * @param autoCancel - * whether the producer should automatically send a cancel message - * after it has collected all interactive continuation pieces. + * @param config + * Configuration parameters. */ public MllpEndpoint( - MllpComponent mllpComponent, + ComponentType mllpComponent, Mina2Endpoint wrappedEndpoint, - boolean audit, - SSLContext sslContext, - ClientAuthType clientAuthType, - String[] customInterceptorBeans, - List customInterceptorFactories, - String[] sslProtocols, - String[] sslCiphers, - boolean supportInteractiveContinuation, - boolean supportUnsolicitedFragmentation, - boolean supportSegmentFragmentation, - int interactiveContinuationDefaultThreshold, - int unsolicitedFragmentationThreshold, - int segmentFragmentationThreshold, - InteractiveContinuationStorage interactiveContinuationStorage, - UnsolicitedFragmentationStorage unsolicitedFragmentationStorage, - boolean autoCancel) + ConfigType config) { - Validate.notNull(mllpComponent); - Validate.notNull(wrappedEndpoint); - Validate.noNullElements(customInterceptorBeans); - Validate.noNullElements(customInterceptorFactories); - Validate.notNull(clientAuthType); - - this.mllpComponent = mllpComponent; - this.wrappedEndpoint = wrappedEndpoint; - this.audit = audit; - this.sslContext = sslContext; - this.clientAuthType = clientAuthType; - this.customInterceptorBeans = customInterceptorBeans; - this.customInterceptorFactories = customInterceptorFactories; - this.sslProtocols = sslProtocols; - this.sslCiphers = sslCiphers; - - this.supportInteractiveContinuation = supportInteractiveContinuation; - this.supportUnsolicitedFragmentation = supportUnsolicitedFragmentation; - this.supportSegmentFragmentation = supportSegmentFragmentation; - this.interactiveContinuationDefaultThreshold = interactiveContinuationDefaultThreshold; - this.unsolicitedFragmentationThreshold = unsolicitedFragmentationThreshold; - this.segmentFragmentationThreshold = segmentFragmentationThreshold; - this.interactiveContinuationStorage = interactiveContinuationStorage; - this.unsolicitedFragmentationStorage = unsolicitedFragmentationStorage; - this.autoCancel = autoCancel; - } - - - private synchronized List getCustomInterceptors() { + this.mllpComponent = Validate.notNull(mllpComponent); + this.wrappedEndpoint = Validate.notNull(wrappedEndpoint); + this.config = Validate.notNull(config); + } + + + protected synchronized List getCustomInterceptors() { List result = new ArrayList(); - for (String beanName : customInterceptorBeans) { + for (String beanName : config.getCustomInterceptorBeans()) { result.add(getCamelContext().getRegistry().lookupByNameAndType(beanName, Hl7v2Interceptor.class)); } - for (Hl7v2InterceptorFactory customInterceptorFactory: customInterceptorFactories) { + for (Hl7v2InterceptorFactory customInterceptorFactory : config.getCustomInterceptorFactories()) { result.add(customInterceptorFactory.getNewInstance()); } return result; } + protected abstract List createInitialConsumerInterceptorChain(); + protected abstract List createInitialProducerInterceptorChain(); + + private List getConsumerInterceptorChain() { // set up initial interceptor chain - List initialChain = new ArrayList(); - initialChain.add(new ConsumerStringProcessingInterceptor()); - if (isSupportUnsolicitedFragmentation()) { - initialChain.add(new ConsumerRequestDefragmenterInterceptor()); - } - initialChain.add(new ConsumerMarshalInterceptor()); - initialChain.add(new ConsumerRequestAcceptanceInterceptor()); - if (isSupportInteractiveContinuation()) { - initialChain.add(new ConsumerInteractiveResponseSenderInterceptor()); - } - if (isAudit()) { - initialChain.add(new ConsumerAuditInterceptor()); - } - initialChain.add(new ConsumerResponseAcceptanceInterceptor()); - initialChain.add(new ConsumerAdaptingInterceptor(getCharsetName())); - if (isAudit()) { - initialChain.add(new ConsumerAuthenticationFailureInterceptor()); - } + List initialChain = createInitialConsumerInterceptorChain(); // add interceptors provided by the user List additionalInterceptors = new ArrayList(); @@ -216,20 +113,7 @@ private List getConsumerInterceptorChain() { private List getProducerInterceptorChain() { // set up initial interceptor chain - List initialChain = new ArrayList(); - initialChain.add(new ProducerStringProcessingInterceptor()); - if (isSupportUnsolicitedFragmentation()) { - initialChain.add(new ProducerRequestFragmenterInterceptor()); - } - initialChain.add(isSupportInteractiveContinuation() - ? new ProducerMarshalAndInteractiveResponseReceiverInterceptor() - : new ProducerMarshalInterceptor()); - initialChain.add(new ProducerResponseAcceptanceInterceptor()); - if (isAudit()) { - initialChain.add(new ProducerAuditInterceptor()); - } - initialChain.add(new ProducerRequestAcceptanceInterceptor()); - initialChain.add(new ProducerAdaptingInterceptor()); + List initialChain = createInitialProducerInterceptorChain(); // add interceptors provided by the user List additionalInterceptors = new ArrayList(); @@ -258,16 +142,16 @@ public Consumer createConsumer(Processor originalProcessor) throws Exception { processor = interceptor; } - Mina2Consumer consumer = (Mina2Consumer)wrappedEndpoint.createConsumer(processor); - if (sslContext != null) { + Mina2Consumer consumer = (Mina2Consumer) wrappedEndpoint.createConsumer(processor); + if (config.getSslContext() != null) { DefaultIoFilterChainBuilder filterChain = consumer.getAcceptor().getFilterChain(); if (! filterChain.contains("ssl")) { - HandshakeCallbackSSLFilter filter = new HandshakeCallbackSSLFilter(sslContext); - filter.setNeedClientAuth(clientAuthType == ClientAuthType.MUST); - filter.setWantClientAuth(clientAuthType == ClientAuthType.WANT); + HandshakeCallbackSSLFilter filter = new HandshakeCallbackSSLFilter(config.getSslContext()); + filter.setNeedClientAuth(config.getClientAuthType() == ClientAuthType.MUST); + filter.setWantClientAuth(config.getClientAuthType() == ClientAuthType.WANT); filter.setHandshakeExceptionCallback(new HandshakeFailureCallback()); - filter.setEnabledProtocols(sslProtocols); - filter.setEnabledCipherSuites(sslCiphers); + filter.setEnabledProtocols(config.getSslProtocols()); + filter.setEnabledCipherSuites(config.getSslCiphers()); filterChain.addFirst("ssl", filter); } } @@ -284,14 +168,14 @@ public Consumer createConsumer(Processor originalProcessor) throws Exception { public Producer createProducer() throws Exception { Mina2Producer producer = (Mina2Producer)wrappedEndpoint.createProducer(); - if (sslContext != null) { + if (config.getSslContext() != null) { DefaultIoFilterChainBuilder filterChain = producer.getFilterChain(); if (!filterChain.contains("ssl")) { - HandshakeCallbackSSLFilter filter = new HandshakeCallbackSSLFilter(sslContext); + HandshakeCallbackSSLFilter filter = new HandshakeCallbackSSLFilter(config.getSslContext()); filter.setUseClientMode(true); filter.setHandshakeExceptionCallback(new HandshakeFailureCallback()); - filter.setEnabledProtocols(sslProtocols); - filter.setEnabledCipherSuites(sslCiphers); + filter.setEnabledProtocols(config.getSslProtocols()); + filter.setEnabledCipherSuites(config.getSslCiphers()); filterChain.addFirst("ssl", filter); } } @@ -305,35 +189,14 @@ public Producer createProducer() throws Exception { private class HandshakeFailureCallback implements HandshakeCallbackSSLFilter.Callback { @Override public void run(IoSession session) { - if (isAudit()) { + if (config.isAudit()) { String hostAddress = session.getRemoteAddress().toString(); - getServerAuditStrategy().auditAuthenticationNodeFailure(hostAddress); + MllpAuditStrategy.auditAuthenticationNodeFailure(hostAddress); } } } // ----- getters ----- - /** - * Returns true when ATNA auditing should be performed. - */ - @ManagedAttribute(description = "Audit Enabled") - public boolean isAudit() { - return audit; - } - - /** - * Returns client-side audit strategy instance. - */ - public MllpAuditStrategy getClientAuditStrategy() { - return mllpComponent.getClientAuditStrategy(); - } - - /** - * Returns server-side audit strategy instance. - */ - public MllpAuditStrategy getServerAuditStrategy() { - return mllpComponent.getServerAuditStrategy(); - } /** * Returns transaction configuration. @@ -351,20 +214,12 @@ public NakFactory getNakFactory() { return mllpComponent.getNakFactory(); } - /** - * Returns true if this endpoint supports interactive continuation. - */ - @ManagedAttribute(description = "Support Interactive Continuation Enabled") - public boolean isSupportInteractiveContinuation() { - return supportInteractiveContinuation; - } - /** * Returns true if this endpoint supports unsolicited message fragmentation. */ @ManagedAttribute(description = "Support Unsolicited Fragmentation Enabled") public boolean isSupportUnsolicitedFragmentation() { - return supportUnsolicitedFragmentation; + return config.isSupportUnsolicitedFragmentation(); } /** @@ -372,21 +227,7 @@ public boolean isSupportUnsolicitedFragmentation() { */ @ManagedAttribute(description = "Support Segment Fragmentation Enabled") public boolean isSupportSegmentFragmentation() { - return supportSegmentFragmentation; - } - - /** - * Returns default threshold for interactive continuation - * (relevant on consumer side only). - *

- * This value will be used when interactive continuation is generally supported - * by this endpoint and is particularly applicable for the current response message, - * and the corresponding request message does not set the records count threshold - * explicitly (RCP-2-1==integer, RCP-2-2=='RD'). - */ - @ManagedAttribute(description = "Interactive Continuation Default Threshold") - public int getInteractiveContinuationDefaultThreshold() { - return interactiveContinuationDefaultThreshold; + return config.isSupportSegmentFragmentation(); } /** @@ -395,7 +236,7 @@ public int getInteractiveContinuationDefaultThreshold() { */ @ManagedAttribute(description = "Unsolicited Fragmentation Threshold") public int getUnsolicitedFragmentationThreshold() { - return unsolicitedFragmentationThreshold; + return config.getUnsolicitedFragmentationThreshold(); } /** @@ -403,37 +244,21 @@ public int getUnsolicitedFragmentationThreshold() { */ @ManagedAttribute(description = "Segment Fragmentation Threshold") public int getSegmentFragmentationThreshold() { - return segmentFragmentationThreshold; - } - - /** - * Returns the interactive continuation storage bean. - */ - public InteractiveContinuationStorage getInteractiveContinuationStorage() { - return interactiveContinuationStorage; + return config.getSegmentFragmentationThreshold(); } /** * Returns the unsolicited fragmentation storage bean. */ public UnsolicitedFragmentationStorage getUnsolicitedFragmentationStorage() { - return unsolicitedFragmentationStorage; - } - - /** - * Returns true, when the producer should automatically send a cancel - * message after it has collected all interactive continuation pieces. - */ - @ManagedAttribute(description = "Auto Cancel Enabled") - public boolean isAutoCancel() { - return autoCancel; + return config.getUnsolicitedFragmentationStorage(); } /** * @return the sslContext */ public SSLContext getSslContext() { - return sslContext; + return config.getSslContext(); } /** @@ -441,7 +266,7 @@ public SSLContext getSslContext() { */ @ManagedAttribute(description = "Defined SSL Protocols") public String[] getSslProtocols() { - return sslProtocols; + return config.getSslProtocols(); } /** @@ -449,7 +274,7 @@ public String[] getSslProtocols() { */ @ManagedAttribute(description = "Defined SSL Ciphers") public String[] getSslCiphers() { - return sslCiphers; + return config.getSslCiphers(); } @ManagedAttribute(description = "Component Type Name") @@ -483,12 +308,6 @@ public String[] getIoFilters() { return toStringArray(filters); } - @ManagedAttribute(description = "Interactive Continuation Storage Cache Type") - public String getInteractiveContinuationStorageType() { - return isSupportInteractiveContinuation() ? - getInteractiveContinuationStorage().getClass().getName() : ""; - } - @ManagedAttribute(description = "Unsolicited Fragmentation Storage Cache Type") public String getUnsolicitedFragmentationStorageType() { return isSupportUnsolicitedFragmentation() ? @@ -504,7 +323,7 @@ public boolean isSslSecure() { * @return the client authentication type. */ public ClientAuthType getClientAuthType() { - return clientAuthType; + return config.getClientAuthType(); } @ManagedAttribute(description = "Client Authentication Type") @@ -517,14 +336,14 @@ public String getClientAuthTypeClass() { */ @ManagedAttribute(description = "Custom Interceptor Beans") public String[] getCustomInterceptorBeans() { - return this.customInterceptorBeans; + return config.getCustomInterceptorBeans(); } /** * @return the customInterceptorFactories */ public List getCustomInterceptorFactories() { - return customInterceptorFactories; + return config.getCustomInterceptorFactories(); } /** @@ -543,13 +362,6 @@ private String[] toStringArray(List list) { return result; } - /** - * @return - * the wrapped MINA endpoint. - */ - public Mina2Endpoint getWrappedEndpoint() { - return wrappedEndpoint; - } /* ----- dumb delegation, nothing interesting below ----- */ @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -581,11 +393,10 @@ public PollingConsumer createPollingConsumer() throws Exception { @Override public boolean equals(Object object) { if (object instanceof MllpEndpoint) { - MllpEndpoint that = (MllpEndpoint) object; - return this.getWrappedEndpoint().equals(that.getWrappedEndpoint()); + MllpEndpoint that = (MllpEndpoint) object; + return wrappedEndpoint.equals(that.getWrappedEndpoint()); } - else - return false; + return false; } @Override diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpEndpointConfiguration.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpEndpointConfiguration.java new file mode 100644 index 0000000000..4b7a552ab6 --- /dev/null +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpEndpointConfiguration.java @@ -0,0 +1,127 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed 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.openehealth.ipf.platform.camel.ihe.mllp.core; + +import lombok.Getter; +import org.apache.camel.spring.GenericBeansException; +import org.apache.camel.spring.SpringCamelContext; +import org.apache.commons.lang3.StringUtils; +import org.apache.mina.filter.codec.ProtocolCodecFactory; +import org.openehealth.ipf.commons.ihe.core.ClientAuthType; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2InterceptorFactory; +import org.springframework.context.ApplicationContext; + +import javax.net.ssl.SSLContext; +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * Configuration of an MLLP endpoint. + * @author Dmytro Rud + */ +public class MllpEndpointConfiguration implements Serializable { + private static final long serialVersionUID = -3604219045768985192L; + + @Getter private final ProtocolCodecFactory codecFactory; + + @Getter private final boolean audit; + @Getter private final SSLContext sslContext; + @Getter private final String[] customInterceptorBeans; + @Getter private final List customInterceptorFactories; + @Getter private final ClientAuthType clientAuthType; + @Getter private final String[] sslProtocols; + @Getter private final String[] sslCiphers; + + @Getter private final boolean supportUnsolicitedFragmentation; + @Getter private final boolean supportSegmentFragmentation; + @Getter private final int unsolicitedFragmentationThreshold; + @Getter private final int segmentFragmentationThreshold; + @Getter private final UnsolicitedFragmentationStorage unsolicitedFragmentationStorage; + + + protected MllpEndpointConfiguration(MllpComponent component, Map parameters) throws Exception { + codecFactory = component.getCamelContext().getRegistry().lookupByNameAndType( + extractBeanName((String) parameters.get("codec")), + ProtocolCodecFactory.class); + + audit = component.getAndRemoveParameter(parameters, "audit", boolean.class, true); + + clientAuthType = component.getAndRemoveParameter(parameters, "clientAuth", + ClientAuthType.class, ClientAuthType.NONE); + + String sslProtocolsString = component.getAndRemoveParameter(parameters, "sslProtocols", String.class, null); + String sslCiphersString = component.getAndRemoveParameter(parameters, "sslCiphers", String.class, null); + sslProtocols = sslProtocolsString != null ? sslProtocolsString.split(",") : null; + sslCiphers = sslCiphersString != null ? sslCiphersString.split(",") : null; + + boolean secure = component.getAndRemoveParameter(parameters, "secure", boolean.class, false); + sslContext = secure ? component.resolveAndRemoveReferenceParameter( + parameters, + "sslContext", + SSLContext.class, + SSLContext.getDefault()) : null; + + supportUnsolicitedFragmentation = component.getAndRemoveParameter( + parameters, "supportUnsolicitedFragmentation", boolean.class, false); + unsolicitedFragmentationThreshold = component.getAndRemoveParameter( + parameters, "unsolicitedFragmentationThreshold", int.class, -1); // >= 3 segments + + supportSegmentFragmentation = component.getAndRemoveParameter( + parameters, "supportSegmentFragmentation", boolean.class, false); + segmentFragmentationThreshold = component.getAndRemoveParameter( + parameters, "segmentFragmentationThreshold", int.class, -1); // >= 5 characters + + unsolicitedFragmentationStorage = component.resolveAndRemoveReferenceParameter( + parameters, + "unsolicitedFragmentationStorage", + UnsolicitedFragmentationStorage.class); + + customInterceptorFactories = component.resolveAndRemoveReferenceListParameter( + parameters, "interceptorFactories", Hl7v2InterceptorFactory.class); + + customInterceptorBeans = extractInterceptorBeanNames(component, parameters); + } + + + private static String extractBeanName(String originalBeanName) { + return originalBeanName.startsWith("#") ? originalBeanName.substring(1) : originalBeanName; + } + + + private String[] extractInterceptorBeanNames(MllpComponent component, Map parameters) { + SpringCamelContext camelContext = (SpringCamelContext) component.getCamelContext(); + ApplicationContext applicationContext = camelContext.getApplicationContext(); + + String paramValue = component.getAndRemoveParameter(parameters, "interceptors", String.class); + if (StringUtils.isEmpty(paramValue)) { + return new String[0]; + } + + String[] beanNames = paramValue.split(","); + for (int i = 0; i < beanNames.length; ++i) { + beanNames[i] = extractBeanName(beanNames[i]); + if (! applicationContext.isPrototype(beanNames[i])) { + throw new GenericBeansException("Custom HL7v2 interceptor bean '" + + beanNames[i] + "' shall have scope=\"prototype\""); + } + } + + return beanNames; + } + +} diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionComponent.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionComponent.java new file mode 100644 index 0000000000..a54867d84b --- /dev/null +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionComponent.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed 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.openehealth.ipf.platform.camel.ihe.mllp.core; + +import org.apache.camel.CamelContext; +import org.apache.camel.component.mina2.Mina2Endpoint; + +import java.util.Map; + +/** + * Camel component for MLLP-based eHealth transactions (like IHE PIX, PDQ, XAD-PID, etc.). + * @author Dmytro Rud + */ +public abstract class MllpTransactionComponent + extends MllpComponent +{ + + protected MllpTransactionComponent() { + super(); + } + + protected MllpTransactionComponent(CamelContext camelContext) { + super(camelContext); + } + + @Override + protected MllpTransactionEndpointConfiguration createConfig(Map parameters) throws Exception { + return new MllpTransactionEndpointConfiguration(this, parameters); + } + + @Override + protected MllpEndpoint createEndpoint(Mina2Endpoint wrappedEndpoint, MllpTransactionEndpointConfiguration config) { + return new MllpTransactionEndpoint(this, wrappedEndpoint, config); + } + + /** + * Returns server-side ATNA audit strategy. + */ + public abstract MllpAuditStrategy getServerAuditStrategy(); + + /** + * Returns client-side ATNA audit strategy. + */ + public abstract MllpAuditStrategy getClientAuditStrategy(); +} diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionEndpoint.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionEndpoint.java new file mode 100644 index 0000000000..525ae2a54e --- /dev/null +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionEndpoint.java @@ -0,0 +1,181 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed 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.openehealth.ipf.platform.camel.ihe.mllp.core; + +import org.apache.camel.api.management.ManagedAttribute; +import org.apache.camel.component.mina2.Mina2Endpoint; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2Interceptor; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerAdaptingInterceptor; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerMarshalInterceptor; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerRequestAcceptanceInterceptor; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerResponseAcceptanceInterceptor; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.producer.ProducerAdaptingInterceptor; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.producer.ProducerMarshalInterceptor; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.producer.ProducerRequestAcceptanceInterceptor; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.producer.ProducerResponseAcceptanceInterceptor; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.consumer.*; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.producer.ProducerAuditInterceptor; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.producer.ProducerMarshalAndInteractiveResponseReceiverInterceptor; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.producer.ProducerRequestFragmenterInterceptor; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.producer.ProducerStringProcessingInterceptor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Camel endpoint for MLLP-based eHealth transactions (like IHE PIX, PDQ, XAD-PID, etc.). + * @author Dmytro Rud + */ +public class MllpTransactionEndpoint + extends MllpEndpoint> +{ + + /** + * Constructor. + * @param mllpComponent + * MLLP Component instance which is creating this endpoint. + * @param wrappedEndpoint + * The original camel-mina endpoint instance. + * @param config + * Configuration parameters. + */ + public MllpTransactionEndpoint( + MllpTransactionComponent mllpComponent, + Mina2Endpoint wrappedEndpoint, + MllpTransactionEndpointConfiguration config) + { + super(mllpComponent, wrappedEndpoint, config); + } + + + @Override + protected List createInitialConsumerInterceptorChain() { + List initialChain = new ArrayList(); + initialChain.add(new ConsumerStringProcessingInterceptor()); + if (isSupportUnsolicitedFragmentation()) { + initialChain.add(new ConsumerRequestDefragmenterInterceptor()); + } + initialChain.add(new ConsumerMarshalInterceptor()); + initialChain.add(new ConsumerRequestAcceptanceInterceptor()); + if (isSupportInteractiveContinuation()) { + initialChain.add(new ConsumerInteractiveResponseSenderInterceptor()); + } + if (isAudit()) { + initialChain.add(new ConsumerAuditInterceptor()); + } + initialChain.add(new ConsumerResponseAcceptanceInterceptor()); + initialChain.add(new ConsumerAdaptingInterceptor(getCharsetName())); + if (isAudit()) { + initialChain.add(new ConsumerAuthenticationFailureInterceptor()); + } + return initialChain; + } + + + @Override + protected List createInitialProducerInterceptorChain() { + List initialChain = new ArrayList(); + initialChain.add(new ProducerStringProcessingInterceptor()); + if (isSupportUnsolicitedFragmentation()) { + initialChain.add(new ProducerRequestFragmenterInterceptor()); + } + initialChain.add(isSupportInteractiveContinuation() + ? new ProducerMarshalAndInteractiveResponseReceiverInterceptor() + : new ProducerMarshalInterceptor()); + initialChain.add(new ProducerResponseAcceptanceInterceptor()); + if (isAudit()) { + initialChain.add(new ProducerAuditInterceptor()); + } + initialChain.add(new ProducerRequestAcceptanceInterceptor()); + initialChain.add(new ProducerAdaptingInterceptor()); + return initialChain; + } + + + /** + * Returns true when ATNA auditing should be performed. + */ + @ManagedAttribute(description = "Audit Enabled") + public boolean isAudit() { + return getConfig().isAudit(); + } + + + /** + * Returns client-side audit strategy instance. + */ + public MllpAuditStrategy getClientAuditStrategy() { + return getMllpComponent().getClientAuditStrategy(); + } + + + /** + * Returns server-side audit strategy instance. + */ + public MllpAuditStrategy getServerAuditStrategy() { + return getMllpComponent().getServerAuditStrategy(); + } + + + /** + * Returns true if this endpoint supports interactive continuation. + */ + @ManagedAttribute(description = "Support Interactive Continuation Enabled") + public boolean isSupportInteractiveContinuation() { + return getConfig().isSupportInteractiveContinuation(); + } + + + /** + * Returns default threshold for interactive continuation + * (relevant on consumer side only). + *

+ * This value will be used when interactive continuation is generally supported + * by this endpoint and is particularly applicable for the current response message, + * and the corresponding request message does not set the records count threshold + * explicitly (RCP-2-1==integer, RCP-2-2=='RD'). + */ + @ManagedAttribute(description = "Interactive Continuation Default Threshold") + public int getInteractiveContinuationDefaultThreshold() { + return getConfig().getInteractiveContinuationDefaultThreshold(); + } + + + /** + * Returns the interactive continuation storage bean. + */ + public InteractiveContinuationStorage getInteractiveContinuationStorage() { + return getConfig().getInteractiveContinuationStorage(); + } + + + /** + * Returns true, when the producer should automatically send a cancel + * message after it has collected all interactive continuation pieces. + */ + @ManagedAttribute(description = "Auto Cancel Enabled") + public boolean isAutoCancel() { + return getConfig().isAutoCancel(); + } + + + @ManagedAttribute(description = "Interactive Continuation Storage Cache Type") + public String getInteractiveContinuationStorageType() { + return isSupportInteractiveContinuation() ? + getInteractiveContinuationStorage().getClass().getName() : ""; + } + +} diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionEndpointConfiguration.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionEndpointConfiguration.java new file mode 100644 index 0000000000..a613642f63 --- /dev/null +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTransactionEndpointConfiguration.java @@ -0,0 +1,52 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed 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.openehealth.ipf.platform.camel.ihe.mllp.core; + +import lombok.Getter; + +import java.util.Map; + +/** + * Camel endpoint configuration for MLLP-based eHealth transactions (like IHE PIX, PDQ, XAD-PID, etc.). + * @author Dmytro Rud + */ +public class MllpTransactionEndpointConfiguration extends MllpEndpointConfiguration { + private static final long serialVersionUID = -6154765290339153487L; + + @Getter private final boolean supportInteractiveContinuation; + @Getter private final int interactiveContinuationDefaultThreshold; + @Getter private final InteractiveContinuationStorage interactiveContinuationStorage; + @Getter private final boolean autoCancel; + + + protected MllpTransactionEndpointConfiguration(MllpComponent component, Map parameters) throws Exception { + super(component, parameters); + + supportInteractiveContinuation = component.getAndRemoveParameter( + parameters, "supportInteractiveContinuation", boolean.class, false); + interactiveContinuationDefaultThreshold = component.getAndRemoveParameter( + parameters, "interactiveContinuationDefaultThreshold", int.class, -1); // >= 1 data record + + interactiveContinuationStorage = component.resolveAndRemoveReferenceParameter( + parameters, + "interactiveContinuationStorage", + InteractiveContinuationStorage.class); + + autoCancel = component.getAndRemoveParameter(parameters, "autoCancel", boolean.class, false); + } + +} diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/AbstractMllpInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/AbstractMllpInterceptor.java index 270387f235..bd2d44a11b 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/AbstractMllpInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/AbstractMllpInterceptor.java @@ -16,7 +16,6 @@ package org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept; import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.AbstractHl7v2Interceptor; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpEndpoint; @@ -24,13 +23,11 @@ * Abstract Camel interceptor for MLLP-based HL7v2 transactions. * @author Dmytro Rud */ -public abstract class AbstractMllpInterceptor - extends AbstractHl7v2Interceptor - implements MllpInterceptor +public abstract class AbstractMllpInterceptor extends AbstractHl7v2Interceptor implements MllpInterceptor { @SuppressWarnings("unchecked") @Override - public MllpEndpoint getMllpEndpoint() { - return (MllpEndpoint) getConfigurationHolder(); + public T getMllpEndpoint() { + return (T) getConfigurationHolder(); } } diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/AuditInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/AuditInterceptor.java index 43b2d1de2b..a4f4e6de60 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/AuditInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/AuditInterceptor.java @@ -23,7 +23,7 @@ * Interface for PIX/PDQ auditing interceptors. * @author Dmytro Rud */ -public interface AuditInterceptor extends MllpInterceptor { +public interface AuditInterceptor extends MllpInterceptor { /** * Determines local and remote network addresses on the basis of the diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/MllpInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/MllpInterceptor.java index 4927dda71b..6a1f977611 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/MllpInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/MllpInterceptor.java @@ -16,7 +16,6 @@ package org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept; import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2Interceptor; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpEndpoint; @@ -24,11 +23,11 @@ * Camel interceptor interface for PIX/PDQ transactions. * @author Dmytro Rud */ -public interface MllpInterceptor extends Hl7v2Interceptor { +public interface MllpInterceptor extends Hl7v2Interceptor { /** * Returns the endpoint instance to which this interceptor belongs. */ - public MllpEndpoint getMllpEndpoint(); + public T getMllpEndpoint(); } diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerAuditInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerAuditInterceptor.java index 19e42ff40b..8507d98062 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerAuditInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerAuditInterceptor.java @@ -22,6 +22,7 @@ import org.apache.camel.component.mina2.Mina2Constants; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditStrategy; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpTransactionEndpoint; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AuditInterceptor; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AuditInterceptorUtils; @@ -31,9 +32,9 @@ * Consumer-side ATNA auditing Camel interceptor. * @author Dmytro Rud */ -public class ConsumerAuditInterceptor - extends AbstractMllpInterceptor - implements AuditInterceptor +public class ConsumerAuditInterceptor + extends AbstractMllpInterceptor + implements AuditInterceptor { @Override public void process(Exchange exchange) throws Exception { @@ -42,7 +43,8 @@ public void process(Exchange exchange) throws Exception { @Override public MllpAuditStrategy getAuditStrategy() { - return getMllpEndpoint().getServerAuditStrategy(); + MllpTransactionEndpoint mllpEndpoint = (MllpTransactionEndpoint) getMllpEndpoint(); + return mllpEndpoint.getServerAuditStrategy(); } @Override diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerAuthenticationFailureInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerAuthenticationFailureInterceptor.java index 2441b1d800..ac2cdd40fe 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerAuthenticationFailureInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerAuthenticationFailureInterceptor.java @@ -17,7 +17,7 @@ import org.apache.camel.Exchange; import org.apache.camel.component.mina2.Mina2Constants; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditStrategy; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuthenticationFailure; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; @@ -27,7 +27,7 @@ * Interceptor that handles any {@link MllpAuthenticationFailure} that occurred while * processing an exchange. */ -public class ConsumerAuthenticationFailureInterceptor extends AbstractMllpInterceptor { +public class ConsumerAuthenticationFailureInterceptor extends AbstractMllpInterceptor { @Override public void process(Exchange exchange) throws Exception { @@ -35,7 +35,7 @@ public void process(Exchange exchange) throws Exception { getWrappedProcessor().process(exchange); } catch (MllpAuthenticationFailure e) { - getMllpEndpoint().getServerAuditStrategy().auditAuthenticationNodeFailure(getRemoteAddress(exchange)); + MllpAuditStrategy.auditAuthenticationNodeFailure(getRemoteAddress(exchange)); throw e; } } diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerDispatchingInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerDispatchingInterceptor.java new file mode 100644 index 0000000000..b1dd2af589 --- /dev/null +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerDispatchingInterceptor.java @@ -0,0 +1,132 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed 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.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.consumer; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.StartupListener; +import org.apache.camel.component.mina2.Mina2Consumer; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2AcceptanceException; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2TransactionConfiguration; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2Interceptor; +import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerRequestAcceptanceInterceptor; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.IdentityHashMap; + +import static org.apache.commons.lang3.StringUtils.split; +import static org.apache.commons.lang3.StringUtils.splitPreserveAllTokens; + +/** + * Interceptor which dispatches an incoming request message to another MLLP route. + * @author Dmytro Rud + */ +public class ConsumerDispatchingInterceptor extends AbstractMllpInterceptor implements StartupListener { + private static final transient Logger LOG = LoggerFactory.getLogger(ConsumerDispatchingInterceptor.class); + + private final String[] routeIds; + private IdentityHashMap map; + + + /** + * Constructs a dispatching interceptor. + * @param camelContext + * Camel context. + * @param routeIds + * IDs of routes containing target IPF MLLP endpoints. + */ + public ConsumerDispatchingInterceptor(CamelContext camelContext, String[] routeIds) { + this.routeIds = routeIds; + + try { + camelContext.addStartupListener(this); + } catch (Exception e) { + throw new RuntimeCamelException(e); + } + } + + + @Override + public void onCamelContextStarted(CamelContext camelContext, boolean alreadyStarted) throws Exception { + map = new IdentityHashMap(routeIds.length); + for (String routeId : routeIds) { + Mina2Consumer consumer = (Mina2Consumer) camelContext.getRoute(routeId).getConsumer(); + Hl7v2Interceptor interceptor = (Hl7v2Interceptor) consumer.getProcessor(); + while (! (interceptor instanceof ConsumerRequestAcceptanceInterceptor)) { + interceptor = (Hl7v2Interceptor) interceptor.getWrappedProcessor(); + } + + map.put((Hl7v2Interceptor) interceptor.getWrappedProcessor(), routeId); + } + } + + + @Override + public void process(Exchange exchange) throws Exception { + String messageType = null; + String triggerEvent = null; + String messageStructure = null; + String version = null; + + // determine attributes of the message + String message = exchange.getIn().getBody(String.class); + String[] segments = split(message, '\r'); + if (segments.length > 0) { + String msh = segments[0]; + if (msh.length() > 10) { + String[] mshFields = splitPreserveAllTokens(msh, msh.charAt(3)); + if (mshFields.length > 11) { + String[] msh9Components = split(mshFields[8], msh.charAt(4)); + if (msh9Components.length > 1) { + messageType = msh9Components[0]; + triggerEvent = msh9Components[1]; + } + if (msh9Components.length > 2) { + messageStructure = msh9Components[2]; + } + version = mshFields[11]; + } + } + } + + // check who can accept the message + boolean found = false; + for (Hl7v2Interceptor interceptor : map.keySet()) { + Hl7v2TransactionConfiguration config = interceptor.getConfigurationHolder().getHl7v2TransactionConfiguration(); + try { + config.checkMessageAcceptance(messageType, triggerEvent, messageStructure, version, true); + + LOG.debug("Dispatch message with MSH-9-1='{}', MSH-9-2='{}', MSH-9-3='{}', MSH-12='{}' to route '{}'", + messageType, triggerEvent, messageStructure, version, map.get(interceptor)); + found = true; + interceptor.process(exchange); + break; + } catch (Hl7v2AcceptanceException e) { + // no problem + } + } + + if (! found) { + LOG.debug("Nobody can process message with MSH-9-1='{}', MSH-9-2='{}', MSH-9-3='{}', MSH-12='{}'", + messageType, triggerEvent, messageStructure, version); + throw new Hl7v2AcceptanceException("Unsupported message type and/or version", 207); + } + } + +} diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerInPayloadLoggerInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerInPayloadLoggerInterceptor.java index 598de007bc..4a0ed38a6b 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerInPayloadLoggerInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerInPayloadLoggerInterceptor.java @@ -17,7 +17,6 @@ import lombok.experimental.Delegate; import org.apache.camel.Exchange; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.MllpPayloadLoggerBase; @@ -29,7 +28,7 @@ * * @author Dmytro Rud */ -public class ConsumerInPayloadLoggerInterceptor extends AbstractMllpInterceptor { +public class ConsumerInPayloadLoggerInterceptor extends AbstractMllpInterceptor { @Delegate private final MllpPayloadLoggerBase base = new MllpPayloadLoggerBase(); public ConsumerInPayloadLoggerInterceptor(String fileNamePattern) { diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerInteractiveResponseSenderInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerInteractiveResponseSenderInterceptor.java index fdfaf4a591..1759253c89 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerInteractiveResponseSenderInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerInteractiveResponseSenderInterceptor.java @@ -21,6 +21,7 @@ import ca.uhn.hl7v2.util.Terser; import org.apache.camel.Exchange; import org.apache.commons.lang3.Validate; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpTransactionEndpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.openehealth.ipf.modules.hl7.message.MessageUtils; @@ -29,7 +30,6 @@ import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2ConfigurationHolder; import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2TransactionConfiguration; import org.openehealth.ipf.platform.camel.ihe.mllp.core.InteractiveContinuationStorage; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; import java.util.ArrayList; @@ -45,7 +45,7 @@ * as described in paragraph 5.6.3 of the HL7 v2.5 specification. * @author Dmytro Rud */ -public class ConsumerInteractiveResponseSenderInterceptor extends AbstractMllpInterceptor { +public class ConsumerInteractiveResponseSenderInterceptor extends AbstractMllpInterceptor { private static final transient Logger LOG = LoggerFactory.getLogger(ConsumerInteractiveResponseSenderInterceptor.class); private InteractiveContinuationStorage storage; @@ -53,13 +53,15 @@ public class ConsumerInteractiveResponseSenderInterceptor extends AbstractMllpIn @Override public void setConfigurationHolder(Hl7v2ConfigurationHolder configurationHolder) { super.setConfigurationHolder(configurationHolder); - this.storage = getMllpEndpoint().getInteractiveContinuationStorage(); - Validate.notNull(storage); + MllpTransactionEndpoint endpoint = (MllpTransactionEndpoint) getMllpEndpoint(); + this.storage = Validate.notNull(endpoint.getInteractiveContinuationStorage()); } @Override public void process(Exchange exchange) throws Exception { + MllpTransactionEndpoint endpoint = (MllpTransactionEndpoint) getMllpEndpoint(); + Parser parser = getHl7v2TransactionConfiguration().getParser(); MessageAdapter request = (MessageAdapter) exchange.getIn().getHeader(ORIGINAL_MESSAGE_ADAPTER_HEADER_NAME); Message requestMessage = request.getHapiMessage(); @@ -111,7 +113,7 @@ public void process(Exchange exchange) throws Exception { LOG.warn("Cannot parse RCP-2-1, try to use default threshold", nfe); } if (threshold < 1) { - threshold = getMllpEndpoint().getInteractiveContinuationDefaultThreshold(); + threshold = endpoint.getInteractiveContinuationDefaultThreshold(); } if (threshold < 1) { LOG.debug("Cannot perform interactive continuation: invalid or missing threshold"); diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerOutPayloadLoggerInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerOutPayloadLoggerInterceptor.java index 5c34452eb0..5362963c1b 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerOutPayloadLoggerInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerOutPayloadLoggerInterceptor.java @@ -17,7 +17,6 @@ import lombok.experimental.Delegate; import org.apache.camel.Exchange; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.MllpPayloadLoggerBase; @@ -29,7 +28,7 @@ * * @author Dmytro Rud */ -public class ConsumerOutPayloadLoggerInterceptor extends AbstractMllpInterceptor { +public class ConsumerOutPayloadLoggerInterceptor extends AbstractMllpInterceptor { @Delegate private final MllpPayloadLoggerBase base = new MllpPayloadLoggerBase(); public ConsumerOutPayloadLoggerInterceptor(String fileNamePattern) { diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerRequestDefragmenterInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerRequestDefragmenterInterceptor.java index 0ea39be127..b4fa0b1f51 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerRequestDefragmenterInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerRequestDefragmenterInterceptor.java @@ -26,7 +26,6 @@ import org.openehealth.ipf.modules.hl7.message.MessageUtils; import org.openehealth.ipf.platform.camel.core.util.Exchanges; import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2ConfigurationHolder; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.UnsolicitedFragmentationStorage; import ca.uhn.hl7v2.model.Message; @@ -41,7 +40,7 @@ * * @author Dmytro Rud */ -public class ConsumerRequestDefragmenterInterceptor extends AbstractMllpInterceptor { +public class ConsumerRequestDefragmenterInterceptor extends AbstractMllpInterceptor { private static final transient Logger LOG = LoggerFactory.getLogger(ConsumerRequestDefragmenterInterceptor.class); // keys consist of: continuation pointer, MSH-3-1, MSH-3-2, and MSH-3-3 diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerStringProcessingInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerStringProcessingInterceptor.java index bb86e96a5b..7b43218a2a 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerStringProcessingInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/consumer/ConsumerStringProcessingInterceptor.java @@ -20,7 +20,6 @@ import org.openehealth.ipf.platform.camel.core.util.Exchanges; import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2MarshalUtils; import org.openehealth.ipf.platform.camel.ihe.mllp.core.FragmentationUtils; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; @@ -29,7 +28,7 @@ * for the given endpoint, and handles segment fragmentation (\rADD|...). * @author Dmytro Rud */ -public class ConsumerStringProcessingInterceptor extends AbstractMllpInterceptor { +public class ConsumerStringProcessingInterceptor extends AbstractMllpInterceptor { @Override public void process(Exchange exchange) throws Exception { diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerAuditInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerAuditInterceptor.java index dd94d2fab9..deb625aa80 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerAuditInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerAuditInterceptor.java @@ -18,6 +18,7 @@ import org.apache.camel.Exchange; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditStrategy; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpTransactionEndpoint; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AuditInterceptor; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AuditInterceptorUtils; @@ -29,18 +30,18 @@ * Producer-side ATNA auditing Camel interceptor. * @author Dmytro Rud */ -public class ProducerAuditInterceptor extends AbstractMllpInterceptor implements AuditInterceptor { +public class ProducerAuditInterceptor extends AbstractMllpInterceptor implements AuditInterceptor { @Override public void process(Exchange exchange) throws Exception { AuditInterceptorUtils.doProcess(this, exchange); } - + @Override public void determineParticipantsAddresses( Exchange exchange, - MllpAuditDataset auditDataset) throws Exception + MllpAuditDataset auditDataset) throws Exception { auditDataset.setLocalAddress(InetAddress.getLocalHost().getCanonicalHostName()); auditDataset.setRemoteAddress(getMllpEndpoint().getEndpointUri()); @@ -49,6 +50,7 @@ public void determineParticipantsAddresses( @Override public MllpAuditStrategy getAuditStrategy() { - return getMllpEndpoint().getClientAuditStrategy(); + MllpTransactionEndpoint endpoint = (MllpTransactionEndpoint) getMllpEndpoint(); + return endpoint.getClientAuditStrategy(); } } diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerInPayloadLoggerInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerInPayloadLoggerInterceptor.java index 8d734bdc33..ae3f25788c 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerInPayloadLoggerInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerInPayloadLoggerInterceptor.java @@ -17,7 +17,6 @@ import lombok.experimental.Delegate; import org.apache.camel.Exchange; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.MllpPayloadLoggerBase; @@ -29,7 +28,7 @@ * * @author Dmytro Rud */ -public class ProducerInPayloadLoggerInterceptor extends AbstractMllpInterceptor { +public class ProducerInPayloadLoggerInterceptor extends AbstractMllpInterceptor { @Delegate private final MllpPayloadLoggerBase base = new MllpPayloadLoggerBase(); public ProducerInPayloadLoggerInterceptor(String fileNamePattern) { diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerMarshalAndInteractiveResponseReceiverInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerMarshalAndInteractiveResponseReceiverInterceptor.java index fa746f316a..13ec6742e1 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerMarshalAndInteractiveResponseReceiverInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerMarshalAndInteractiveResponseReceiverInterceptor.java @@ -22,6 +22,7 @@ import ca.uhn.hl7v2.parser.Parser; import ca.uhn.hl7v2.util.Terser; import org.apache.camel.Exchange; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpTransactionEndpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.openehealth.ipf.modules.hl7.message.MessageUtils; @@ -30,7 +31,6 @@ import org.openehealth.ipf.platform.camel.core.util.Exchanges; import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2TransactionConfiguration; import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.producer.ProducerMarshalInterceptor; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; import java.util.List; @@ -46,7 +46,7 @@ * * @author Dmytro Rud */ -public class ProducerMarshalAndInteractiveResponseReceiverInterceptor extends AbstractMllpInterceptor { +public class ProducerMarshalAndInteractiveResponseReceiverInterceptor extends AbstractMllpInterceptor { private static final transient Logger LOG = LoggerFactory.getLogger(ProducerMarshalAndInteractiveResponseReceiverInterceptor.class); public ProducerMarshalAndInteractiveResponseReceiverInterceptor() { @@ -59,6 +59,8 @@ public ProducerMarshalAndInteractiveResponseReceiverInterceptor() { */ @Override public void process(Exchange exchange) throws Exception { + MllpTransactionEndpoint endpoint = (MllpTransactionEndpoint) getMllpEndpoint(); + Hl7v2TransactionConfiguration config = getHl7v2TransactionConfiguration(); MessageAdapter request = exchange.getIn().getBody(MessageAdapter.class); @@ -72,7 +74,7 @@ public void process(Exchange exchange) throws Exception { // 2. It must be allowed for the given request message type. // 3. The user must not have already filled the DSC segment. boolean supportContinuations = false; - if (getMllpEndpoint().isSupportInteractiveContinuation()) { + if (endpoint.isSupportInteractiveContinuation()) { requestTerser = new Terser(request.getHapiMessage()); if (config.isContinuable(requestTerser.get("MSH-9-1")) && isEmpty(requestTerser.get("DSC-1"))) { supportContinuations = true; @@ -171,7 +173,7 @@ else if (config.isFooterStartSegment(segments, i)) { // prepare and send automatic cancel request, if necessary. // All errors will be ignored - if (getMllpEndpoint().isAutoCancel()) { + if (endpoint.isAutoCancel()) { try { String cancel = createCancelMessage(request.getHapiMessage(), config.getParser()); exchange.getIn().setBody(cancel); diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerOutPayloadLoggerInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerOutPayloadLoggerInterceptor.java index ad0ea93c5f..22ae766c3d 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerOutPayloadLoggerInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerOutPayloadLoggerInterceptor.java @@ -17,7 +17,6 @@ import lombok.experimental.Delegate; import org.apache.camel.Exchange; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.MllpPayloadLoggerBase; @@ -29,7 +28,7 @@ * * @author Dmytro Rud */ -public class ProducerOutPayloadLoggerInterceptor extends AbstractMllpInterceptor { +public class ProducerOutPayloadLoggerInterceptor extends AbstractMllpInterceptor { @Delegate private final MllpPayloadLoggerBase base = new MllpPayloadLoggerBase(); public ProducerOutPayloadLoggerInterceptor(String fileNamePattern) { diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerRequestFragmenterInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerRequestFragmenterInterceptor.java index ef6d4402f4..f8282100de 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerRequestFragmenterInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerRequestFragmenterInterceptor.java @@ -21,7 +21,6 @@ import org.slf4j.LoggerFactory; import org.openehealth.ipf.modules.hl7.message.MessageUtils; import org.openehealth.ipf.platform.camel.core.util.Exchanges; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; import java.util.List; @@ -34,7 +33,7 @@ * fragmentation as described in paragraph 2.10.2.2 of the HL7 v.2.5 specification. * @author Dmytro Rud */ -public class ProducerRequestFragmenterInterceptor extends AbstractMllpInterceptor { +public class ProducerRequestFragmenterInterceptor extends AbstractMllpInterceptor { private static final transient Logger LOG = LoggerFactory.getLogger(ProducerRequestFragmenterInterceptor.class); diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerStringProcessingInterceptor.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerStringProcessingInterceptor.java index dac62b01a2..8471a25ec5 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerStringProcessingInterceptor.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/intercept/producer/ProducerStringProcessingInterceptor.java @@ -20,7 +20,6 @@ import org.openehealth.ipf.platform.camel.core.util.Exchanges; import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2MarshalUtils; import org.openehealth.ipf.platform.camel.ihe.mllp.core.FragmentationUtils; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.core.intercept.AbstractMllpInterceptor; @@ -29,7 +28,7 @@ * for the given endpoint, and handles segment fragmentation (\rADD|...). * @author Dmytro Rud */ -public class ProducerStringProcessingInterceptor extends AbstractMllpInterceptor { +public class ProducerStringProcessingInterceptor extends AbstractMllpInterceptor { @Override public void process(Exchange exchange) throws Exception { diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti10/Iti10Component.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti10/Iti10Component.java index 0ac7980ddb..95bd59dfba 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti10/Iti10Component.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti10/Iti10Component.java @@ -20,14 +20,14 @@ import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2TransactionConfiguration; import org.openehealth.ipf.platform.camel.ihe.hl7v2.NakFactory; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditStrategy; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpComponent; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpTransactionComponent; import org.openehealth.ipf.platform.camel.ihe.mllp.core.QueryAuditDataset; /** * Camel component for ITI-10 (PIX Update Notification). * @author Dmytro Rud */ -public class Iti10Component extends MllpComponent { +public class Iti10Component extends MllpTransactionComponent { public static final Hl7v2TransactionConfiguration CONFIGURATION = new Hl7v2TransactionConfiguration( "2.5", diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti21/Iti21Component.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti21/Iti21Component.java index 55f96f08f9..0afc8a4087 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti21/Iti21Component.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti21/Iti21Component.java @@ -25,7 +25,7 @@ import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2Interceptor; import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerSegmentEchoingInterceptor; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditStrategy; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpComponent; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpTransactionComponent; import org.openehealth.ipf.platform.camel.ihe.mllp.core.QpdAwareNakFactory; import org.openehealth.ipf.platform.camel.ihe.mllp.core.QueryAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.pdqcore.PdqTransactionConfiguration; @@ -34,7 +34,7 @@ * Camel component for ITI-21 (PDQ). * @author Dmytro Rud */ -public class Iti21Component extends MllpComponent { +public class Iti21Component extends MllpTransactionComponent { public static final Hl7v2TransactionConfiguration CONFIGURATION = new PdqTransactionConfiguration( "2.5", diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti22/Iti22Component.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti22/Iti22Component.java index 60f9eb7c31..674aaead8a 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti22/Iti22Component.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti22/Iti22Component.java @@ -25,7 +25,7 @@ import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2Interceptor; import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerSegmentEchoingInterceptor; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditStrategy; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpComponent; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpTransactionComponent; import org.openehealth.ipf.platform.camel.ihe.mllp.core.QpdAwareNakFactory; import org.openehealth.ipf.platform.camel.ihe.mllp.core.QueryAuditDataset; import org.openehealth.ipf.platform.camel.ihe.mllp.pdqcore.PdqTransactionConfiguration; @@ -34,7 +34,7 @@ * Camel component for ITI-22 (PDQ). * @author Dmytro Rud */ -public class Iti22Component extends MllpComponent { +public class Iti22Component extends MllpTransactionComponent { public static final Hl7v2TransactionConfiguration CONFIGURATION = new PdqTransactionConfiguration( "2.5", diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti64/Iti64Component.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti64/Iti64Component.java index 225108019c..b25135660e 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti64/Iti64Component.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti64/Iti64Component.java @@ -20,13 +20,13 @@ import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2TransactionConfiguration; import org.openehealth.ipf.platform.camel.ihe.hl7v2.NakFactory; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditStrategy; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpComponent; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpTransactionComponent; /** * Camel component for ITI-64 (XAD-PID Change Management - XPID). * @author Boris Stanojevic */ -public class Iti64Component extends MllpComponent { +public class Iti64Component extends MllpTransactionComponent { public static final Hl7v2TransactionConfiguration CONFIGURATION = new Hl7v2TransactionConfiguration( "2.5", diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti8/Iti8Component.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti8/Iti8Component.java index 3b5f134de7..feb8306220 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti8/Iti8Component.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti8/Iti8Component.java @@ -25,7 +25,7 @@ * Camel component for ITI-8 (PIX Feed). * @author Dmytro Rud */ -public class Iti8Component extends MllpComponent { +public class Iti8Component extends MllpTransactionComponent { public static final Hl7v2TransactionConfiguration CONFIGURATION = new Hl7v2TransactionConfiguration( "2.3.1", diff --git a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti9/Iti9Component.java b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti9/Iti9Component.java index a658062b38..3c47ed82ab 100644 --- a/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti9/Iti9Component.java +++ b/platform-camel/ihe/mllp/src/main/java/org/openehealth/ipf/platform/camel/ihe/mllp/iti9/Iti9Component.java @@ -22,7 +22,7 @@ import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.Hl7v2Interceptor; import org.openehealth.ipf.platform.camel.ihe.hl7v2.intercept.consumer.ConsumerSegmentEchoingInterceptor; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditStrategy; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpComponent; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpTransactionComponent; import org.openehealth.ipf.platform.camel.ihe.mllp.core.QpdAwareNakFactory; import org.openehealth.ipf.platform.camel.ihe.mllp.core.QueryAuditDataset; @@ -33,7 +33,7 @@ * Camel component for ITI-9 (PIX Query). * @author Dmytro Rud */ -public class Iti9Component extends MllpComponent { +public class Iti9Component extends MllpTransactionComponent { public static final Hl7v2TransactionConfiguration CONFIGURATION = new Hl7v2TransactionConfiguration( "2.5", diff --git a/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/core/ManagedMllpItiEndpointTest.groovy b/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/core/ManagedMllpItiEndpointTest.groovy index 16263a2411..258c2b3104 100644 --- a/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/core/ManagedMllpItiEndpointTest.groovy +++ b/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/core/ManagedMllpItiEndpointTest.groovy @@ -49,15 +49,15 @@ public class ManagedMllpItiEndpointTest extends MllpTestContainer { @Test void endpointManagedType() throws Exception { ObjectName on = queryForNamedObjects( - 'org.apache.camel:*,type=endpoints,name=\"mina2:tcp:*\"') + 'org.apache.camel:*,type=endpoints,name=\"some-mllp-iti:*\"') ObjectInstance oi = getMBeanServer().getObjectInstance(on) - assertEquals(MllpEndpoint.class.getCanonicalName(), oi.getClassName()); + assertEquals(MllpTransactionEndpoint.class.getCanonicalName(), oi.getClassName()); } @Test void endpointAttributes() throws Exception { ObjectName on = queryForNamedObjects( - 'org.apache.camel:*,type=endpoints,name=\"mina2:tcp:*\"') + 'org.apache.camel:*,type=endpoints,name=\"some-mllp-iti:*\"') assertEquals(SomeMllpItiComponent.class.getCanonicalName(), (String) getMBeanServer().getAttribute(on, "ComponentType")); assertEquals(true, diff --git a/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTestContainer.groovy b/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTestContainer.groovy index a8a32eddbc..44f1151362 100644 --- a/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTestContainer.groovy +++ b/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/core/MllpTestContainer.groovy @@ -35,18 +35,17 @@ import org.springframework.context.support.ClassPathXmlApplicationContext * @author Dmytro Rud */ class MllpTestContainer { - def static CONTEXT_DESCRIPTOR = 'some-mllp-iti-context.xml' - - def static producerTemplate - def static camelContext - def static auditSender - def static appContext + + static ProducerTemplate producerTemplate + static CamelContext camelContext + static MockedSender auditSender + static ClassPathXmlApplicationContext appContext /** * Initializes a test on the basis of a Spring descriptor. */ - def static init(String descriptorFile, boolean standalone) { + static void init(String descriptorFile, boolean standalone) { appContext = new ClassPathXmlApplicationContext(descriptorFile) producerTemplate = appContext.getBean('template', ProducerTemplate.class) camelContext = appContext.getBean('camelContext', CamelContext.class) diff --git a/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/dispatch/DispatchRouteBuilder.groovy b/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/dispatch/DispatchRouteBuilder.groovy new file mode 100644 index 0000000000..99bd02de44 --- /dev/null +++ b/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/dispatch/DispatchRouteBuilder.groovy @@ -0,0 +1,51 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed 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.openehealth.ipf.platform.camel.ihe.mllp.dispatch + +import org.apache.camel.spring.SpringRouteBuilder +import org.openehealth.ipf.modules.hl7.message.MessageUtils +import org.openehealth.ipf.platform.camel.ihe.mllp.PixPdqCamelValidators + +import static org.openehealth.ipf.platform.camel.core.util.Exchanges.resultMessage + +/** + * @author Dmytro Rud + */ +class DispatchRouteBuilder extends SpringRouteBuilder { + + @Override + void configure() throws Exception { + from('mllp-dispatch://0.0.0.0:18500?routes=pixfeed,xadpid').process {} + + from('pix-iti8://0.0.0.0:18501') + .routeId('pixfeed') + .process(PixPdqCamelValidators.iti8RequestValidator()) + .process { + resultMessage(it).body = MessageUtils.ack(it.in.body.target) + } + .process(PixPdqCamelValidators.iti8ResponseValidator()) + + from('xpid-iti64://0.0.0.0:18502') + .routeId('xadpid') + .process(PixPdqCamelValidators.iti8RequestValidator()) + .process { + resultMessage(it).body = MessageUtils.ack(it.in.body.target) + } + .process(PixPdqCamelValidators.iti8ResponseValidator()) + + } + +} diff --git a/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/dispatch/TestDispatch.groovy b/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/dispatch/TestDispatch.groovy new file mode 100644 index 0000000000..4a22c0ecca --- /dev/null +++ b/platform-camel/ihe/mllp/src/test/groovy/org/openehealth/ipf/platform/camel/ihe/mllp/dispatch/TestDispatch.groovy @@ -0,0 +1,104 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed 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.openehealth.ipf.platform.camel.ihe.mllp.dispatch + +import org.apache.camel.impl.DefaultExchange +import org.junit.BeforeClass +import org.junit.Test +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpTestContainer + +import static org.junit.Assert.assertEquals +import static org.openehealth.ipf.platform.camel.ihe.mllp.PixPdqCamelValidators.* + +/** + * @author Dmytro Rud + */ +class TestDispatch extends MllpTestContainer { + static final String CONTEXT_DESCRIPTOR = 'dispatch/dispatch.xml' + + static final String ITI_8_REQUEST = + 'MSH|^~\\&|MESA_PD_SUPPLIER|XYZ_HOSPITAL|dummy|dummy|20081204114742||ADT^A01|123456|T|2.3.1|||ER\n' + + 'EVN|A01|20081204114742\n' + + 'PID|1||001^^^XREF2005~002^^^HIMSS2005||Multiple^Christof^Maria^Prof.|Eisner|' + + '19530429|M|||Bahnhofstr. 1^^Testort^^01234^DE^H|||||||AccNr01^^^ANICPA|' + + '111-222-333|\n' + + 'PV1|1|O|\n' + + static final String ITI_9_REQUEST = + 'MSH|^~\\&|MESA_PIX_CLIENT|MESA_DEPARTMENT|MESA_XREF|XYZ_HOSPITAL|'+ + '200603121200||QBP^Q23^QBP_Q21|10501110|P|2.5||||||||\n' + + 'QPD|QRY_1001^Query for Corresponding Identifiers^IHEDEMO|QRY10501110|' + + 'ABC10501^^^HIMSS2005&1.3.6.1.4.1.21367.2005.1.1&ISO^PI|||||\n' + + 'RCP|I||||||\n' + + static final String ITI_64_REQUEST = + 'MSH|^~\\&|REPOSITORY|ENT|RSP1P8|GOOD HEALTH HOSPITAL|200701051530|SEC|ADT^A43^ADT_A43|0000009|P|2.5\n' + + 'EVN|A43|200701051530\n' + + 'PID|1|E2|new^^^&1.2.3.4&ISO~source^^^&1.2.3.4&ISO|||EVERYWOMAN^EVE|\n' + + 'MRG|old^^^&1.2.3.4&ISO|||E1\n' + + + static void main(args) { + init(CONTEXT_DESCRIPTOR, true) + } + + @BeforeClass + static void setUpClass() { + init(CONTEXT_DESCRIPTOR, false) + } + + + // ITI-8 and ITI-64 can be dispatched, ITI-9 must fail + @Test + void testHappyCaseAndAudit1() { + DefaultExchange exchange = new DefaultExchange(camelContext); + + exchange.in.body = send('pix-iti8://localhost:18500', ITI_8_REQUEST) + iti8ResponseValidator().process(exchange) + assertACK(exchange.in.body) + + exchange.in.body = send('pix-iti9://localhost:18500', ITI_9_REQUEST) + iti9ResponseValidator().process(exchange) + assertNAK(exchange.in.body) + + exchange.in.body = send('xpid-iti64://localhost:18500', ITI_64_REQUEST) + iti64ResponseValidator().process(exchange) + assertACK(exchange.in.body) + + // ITI-8 from server + // ITI-8 from client + // ITI-9 from client (failure) + // ITI-64 from server + // ITI-64 from client + assertEquals(5, auditSender.messages.size()) + + assertEquals(2, auditSender.messages.findAll { + it.auditMessage.eventIdentification.eventTypeCode[0].code == 'ITI-8' && + it.auditMessage.eventIdentification.eventOutcomeIndicator == 0} + .size()) + + assertEquals(1, auditSender.messages.findAll { + it.auditMessage.eventIdentification.eventTypeCode[0].code == 'ITI-9' && + it.auditMessage.eventIdentification.eventOutcomeIndicator == 12} + .size()) + + assertEquals(2, auditSender.messages.findAll { + it.auditMessage.eventIdentification.eventTypeCode[0].code == 'ITI-64' && + it.auditMessage.eventIdentification.eventOutcomeIndicator == 0} + .size()) + } + +} diff --git a/platform-camel/ihe/mllp/src/test/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/mbean/SomeMllpItiComponent.java b/platform-camel/ihe/mllp/src/test/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/mbean/SomeMllpItiComponent.java index c6c82250e2..20bc65d41c 100644 --- a/platform-camel/ihe/mllp/src/test/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/mbean/SomeMllpItiComponent.java +++ b/platform-camel/ihe/mllp/src/test/java/org/openehealth/ipf/platform/camel/ihe/mllp/core/mbean/SomeMllpItiComponent.java @@ -19,12 +19,12 @@ import org.openehealth.ipf.platform.camel.ihe.hl7v2.Hl7v2TransactionConfiguration; import org.openehealth.ipf.platform.camel.ihe.hl7v2.NakFactory; import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpAuditStrategy; -import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpComponent; +import org.openehealth.ipf.platform.camel.ihe.mllp.core.MllpTransactionComponent; /** * Test MLLP Component implementation */ -public class SomeMllpItiComponent extends MllpComponent { +public class SomeMllpItiComponent extends MllpTransactionComponent { public static final Hl7v2TransactionConfiguration CONFIGURATION = new Hl7v2TransactionConfiguration( diff --git a/platform-camel/ihe/mllp/src/test/resources/dispatch/dispatch.xml b/platform-camel/ihe/mllp/src/test/resources/dispatch/dispatch.xml new file mode 100644 index 0000000000..0916d15b70 --- /dev/null +++ b/platform-camel/ihe/mllp/src/test/resources/dispatch/dispatch.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +