private static void encodeSchema(final ByteBuffer byteBuffer) throws Exception { final Path path = Paths.get("example-schema.xml"); try (InputStream in = new BufferedInputStream(Files.newInputStream(path))) { final MessageSchema schema = XmlSchemaParser.parse(in, ParserOptions.DEFAULT); final Ir ir = new IrGenerator().generate(schema); try (IrEncoder irEncoder = new IrEncoder(byteBuffer, ir)) { irEncoder.encode(); } } }
/** * Construct a ValidValue given the XML node and the encodingType. * * @param node that contains the validValue * @param encodingType for the enum */ public ValidValue(final Node node, final PrimitiveType encodingType) { name = getAttributeValue(node, "name"); description = getAttributeValueOrNull(node, "description"); value = PrimitiveValue.parse(node.getFirstChild().getNodeValue(), encodingType); sinceVersion = Integer.parseInt(getAttributeValue(node, "sinceVersion", "0")); deprecated = Integer.parseInt(getAttributeValue(node, "deprecated", "0")); checkForValidName(node, name); }
document.setUserData(ERROR_HANDLER_KEY, errorHandler, null); final Map<String, Type> typeByNameMap = findTypes(document, xPath); errorHandler.checkIfShouldExit(); final Map<Long, Message> messageByIdMap = findMessages(document, xPath, typeByNameMap); errorHandler.checkIfShouldExit();
public MessageSchema( final Node schemaNode, final Map<String, Type> typeByNameMap, final Map<Long, Message> messageByIdMap) { this.packageName = getAttributeValue(schemaNode, "package"); this.description = getAttributeValueOrNull(schemaNode, "description"); this.id = Integer.parseInt(getAttributeValue(schemaNode, "id")); this.version = Integer.parseInt(getAttributeValue(schemaNode, "version", "0")); this.semanticVersion = getAttributeValueOrNull(schemaNode, "semanticVersion"); this.byteOrder = getByteOrder(getAttributeValue(schemaNode, "byteOrder", "littleEndian")); this.typeByNameMap = typeByNameMap; this.messageByIdMap = messageByIdMap; final String headerType = getAttributeValueOrNull(schemaNode, "headerType"); this.headerType = null == headerType ? HEADER_TYPE_DEFAULT : headerType; Verify.present(typeByNameMap, this.headerType, "Message header"); ((CompositeType)typeByNameMap.get(this.headerType)).checkForWellFormedMessageHeader(schemaNode); }
/** * Construct a new Type from XML Schema. Called by subclasses to mostly set common fields * * @param node from the XML Schema Parsing * @param givenName of this node, if null then the attributed name will be used. * @param referencedName of the type when created from a ref in a composite. */ public Type(final Node node, final String givenName, final String referencedName) { if (null == givenName) { name = getAttributeValue(node, "name"); } else { name = givenName; } this.referencedName = referencedName; presence = Presence.get(getAttributeValue(node, "presence", "required")); description = getAttributeValueOrNull(node, "description"); sinceVersion = Integer.parseInt(getAttributeValue(node, "sinceVersion", "0")); deprecated = Integer.parseInt(getAttributeValue(node, "deprecated", "0")); semanticType = getAttributeValueOrNull(node, "semanticType"); offsetAttribute = Integer.parseInt(getAttributeValue(node, "offset", "-1")); }
private Field parseGroupField(final NodeList nodeList, final int nodeIndex) throws XPathExpressionException final String dimensionTypeName = getAttributeValue(node, "dimensionType", "groupSizeEncoding"); Type dimensionType = typeByNameMap.get(dimensionTypeName); if (dimensionType == null) handleError(node, "could not find dimensionType: " + dimensionTypeName); handleError(node, "dimensionType should be a composite type: " + dimensionTypeName); dimensionType = null; .name(getAttributeValue(node, "name")) .description(getAttributeValueOrNull(node, "description")) .id(Integer.parseInt(getAttributeValue(node, "id"))) .blockLength(Integer.parseInt(getAttributeValue(node, "blockLength", "0"))) .sinceVersion(Integer.parseInt(getAttributeValue(node, "sinceVersion", "0"))) .deprecated(Integer.parseInt(getAttributeValue(node, "deprecated", "0"))) .dimensionType((CompositeType)dimensionType) .build(); XmlSchemaParser.checkForValidName(node, field.name());
!semanticType.equals(type.semanticType())) handleError(node, "Mismatched semanticType on type and field: " + name); checkForValidName(node, name); handleError(node, "valueRef not set for constant enum"); handleError(node, "valueRef does not match field type: " + valueRef); handleError(node, "valueRef does not match field type: " + valueRef); handleError(node, "valueRef for enum name not found: " + valueRefType);
primitiveType = PrimitiveType.get(getAttributeValue(node, "primitiveType")); final String lengthAttr = getAttributeValueOrNull(node, "length"); length = Integer.parseInt(null == lengthAttr ? "1" : lengthAttr); varLen = Boolean.parseBoolean(getAttributeValue(node, "variableLength", "false")); valueRef = getAttributeValueOrNull(node, "valueRef"); handleError(node, "valueRef format not valid (enum-name.valid-value-name): " + valueRef); handleError(node, "present must be constant when valueRef is set: " + valueRef); characterEncoding = getAttributeValue(node, "characterEncoding", "US-ASCII").trim().toUpperCase(); final String characterEncoding = getAttributeValueOrNull(node, "characterEncoding"); this.characterEncoding = characterEncoding == null ? null : characterEncoding.trim().toUpperCase(); handleError(node, "type has declared presence as \"constant\" but XML node has no data"); constValue = null; final String minValStr = getAttributeValueOrNull(node, "minValue"); minValue = minValStr != null ? PrimitiveValue.parse(minValStr, primitiveType) : null; final String maxValStr = getAttributeValueOrNull(node, "maxValue"); maxValue = maxValStr != null ? PrimitiveValue.parse(maxValStr, primitiveType) : null; final String nullValStr = getAttributeValueOrNull(node, "nullValue"); if (nullValStr != null) handleWarning(node, "nullValue set, but presence is not optional");
private Field parseField(final NodeList nodeList, final int nodeIndex) { final Node node = nodeList.item(nodeIndex); final String typeName = getAttributeValue(node, "type"); final Type fieldType = typeByNameMap.get(typeName); if (fieldType == null) { handleError(node, "could not find type: " + typeName); } final Field field = new Field.Builder() .name(getAttributeValue(node, "name")) .description(getAttributeValueOrNull(node, "description")) .id(Integer.parseInt(getAttributeValue(node, "id"))) .offset(Integer.parseInt(getAttributeValue(node, "offset", "0"))) .semanticType(getAttributeValueOrNull(node, "semanticType")) .presence(getPresence(node, fieldType)) .valueRef(getAttributeValueOrNull(node, "valueRef")) .sinceVersion(Integer.parseInt(getAttributeValue(node, "sinceVersion", "0"))) .deprecated(Integer.parseInt(getAttributeValue(node, "deprecated", "0"))) .epoch(getAttributeValueOrNull(node, "epoch")) .timeUnit(getAttributeValueOrNull(node, "timeUnit")) .type(fieldType) .build(); field.validate(node, typeByNameMap); return field; }
XmlSchemaParser.handleError(node, "composite for variable length data encoding must have \"length\""); if (!isUnsigned(primitiveType)) XmlSchemaParser.handleError(node, "\"length\" must be unsigned type"); XmlSchemaParser.handleWarning(node, "\"length\" should be UINT8, UINT16, or UINT32"); if ("optional".equals(getAttributeValueOrNull(node, "presence"))) XmlSchemaParser.handleError( node, "composite for variable length data encoding cannot have presence=\"optional\""); XmlSchemaParser.handleError(node, "composite for variable length data encoding must have \"varData\"");
private static void addTypeWithNameCheck(final Map<String, Type> typeByNameMap, final Type type, final Node node) { if (typeByNameMap.get(type.name()) != null) { handleWarning(node, "type already exists for name: " + type.name()); } checkForValidName(node, type.name()); typeByNameMap.put(type.name(), type); }
private static void validateBlockLength( final Node node, final long specifiedBlockLength, final long computedBlockLength) { if (0 != specifiedBlockLength && computedBlockLength > specifiedBlockLength) { final String msg = "specified blockLength provides insufficient space " + computedBlockLength + " > " + specifiedBlockLength; handleError(node, msg); } }
/** * Scan XML for all message definitions and save in map * * @param document for the XML parsing * @param xPath for XPath expression reuse * @param typeByNameMap to use for Type objects * @return {@link java.util.Map} of schemaId to Message * @throws Exception on parsing error. */ public static Map<Long, Message> findMessages( final Document document, final XPath xPath, final Map<String, Type> typeByNameMap) throws Exception { final Map<Long, Message> messageByIdMap = new HashMap<>(); final ObjectHashSet<String> distinctNames = new ObjectHashSet<>(); forEach((NodeList)xPath.compile(MESSAGE_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), (node) -> addMessageWithIdCheck(distinctNames, messageByIdMap, new Message(node, typeByNameMap), node)); return messageByIdMap; }
typeByNameMap.put("double", new EncodedDataType("double", REQUIRED, null, null, DOUBLE, 1, false)); forEach((NodeList)xPath.compile(TYPE_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), (node) -> addTypeWithNameCheck(typeByNameMap, new EncodedDataType(node), node)); forEach((NodeList)xPath.compile(COMPOSITE_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), (node) -> addTypeWithNameCheck(typeByNameMap, new CompositeType(node), node)); forEach((NodeList)xPath.compile(ENUM_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), (node) -> addTypeWithNameCheck(typeByNameMap, new EnumType(node), node)); forEach((NodeList)xPath.compile(SET_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), (node) -> addTypeWithNameCheck(typeByNameMap, new SetType(node), node));
/** * Handle an error condition as consequence of parsing. * * @param node that is the context of the warning. * @param msg associated with the error. */ public static void handleError(final Node node, final String msg) { final ErrorHandler handler = (ErrorHandler)node.getOwnerDocument().getUserData(ERROR_HANDLER_KEY); if (handler == null) { throw new IllegalStateException("ERROR: " + formatLocationInfo(node) + msg); } else { handler.error(formatLocationInfo(node) + msg); } }
XmlSchemaParser.handleError(node, "composite for message header must have \"blockLength\""); XmlSchemaParser.handleError(node, "\"blockLength\" must be unsigned"); XmlSchemaParser.handleWarning(node, "\"blockLength\" should be UINT16"); XmlSchemaParser.handleError(node, "composite for message header must have \"templateId\""); XmlSchemaParser.handleWarning(node, "\"templateId\" should be UINT16"); XmlSchemaParser.handleError(node, "composite for message header must have \"schemaId\""); XmlSchemaParser.handleWarning(node, "\"schemaId\" should be UINT16"); XmlSchemaParser.handleError(node, "composite for message header must have \"version\""); XmlSchemaParser.handleWarning(node, "\"version\" should be UINT16");
final String encodingTypeStr = getAttributeValue(node, "encodingType"); else if (Integer.parseInt(getAttributeValue(encodingTypeNode, "length", "1")) != 1) encodingType = PrimitiveType.get(getAttributeValue(encodingTypeNode, "primitiveType")); handleWarning(node, "Choice value already defined: " + c.primitiveValue()); handleWarning(node, "Choice already exists for name: " + c.name());
final String refName = XmlSchemaParser.getAttributeValue(subTypeNode, "name"); final String refTypeName = XmlSchemaParser.getAttributeValue(subTypeNode, "type"); final int refOffset = Integer.parseInt(XmlSchemaParser.getAttributeValue(subTypeNode, "offset", "-1")); final Node refTypeNode = (Node)xPath.compile( "/*[local-name() = 'messageSchema']/types/*[@name='" + refTypeName + "']") XmlSchemaParser.handleError(subTypeNode, "ref type not found: " + refTypeName); XmlSchemaParser.handleError(refTypeNode, "ref types cannot create circular dependencies."); throw new IllegalStateException("ref types cannot create circular dependencies");
private static String formatLocationInfo(final Node node) { final Node parentNode = node.getParentNode(); return "at " + "<" + parentNode.getNodeName() + (getAttributeValueOrNull(parentNode, "name") == null ? ">" : (" name=\"" + getAttributeValueOrNull(parentNode, "name") + "\"> ")) + "<" + node.getNodeName() + (getAttributeValueOrNull(node, "name") == null ? ">" : (" name=\"" + getAttributeValueOrNull(node, "name") + "\"> ")); }
/** * Scan XML for all message definitions and save in map * * @param document for the XML parsing * @param xPath for XPath expression reuse * @param typeByNameMap to use for Type objects * @return {@link java.util.Map} of schemaId to Message * @throws Exception on parsing error. */ public static Map<Long, Message> findMessages( final Document document, final XPath xPath, final Map<String, Type> typeByNameMap) throws Exception { final Map<Long, Message> messageByIdMap = new HashMap<>(); forEach((NodeList)xPath.compile(MESSAGE_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), new NodeFunction() { public void execute(final Node node) throws XPathExpressionException { addMessageWithIdCheck(messageByIdMap, new Message(node, typeByNameMap), node); } }); return messageByIdMap; }