net.jangaroo.exml.parser.ExmlMetadataHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of exml-compiler Show documentation
Show all versions of exml-compiler Show documentation
parses an EXML and generates an AS config class
package net.jangaroo.exml.parser;
import net.jangaroo.exml.api.ExmlcException;
import net.jangaroo.exml.compiler.Exmlc;
import net.jangaroo.jooc.json.JsonObject;
import net.jangaroo.exml.model.AnnotationAt;
import net.jangaroo.exml.model.ConfigAttribute;
import net.jangaroo.exml.model.ConfigClass;
import net.jangaroo.exml.model.ConfigClassType;
import net.jangaroo.exml.model.DescriptionHolder;
import net.jangaroo.exml.model.Declaration;
import net.jangaroo.exml.model.PublicApiMode;
import net.jangaroo.exml.utils.ExmlUtils;
import net.jangaroo.jooc.Jooc;
import net.jangaroo.utils.CharacterRecordingHandler;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import javax.xml.namespace.QName;
import java.util.Deque;
import java.util.LinkedList;
/**
* Generates an internal representation of all metadata of the component described by the given EXML.
*/
public class ExmlMetadataHandler extends CharacterRecordingHandler {
private ConfigClass configClass;
private Locator locator;
private Deque elementPath = new LinkedList();
public ExmlMetadataHandler(ConfigClass configClass) {
this.configClass = configClass;
}
@Override
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if (ExmlUtils.isExmlNamespace(uri)) {
if (Exmlc.EXML_ROOT_NODE_NAMES.contains(localName)) {
configClass.setType(ConfigClassType.fromExmlRootNodeName(localName));
for (int i = 0; i < atts.getLength(); i++) {
//baseClass attribute has been specified, so the super class of the component is actually that
if (Exmlc.EXML_PUBLIC_API_ATTRIBUTE.equals(atts.getLocalName(i))) {
PublicApiMode publicApiMode = Exmlc.parsePublicApiMode(atts.getValue(i));
if (publicApiMode != PublicApiMode.FALSE) {
configClass.addAnnotation(Jooc.PUBLIC_API_INCLUSION_ANNOTATION_NAME);
}
}
}
} else if (Exmlc.EXML_ANNOTATION_NODE_NAME.equals(localName)) {
AnnotationAt annotationAt = AnnotationAt.BOTH; // default for "at" is "both"
for (int i = 0; i < atts.getLength(); i++) {
if (Exmlc.EXML_ANNOTATION_AT_ATTRIBUTE.equals(atts.getLocalName(i))) {
// found "at" attribute: parse it (might throw ExmlcException)
annotationAt = Exmlc.parseAnnotationAtValue(atts.getValue(i));
break;
}
}
if (annotationAt != AnnotationAt.TARGET) {
startRecordingCharacters();
}
} else if (Exmlc.EXML_CFG_NODE_NAME.equals(localName)) {
//handle config elements
ConfigAttribute cfg = new ConfigAttribute(atts.getValue(Exmlc.EXML_CFG_NAME_ATTRIBUTE), atts.getValue(Exmlc.EXML_CFG_TYPE_ATTRIBUTE), null);
if(!configClass.contains(cfg)) {
configClass.addCfg(cfg);
} else {
throw new ExmlcException("Config '" + cfg.getName() + "' already defined.", locator.getLineNumber(), locator.getColumnNumber());
}
} else if (Exmlc.EXML_DESCRIPTION_NODE_NAME.equals(localName)) {
if (isLastInPathExmlClass() || isLastInPathConfig() || isLastInPathConstant()) {
// start recording characters of the description:
startRecordingCharacters();
}
} else if (Exmlc.EXML_DECLARATION_VALUE_NODE_NAME.equals(localName)) {
if (isLastInPathConstant()) {
// start recording characters of the constant value:
startRecordingCharacters();
}
} else if (Exmlc.EXML_CONSTANT_NODE_NAME.equals(localName)) {
final String name = atts.getValue(Exmlc.EXML_DECLARATION_NAME_ATTRIBUTE);
final String type = atts.getValue(Exmlc.EXML_DECLARATION_TYPE_ATTRIBUTE);
final String value = atts.getValue(Exmlc.EXML_DECLARATION_VALUE_ATTRIBUTE);
Declaration constant = new Declaration(name, formatValue(value, type), type);
if(!configClass.getConstants().contains(constant)) {
configClass.addConstant(constant);
} else {
throw new ExmlcException("Constant '" + constant.getName() + "' already defined.", locator.getLineNumber(), locator.getColumnNumber());
}
} else if (Exmlc.EXML_IMPORT_NODE_NAME.equals(localName)) {
String importedClassName = atts.getValue(Exmlc.EXML_IMPORT_CLASS_ATTRIBUTE);
if (importedClassName != null) {
// TODO: check illegal values? Throw error when null?
configClass.addImport(importedClassName);
}
}
} else if (elementPath.size() == 1) {
if (configClass.getSuperClassName() != null) {
throw new ExmlcException("root node of EXML contained more than one component definition", locator.getLineNumber(), locator.getColumnNumber());
}
String thePackage = ExmlUtils.parsePackageFromNamespace(uri);
if (thePackage == null) {
throw new ExmlcException("namespace '" + uri + "' of superclass element in EXML file does not denote a config package", locator.getLineNumber(), locator.getColumnNumber());
}
configClass.setSuperClassName(thePackage + "." + localName);
}
elementPath.push(new QName(uri, localName));
}
private static String formatValue(String value, String type) {
return value == null ? null
: JsonObject.valueToString(ExmlToModelParser.getAttributeValue(value, type), 2, 4);
}
private boolean isLastInPathExmlClass() {
QName parent = elementPath.peek();
return ExmlUtils.isExmlNamespace(parent.getNamespaceURI()) && Exmlc.EXML_ROOT_NODE_NAMES.contains(parent.getLocalPart());
}
private boolean isLastInPathConfig() {
QName parent = elementPath.peek();
return ExmlUtils.isExmlNamespace(parent.getNamespaceURI()) && Exmlc.EXML_CFG_NODE_NAME.equals(parent.getLocalPart());
}
private boolean isLastInPathConstant() {
QName parent = elementPath.peek();
return ExmlUtils.isExmlNamespace(parent.getNamespaceURI()) && Exmlc.EXML_CONSTANT_NODE_NAME.equals(parent.getLocalPart());
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
elementPath.pop();
if (ExmlUtils.isExmlNamespace(uri)) {
if (Exmlc.EXML_DESCRIPTION_NODE_NAME.equals(localName)) {
String characters = popRecordedCharacters();
if (characters != null) {
DescriptionHolder descriptionHolder =
isLastInPathConfig() ? configClass.getCfgs().get(configClass.getCfgs().size() - 1)
: isLastInPathExmlClass() ? configClass
: isLastInPathConstant() ? getLastConstantDeclaration()
: null;
if (descriptionHolder != null) {
descriptionHolder.setDescription(characters);
}
}
} else if (Exmlc.EXML_DECLARATION_VALUE_NODE_NAME.equals(localName)) {
String characters = popRecordedCharacters();
if (characters != null) {
final Declaration lastConstantDeclaration = getLastConstantDeclaration();
lastConstantDeclaration.setValue(formatValue(characters, lastConstantDeclaration.getType()));
}
} else if (Exmlc.EXML_ANNOTATION_NODE_NAME.equals(localName)) {
String characters = popRecordedCharacters();
if (characters != null) {
configClass.addAnnotation(characters);
}
}
if (elementPath.isEmpty() && configClass.getSuperClassName() == null) {
// if nothing else is specified, extend default config class depending on the config class type:
configClass.setSuperClassName(configClass.getType().getDefaultSuperConfigClassName());
}
}
}
private Declaration getLastConstantDeclaration() {
return configClass.getConstants().get(configClass.getConstants().size() - 1);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy