package org.wso2.carbon.inbound.endpoint.protocol.hl7.codec;
/**
* 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.wso2.carbon.inbound.endpoint.protocol.hl7.context.MLLPContext;
import org.wso2.carbon.inbound.endpoint.protocol.hl7.core.MLLPConstants;
import org.wso2.carbon.inbound.endpoint.protocol.hl7.core.MLLProtocolException;
import org.wso2.carbon.inbound.endpoint.protocol.hl7.util.HL7MessageUtils;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.CharsetDecoder;
public class HL7Codec {
private static final Log log = LogFactory.getLog(HL7Codec.class);
public static final int READ_HEADER = 0;
public static final int READ_CONTENT = 1;
public static final int READ_TRAILER = 2;
public static final int READ_COMPLETE = 3;
public static final int WRITE_HEADER = 4;
public static final int WRITE_CONTENT = 5;
public static final int WRITE_TRAILER = 6;
public static final int WRITE_COMPLETE = 7;
private CharsetDecoder charsetDecoder;
private volatile int state;
private int responseReadPosition = 0;
private byte[] responseBytes = null;
public HL7Codec() {
this.state = READ_HEADER;
this.charsetDecoder = MLLPConstants.UTF8_CHARSET.newDecoder();
}
public HL7Codec(CharsetDecoder charsetDecoder) {
this.state = READ_HEADER;
setCharsetDecoder(charsetDecoder);
}
public int decode(ByteBuffer dst, MLLPContext context) throws IOException, MLLProtocolException, HL7Exception {
if (this.state >= READ_COMPLETE || dst.position() < 0) {
return -1;
}
if (this.state == READ_HEADER) {
if(dst.get(0) == MLLPConstants.HL7_HEADER[0]) {
dst.position(1);
this.state = READ_CONTENT;
} else {
throw new MLLProtocolException("Could not find header in incoming message.");
}
}
if (this.state == READ_CONTENT) {
int trailerIndex = findTrailer(dst);
if(trailerIndex > -1) {
dst.limit(trailerIndex);
this.state = READ_TRAILER;
}
context.getRequestBuffer().append(charsetDecoder.decode(dst).toString());
}
if (this.state == READ_TRAILER) {
this.state = READ_COMPLETE;
try {
if (context.isPreProcess()) {
context.setHl7Message(HL7MessageUtils.parse(context.getRequestBuffer().toString(),
context.getPreProcessParser()));
} else {
context.setHl7Message(HL7MessageUtils.parse(context.getRequestBuffer().toString(), context.isValidateMessage()));
}
context.getRequestBuffer().setLength(0);
} catch (HL7Exception e) {
log.error("Error while parsing request message: " + context.getRequestBuffer());
throw e;
}
}
return 0;
}
private int findTrailer(ByteBuffer dst) {
for(int i=0; i<dst.limit(); i++) {
if(dst.get(i) == MLLPConstants.HL7_TRAILER[0]) {
if(dst.get(i+1) == MLLPConstants.HL7_TRAILER[1]) {
return i-1;
}
}
}
return -1;
}
public int encode(ByteBuffer outBuf, MLLPContext context) throws HL7Exception, IOException {
if (this.state < READ_COMPLETE) {
return 0;
}
if (this.state == READ_COMPLETE) {
if ((context.isAutoAck() || context.isApplicationAck()) && !context.isNackMode()) {
responseBytes = context.getHl7Message().generateACK().encode().getBytes(charsetDecoder.charset());
context.setApplicationAck(false);
} else {
responseBytes = context.getHl7Message().encode().getBytes(charsetDecoder.charset());
}
this.state = WRITE_HEADER;
}
if (this.state >= WRITE_HEADER) {
return fillBuffer(outBuf, responseBytes);
}
return 0;
}
private int fillBuffer(ByteBuffer byteBuffer, byte[] responseBytes) {
if (responseBytes == null) {
return 0;
}
byte b;
int count = 0;
int headerPosition = 0;
if (this.state == WRITE_HEADER) {
byteBuffer.put(MLLPConstants.HL7_HEADER[0]);
headerPosition = 1;
this.state = WRITE_CONTENT;
}
int MAX = byteBuffer.capacity();
if (byteBuffer.capacity() - (responseBytes.length - responseReadPosition + headerPosition) > 0) {
MAX = responseBytes.length - responseReadPosition + headerPosition;
}
for (int i=responseReadPosition; i<MAX+responseReadPosition-headerPosition; i++) {
count++;
b = responseBytes[i];
byteBuffer.put(b);
}
responseReadPosition += count;
if (responseReadPosition == responseBytes.length) {
this.state = WRITE_TRAILER;
responseReadPosition = 0;
}
byteBuffer.flip();
return count;
}
public boolean isReadComplete() {
if (this.state >= READ_COMPLETE) {
return true;
}
return false;
}
public boolean isWriteTrailer() {
if (this.state == WRITE_TRAILER) {
return true;
}
return false;
}
public boolean isWriteComplete() {
if (this.state == WRITE_COMPLETE) {
return true;
}
return false;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public CharsetDecoder getCharsetDecoder() {
return charsetDecoder;
}
private void setCharsetDecoder(CharsetDecoder charsetDecoder) {
this.charsetDecoder = charsetDecoder;
}
}