/*******************************************************************************
* Copyright (C) 2013, 2014, International Business Machines Corporation
* All Rights Reserved
*******************************************************************************/
package com.ibm.streamsx.messaging.jms;
import java.math.BigDecimal;
import java.util.List;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageEOFException;
import javax.jms.MessageFormatException;
import javax.jms.MessageNotReadableException;
import javax.jms.Session;
import javax.jms.StreamMessage;
import com.ibm.streams.operator.OutputTuple;
import com.ibm.streams.operator.Tuple;
import com.ibm.streams.operator.metrics.Metric;
import com.ibm.streams.operator.types.Blob;
import com.ibm.streams.operator.types.Timestamp;
//This class handles the JMS Stream message type
class StreamMessageHandler extends JMSMessageHandlerImpl {
// constructor
public StreamMessageHandler(List<NativeSchema> nativeSchemaObjects) {
super(nativeSchemaObjects);
}
// constructor
public StreamMessageHandler(List<NativeSchema> nativeSchemaObjects,
Metric nTruncatedInserts) {
super(nativeSchemaObjects, nTruncatedInserts);
}
// For JMSSink operator, convert the incoming tuple to a JMS StreamMessage
public Message convertTupleToMessage(Tuple tuple, Session session)
throws JMSException {
// create a new StreamMessage
StreamMessage message;
synchronized (session) {
message = session.createStreamMessage();
}
// variable to specify if any of the attributes in the message is
// truncated
boolean isTruncated = false;
// get the attributes from the native schema
for (NativeSchema currentObject : nativeSchemaObjects) {
// iterate through the native schema elements
// extract the name, type and length
final String name = currentObject.getName();
final NativeTypes type = currentObject.getType();
final int length = currentObject.getLength();
// handle based on the data-type
switch (type) {
// For all cases, IllegalArgumentException and NPE(for setBytes) is
// not caught since name is always verified and is not null or not
// empty string.
case Bytes: {
// extract the blob from the tuple
// get its size
Blob bl = tuple.getBlob(name);
long size = bl.getLength();
// check for length in native schema
// if the length of the blob is greater than the length
// specified in native schema
// set the isTruncated to true
// truncate the blob
if (size > length && length != LENGTH_ABSENT_IN_NATIVE_SCHEMA) {
isTruncated = true;
size = length;
}
// set the bytes in the message
byte[] blobdata = new byte[(int) size];
bl.getByteBuffer(0, (int) size).get(blobdata);
message.writeBytes(blobdata);
}
break;
case String: {
switch (tuple.getStreamSchema().getAttribute(name).getType()
.getMetaType()) {
case RSTRING:
case USTRING:
// extract the String
// get its length
String rdata = tuple.getString(name);
int size = rdata.length();
// If no length was specified in native schema or
// if the length of the String rdata is less than the length
// specified in native schema
if (length == LENGTH_ABSENT_IN_NATIVE_SCHEMA
|| size <= length) {
message.writeString(rdata);
}
// if the length of rdate is greater than the length
// specified in native schema
// set the isTruncated to true
// truncate the String
else if (size > length) {
isTruncated = true;
String stringdata = rdata.substring(0, length);
message.writeString(stringdata);
}
break;
// spl types decimal32, decimal64,decimal128, timestamp are
// mapped to String.
case DECIMAL32:
case DECIMAL64:
case DECIMAL128:
message.writeString(tuple.getBigDecimal(name).toString());
break;
case TIMESTAMP:
message.writeString((tuple.getTimestamp(name)
.getTimeAsSeconds()).toString());
break;
}
}
break;
case Byte:
message.writeByte(tuple.getByte(name));
break;
case Short:
message.writeShort(tuple.getShort(name));
break;
case Int:
message.writeInt(tuple.getInt(name));
break;
case Long:
message.writeLong(tuple.getLong(name));
break;
case Float:
message.writeFloat(tuple.getFloat(name));
break;
case Double:
message.writeDouble(tuple.getDouble(name));
break;
case Boolean:
message.writeBoolean(tuple.getBoolean(name));
break;
}
}
// if the isTruncated boolean is set, increment the metric
// nTruncatedInserts
if (isTruncated) {
nTruncatedInserts.incrementValue(1);
}
return message;
}
// For JMSSource operator, convert the incoming JMS MapMessage to tuple
public MessageAction convertMessageToTuple(Message message,
OutputTuple tuple) throws JMSException {
// We got a wrong message type so throw an error
if (!(message instanceof StreamMessage)) {
return MessageAction.DISCARD_MESSAGE_WRONG_TYPE;
}
StreamMessage streamMessage = (StreamMessage) message;
// Iterate through the native schema attributes
for (NativeSchema currentObject : nativeSchemaObjects) {
// Added the try catch block to catch the MessageEOFException
// This exception must be thrown when an unexpected end of stream
// has been reached when a StreamMessage is being read.
try {
// extract the name and type
final String name = currentObject.getName();
final NativeTypes type = currentObject.getType();
// handle based on data-tye
// extract the data from the message for each native schema
// attrbute and set into the tuple
switch (type) {
case Byte:
byte byteData = streamMessage.readByte();
// we are interested in this currentObject only if it is
// present in streams schema
if (currentObject.getIsPresentInStreamSchema()) {
tuple.setByte(name, byteData);
}
break;
case Short:
short shortData = streamMessage.readShort();
// we are interested in this currentObject only if it is
// present in streams schema
if (currentObject.getIsPresentInStreamSchema()) {
tuple.setShort(name, shortData);
}
break;
case Int:
int intData = streamMessage.readInt();
// we are interested in this currentObject only if it is
// present in streams schema
if (currentObject.getIsPresentInStreamSchema()) {
tuple.setInt(name, intData);
}
break;
case Long:
long longData = streamMessage.readLong();
// we are interested in this currentObject only if it is
// present in streams schema
if (currentObject.getIsPresentInStreamSchema()) {
tuple.setLong(name, longData);
}
break;
case Float:
float floatData = streamMessage.readFloat();
// we are interested in this currentObject only if it is
// present in streams schema
if (currentObject.getIsPresentInStreamSchema()) {
tuple.setFloat(name, floatData);
}
break;
case Double:
double doubleData = streamMessage.readDouble();
// we are interested in this currentObject only if it is
// present in streams schema
if (currentObject.getIsPresentInStreamSchema()) {
tuple.setDouble(name, doubleData);
}
break;
case Boolean:
boolean booleanData = streamMessage.readBoolean();
// we are interested in this currentObject only if it is
// present in streams schema
if (currentObject.getIsPresentInStreamSchema()) {
tuple.setBoolean(name, booleanData);
}
break;
case String:
switch (tuple.getStreamSchema().getAttribute(name)
.getType().getMetaType()) {
case RSTRING:
case USTRING:
String stringData = streamMessage.readString();
// we are interested in this currentObject only if it is
// present in streams schema
if (currentObject.getIsPresentInStreamSchema()) {
tuple.setString(name, stringData);
}
break;
case DECIMAL32:
case DECIMAL64:
case DECIMAL128: {
BigDecimal bigDecValue = new BigDecimal(
streamMessage.readString());
// we are interested in this currentObject only if it is
// present in streams schema
if (currentObject.getIsPresentInStreamSchema()) {
tuple.setBigDecimal(name, bigDecValue);
}
}
break;
case TIMESTAMP: {
BigDecimal bigDecValue = new BigDecimal(
streamMessage.readString());
// we are interested in this currentObject only if it is
// present in streams schema
if (currentObject.getIsPresentInStreamSchema()) {
tuple.setTimestamp(name,
Timestamp.getTimestamp(bigDecValue));
}
}
break;
}
break;
}
} catch (MessageEOFException meofEx) {
return MessageAction.DISCARD_MESSAGE_EOF_REACHED;
} catch (MessageNotReadableException mnrEx) {
return MessageAction.DISCARD_MESSAGE_UNREADABLE;
} catch (MessageFormatException mfEx) {
return MessageAction.DISCARD_MESSAGE_MESSAGE_FORMAT_ERROR;
}
}// end for
// Messsage was successfully read
return MessageAction.SUCCESSFUL_MESSAGE;
}
}