/******************************************************************************* * Copyright (C) 2013, 2014, International Business Machines Corporation * All Rights Reserved *******************************************************************************/ package com.ibm.streamsx.messaging.jms; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.ibm.streams.operator.Attribute; import com.ibm.streams.operator.StreamSchema; import com.ibm.streams.operator.Type; import com.ibm.streams.operator.Type.MetaType; import com.ibm.streamsx.messaging.jms.Messages; //This class parses and validates the connections document class ConnectionDocumentParser { // Variable to hold the supported SPL data types for the adapter private static final Set<String> supportedSPLTypes = new HashSet<String>(Arrays.asList("int8", "uint8", "int16", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ "uint16", "int32", "uint32", "int64", "float32", "float64", "boolean", "blob", "rstring", "uint64", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ "decimal32", "decimal64", "decimal128", "ustring", "timestamp", "xml")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ // If the length is absent in native schema, we use -999 static final int LENGTH_ABSENT_IN_NATIVE_SCHEMA = -999; // Variable to hold msgClass private MessageClass msgClass; // variables to connection related parameters in connection specification // document // context Factory private String initialContextFactory; // provider URL private String providerURL; // connection Factory private String connectionFactory; // destination private String destination; // delivery Mode can be persistent or non_persistent, default is persistent private String deliveryMode; // user Principal private String userPrincipal; // user Credentials private String userCredential; // variables to hold the native schema attributes which are specified in // connection document private List<NativeSchema> nativeSchemaObjects = new ArrayList<NativeSchema>(); // Variable to create a mapping table for mapping between SPL datatypes and // their equivalent native schema data type for different message classes // mapping for JMSBytes Message class private final static HashMap<String, String> mapSPLToNativeSchemaDataTypesForBytes; // mapping for JMSText Message class private final static HashMap<String, String> mapSPLToNativeSchemaDataTypesForText; // mapping for other Message classes like JMSStream and JMS Map Message // class private final static HashMap<String, String> mapSPLToNativeSchemaDataTypesForOtherMsgClass; // static initializer blocks for above static { mapSPLToNativeSchemaDataTypesForBytes = new HashMap<String, String>(); mapSPLToNativeSchemaDataTypesForOtherMsgClass = new HashMap<String, String>(); mapSPLToNativeSchemaDataTypesForText = new HashMap<String, String>(); // method to populate mapSPLToNativeSchemaDataTypesForOtherMsgClass mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("int8", "Byte"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("uint8", "Byte"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("int16", "Short"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("uint16", "Short"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("int32", "Int"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("uint32", "Int"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("int64", "Long"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("uint64", "Long"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("float32", "Float"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("float64", "Double"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("boolean", "Boolean"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("blob", "Bytes"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("rstring", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("ustring", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("decimal32", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("decimal64", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("decimal128", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("timestamp", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForOtherMsgClass.put("xml", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("int8", "Byte"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("uint8", "Byte"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("int16", "Short"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("uint16", "Short"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("int32", "Int"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("uint32", "Int"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("int64", "Long"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("uint64", "Long"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("float32", "Float"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("float64", "Double"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("boolean", "Boolean"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("blob", "Bytes"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("rstring", "Bytes"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("ustring", "Bytes"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("decimal32", "Bytes"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("decimal64", "Bytes"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("decimal128", "Bytes"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("timestamp", "Bytes"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForBytes.put("xml", "Bytes"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("int8", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("uint8", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("int16", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("uint16", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("int32", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("uint32", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("int64", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("uint64", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("float32", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("float64", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("boolean", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("blob", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("rstring", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("ustring", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("decimal32", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("decimal64", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("decimal128", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("timestamp", "String"); //$NON-NLS-1$ //$NON-NLS-2$ mapSPLToNativeSchemaDataTypesForText.put("xml", "String"); //$NON-NLS-1$ //$NON-NLS-2$ } // getter for NativeSchemaObjects public List<NativeSchema> getNativeSchemaObjects() { return nativeSchemaObjects; } // getter for initialContextFactory public String getInitialContextFactory() { return initialContextFactory; } // getter for providerURL public String getProviderURL() { return providerURL; } // getter for destination public String getDestination() { return destination; } // getter for DeliveryMode public String getDeliveryMode() { return deliveryMode; } // getter for userPrinical public String getUserPrincipal() { return userPrincipal; } // getter for userCredential public String getUserCredential() { return userCredential; } // getter for connectionFactory public String getConnectionFactory() { return connectionFactory; } // getter for MessageType public MessageClass getMessageType() { return msgClass; } // Convert relative provider url path to absolute path for wmq only. // non-absolute path should be relative to application directory. // i.e file:./etc/ will be converted to applicationDir + ./etc/ private void convertProviderURLPath(File applicationDir) throws ParseConnectionDocumentException { if(!isAMQ()) { // provider_url can not be empty if(this.providerURL == null || this.providerURL.trim().length() == 0) { throw new ParseConnectionDocumentException(Messages.getString("PROVIDER_URL_MUST_BE_SPECIFIED_IN_CONN_DOC")); //$NON-NLS-1$ } // provider_url has a value specified try { URL url = new URL(providerURL); // We only care about url with file scheme. if("file".equalsIgnoreCase(url.getProtocol())) { //$NON-NLS-1$ String path = url.getPath(); // relative path is considered being relative to the application directory if(!path.startsWith("/")) { //$NON-NLS-1$ URL absProviderURL = new URL(url.getProtocol(), url.getHost(), applicationDir.getAbsolutePath() + File.separator + path); this.providerURL = absProviderURL.toExternalForm(); } } } catch (MalformedURLException e) { throw new ParseConnectionDocumentException(Messages.getString("INVALID_PROVIDER_URL", e.getMessage())); //$NON-NLS-1$ } } } // subroutine to parse and validate the connection document // called by both the JMSSink and JMSSource public void parseAndValidateConnectionDocument(String connectionDocument, String connection, String access, StreamSchema streamSchema, boolean isProducer, File applicationDir) throws ParseConnectionDocumentException, SAXException, IOException, ParserConfigurationException { // validate the connections document against the xsd validateConnectionsXML(connectionDocument); // create document builder Element docEle = createDocumentBuilder(connectionDocument); // parse validate the connection_specification tag in connections // document parseConnSpecElement(connection, docEle); // parse validate the access_specification tag in connections document Node nativeSchema = parseAccessSpecElement(connection, access, docEle); // perform validations common to JMSSink and JMSSource connDocChecksCommonToSourceSink(streamSchema, nativeSchema); // perform validations for JMSSource if (!isProducer) { connDocChecksSource(streamSchema); } // perform native schema validations if (msgClass != MessageClass.empty) { nativeSchemaChecks(isProducer, streamSchema, nativeSchema); } // convert provider_url to absolute if needed convertProviderURLPath(applicationDir); } // subroutine to validate the connections document against the xsd private void validateConnectionsXML(String connectionDocument) throws SAXException, IOException { // validate against the xsd, if validation error occurs, it throws the // error and aborts at runtime SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); // read schema from classpath InputStream resourceAsStream = getClass().getResourceAsStream("jmsconnection.xsd"); //$NON-NLS-1$ Source streamSource = new StreamSource(resourceAsStream); Schema schema = factory.newSchema(streamSource); Validator validator = schema.newValidator(); Source source = new StreamSource(connectionDocument); validator.validate(source); } // subroutine to create document builder private Element createDocumentBuilder(String connectionDocument) throws ParserConfigurationException, IOException, SAXException { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(connectionDocument); Element docEle = doc.getDocumentElement(); return docEle; } // subroutine to parse validate the connection_specification tag in // connections document private void parseConnSpecElement(String connection, Element docEle) throws ParseConnectionDocumentException { // variable to specify if the connection_specification name as specified // in the connection parameter of the operator model is found. // set to true if its found, false otherwise boolean connectionFound = false; // extract the connection_specification elements NodeList connection_specification = docEle.getElementsByTagName("connection_specification"); //$NON-NLS-1$ // iterate through the list to verify if the connection_specification // with value as connection exists for (int i = 0; i < connection_specification.getLength(); i++) { if (connection.equals(connection_specification.item(i).getAttributes().getNamedItem("name").getNodeValue())) { //$NON-NLS-1$ // found connection_specification int jmsIndex = -1; // Extract the child nodes NodeList connSpecChildNodes = connection_specification.item(i).getChildNodes(); // verify if it has a JMS tag for (int j = 0; j < connSpecChildNodes.getLength(); j++) { if (connSpecChildNodes.item(j).getNodeName().equals("JMS")) { //$NON-NLS-1$ jmsIndex = j; break; } } // extract the jms element Node destination = connSpecChildNodes.item(jmsIndex); // extract the provider URL from the JMS element providerURL = destination.getAttributes().getNamedItem("provider_url").getNodeValue(); //$NON-NLS-1$ // extract the initialContext from the JMS element initialContextFactory = destination.getAttributes().getNamedItem("initial_context").getNodeValue(); //$NON-NLS-1$ // extract the connectionFactory from the JMS element connectionFactory = destination.getAttributes().getNamedItem("connection_factory").getNodeValue(); //$NON-NLS-1$ // check if optional elements user and password are specified // if speciifed extract those if (destination.getAttributes().getNamedItem("user") != null) { //$NON-NLS-1$ userPrincipal = destination.getAttributes().getNamedItem("user").getNodeValue(); //$NON-NLS-1$ } if (destination.getAttributes().getNamedItem("password") != null) { //$NON-NLS-1$ userCredential = destination.getAttributes().getNamedItem("password").getNodeValue(); //$NON-NLS-1$ } // Verify if either both user and password are present or none // is present // throw a ParseConnectionDocumentException otherwise if (userPrincipal == null && userCredential != null || userPrincipal != null && userCredential == null) { throw new ParseConnectionDocumentException(Messages.getString("USERPRINCIPAL_AND_USERCREDENTIAL_MUST_BE_SET")); //$NON-NLS-1$ } // set the connectionFound to true connectionFound = true; break; } } // throw ParseConnectionDocumentException if the connection value // specified in the parameter is not found in the connection document if (!connectionFound) { throw new ParseConnectionDocumentException(Messages.getString("VALUE_OF_CONNECTION_PARAM_NOT_FOUND_IN_CONN_DOC", connection)); //$NON-NLS-1$ } return; } // subroutine to parse validate the access_specification tag in connections // document private Node parseAccessSpecElement(String connection, String access, Element docEle) throws ParseConnectionDocumentException { // variable to specify if the access_specification name as specified in // the access parameter of the operator model is found. // set to true if its found, false otherwise boolean accessFound = false; // native schema attribute list Node nativeSchema = null; // extract the access_specification node list NodeList access_specification = docEle.getElementsByTagName("access_specification"); //$NON-NLS-1$ // iterate through the node list to find the access_specification // element with value as access paramter for (int i = 0; i < access_specification.getLength(); i++) { if (access.equals(access_specification.item(i).getAttributes().getNamedItem("name").getNodeValue())) { //$NON-NLS-1$ // access_specification element found accessFound = true; int destIndex = -1; int nativeSchemaIndex = -1; // get the child nodes NodeList accessSpecChildNodes = access_specification.item(i).getChildNodes(); // iterate througgh the child nodes to find all the required // elements for (int j = 0; j < accessSpecChildNodes.getLength(); j++) { if (accessSpecChildNodes.item(j).getNodeName().equals("destination")) { //$NON-NLS-1$ // extract destination destIndex = j; } else if (accessSpecChildNodes.item(j).getNodeName().equals("uses_connection")) { //$NON-NLS-1$ // check if the uses_connection uses the same // connections as specified // in the SPL under connection parameter. Else throw // ParseConnectionDocumentException if (!connection.equals(accessSpecChildNodes.item(j).getAttributes().getNamedItem("connection") //$NON-NLS-1$ .getNodeValue())) { throw new ParseConnectionDocumentException(Messages.getString("VALUE_OF_CONNECTION_PARAM_NOT_THE_SAME_AS_CONN_USED_BY_ACCESS_ELEMENT", connection, access )); //$NON-NLS-1$ } } else if (accessSpecChildNodes.item(j).getNodeName().equals("native_schema")) { //$NON-NLS-1$ nativeSchemaIndex = j; } } String messageClass; // get the destination node Node dest = accessSpecChildNodes.item(destIndex); // get the destination value destination = dest.getAttributes().getNamedItem("identifier").getNodeValue(); //$NON-NLS-1$ // get the message class messageClass = dest.getAttributes().getNamedItem("message_class").getNodeValue(); //$NON-NLS-1$ // get the delivery mode if its present if (dest.getAttributes().getNamedItem("delivery_mode") != null) { //$NON-NLS-1$ deliveryMode = dest.getAttributes().getNamedItem("delivery_mode").getNodeValue(); //$NON-NLS-1$ } // Extract the message class msgClass = MessageClass.valueOf(messageClass.trim()); // get the native schema node list, it will not be present for // empty message class if (accessSpecChildNodes.item(nativeSchemaIndex) != null) { nativeSchema = access_specification.item(i).getChildNodes().item(nativeSchemaIndex); } break; } } // if accessFound is false , throw ParseConnectionDocumentException if (!accessFound) { throw new ParseConnectionDocumentException(Messages.getString("VALUE_OF_ACCESS_PARAM_NOT_FOUND_IN_CONN_DOC", access )); //$NON-NLS-1$ } return nativeSchema; } // subroutine to perform validations common for JMSSource and JMSSink private void connDocChecksCommonToSourceSink(StreamSchema streamSchema, Node nativeSchema) throws ParseConnectionDocumentException { // Native schema should be present for all message classes except empty // throw ParseConnectionDocumentException otherwise if (nativeSchema == null && msgClass != MessageClass.empty) { throw new ParseConnectionDocumentException(Messages.getString("NATIVE_SCHEMA_MUST_BE_SPECIFIED_FOR_MESSAGE_CLASS", msgClass)); //$NON-NLS-1$ } // Native schema should not be present for message class empty // if present throw ParseConnectionDocumentException if (nativeSchema != null && msgClass == MessageClass.empty) { throw new ParseConnectionDocumentException(Messages.getString("NATIVE_SCHEMA_CANNOT_BE_SPECIFIED_WITH_MSG_CLASS_EMPTY")); //$NON-NLS-1$ } // check if attributes in streamschema are of supported type // or not for (Attribute attr : streamSchema) { String streamAttrName = attr.getName(); MetaType streamAttrMetaType = attr.getType().getMetaType(); if (!supportedSPLTypes.contains(streamAttrMetaType.getLanguageType())) { throw new ParseConnectionDocumentException(Messages.getString("ATTRIB_TYPE_FOR_STREAM_ATTRIB_NOT_SUPPORTED_SPL_TYPE", streamAttrMetaType.getLanguageType(), streamAttrName )); //$NON-NLS-1$ } } return; } // subroutine to perform validations for JMSSource private void connDocChecksSource(StreamSchema streamSchema) throws ParseConnectionDocumentException { // Message classes xml, wbe and wbe22 are not allowed for JMSSource // throw ParseConnectionDocumentException if specified if (msgClass == MessageClass.xml || msgClass == MessageClass.wbe || msgClass == MessageClass.wbe22) { throw new ParseConnectionDocumentException( Messages.getString("UNSUPPORTED_MSG_CLASSES_FOR_JMSSOURCE")); //$NON-NLS-1$ } for (Attribute attr : streamSchema) { MetaType streamAttrMetaType = attr.getType().getMetaType(); // If the adapter is JMSSource, we dont support blob // type if (streamAttrMetaType == Type.MetaType.BLOB) { throw new ParseConnectionDocumentException(Messages.getString("BLOB_NOT_SUPPORTED_FOR_JMSSOURCE")); //$NON-NLS-1$ } } return; } // subroutine to perform native schema validations private void nativeSchemaChecks(boolean isProducer, StreamSchema streamSchema, Node nativeSchema) throws ParseConnectionDocumentException { // get the attribute list NodeList attrList = nativeSchema.getChildNodes(); for (int i = 0; i < attrList.getLength(); i++) { if (attrList.item(i).hasAttributes()) { // extract the native schema attribute name, type and length String nativeAttrName = (attrList.item(i).getAttributes().getNamedItem("name").getNodeValue()); //$NON-NLS-1$ String nativeAttrType = (attrList.item(i).getAttributes().getNamedItem("type").getNodeValue()); //$NON-NLS-1$ int nativeAttrLength; // if length is not specified for that parameter if (attrList.item(i).getAttributes().getNamedItem("length") == null) { //$NON-NLS-1$ nativeAttrLength = LENGTH_ABSENT_IN_NATIVE_SCHEMA; } else { nativeAttrLength = Integer.parseInt((attrList.item(i).getAttributes().getNamedItem("length") //$NON-NLS-1$ .getNodeValue())); } // Do not support blob data type if message class is wbe, wbe22 if ((msgClass == MessageClass.wbe || msgClass == MessageClass.wbe22) && ((streamSchema.getAttribute(nativeAttrName) != null) && (streamSchema .getAttribute(nativeAttrName).getType().getMetaType() == Type.MetaType.BLOB))) { throw new ParseConnectionDocumentException(Messages.getString("BLOB_NOT_SUPPORTED_FOR_MSG_CLASS", msgClass)); //$NON-NLS-1$ } // validate that the attribute name is not already // existing in the native schema Iterator<NativeSchema> it = nativeSchemaObjects.iterator(); while (it.hasNext()) { if (it.next().getName().equals(nativeAttrName)) { throw new ParseConnectionDocumentException(Messages.getString("PARAMETER_NOT_UNIQUE_IN_NATIVE_SCHEMA", nativeAttrName )); //$NON-NLS-1$ } } // set to hold the data types which can have length specified in // native schema Set<String> typesWithLength = new HashSet<String>(Arrays.asList("String", "Bytes")); //$NON-NLS-1$ //$NON-NLS-2$ // if message class is text, length on String attribute type is // optional if (msgClass == MessageClass.text) { typesWithLength = new HashSet<String>(Arrays.asList("Bytes")); //$NON-NLS-1$ } // set to hold the data types which can not have length // specified in native schema Set<String> typesWithoutLength = new HashSet<String>(Arrays.asList("Byte", "Short", "Int", "Long", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "Float", "Double", "Boolean")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ // Length value should not be present if the data type belongs // to typesWithoutLength if (typesWithoutLength.contains(nativeAttrType) && nativeAttrLength != LENGTH_ABSENT_IN_NATIVE_SCHEMA) { throw new ParseConnectionDocumentException(Messages.getString("LENGTH_ATTRIB_SHOULD_NOT_BE_PRESENT_FOR_PARAM_IN_NATIVE_SCHEMA", nativeAttrName )); //$NON-NLS-1$ } // Since for xml, wbe and wbe22 all the String, a new check is // required if ((nativeAttrLength != LENGTH_ABSENT_IN_NATIVE_SCHEMA) && (msgClass == MessageClass.wbe || msgClass == MessageClass.wbe22 || msgClass == MessageClass.xml) && (streamSchema.getAttribute(nativeAttrName) != null) && (streamSchema.getAttribute(nativeAttrName).getType().getMetaType() != Type.MetaType.RSTRING) && (streamSchema.getAttribute(nativeAttrName).getType().getMetaType() != Type.MetaType.USTRING) && (streamSchema.getAttribute(nativeAttrName).getType().getMetaType() != Type.MetaType.BLOB)) { throw new ParseConnectionDocumentException(Messages.getString("LENGTH_ATTRIB_SHOULD_NOT_BE_PRESENT_FOR_PARAM_IN_NATIVE_SCHEMA", nativeAttrName )); //$NON-NLS-1$ } // Since decimal32, decimal64, decimal128 and timestamp are // mapped to bytes for message class bytes // and in message class bytes, since String/Bytes expect a // length, we, set a default length of -4. // Add a check that Streamschema has this particular native // schema attribute if (streamSchema.getAttribute(nativeAttrName) != null) { MetaType metaType = streamSchema.getAttribute(nativeAttrName).getType().getMetaType(); if (metaType == Type.MetaType.DECIMAL32 || metaType == Type.MetaType.DECIMAL64 || metaType == Type.MetaType.DECIMAL128 || metaType == Type.MetaType.TIMESTAMP) { if (nativeAttrLength != LENGTH_ABSENT_IN_NATIVE_SCHEMA) { throw new ParseConnectionDocumentException( Messages.getString("LENGTH_ATTRIB_SHOULD_NOT_BE_PRESENT_FOR_PARAM_WITH_TYPE_IN_NATIVE_SCHEMA", nativeAttrName, metaType )); //$NON-NLS-1$ } if (msgClass == MessageClass.bytes) { nativeAttrLength = -4; } } } // Length value should be present if the data type belongs to // typesWithLength and message class is bytes if (typesWithLength.contains(nativeAttrType)) { if (nativeAttrLength == LENGTH_ABSENT_IN_NATIVE_SCHEMA && msgClass == MessageClass.bytes) { throw new ParseConnectionDocumentException(Messages.getString("LENGTH_ATTRIB_SHOULD_NOT_BE_PRESENT_FOR_PARAM_IN_NATIVE_SCHEMA_FOR_MSG_CLASS_BYTES", nativeAttrName )); //$NON-NLS-1$ } // Length attribute can be non negative -2,-4 only for // message class bytes if ((nativeAttrLength < 0) && nativeAttrLength != LENGTH_ABSENT_IN_NATIVE_SCHEMA) { if (msgClass != MessageClass.bytes) { throw new ParseConnectionDocumentException( Messages.getString("LENGTH_ATTRIB_CAN_BE_NONNEG-2-4_ONLY_FOR_MSG_CLASS_BYTES_FOR_PARAM_IN_NATIVE_SCHEMA", nativeAttrName )); //$NON-NLS-1$ } // If the Length attribute is non negative, it can only // be -2,-4 for message class bytes if (nativeAttrLength != -2 && nativeAttrLength != -4) { throw new ParseConnectionDocumentException( Messages.getString("LENGTH_ATTRIB_SHOULD_BE_NONNEG-2-4_FOR_PARAM_IN_NATIVE_SCHEMA", nativeAttrName )); //$NON-NLS-1$ } } } // validate if the input port stream schema contains this // attributes from the // native schema file if (streamSchema.getAttribute(nativeAttrName) == null && isProducer == true) { // for JMSSink , each and every attribute in // native schema // should be present in input stream throw new ParseConnectionDocumentException(Messages.getString("ATTRIB_WITH_TYPE_IN_NATIVE_SCHEMA_NOT_FOUND_IN_STREAM_SCHEMA", nativeAttrName, nativeAttrType )); //$NON-NLS-1$ } // Here we are comparing the data type of the native schema // attribute with the stream schema attribute of the same name // and throw an error if a mismatch happens String streamAttrName; MetaType streamAttrMetaType = null; if (streamSchema.getAttribute(nativeAttrName) != null) { streamAttrName = streamSchema.getAttribute(nativeAttrName).getName(); streamAttrMetaType = streamSchema.getAttribute(nativeAttrName).getType().getMetaType(); // for message classes map and stream if ((msgClass == MessageClass.stream || msgClass == MessageClass.map) && !mapSPLToNativeSchemaDataTypesForOtherMsgClass.get(streamAttrMetaType.getLanguageType()) .equals(nativeAttrType)) { throw new ParseConnectionDocumentException(Messages.getString("ATTRIB_WITH_TYPE_IN_NATIVE_SCHEMA_CANNOT_BE_MAPPED_TO_ATTRIB_WITH_TYPE", nativeAttrName, nativeAttrType, streamAttrName, streamAttrMetaType.getLanguageType())); //$NON-NLS-1$ } // for message class bytes else if (msgClass == MessageClass.bytes && !mapSPLToNativeSchemaDataTypesForBytes.get(streamAttrMetaType.getLanguageType()).equals( nativeAttrType)) { throw new ParseConnectionDocumentException(Messages.getString("ATTRIB_WITH_TYPE_IN_NATIVE_SCHEMA_CANNOT_BE_MAPPED_TO_ATTRIB_WITH_TYPE", nativeAttrName, nativeAttrType, streamAttrName, streamAttrMetaType.getLanguageType())); //$NON-NLS-1$ } // for message classes xml,wbe,wbe22 else if ((msgClass == MessageClass.wbe || msgClass == MessageClass.wbe22 || msgClass == MessageClass.xml) && !mapSPLToNativeSchemaDataTypesForText.get(streamAttrMetaType.getLanguageType()).equals( nativeAttrType)) { throw new ParseConnectionDocumentException(Messages.getString("ATTRIB_WITH_TYPE_IN_NATIVE_SCHEMA_CANNOT_BE_MAPPED_TO_ATTRIB_WITH_TYPE", nativeAttrName, nativeAttrType, streamAttrName, streamAttrMetaType.getLanguageType())); //$NON-NLS-1$ } else if (msgClass == MessageClass.text) { if (streamAttrMetaType != MetaType.RSTRING && streamAttrMetaType != MetaType.USTRING && streamAttrMetaType != MetaType.XML) { throw new ParseConnectionDocumentException(Messages.getString("ATTRIB_IN_SPL_SCHEMA_MUST_BE_RSTRING_USTRING_OR_XML", streamAttrName)); //$NON-NLS-1$ } if (!nativeAttrType.equals("String")) //$NON-NLS-1$ { throw new ParseConnectionDocumentException(Messages.getString("ATTRIB_WITH_TYPE_IS_INVALID_MUST_BE_STRING", nativeAttrName, nativeAttrType )); //$NON-NLS-1$ } } } // the native schema parameter is valid, add to list NativeSchema currentObject; // if the paramter is present in streams schema, set the // isPresentInStreamSchema to true // else set it ti false if (streamSchema.getAttribute(nativeAttrName) == null) { currentObject = new NativeSchema(nativeAttrName, NativeTypes.valueOf(nativeAttrType), nativeAttrLength, false); } else { currentObject = new NativeSchema(nativeAttrName, NativeTypes.valueOf(nativeAttrType), nativeAttrLength, true); } nativeSchemaObjects.add(currentObject); } } // additional checks for message class text if (msgClass == MessageClass.text) { // for message class text, only allow one attribute on native schema if (nativeSchemaObjects.size() != 1) { throw new ParseConnectionDocumentException( Messages.getString("NATIVE_SCHEMA_CANNOT_CONTAIN_MORE_THAN_ONE_ATTRIB_WITH_MSG_CLASS_TXT")); //$NON-NLS-1$ } } return; } // subroutine to verify if the JMSProvider is Active MQ public boolean isAMQ() { if (initialContextFactory.contains("activemq")) { //$NON-NLS-1$ return true; } return false; } }