/*******************************************************************************
* Copyright (C) 2013, 2014, International Business Machines Corporation
* All Rights Reserved
*******************************************************************************/
package com.ibm.streamsx.messaging.jms;
import java.util.List;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.ibm.streams.operator.Tuple;
import com.ibm.streams.operator.metrics.Metric;
import com.ibm.streams.operator.types.Blob;
//This class handles the wbe22 message type
class XMLTextMessageHandler extends BaseXMLMessageHandler {
// the document builder
private DocumentBuilder documentBuilder;
// constructor
public XMLTextMessageHandler(List<NativeSchema> nativeSchemaObjects,
String eventName) throws ParserConfigurationException,
TransformerConfigurationException {
// call the base class constructor to initialize the native schema
// attributes and event name
super(nativeSchemaObjects, eventName);
documentBuilder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
}
// constructor
public XMLTextMessageHandler(List<NativeSchema> nativeSchemaObjects,
String eventName, Metric nTruncatedInserts)
throws ParserConfigurationException,
TransformerConfigurationException {
// call the base class constructor to initialize the native schema
// attributes,nTruncatedInserts and event name
super(nativeSchemaObjects, eventName, nTruncatedInserts);
documentBuilder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
}
// For JMSSink operator, convert the incoming tuple to a JMS TextMessage
public Message convertTupleToMessage(Tuple tuple, Session session)
throws JMSException, ParserConfigurationException,
TransformerException {
// create a new TextMessage
TextMessage message;
synchronized (session) {
message = (TextMessage) session.createTextMessage();
}
// create document element
Document document;
// Since there are not thread safe
synchronized (documentBuilder) {
document = documentBuilder.newDocument();
}
// create elements for constructing the xml document
// with spl xml data type format
Element attr;
// creates an element for root tuple
Element rootElement = document.createElement("tuple"); //$NON-NLS-1$
rootElement.setAttribute("xmlns", //$NON-NLS-1$
"http://www.ibm.com/xmlns/prod/streams/spl/tuple"); //$NON-NLS-1$
// variable to specify if any of the attributes in the message is
// truncated
boolean isTruncated = false;
String stringdata = new String();
for (NativeSchema currentObject : nativeSchemaObjects) {
// iterate through the native schema elements
// extract the name, type and length
final String name = currentObject.getName();
final int length = currentObject.getLength();
attr = document.createElement("attr"); // create another //$NON-NLS-1$
// element
attr.setAttribute("name", name); //$NON-NLS-1$
attr.setAttribute("type", tuple.getStreamSchema() //$NON-NLS-1$
.getAttribute(name).getType().getLanguageType());
// handle based on data type
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) {
stringdata = 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;
stringdata = rdata.substring(0, length);
}
}
break;
// spl types decimal32, decimal64,decimal128, timestamp are mapped
// to String.
case TIMESTAMP: {
stringdata = (tuple.getTimestamp(name).getTimeAsSeconds())
.toString();
}
break;
case DECIMAL32:
case DECIMAL64:
case DECIMAL128: {
stringdata = tuple.getBigDecimal(name).toString();
}
break;
case BLOB: {
// extract the blob
// get its length
Blob bl = tuple.getBlob(name);
long size = bl.getLength();
// 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);
// set the bytes into the messaage
StringBuilder sb = new StringBuilder();
for (byte b : blobdata)
sb.append(String.format("%02x", b & 0xff)); //$NON-NLS-1$
stringdata = sb.toString();
}
break;
default:
stringdata = tuple.getString(name);
break;
}
attr.appendChild(document.createTextNode((stringdata)));
rootElement.appendChild(attr); // add element1 under rootElement
}
document.appendChild(rootElement); // add the rootElement to the
// document
// set the message
message.setText(createFinalDocument(document));
// if the isTruncated boolean is set, increment the metric
// nTruncatedInserts
if (isTruncated) {
nTruncatedInserts.incrementValue(1);
}
return message;
}// convert end
}