com.thaiopensource.validate.mns.SchemaImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jing Show documentation
Show all versions of jing Show documentation
Jing - tool for validating RelaxNG - (OSGi-compatible version)
package com.thaiopensource.validate.mns;
import com.thaiopensource.util.Localizer;
import com.thaiopensource.util.PropertyMap;
import com.thaiopensource.util.Uri;
import com.thaiopensource.util.PropertyMapBuilder;
import com.thaiopensource.validate.IncorrectSchemaException;
import com.thaiopensource.validate.Schema;
import com.thaiopensource.validate.ValidateProperty;
import com.thaiopensource.validate.Validator;
import com.thaiopensource.validate.AbstractSchema;
import com.thaiopensource.validate.auto.SchemaFuture;
import com.thaiopensource.xml.sax.XmlBaseHandler;
import com.thaiopensource.xml.sax.DelegatingContentHandler;
import com.thaiopensource.xml.sax.CountingErrorHandler;
import com.thaiopensource.xml.util.Name;
import com.thaiopensource.xml.util.StringSplitter;
import com.thaiopensource.xml.util.WellKnownNamespaces;
import org.xml.sax.Attributes;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.LocatorImpl;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Stack;
class SchemaImpl extends AbstractSchema {
static final String MNS_URI = "http://www.thaiopensource.com/ns/mns";
private final Hashtable modeMap = new Hashtable();
private Mode startMode;
private static final String DEFAULT_MODE_NAME = "#default";
private final boolean attributesSchema;
static private final class WrappedIOException extends RuntimeException {
private final IOException exception;
private WrappedIOException(IOException exception) {
this.exception = exception;
}
private IOException getException() {
return exception;
}
}
static class ElementAction {
private final Schema schema;
private final Mode mode;
private final ContextMap contextMap;
private final ElementsOrAttributes prune;
private final Hashset covered = new Hashset();
ElementAction(String ns, Schema schema, Mode mode, ContextMap contextMap, ElementsOrAttributes prune) {
this.schema = schema;
this.mode = mode;
this.contextMap = contextMap;
this.prune = prune;
covered.add(ns);
}
Mode getMode() {
return mode;
}
ContextMap getContextMap() {
return contextMap;
}
Schema getSchema() {
return schema;
}
ElementsOrAttributes getPrune() {
return prune;
}
Hashset getCoveredNamespaces() {
return covered;
}
}
static class Mode {
private Locator whereDefined;
private boolean defined = false;
private ElementsOrAttributes lax;
private boolean strictDefined = false;
private final Hashtable elementMap = new Hashtable();
private final Hashtable attributesMap = new Hashtable();
Mode(ElementsOrAttributes lax) {
this.lax = lax;
}
ElementsOrAttributes getLax() {
return lax;
}
Schema getAttributesSchema(String ns) {
return (Schema)attributesMap.get(ns);
}
ElementAction getElementAction(String ns) {
return (ElementAction)elementMap.get(ns);
}
}
private class Handler extends DelegatingContentHandler implements SchemaFuture {
private final SchemaReceiverImpl sr;
private ElementAction currentElementAction;
private boolean hadError = false;
private final ErrorHandler eh;
private final CountingErrorHandler ceh;
private final Localizer localizer = new Localizer(SchemaImpl.class);
private Locator locator;
private final XmlBaseHandler xmlBaseHandler = new XmlBaseHandler();
private int foreignDepth = 0;
private String contextNs;
private Mode contextMode;
private String elementNs;
private String defaultSchemaType;
private final Stack nameStack = new Stack();
private boolean isRoot;
private int pathDepth = 0;
private Validator validator;
Handler(SchemaReceiverImpl sr) {
this.sr = sr;
this.eh = sr.getProperties().get(ValidateProperty.ERROR_HANDLER);
this.ceh = new CountingErrorHandler(eh);
}
public void setDocumentLocator(Locator locator) {
xmlBaseHandler.setLocator(locator);
this.locator = locator;
}
public void startDocument() throws SAXException {
try {
PropertyMapBuilder builder = new PropertyMapBuilder(sr.getProperties());
builder.put(ValidateProperty.ERROR_HANDLER, ceh);
validator = sr.getMnsSchema().createValidator(builder.toPropertyMap());
}
catch (IOException e) {
throw new WrappedIOException(e);
}
catch (IncorrectSchemaException e) {
throw new RuntimeException("internal error in RNG schema for MNS");
}
setDelegate(validator.getContentHandler());
if (locator != null)
super.setDocumentLocator(locator);
super.startDocument();
}
public Schema getSchema() throws IncorrectSchemaException, SAXException {
if (validator == null || ceh.getHadErrorOrFatalError())
throw new IncorrectSchemaException();
for (Enumeration e = modeMap.keys(); e.hasMoreElements();) {
String modeName = (String)e.nextElement();
Mode mode = (Mode)modeMap.get(modeName);
if (!mode.defined && !modeName.equals(DEFAULT_MODE_NAME))
error("undefined_mode", modeName, mode.whereDefined);
}
if (hadError)
throw new IncorrectSchemaException();
return SchemaImpl.this;
}
public RuntimeException unwrapException(RuntimeException e) throws SAXException, IOException, IncorrectSchemaException {
if (e instanceof WrappedIOException)
throw ((WrappedIOException)e).getException();
return e;
}
public void startElement(String uri, String localName,
String qName, Attributes attributes)
throws SAXException {
super.startElement(uri, localName, qName, attributes);
xmlBaseHandler.startElement();
String xmlBase = attributes.getValue(WellKnownNamespaces.XML, "base");
if (xmlBase != null)
xmlBaseHandler.xmlBaseAttribute(xmlBase);
if (!MNS_URI.equals(uri) || foreignDepth > 0) {
foreignDepth++;
return;
}
if (ceh.getHadErrorOrFatalError())
return;
if (localName.equals("rules"))
parseRules(attributes);
else if (localName.equals("cover"))
parseCover(attributes);
else if (localName.equals("context"))
parseContext(attributes);
else if (localName.equals("root"))
parseRoot(attributes);
else if (localName.equals("element"))
parseElement(attributes);
else if (localName.equals("lax"))
parseLax(attributes);
else
parseValidate(localName.equals("validateAttributes"), attributes);
}
public void endElement(String namespaceURI, String localName,
String qName)
throws SAXException {
super.endElement(namespaceURI, localName, qName);
xmlBaseHandler.endElement();
if (foreignDepth > 0) {
foreignDepth--;
return;
}
if (pathDepth > 0) {
pathDepth--;
if (pathDepth == 0)
endPath();
}
}
private void parseRules(Attributes attributes) {
String modeName = attributes.getValue("", "startMode");
if (modeName == null)
modeName = DEFAULT_MODE_NAME;
defaultSchemaType = getSchemaType(attributes);
startMode = lookupCreateMode(modeName);
}
private void parseCover(Attributes attributes) throws SAXException {
String ns = getNs(attributes, false);
currentElementAction.covered.add(ns);
}
private void parseLax(Attributes attributes) throws SAXException {
String[] modeNames = getInModes(attributes);
Mode[] modes = getModes(modeNames);
ElementsOrAttributes lax = toElementsOrAttributes(attributes.getValue("", "allow"),
ElementsOrAttributes.BOTH);
for (int i = 0; i < modes.length; i++) {
if (modes[i].strictDefined)
error("lax_multiply_defined", modeNames[i]);
else {
modes[i].lax = lax;
modes[i].strictDefined = true;
}
}
}
private void parseValidate(boolean isAttribute, Attributes attributes) throws SAXException {
String[] modeNames = getInModes(attributes);
Mode[] modes = getModes(modeNames);
String ns = getNs(attributes, isAttribute);
String schemaUri = getSchema(attributes);
String schemaType = getSchemaType(attributes);
if (schemaType == null)
schemaType = defaultSchemaType;
try {
if (isAttribute) {
Schema schema = sr.createChildSchema(new InputSource(schemaUri), schemaType, true);
for (int i = 0; i < modes.length; i++) {
if (modes[i].attributesMap.get(ns) != null)
error("validate_attributes_multiply_defined", modeNames[i], ns);
else
modes[i].attributesMap.put(ns, schema);
}
}
else {
Schema schema = sr.createChildSchema(new InputSource(schemaUri), schemaType, false);
currentElementAction = new ElementAction(ns,
schema,
getUseMode(attributes),
new ContextMap(),
getPrune(attributes));
contextNs = ns;
for (int i = 0; i < modes.length; i++) {
if (modes[i].elementMap.get(ns) != null)
error("validate_element_multiply_defined", modeNames[i], ns);
else
modes[i].elementMap.put(ns, currentElementAction);
}
}
}
catch (IncorrectSchemaException e) {
hadError = true;
}
catch (IOException e) {
throw new WrappedIOException(e);
}
}
private void parseContext(Attributes attributes) throws SAXException {
String ns = getNs(attributes, false);
if (ns != null)
contextNs = ns;
elementNs = contextNs;
contextMode = getUseMode(attributes);
}
private void parseRoot(Attributes attributes) throws SAXException {
String ns = getNs(attributes, false);
if (ns != null)
elementNs = ns;
isRoot = true;
pathDepth++;
}
private void parseElement(Attributes attributes) throws SAXException {
String ns = getNs(attributes, false);
if (ns != null)
elementNs = ns;
if (!currentElementAction.covered.contains(elementNs))
error("context_ns_not_covered", elementNs);
nameStack.push(new Name(elementNs, attributes.getValue("", "name").trim()));
pathDepth++;
}
private void endPath() throws SAXException {
if (!currentElementAction.contextMap.put(isRoot, nameStack, contextMode))
error("path_multiply_defined", displayPath(isRoot, nameStack));
elementNs = contextNs;
isRoot = false;
nameStack.setSize(0);
}
private String displayPath(boolean isRoot, Stack nameStack) {
StringBuffer buf = new StringBuffer();
for (int i = 0, len = nameStack.size(); i < len; i++) {
if (i > 0 || isRoot)
buf.append('/');
Name name = (Name)nameStack.elementAt(i);
if (name.getNamespaceUri().length() > 0) {
buf.append('{');
buf.append(name.getNamespaceUri());
buf.append('}');
}
buf.append(name.getLocalName());
}
return buf.toString();
}
private String getSchema(Attributes attributes) throws SAXException {
String schemaUri = attributes.getValue("", "schema");
if (Uri.hasFragmentId(schemaUri))
error("schema_fragment_id");
return Uri.resolve(xmlBaseHandler.getBaseUri(),
Uri.escapeDisallowedChars(schemaUri));
}
private String getSchemaType(Attributes attributes) {
return attributes.getValue("", "schemaType");
}
private ElementsOrAttributes getPrune(Attributes attributes) {
return toElementsOrAttributes(attributes.getValue("", "prune"),
ElementsOrAttributes.NEITHER);
}
private ElementsOrAttributes toElementsOrAttributes(String value, ElementsOrAttributes defaultValue) {
if (value == null)
return defaultValue;
ElementsOrAttributes eoa = ElementsOrAttributes.NEITHER;
if (value.indexOf("elements") >= 0)
eoa = eoa.addElements();
if (value.indexOf("attributes") >= 0)
eoa = eoa.addAttributes();
return eoa;
}
private Mode getUseMode(Attributes attributes) {
String modeName = attributes.getValue("", "useMode");
if (modeName == null)
modeName = DEFAULT_MODE_NAME;
Mode mode = lookupCreateMode(modeName);
if (mode.whereDefined == null && locator != null)
mode.whereDefined = new LocatorImpl(locator);
return mode;
}
private String getNs(Attributes attributes, boolean forbidEmpty) throws SAXException {
String ns = attributes.getValue("", "ns");
if (ns != null && !Uri.isAbsolute(ns) && (forbidEmpty || !ns.equals("")))
error("ns_absolute");
return ns;
}
private Mode[] getModes(String[] modeNames) {
Mode[] modes = new Mode[modeNames.length];
for (int i = 0; i < modes.length; i++) {
modes[i] = lookupCreateMode(modeNames[i]);
modes[i].defined = true;
}
return modes;
}
private String[] getInModes(Attributes attributes) {
String inModes = attributes.getValue("", "inModes");
if (inModes == null)
return new String[] { DEFAULT_MODE_NAME };
return StringSplitter.split(inModes);
}
void error(String key) throws SAXException {
hadError = true;
if (eh == null)
return;
eh.error(new SAXParseException(localizer.message(key), locator));
}
void error(String key, String arg) throws SAXException {
hadError = true;
if (eh == null)
return;
eh.error(new SAXParseException(localizer.message(key, arg), locator));
}
void error(String key, String arg, Locator locator) throws SAXException {
hadError = true;
if (eh == null)
return;
eh.error(new SAXParseException(localizer.message(key, arg), locator));
}
void error(String key, String arg1, String arg2) throws SAXException {
hadError = true;
if (eh == null)
return;
eh.error(new SAXParseException(localizer.message(key, arg1, arg2), locator));
}
}
SchemaImpl(boolean attributesSchema) {
this.attributesSchema = attributesSchema;
}
SchemaFuture installHandlers(XMLReader in, SchemaReceiverImpl sr) {
Handler h = new Handler(sr);
in.setContentHandler(h);
return h;
}
public Validator createValidator(PropertyMap properties) {
return new ValidatorImpl(startMode, properties);
}
private Mode lookupCreateMode(String name) {
Mode mode = (Mode)modeMap.get(name);
if (mode == null) {
mode = new Mode(attributesSchema ? ElementsOrAttributes.ELEMENTS : ElementsOrAttributes.NEITHER);
modeMap.put(name, mode);
}
return mode;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy