package org.wso2.carbon.inbound.endpoint.protocol.hl7.core;
/**
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import ca.uhn.hl7v2.HL7Exception;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.nio.reactor.IOEventDispatch;
import org.apache.http.nio.reactor.IOSession;
import org.apache.synapse.transport.passthru.util.BufferFactory;
import org.apache.synapse.transport.passthru.util.ControlledByteBuffer;
import org.wso2.carbon.inbound.endpoint.protocol.hl7.codec.HL7Codec;
import org.wso2.carbon.inbound.endpoint.protocol.hl7.context.MLLPContext;
import org.wso2.carbon.inbound.endpoint.protocol.hl7.context.MLLPContextFactory;
import org.wso2.carbon.inbound.endpoint.protocol.hl7.util.HL7MessageUtils;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
public class MLLPSourceHandler implements IOEventDispatch {
private static final Log log = LogFactory.getLog(MLLPSourceHandler.class);
private volatile HL7Processor hl7Processor;
private final ByteBuffer hl7TrailerBuf = ByteBuffer.wrap(MLLPConstants.HL7_TRAILER);
private BufferFactory bufferFactory;
private ControlledByteBuffer inputBuffer;
private ControlledByteBuffer outputBuffer;
public MLLPSourceHandler() { /* default constructor */ }
public MLLPSourceHandler(HL7Processor hl7Processor) {
super();
this.hl7Processor = hl7Processor;
this.bufferFactory = (BufferFactory) hl7Processor.getInboundParameterMap().get(
MLLPConstants.INBOUND_HL7_BUFFER_FACTORY);
}
@Override
public void connected(IOSession session) {
if (session.getAttribute(MLLPConstants.MLLP_CONTEXT) == null) {
session.setAttribute(MLLPConstants.MLLP_CONTEXT,
MLLPContextFactory.createMLLPContext(session, hl7Processor));
}
inputBuffer = bufferFactory.getBuffer();
outputBuffer = bufferFactory.getBuffer();
}
@Override
public void inputReady(IOSession session) {
ReadableByteChannel ch = (ReadableByteChannel) session.channel();
MLLPContext mllpContext = (MLLPContext) session.getAttribute(MLLPConstants.MLLP_CONTEXT);
inputBuffer.clear();
try {
int read;
while ((read = ch.read(inputBuffer.getByteBuffer())) > 0) {
inputBuffer.flip();
try {
mllpContext.getCodec().decode(inputBuffer.getByteBuffer(), mllpContext);
} catch (MLLProtocolException e) {
handleException(session, mllpContext, e);
clearInputBuffers(mllpContext);
return;
} catch (HL7Exception e) {
handleException(session, mllpContext, e);
if (mllpContext.isAutoAck()) {
mllpContext.setNackMode(true);
mllpContext.setHl7Message(HL7MessageUtils.createDefaultNack(e.getMessage()));
mllpContext.requestOutput();
} else {
hl7Processor.processError(mllpContext, e);
}
return;
} catch (IOException e) {
shutdownConnection(session, mllpContext, e);
return;
}
}
if (mllpContext.getCodec().isReadComplete()) {
if (mllpContext.isAutoAck()) {
mllpContext.requestOutput();
bufferFactory.release(inputBuffer);
inputBuffer = bufferFactory.getBuffer();
}
try {
hl7Processor.processRequest(mllpContext);
} catch (Exception e) {
shutdownConnection(session, mllpContext, e);
}
}
if (read < 0) {
clearInputBuffers(mllpContext);
session.close();
}
} catch (IOException e) {
shutdownConnection(session, mllpContext, e);
}
}
private void clearInputBuffers(MLLPContext context) {
bufferFactory.release(inputBuffer);
inputBuffer = bufferFactory.getBuffer();
context.reset();
}
@Override
public void outputReady(IOSession session) {
MLLPContext mllpContext = (MLLPContext) session.getAttribute(MLLPConstants.MLLP_CONTEXT);
writeOut(session, mllpContext);
}
private void writeOut(IOSession session, MLLPContext mllpContext) {
outputBuffer.clear();
try {
mllpContext.getCodec().encode(outputBuffer.getByteBuffer(), mllpContext);
} catch (HL7Exception e) {
shutdownConnection(session, mllpContext, e);
} catch (IOException e) {
shutdownConnection(session, mllpContext, e);
}
if (outputBuffer == null) {
handleException(session, mllpContext, new MLLProtocolException("HL7 Codec is in an inconsistent state: "
+ mllpContext.getCodec().getState() + ". Shutting down connection."));
return;
}
try {
session.channel().write(outputBuffer.getByteBuffer());
if (mllpContext.getCodec().isWriteTrailer()) {
session.channel().write(hl7TrailerBuf);
hl7TrailerBuf.flip();
mllpContext.getCodec().setState(HL7Codec.WRITE_COMPLETE);
}
// bufferFactory.release(outputBuffer);
} catch (IOException e) {
shutdownConnection(session, mllpContext, e);
}
if (mllpContext.getCodec().isWriteComplete()) {
if (mllpContext.isMarkForClose()) {
shutdownConnection(session, mllpContext, null);
} else {
bufferFactory.release(outputBuffer);
outputBuffer = bufferFactory.getBuffer();
mllpContext.setMessageId("RESPONDED");
mllpContext.reset();
mllpContext.requestInput();
}
}
}
@Override
public void timeout(IOSession session) {
MLLPContext mllpContext = (MLLPContext) session.getAttribute(MLLPConstants.MLLP_CONTEXT);
shutdownConnection(session, mllpContext, null);
}
@Override
public void disconnected(IOSession session) {
MLLPContext mllpContext = (MLLPContext) session.getAttribute(MLLPConstants.MLLP_CONTEXT);
shutdownConnection(session, mllpContext, null);
}
private void shutdownConnection(IOSession session, MLLPContext mllpContext, Exception e) {
if (e != null) {
log.error("An unexpected error has occurred.");
handleException(session, mllpContext, e);
}
bufferFactory.release(inputBuffer);
bufferFactory.release(outputBuffer);
session.close();
}
private void handleException(IOSession session, MLLPContext mllpContext, Exception e) {
log.error("Exception caught in I/O handler.", e);
}
}