1 package com.thaiopensource.validate.mns; 2 3 import com.thaiopensource.validate.Schema; 4 import com.thaiopensource.validate.Validator; 5 import com.thaiopensource.validate.ValidateProperty; 6 import com.thaiopensource.validate.mns.ContextMap; 7 import com.thaiopensource.validate.mns.Hashset; 8 import com.thaiopensource.validate.mns.ElementsOrAttributes; 9 import com.thaiopensource.xml.util.Name; 10 import com.thaiopensource.util.Localizer; 11 import com.thaiopensource.util.PropertyMap; 12 import org.xml.sax.Attributes ; 13 import org.xml.sax.ErrorHandler ; 14 import org.xml.sax.Locator ; 15 import org.xml.sax.SAXException ; 16 import org.xml.sax.SAXParseException ; 17 import org.xml.sax.ContentHandler ; 18 import org.xml.sax.DTDHandler ; 19 import org.xml.sax.helpers.DefaultHandler ; 20 21 import java.util.Stack ; 22 import java.util.Hashtable ; 23 24 class ValidatorImpl extends DefaultHandler implements Validator { 25 private static final String BEARER_URI = ""; 26 private static final String BEARER_LOCAL_NAME = "#bearer"; 27 private SchemaImpl.Mode currentMode; 28 private int laxDepth = 0; 29 private final ErrorHandler eh; 30 private final PropertyMap properties; 31 private Locator locator; 32 private Subtree subtrees = null; 33 private final Hashset attributeNamespaces = new Hashset(); 34 private PrefixMapping prefixMapping = null; 35 private final Localizer localizer = new Localizer(ValidatorImpl.class); 36 private final Hashtable validatorCache = new Hashtable (); 37 38 static private class Subtree { 39 final Subtree parent; 40 final Validator validator; 41 final Schema schema; 42 final Hashset coveredNamespaces; 43 final ElementsOrAttributes prune; 44 final SchemaImpl.Mode parentMode; 45 final int parentLaxDepth; 46 final Stack context = new Stack (); 47 final ContextMap contextMap; 48 49 Subtree(Hashset coveredNamespaces, ContextMap contextMap, 50 ElementsOrAttributes prune, Validator validator, 51 Schema schema, SchemaImpl.Mode parentMode, int parentLaxDepth, Subtree parent) { 52 this.coveredNamespaces = coveredNamespaces; 53 this.contextMap = contextMap; 54 this.prune = prune; 55 this.validator = validator; 56 this.schema = schema; 57 this.parentMode = parentMode; 58 this.parentLaxDepth = parentLaxDepth; 59 this.parent = parent; 60 } 61 } 62 63 static private class PrefixMapping { 64 final String prefix; 65 final String uri; 66 final PrefixMapping parent; 67 68 PrefixMapping(String prefix, String uri, PrefixMapping parent) { 69 this.prefix = prefix; 70 this.uri = uri; 71 this.parent = parent; 72 } 73 } 74 75 ValidatorImpl(SchemaImpl.Mode mode, PropertyMap properties) { 76 this.currentMode = mode; 77 this.properties = properties; 78 this.eh = ValidateProperty.ERROR_HANDLER.get(properties); 79 } 80 81 public void setDocumentLocator(Locator locator) { 82 this.locator = locator; 83 } 84 85 public void characters(char ch[], int start, int length) 86 throws SAXException { 87 for (Subtree st = subtrees; wantsEvent(st); st = st.parent) 88 st.validator.getContentHandler().characters(ch, start, length); 89 } 90 91 public void ignorableWhitespace(char ch[], int start, int length) 92 throws SAXException { 93 for (Subtree st = subtrees; wantsEvent(st); st = st.parent) 94 st.validator.getContentHandler().ignorableWhitespace(ch, start, length); 95 } 96 97 private SchemaImpl.Mode getMode() { 98 if (subtrees != null) { 99 SchemaImpl.Mode mode = (SchemaImpl.Mode)subtrees.contextMap.get(subtrees.context); 100 if (mode != null) 101 return mode; 102 } 103 return currentMode; 104 } 105 106 public void startElement(String uri, String localName, 107 String qName, Attributes attributes) 108 throws SAXException { 109 if (namespaceCovered(uri)) 110 subtrees.context.push(new Name(uri, localName)); 111 else { 112 SchemaImpl.Mode mode = getMode(); 113 SchemaImpl.ElementAction elementAction = mode.getElementAction(uri); 114 if (elementAction == null) { 115 if (laxDepth == 0 && !mode.getLax().containsElements()) 116 error("element_undeclared_namespace", uri); 117 laxDepth++; 118 } 119 else { 120 subtrees = new Subtree(elementAction.getCoveredNamespaces(), 121 elementAction.getContextMap(), 122 elementAction.getPrune(), 123 createValidator(elementAction.getSchema()), 124 elementAction.getSchema(), 125 currentMode, 126 laxDepth, 127 subtrees); 128 subtrees.context.push(new Name(uri, localName)); 129 currentMode = elementAction.getMode(); 130 laxDepth = 0; 131 startSubtree(subtrees.validator.getContentHandler()); 132 } 133 } 134 for (Subtree st = subtrees; wantsEvent(st); st = st.parent) { 135 Attributes prunedAtts; 136 if (st.prune.containsAttributes()) 137 prunedAtts = new NamespaceFilteredAttributes(uri, true, attributes); 138 else 139 prunedAtts = attributes; 140 st.validator.getContentHandler().startElement(uri, localName, qName, prunedAtts); 141 } 142 for (int i = 0, len = attributes.getLength(); i < len; i++) { 143 String ns = attributes.getURI(i); 144 if (!ns.equals("") 145 && !ns.equals(uri) 146 && !namespaceCovered(ns) 147 && !attributeNamespaces.contains(ns)) { 148 attributeNamespaces.add(ns); 149 validateAttributes(ns, attributes); 150 } 151 } 152 attributeNamespaces.clear(); 153 } 154 155 private boolean namespaceCovered(String ns) { 156 return (laxDepth == 0 157 && subtrees != null 158 && subtrees.coveredNamespaces.contains(ns)); 159 } 160 161 private boolean wantsEvent(Subtree st) { 162 return st != null && (!st.prune.containsElements() || (laxDepth == 0 && st == subtrees)); 163 } 164 165 private void validateAttributes(String ns, Attributes attributes) throws SAXException { 166 SchemaImpl.Mode mode = getMode(); 167 Schema attributesSchema = mode.getAttributesSchema(ns); 168 if (attributesSchema == null) { 169 if (!mode.getLax().containsAttributes()) 170 error("attributes_undeclared_namespace", ns); 171 return; 172 } 173 Validator validator = createValidator(attributesSchema); 174 ContentHandler ch = validator.getContentHandler(); 175 startSubtree(ch); 176 ch.startElement(BEARER_URI, BEARER_LOCAL_NAME, BEARER_LOCAL_NAME, 177 new NamespaceFilteredAttributes(ns, false, attributes)); 178 ch.endElement(BEARER_URI, BEARER_LOCAL_NAME, BEARER_LOCAL_NAME); 179 endSubtree(ch); 180 releaseValidator(attributesSchema, validator); 181 } 182 183 private void startSubtree(ContentHandler ch) throws SAXException { 184 if (locator != null) 185 ch.setDocumentLocator(locator); 186 ch.startDocument(); 187 for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent) 188 ch.startPrefixMapping(pm.prefix, pm.uri); 189 } 190 191 private void endSubtree(ContentHandler ch) throws SAXException { 192 for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent) 193 ch.endPrefixMapping(pm.prefix); 194 ch.endDocument(); 195 } 196 197 public void endElement(String uri, String localName, String qName) 198 throws SAXException { 199 for (Subtree st = subtrees; wantsEvent(st); st = st.parent) 200 st.validator.getContentHandler().endElement(uri, localName, qName); 201 if (laxDepth > 0) 202 laxDepth--; 203 else if (!subtrees.context.empty()) { 204 subtrees.context.pop(); 205 if (subtrees.context.empty()) { 206 endSubtree(subtrees.validator.getContentHandler()); 207 releaseValidator(subtrees.schema, subtrees.validator); 208 currentMode = subtrees.parentMode; 209 laxDepth = subtrees.parentLaxDepth; 210 subtrees = subtrees.parent; 211 } 212 } 213 } 214 215 private Validator createValidator(Schema schema) { 216 Stack stack = (Stack )validatorCache.get(schema); 217 if (stack == null) { 218 stack = new Stack (); 219 validatorCache.put(schema, stack); 220 } 221 if (stack.empty()) 222 return schema.createValidator(properties); 223 return (Validator)stack.pop(); 224 } 225 226 private void releaseValidator(Schema schema, Validator validator) { 227 validator.reset(); 228 ((Stack )validatorCache.get(schema)).push(validator); 229 } 230 231 public void endDocument() 232 throws SAXException { 233 } 234 235 public void startPrefixMapping(String prefix, String uri) 236 throws SAXException { 237 super.startPrefixMapping(prefix, uri); 238 prefixMapping = new PrefixMapping(prefix, uri, prefixMapping); 239 } 240 241 public void endPrefixMapping(String prefix) 242 throws SAXException { 243 super.endPrefixMapping(prefix); 244 prefixMapping = prefixMapping.parent; 245 } 246 247 public void reset() { 248 subtrees = null; 249 locator = null; 250 } 251 252 public ContentHandler getContentHandler() { 253 return this; 254 } 255 256 public DTDHandler getDTDHandler() { 257 return null; 258 } 259 260 private void error(String key, String arg) throws SAXException { 261 eh.error(new SAXParseException (localizer.message(key, arg), locator)); 262 } 263 } 264 | Popular Tags |