blob: 3ee81198e57b436c9e482faaa3169f5a6f364b79 [file] [log] [blame]
#*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*#
#parse ( "common.vm" )
#
#set ( $package = "${packageToolV4}" )
#set ( $className = "${model.name}Xpp3ReaderEx" )
#
#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
#set ( $rootXml = $Helper.xmlClassMetadata( $root ) )
#set ( $rootTag = $rootXml.tagName )
#set ( $rootUcapName = $Helper.capitalise( $root.name ) )
#set ( $rootLcapName = $Helper.uncapitalise( $root.name ) )
#
#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java
// =================== DO NOT EDIT THIS FILE ====================
// Generated by Modello Velocity from ${template}
// template, any modifications will be overwritten.
// ==============================================================
package ${package};
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.maven.api.annotations.Generated;
import org.apache.maven.internal.xml.XmlNodeBuilder;
import ${packageModelV4}.InputSource;
import ${packageModelV4}.InputLocation;
#foreach ( $class in $model.allClasses )
import ${packageModelV4}.${class.name};
#end
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.xml.pull.EntityReplacementMap;
import org.codehaus.plexus.util.xml.pull.MXParser;
import org.codehaus.plexus.util.xml.pull.XmlPullParser;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
@Generated
public class ${className} {
private boolean addDefaultEntities = true;
private final ContentTransformer contentTransformer;
public ${className}() {
this((s, f) -> s);
}
public ${className}(ContentTransformer contentTransformer) {
this.contentTransformer = contentTransformer;
}
/**
* Returns the state of the "add default entities" flag.
*
* @return boolean
*/
public boolean getAddDefaultEntities() {
return addDefaultEntities;
} //-- boolean getAddDefaultEntities()
/**
* Sets the state of the "add default entities" flag.
*
* @param addDefaultEntities a addDefaultEntities object.
*/
public void setAddDefaultEntities(boolean addDefaultEntities) {
this.addDefaultEntities = addDefaultEntities;
} //-- void setAddDefaultEntities(boolean)
/**
* @see ReaderFactory#newXmlReader
*
* @param reader a reader object.
* @param strict a strict object.
* @throws IOException IOException if any.
* @throws XmlPullParserException XmlPullParserException if
* any.
* @return ${root.name}
*/
public ${root.name} read(Reader reader, boolean strict, InputSource source) throws IOException, XmlPullParserException {
XmlPullParser parser = addDefaultEntities ? new MXParser(EntityReplacementMap.defaultEntityReplacementMap) : new MXParser();
parser.setInput(reader);
return read(parser, strict, source);
} //-- ${root.name} read(Reader, boolean)
/**
* Method read.
*
* @param in a in object.
* @param strict a strict object.
* @throws IOException IOException if any.
* @throws XmlPullParserException XmlPullParserException if
* any.
* @return ${root.name}
*/
public ${root.name} read(InputStream in, boolean strict, InputSource source) throws IOException, XmlPullParserException {
return read(ReaderFactory.newXmlReader(in), strict, source);
} //-- ${root.name} read(InputStream, boolean)
/**
* Method read.
*
* @param parser a parser object.
* @param strict a strict object.
* @throws IOException IOException if any.
* @throws XmlPullParserException XmlPullParserException if
* any.
* @return ${root.name}
*/
public ${root.name} read(XmlPullParser parser, boolean strict, InputSource source) throws IOException, XmlPullParserException {
$rootUcapName $rootLcapName = null;
int eventType = parser.getEventType();
boolean parsed = false;
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (strict && ! "${rootTag}".equals(parser.getName())) {
throw new XmlPullParserException("Expected root element '${rootTag}' but found '" + parser.getName() + "'", parser, null);
} else if (parsed) {
// fallback, already expected a XmlPullParserException due to invalid XML
throw new XmlPullParserException("Duplicated tag: '${rootTag}'", parser, null);
}
$rootLcapName = parse${rootUcapName}(parser, strict, source);
parsed = true;
}
eventType = parser.next();
}
if (parsed) {
return $rootLcapName;
}
throw new XmlPullParserException("Expected root element '${rootTag}' but found no element at all: invalid XML document", parser, null);
} //-- ${root.name} read(XmlPullParser, boolean)
#foreach ( $class in $model.allClasses )
#if ( $class.name != "InputSource" && $class.name != "InputLocation" )
#set ( $classUcapName = $Helper.capitalise( $class.name ) )
#set ( $classLcapName = $Helper.uncapitalise( $class.name ) )
#set ( $ancestors = $Helper.ancestors( $class ) )
#set ( $allFields = $Helper.xmlFields( $class ) )
private ${classUcapName} parse${classUcapName}(XmlPullParser parser, boolean strict, InputSource source) throws IOException, XmlPullParserException {
String tagName = parser.getName();
${classUcapName}.Builder ${classLcapName} = ${classUcapName}.newBuilder(true);
${classLcapName}.location("", new InputLocation(parser.getLineNumber(), parser.getColumnNumber(), source));
for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
String name = parser.getAttributeName(i);
String value = parser.getAttributeValue(i);
if (name.indexOf(':') >= 0) {
// just ignore attributes with non-default namespace (for example: xmlns:xsi)
#if ( $class == $root )
} else if ("xmlns".equals(name)) {
// ignore xmlns attribute in root class, which is a reserved attribute name
#end
#foreach ( $field in $allFields )
#if ( $Helper.xmlFieldMetadata( $field ).attribute )
#set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
#set ( $fieldCapName = $Helper.capitalise( $field.name ) )
} else if ("$fieldTagName".equals(name)) {
${classLcapName}.location(name, new InputLocation(parser.getLineNumber(), parser.getColumnNumber(), source));
#if ( $field.type == "String" )
${classLcapName}.${field.name}(interpolatedTrimmed(value, "$fieldTagName"));
#elseif ( $field.type == "boolean" || $field.type == "Boolean" )
${classLcapName}.${field.name}(getBooleanValue(interpolatedTrimmed(value, "$fieldTagName"), "$fieldTagName", parser, ${field.defaultValue}));
#else
// TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
#end
#end
#end
} else {
checkUnknownAttribute(parser, name, tagName, strict);
}
}
Set<String> parsed = new HashSet<>();
while ((strict ? parser.nextTag() : nextTag(parser)) == XmlPullParser.START_TAG) {
String childName = unalias(parser.getName());
if (!parsed.add(childName)) {
throw new XmlPullParserException("Duplicated tag: '" + childName + "'", parser, null);
}
int line = parser.getLineNumber();
int column = parser.getColumnNumber();
Map<Object, InputLocation> locations = null;
switch (childName) {
#set( $ift = "if" )
#foreach ( $field in $allFields )
#if ( ! $Helper.xmlFieldMetadata( $field ).attribute && ! $Helper.xmlFieldMetadata( $field ).transient )
#set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
#if ( ! $fieldTagName )
#set ( $fieldTagName = $field.name )
#end
#set ( $fieldCapName = $Helper.capitalise($field.name))
case "${fieldTagName}": {
#if ( $field.type == "String" )
${classLcapName}.${field.name}(interpolatedTrimmed(parser.nextText(), "${fieldTagName}"));
break;
#elseif ( $field.type == "boolean" || $field.type == "Boolean" )
${classLcapName}.${field.name}(getBooleanValue(interpolatedTrimmed(parser.nextText(), "${fieldTagName}"), "${fieldTagName}", parser, ${field.defaultValue}));
break;
#elseif ( $field.type == "int" )
${classLcapName}.${field.name}(getIntegerValue(interpolatedTrimmed(parser.nextText(), "${fieldTagName}"), "${fieldTagName}", parser, strict, ${field.defaultValue}));
break;
#elseif ( $field.type == "DOM" )
${classLcapName}.${field.name}(XmlNodeBuilder.build(parser, true));
break;
#elseif ( $field.type == "java.util.List" && $field.to == "String" && $field.multiplicity == "*" )
List<String> ${field.name} = new ArrayList<>();
locations = new HashMap<>();
while (parser.nextTag() == XmlPullParser.START_TAG) {
if ("${Helper.singular($fieldTagName)}".equals(parser.getName())) {
locations.put(Integer.valueOf(locations.size()), new InputLocation(parser.getLineNumber(), parser.getColumnNumber(), source));
${field.name}.add(interpolatedTrimmed(parser.nextText(), "${fieldTagName}"));
} else {
checkUnknownElement(parser, strict);
}
}
${classLcapName}.${field.name}(${field.name});
break;
#elseif ( $field.type == "java.util.Properties" && $field.to == "String" && $field.multiplicity == "*" )
Map<String, String> ${field.name} = new LinkedHashMap<>();
locations = new HashMap<>();
while (parser.nextTag() == XmlPullParser.START_TAG) {
String key = parser.getName();
String value = parser.nextText().trim();
locations.put(key, new InputLocation(parser.getLineNumber(), parser.getColumnNumber(), source));
${field.name}.put(key, value);
}
${classLcapName}.${field.name}(${field.name});
break;
#elseif ( $field.to && $field.multiplicity == "1" )
${classLcapName}.${field.name}(parse${field.toClass.name}(parser, strict, source ));
break;
#elseif ( $field.to && $field.multiplicity == "*" )
List<$field.to> ${field.name} = new ArrayList<>();
while (parser.nextTag() == XmlPullParser.START_TAG) {
if ("${Helper.singular($fieldTagName)}".equals(parser.getName())) {
${field.name}.add(parse${field.toClass.name}(parser, strict, source));
} else {
checkUnknownElement(parser, strict);
}
}
${classLcapName}.${field.name}(${field.name});
break;
#else
// TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
break;
#end
}
#set( $ift = "else if" )
#end
#end
default: {
checkUnknownElement(parser, strict);
break;
}
}
${classLcapName}.location(childName, new InputLocation(line, column, source, locations));
}
#if ( $class == $root )
${classLcapName}.modelEncoding(parser.getInputEncoding());
#end
return ${classLcapName}.build();
}
#end
#end
private String unalias(String tagName) {
switch (tagName) {
#set( $aliases = { } )
#foreach( $class in $model.allClasses )
#foreach ( $field in $class.allFields )
#if ( $field.alias )
#set ( $dummy = $aliases.put( $field.alias, $field.name ) )
#end
#end
#end
#foreach( $entry in $aliases.entrySet() )
case "${entry.key}":
return "${entry.value}";
#end
default:
return tagName;
}
}
/**
* Method checkUnknownAttribute.
*
* @param parser a parser object.
* @param strict a strict object.
* @param tagName a tagName object.
* @param attribute a attribute object.
* @throws XmlPullParserException XmlPullParserException if
* any.
* @throws IOException IOException if any.
*/
private void checkUnknownAttribute(XmlPullParser parser, String attribute, String tagName, boolean strict) throws XmlPullParserException, IOException {
// strictXmlAttributes = true for model: if strict == true, not only elements are checked but attributes too
if (strict) {
throw new XmlPullParserException("Unknown attribute '" + attribute + "' for tag '" + tagName + "'", parser, null);
}
} //-- void checkUnknownAttribute(XmlPullParser, String, String, boolean)
/**
* Method checkUnknownElement.
*
* @param parser a parser object.
* @param strict a strict object.
* @throws XmlPullParserException XmlPullParserException if
* any.
* @throws IOException IOException if any.
*/
private void checkUnknownElement(XmlPullParser parser, boolean strict) throws XmlPullParserException, IOException {
if (strict) {
throw new XmlPullParserException("Unrecognised tag: '" + parser.getName() + "'", parser, null);
}
for (int unrecognizedTagCount = 1; unrecognizedTagCount > 0;) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG) {
unrecognizedTagCount++;
} else if (eventType == XmlPullParser.END_TAG) {
unrecognizedTagCount--;
}
}
} //-- void checkUnknownElement(XmlPullParser, boolean)
/**
* Method getTrimmedValue.
*
* @param s a s object.
* @return String
*/
private String getTrimmedValue(String s) {
if (s != null) {
s = s.trim();
}
return s;
} //-- String getTrimmedValue(String)
/**
* Method interpolatedTrimmed.
*
* @param value a value object.
* @param context a context object.
* @return String
*/
private String interpolatedTrimmed(String value, String context) {
return getTrimmedValue(contentTransformer.transform(value, context));
} //-- String interpolatedTrimmed(String, String)
/**
* Method nextTag.
*
* @param parser a parser object.
* @throws IOException IOException if any.
* @throws XmlPullParserException XmlPullParserException if
* any.
* @return int
*/
private int nextTag(XmlPullParser parser) throws IOException, XmlPullParserException {
int eventType = parser.next();
if (eventType == XmlPullParser.TEXT) {
eventType = parser.next();
}
if (eventType != XmlPullParser.START_TAG && eventType != XmlPullParser.END_TAG) {
throw new XmlPullParserException("expected START_TAG or END_TAG not " + XmlPullParser.TYPES[eventType], parser, null);
}
return eventType;
} //-- int nextTag(XmlPullParser)
#foreach ( $class in $model.allClasses )
#foreach ( $field in $class.getFields($version) )
#if ( $field.type == "boolean" || $field.type == "Boolean" )
#set ( $hasBooleanField = true )
#elseif ( $field.type == "int" || $field.type == "Integer" )
#set ( $hasIntegerField = true )
#end
#end
#end
#if ( $hasBooleanField )
/**
* Method getBooleanValue.
*
* @param s a s object.
* @param defaultValue a defaultValue object.
* @param parser a parser object.
* @param attribute a attribute object.
* @throws XmlPullParserException XmlPullParserException if
* any.
* @return boolean
*/
private boolean getBooleanValue(String s, String attribute, XmlPullParser parser, boolean defaultValue) throws XmlPullParserException {
if (s != null && s.length() != 0) {
return Boolean.valueOf(s).booleanValue();
}
return defaultValue;
} //-- boolean getBooleanValue(String, String, XmlPullParser, String)
#end
#if ( $hasIntegerField )
/**
* Method getIntegerValue.
*
* @param s a s object.
* @param strict a strict object.
* @param parser a parser object.
* @param attribute a attribute object.
* @throws XmlPullParserException XmlPullParserException if
* any.
* @return int
*/
private int getIntegerValue(String s, String attribute, XmlPullParser parser, boolean strict, int defaultValue) throws XmlPullParserException {
if (s != null) {
try {
return Integer.valueOf(s).intValue();
} catch (NumberFormatException nfe) {
if (strict) {
throw new XmlPullParserException("Unable to parse element '" + attribute + "', must be an integer", parser, nfe);
}
}
}
return defaultValue;
} //-- int getIntegerValue(String, String, XmlPullParser, boolean)
#end
public static interface ContentTransformer {
/**
* Interpolate the value read from the xpp3 document
* @param source The source value
* @param fieldName A description of the field being interpolated. The implementation may use this to
* log stuff.
* @return The interpolated value.
*/
String transform(String source, String fieldName);
}
}