com.thaiopensource.validate.mns.ValidatorImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wicketstuff-jing Show documentation
Show all versions of wicketstuff-jing Show documentation
Jing is a validator for RELAX NG and other schema languages. This
project was taken from http://code.google.com/p/jing-trang and
mavenized for inclusion in the Wicket Stuff HTML Validator.
The code was taken from the 20091111 release.
package com.thaiopensource.validate.mns;
import com.thaiopensource.util.Localizer;
import com.thaiopensource.util.PropertyMap;
import com.thaiopensource.validate.Schema;
import com.thaiopensource.validate.ValidateProperty;
import com.thaiopensource.validate.Validator;
import com.thaiopensource.xml.util.Name;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.Hashtable;
import java.util.Stack;
class ValidatorImpl extends DefaultHandler implements Validator {
static final Name OWNER_NAME = new Name("http://www.thaiopensource.com/ns/mns/instance", "owner");
private SchemaImpl.Mode currentMode;
private int laxDepth = 0;
private final ErrorHandler eh;
private final PropertyMap properties;
private Locator locator;
private Subtree subtrees = null;
private final Hashset attributeNamespaces = new Hashset();
private PrefixMapping prefixMapping = null;
private final Localizer localizer = new Localizer(ValidatorImpl.class);
private final Hashtable validatorCache = new Hashtable();
static private class Subtree {
final Subtree parent;
final Validator validator;
final Schema schema;
final Hashset coveredNamespaces;
final ElementsOrAttributes prune;
final SchemaImpl.Mode parentMode;
final int parentLaxDepth;
final Stack context = new Stack();
final ContextMap contextMap;
Subtree(Hashset coveredNamespaces, ContextMap contextMap,
ElementsOrAttributes prune, Validator validator,
Schema schema, SchemaImpl.Mode parentMode, int parentLaxDepth, Subtree parent) {
this.coveredNamespaces = coveredNamespaces;
this.contextMap = contextMap;
this.prune = prune;
this.validator = validator;
this.schema = schema;
this.parentMode = parentMode;
this.parentLaxDepth = parentLaxDepth;
this.parent = parent;
}
}
static private class PrefixMapping {
final String prefix;
final String uri;
final PrefixMapping parent;
PrefixMapping(String prefix, String uri, PrefixMapping parent) {
this.prefix = prefix;
this.uri = uri;
this.parent = parent;
}
}
ValidatorImpl(SchemaImpl.Mode mode, PropertyMap properties) {
this.currentMode = mode;
this.properties = properties;
this.eh = properties.get(ValidateProperty.ERROR_HANDLER);
}
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
public void characters(char ch[], int start, int length)
throws SAXException {
for (Subtree st = subtrees; wantsEvent(st); st = st.parent)
st.validator.getContentHandler().characters(ch, start, length);
}
public void ignorableWhitespace(char ch[], int start, int length)
throws SAXException {
for (Subtree st = subtrees; wantsEvent(st); st = st.parent)
st.validator.getContentHandler().ignorableWhitespace(ch, start, length);
}
private SchemaImpl.Mode getMode() {
if (subtrees != null) {
SchemaImpl.Mode mode = (SchemaImpl.Mode)subtrees.contextMap.get(subtrees.context);
if (mode != null)
return mode;
}
return currentMode;
}
public void startElement(String uri, String localName,
String qName, Attributes attributes)
throws SAXException {
if (namespaceCovered(uri))
subtrees.context.push(new Name(uri, localName));
else {
SchemaImpl.Mode mode = getMode();
SchemaImpl.ElementAction elementAction = mode.getElementAction(uri);
if (elementAction == null) {
if (laxDepth == 0 && !mode.getLax().containsElements())
error("element_undeclared_namespace", uri);
laxDepth++;
}
else {
subtrees = new Subtree(elementAction.getCoveredNamespaces(),
elementAction.getContextMap(),
elementAction.getPrune(),
createValidator(elementAction.getSchema()),
elementAction.getSchema(),
currentMode,
laxDepth,
subtrees);
subtrees.context.push(new Name(uri, localName));
currentMode = elementAction.getMode();
laxDepth = 0;
startSubtree(subtrees.validator.getContentHandler());
}
}
for (Subtree st = subtrees; wantsEvent(st); st = st.parent) {
Attributes prunedAtts;
if (st.prune.containsAttributes())
prunedAtts = new NamespaceFilteredAttributes(uri, true, attributes);
else
prunedAtts = attributes;
st.validator.getContentHandler().startElement(uri, localName, qName, prunedAtts);
}
for (int i = 0, len = attributes.getLength(); i < len; i++) {
String ns = attributes.getURI(i);
if (!ns.equals("")
&& !ns.equals(uri)
&& !namespaceCovered(ns)
&& !attributeNamespaces.contains(ns)) {
attributeNamespaces.add(ns);
validateAttributes(ns, attributes);
}
}
attributeNamespaces.clear();
}
private boolean namespaceCovered(String ns) {
return (laxDepth == 0
&& subtrees != null
&& subtrees.coveredNamespaces.contains(ns));
}
private boolean wantsEvent(Subtree st) {
return st != null && (!st.prune.containsElements() || (laxDepth == 0 && st == subtrees));
}
private void validateAttributes(String ns, Attributes attributes) throws SAXException {
SchemaImpl.Mode mode = getMode();
Schema attributesSchema = mode.getAttributesSchema(ns);
if (attributesSchema == null) {
if (!mode.getLax().containsAttributes())
error("attributes_undeclared_namespace", ns);
return;
}
Validator validator = createValidator(attributesSchema);
ContentHandler ch = validator.getContentHandler();
startSubtree(ch);
ch.startElement(OWNER_NAME.getNamespaceUri(), OWNER_NAME.getLocalName(), OWNER_NAME.getLocalName(),
new NamespaceFilteredAttributes(ns, false, attributes));
ch.endElement(OWNER_NAME.getNamespaceUri(), OWNER_NAME.getLocalName(), OWNER_NAME.getLocalName());
endSubtree(ch);
releaseValidator(attributesSchema, validator);
}
private void startSubtree(ContentHandler ch) throws SAXException {
if (locator != null)
ch.setDocumentLocator(locator);
ch.startDocument();
for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent)
ch.startPrefixMapping(pm.prefix, pm.uri);
}
private void endSubtree(ContentHandler ch) throws SAXException {
for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent)
ch.endPrefixMapping(pm.prefix);
ch.endDocument();
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
for (Subtree st = subtrees; wantsEvent(st); st = st.parent)
st.validator.getContentHandler().endElement(uri, localName, qName);
if (laxDepth > 0)
laxDepth--;
else if (!subtrees.context.empty()) {
subtrees.context.pop();
if (subtrees.context.empty()) {
endSubtree(subtrees.validator.getContentHandler());
releaseValidator(subtrees.schema, subtrees.validator);
currentMode = subtrees.parentMode;
laxDepth = subtrees.parentLaxDepth;
subtrees = subtrees.parent;
}
}
}
private Validator createValidator(Schema schema) {
Stack stack = (Stack)validatorCache.get(schema);
if (stack == null) {
stack = new Stack();
validatorCache.put(schema, stack);
}
if (stack.empty())
return schema.createValidator(properties);
return (Validator)stack.pop();
}
private void releaseValidator(Schema schema, Validator validator) {
validator.reset();
((Stack)validatorCache.get(schema)).push(validator);
}
public void endDocument()
throws SAXException {
}
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
super.startPrefixMapping(prefix, uri);
prefixMapping = new PrefixMapping(prefix, uri, prefixMapping);
}
public void endPrefixMapping(String prefix)
throws SAXException {
super.endPrefixMapping(prefix);
prefixMapping = prefixMapping.parent;
}
public void reset() {
subtrees = null;
locator = null;
}
public ContentHandler getContentHandler() {
return this;
}
public DTDHandler getDTDHandler() {
return null;
}
private void error(String key, String arg) throws SAXException {
eh.error(new SAXParseException(localizer.message(key, arg), locator));
}
}