package com.thaiopensource.validate.picl; import com.thaiopensource.validate.Validator; import com.thaiopensource.validate.ValidateProperty; import com.thaiopensource.util.Localizer; import com.thaiopensource.util.PropertyMap; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.LocatorImpl; import org.xml.sax.ContentHandler; import org.xml.sax.Attributes; import org.xml.sax.DTDHandler; import org.xml.sax.SAXException; import org.xml.sax.Locator; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXParseException; import java.util.Stack; class ValidatorImpl extends DefaultHandler implements Validator, Path, PatternManager, ErrorContext { private final Constraint constraint; private final Stack openElements = new Stack(); private final Stack valueHandlers = new Stack(); private final Stack activePatterns = new Stack(); private final AttributePath attributePath = new AttributePath(); private Locator locator; private final ErrorHandler eh; private final Localizer localizer = new Localizer(ValidatorImpl.class); private static class WrappedSAXException extends RuntimeException { final SAXException exception; WrappedSAXException(SAXException exception) { this.exception = exception; } } static class ActivePattern { final int rootDepth; final Pattern pattern; final SelectionHandler handler; ActivePattern(int rootDepth, Pattern pattern, SelectionHandler handler) { this.rootDepth = rootDepth; this.pattern = pattern; this.handler = handler; } } static class OpenElement { final String namespaceUri; final String localName; int nActivePatterns; int nValueHandlers; OpenElement(String namespaceUri, String localName) { this.namespaceUri = namespaceUri; this.localName = localName; } } class AttributePath implements Path { private Attributes atts; private int attIndex; void set(Attributes atts, int attIndex) { this.atts = atts; this.attIndex = attIndex; } public boolean isAttribute() { return true; } public int length() { return ValidatorImpl.this.length() + 1; } public String getLocalName(int i) { if (i == openElements.size()) return atts.getLocalName(attIndex); return ValidatorImpl.this.getLocalName(i); } public String getNamespaceUri(int i) { if (i == openElements.size()) return atts.getURI(attIndex); return ValidatorImpl.this.getNamespaceUri(i); } } ValidatorImpl(Constraint constraint, PropertyMap properties) { this.constraint = constraint; this.eh = properties.get(ValidateProperty.ERROR_HANDLER); } public ContentHandler getContentHandler() { return this; } public DTDHandler getDTDHandler() { return null; } public void reset() { openElements.setSize(0); valueHandlers.setSize(0); activePatterns.setSize(0); locator = null; } public int length() { return openElements.size(); } public String getLocalName(int i) { return ((OpenElement)openElements.elementAt(i)).localName; } public String getNamespaceUri(int i) { return ((OpenElement)openElements.elementAt(i)).namespaceUri; } public boolean isAttribute() { return false; } public void registerPattern(Pattern pattern, SelectionHandler handler) { // XXX what about case where it matches dot? activePatterns.push(new ActivePattern(openElements.size(), pattern, handler)); ((OpenElement)openElements.peek()).nActivePatterns += 1; } public void registerValueHandler(ValueHandler handler) { valueHandlers.push(handler); ((OpenElement)openElements.peek()).nValueHandlers += 1; } public void setDocumentLocator(Locator locator) { this.locator = locator; } public void startDocument() throws SAXException { if (locator == null) { LocatorImpl tem = new LocatorImpl(); tem.setLineNumber(-1); tem.setColumnNumber(-1); locator = tem; } openElements.push(new OpenElement("", "#root")); try { constraint.activate(this); } catch (WrappedSAXException e) { throw e.exception; } } public void endDocument() throws SAXException { try { popOpenElement(); } catch (WrappedSAXException e) { throw e.exception; } } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { try { openElements.push(new OpenElement(uri, localName)); for (int i = 0, len = valueHandlers.size(); i < len; i++) ((ValueHandler)valueHandlers.elementAt(i)).tag(this); for (int i = 0, len = activePatterns.size(); i < len; i++) { ActivePattern ap = (ActivePattern)activePatterns.elementAt(i); if (ap.pattern.matches(this, ap.rootDepth)) ap.handler.selectElement(this, this, this); } int nActivePatterns = activePatterns.size(); for (int i = 0, len = attributes.getLength(); i < len; i++) { attributePath.set(attributes, i); for (int j = 0; j < nActivePatterns; j++) { ActivePattern ap = (ActivePattern)activePatterns.elementAt(j); if (ap.pattern.matches(attributePath, ap.rootDepth)) ap.handler.selectAttribute(this, attributePath, attributes.getValue(i)); } } } catch (WrappedSAXException e) { throw e.exception; } } public void endElement(String uri, String localName, String qName) throws SAXException { try { popOpenElement(); } catch (WrappedSAXException e) { throw e.exception; } } public void characters(char ch[], int start, int length) throws SAXException { try { for (int i = 0, len = valueHandlers.size(); i < len; i++) ((ValueHandler)valueHandlers.elementAt(i)).characters(this, ch, start, length); } catch (WrappedSAXException e) { throw e.exception; } } public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { characters(ch, start, length); } private void popOpenElement() { OpenElement top = (OpenElement)openElements.pop(); for (int i = 0; i < top.nValueHandlers; i++) { ValueHandler h = (ValueHandler)valueHandlers.pop(); h.valueComplete(this); } for (int i = 0; i < top.nActivePatterns; i++) { ActivePattern ap = (ActivePattern)activePatterns.pop(); ap.handler.selectComplete(this); } } public void error(Locator locator, String key) { if (locator == null) locator = this.locator; try { eh.error(new SAXParseException(localizer.message(key), locator)); } catch (SAXException e) { throw new WrappedSAXException(e); } } public void error(Locator locator, String key, String arg) { if (locator == null) locator = this.locator; try { eh.error(new SAXParseException(localizer.message(key, arg), locator)); } catch (SAXException e) { throw new WrappedSAXException(e); } } public Locator saveLocator() { return new LocatorImpl(locator); } }