/******************************************************************************* * 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.MapMessage; import javax.jms.Message; import javax.jms.MessageFormatException; import javax.jms.Session; 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 Map message type class MapMessageHandler extends JMSMessageHandlerImpl { // constructor public MapMessageHandler(List<NativeSchema> nativeSchemaObjects) { // call the base class constructor to initialize the native schema // attributes. super(nativeSchemaObjects); } // constructor public MapMessageHandler(List<NativeSchema> nativeSchemaObjects, Metric nTruncatedInserts) { super(nativeSchemaObjects, nTruncatedInserts); } // For JMSSink operator, convert the incoming tuple to a JMS MapMessage public Message convertTupleToMessage(Tuple tuple, Session session) throws JMSException { // create a new mapMessage MapMessage message; synchronized (session) { message = (MapMessage) session.createMapMessage(); } // 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; } byte[] blobdata = new byte[(int) size]; bl.getByteBuffer(0, (int) size).get(blobdata); // Since name is always verified and never null or empty string, // we dont need to catch NPE // set the bytes into the messaage message.setBytes(name, 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.setString(name, 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.setString(name, stringdata); } break; // spl types decimal32, decimal64,decimal128, timestamp are // mapped to String. case DECIMAL32: case DECIMAL64: case DECIMAL128: message.setString(name, tuple.getBigDecimal(name) .toString()); break; case TIMESTAMP: message.setString(name, (tuple.getTimestamp(name) .getTimeAsSeconds()).toString()); break; } } break; case Byte: message.setByte(name, tuple.getByte(name)); break; case Short: message.setShort(name, tuple.getShort(name)); break; case Int: message.setInt(name, tuple.getInt(name)); break; case Long: message.setLong(name, tuple.getLong(name)); break; case Float: message.setFloat(name, tuple.getFloat(name)); break; case Double: message.setDouble(name, tuple.getDouble(name)); break; case Boolean: message.setBoolean(name, tuple.getBoolean(name)); break; } } // if the isTruncated boolean is set, increment the metric // nTruncatedInserts if (isTruncated) { nTruncatedInserts.incrementValue(1); } // return the message return message; } // For JMSSource operator, convert the incoming JMS MapMessage to tuple public MessageAction convertMessageToTuple(Message message, OutputTuple tuple) throws JMSException { if (!(message instanceof MapMessage)) { // We got a wrong message type so throw an error return MessageAction.DISCARD_MESSAGE_WRONG_TYPE; } else { MapMessage mapMessage = (MapMessage) message; // Iterate through the native schema attributes for (NativeSchema currentObject : nativeSchemaObjects) { try { // extract the name, type and length 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 // we are interested in this currentObject only if it is // present in streams schema if (currentObject.getIsPresentInStreamSchema()) switch (type) { case Byte: tuple.setByte(name, mapMessage.getByte(name)); break; case Short: tuple.setShort(name, mapMessage.getShort(name)); break; case Int: tuple.setInt(name, mapMessage.getInt(name)); break; case Long: tuple.setLong(name, mapMessage.getLong(name)); break; case Float: tuple.setFloat(name, mapMessage.getFloat(name)); break; case Double: tuple.setDouble(name, mapMessage.getDouble(name)); break; case Boolean: tuple.setBoolean(name, mapMessage.getBoolean(name)); break; case String: switch (tuple.getStreamSchema().getAttribute(name) .getType().getMetaType()) { case RSTRING: case USTRING: tuple.setString(name, mapMessage.getString(name)); break; case DECIMAL32: case DECIMAL64: case DECIMAL128: { BigDecimal bigDecValue = new BigDecimal( mapMessage.getString(name)); tuple.setBigDecimal(name, bigDecValue); } break; case TIMESTAMP: { BigDecimal bigDecValue = new BigDecimal( mapMessage.getString(name)); tuple.setTimestamp(name, Timestamp.getTimestamp(bigDecValue)); } break; } break; } } catch (MessageFormatException mfEx) { // if MessageFormatException is thrown return MessageAction.DISCARD_MESSAGE_MESSAGE_FORMAT_ERROR; } } // Messsage was successfully read return MessageAction.SUCCESSFUL_MESSAGE; } } }