1 package com.thaiopensource.validate.nrl; 2 3 import org.xml.sax.helpers.DefaultHandler ; 4 import org.xml.sax.ErrorHandler ; 5 import org.xml.sax.Attributes ; 6 import org.xml.sax.SAXException ; 7 import org.xml.sax.ContentHandler ; 8 import org.xml.sax.Locator ; 9 import org.xml.sax.SAXParseException ; 10 import org.xml.sax.DTDHandler ; 11 import com.thaiopensource.validate.Validator; 12 import com.thaiopensource.validate.Schema; 13 import com.thaiopensource.validate.ValidateProperty; 14 import com.thaiopensource.validate.nrl.ActionSet; 15 import com.thaiopensource.validate.nrl.AttributeActionSet; 16 import com.thaiopensource.validate.nrl.FilteredAttributes; 17 import com.thaiopensource.validate.nrl.Hashset; 18 import com.thaiopensource.validate.nrl.IntSet; 19 import com.thaiopensource.validate.nrl.Mode; 20 import com.thaiopensource.validate.nrl.ModeUsage; 21 import com.thaiopensource.validate.nrl.NoResultAction; 22 import com.thaiopensource.validate.nrl.ResultAction; 23 import com.thaiopensource.validate.nrl.SectionState; 24 import com.thaiopensource.util.Localizer; 25 import com.thaiopensource.util.PropertyMap; 26 27 import java.util.Vector ; 28 import java.util.Stack ; 29 import java.util.Hashtable ; 30 import java.util.Enumeration ; 31 32 class ValidatorImpl extends DefaultHandler implements Validator { 33 private static final String BEARER_URI = ""; 34 private static final String BEARER_LOCAL_NAME = "#bearer"; 35 private static final String NO_NS = "\0"; 36 private final ErrorHandler eh; 37 private final PropertyMap properties; 38 private Locator locator; 39 private Section currentSection; 40 private PrefixMapping prefixMapping = null; 41 private final Hashtable validatorHandlerCache = new Hashtable (); 42 private final Localizer localizer = new Localizer(ValidatorImpl.class); 43 private final Hashset noResultActions = new Hashset(); 44 private final Hashtable attributeNamespaceIndexSets = new Hashtable (); 45 private final Vector activeHandlersAttributeIndexSets = new Vector (); 46 private final Hashset attributeSchemas = new Hashset(); 47 private boolean attributeNamespaceRejected; 48 private Attributes filteredAttributes; 49 private final Mode startMode; 50 51 static private class PrefixMapping { 52 final String prefix; 53 final String uri; 54 final PrefixMapping parent; 55 56 PrefixMapping(String prefix, String uri, PrefixMapping parent) { 57 this.prefix = prefix; 58 this.uri = uri; 59 this.parent = parent; 60 } 61 } 62 63 private class Section implements SectionState { 64 final Section parent; 65 68 final String ns; 69 72 int depth = 0; 73 76 final Vector validators = new Vector (); 77 final Vector schemas = new Vector (); 78 81 final Vector activeHandlers = new Vector (); 82 final Vector activeHandlersAttributeModeUsage = new Vector (); 83 final Vector attributeValidationModeUsages = new Vector (); 84 87 final Vector childPrograms = new Vector (); 88 final Stack context = new Stack (); 89 boolean contextDependent = false; 90 int attributeProcessing = Mode.ATTRIBUTE_PROCESSING_NONE; 91 92 Section(String ns, Section parent) { 93 this.ns = ns; 94 this.parent = parent; 95 } 96 97 public void addChildMode(ModeUsage modeUsage, ContentHandler handler) { 98 childPrograms.addElement(new Program(modeUsage, handler)); 99 if (modeUsage.isContextDependent()) 100 contextDependent = true; 101 } 102 103 public void addValidator(Schema schema, ModeUsage modeUsage) { 104 schemas.addElement(schema); 105 Validator validator = createValidator(schema); 106 validators.addElement(validator); 107 activeHandlers.addElement(validator.getContentHandler()); 108 activeHandlersAttributeModeUsage.addElement(modeUsage); 109 attributeProcessing = Math.max(attributeProcessing, 110 modeUsage.getAttributeProcessing()); 111 childPrograms.addElement(new Program(modeUsage, validator.getContentHandler())); 112 if (modeUsage.isContextDependent()) 113 contextDependent = true; 114 } 115 116 public void addActiveHandler(ContentHandler handler, ModeUsage attributeModeUsage) { 117 activeHandlers.addElement(handler); 118 activeHandlersAttributeModeUsage.addElement(attributeModeUsage); 119 attributeProcessing = Math.max(attributeProcessing, 120 attributeModeUsage.getAttributeProcessing()); 121 if (attributeModeUsage.isContextDependent()) 122 contextDependent = true; 123 } 124 125 public void addAttributeValidationModeUsage(ModeUsage modeUsage) { 126 int ap = modeUsage.getAttributeProcessing(); 127 if (ap != Mode.ATTRIBUTE_PROCESSING_NONE) { 128 attributeValidationModeUsages.addElement(modeUsage); 129 attributeProcessing = Math.max(ap, attributeProcessing); 130 if (modeUsage.isContextDependent()) 131 contextDependent = true; 132 } 133 } 134 135 public void reject() throws SAXException { 136 if (eh != null) 137 eh.error(new SAXParseException (localizer.message("reject_element", ns), 138 locator)); 139 } 140 141 } 142 143 static private class Program { 144 final ModeUsage modeUsage; 145 final ContentHandler handler; 146 147 Program(ModeUsage modeUsage, ContentHandler handler) { 148 this.modeUsage = modeUsage; 149 this.handler = handler; 150 } 151 } 152 153 ValidatorImpl(Mode mode, PropertyMap properties) { 154 this.properties = properties; 155 this.eh = ValidateProperty.ERROR_HANDLER.get(properties); 156 this.startMode = mode; 157 initCurrentSection(); 158 } 159 160 private void initCurrentSection() { 161 currentSection = new Section(NO_NS, null); 162 currentSection.addChildMode(new ModeUsage(startMode, startMode), null); 163 } 164 165 public void setDocumentLocator(Locator locator) { 166 this.locator = locator; 167 } 168 169 public void characters(char ch[], int start, int length) 170 throws SAXException { 171 for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) 172 ((ContentHandler )(currentSection.activeHandlers.elementAt(i))).characters(ch, start, length); 173 174 } 175 176 public void ignorableWhitespace(char ch[], int start, int length) 177 throws SAXException { 178 for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) 179 ((ContentHandler )(currentSection.activeHandlers.elementAt(i))).ignorableWhitespace(ch, start, length); 180 } 181 182 public void startElement(String uri, String localName, 183 String qName, Attributes attributes) 184 throws SAXException { 185 if (!uri.equals(currentSection.ns)) 186 startSection(uri); 187 currentSection.depth++; 188 if (currentSection.contextDependent) 189 currentSection.context.push(localName); 190 boolean transformAttributes = processAttributes(attributes); 191 for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) { 192 ContentHandler handler = (ContentHandler )(currentSection.activeHandlers.elementAt(i)); 193 handler.startElement(uri, localName, qName, 194 transformAttributes 195 ? filterAttributes((IntSet)activeHandlersAttributeIndexSets.elementAt(i), 196 attributes) 197 : attributes); 198 } 199 } 200 201 private static Attributes filterAttributes(IntSet indexSet, Attributes attributes) { 202 if (indexSet.size() == attributes.getLength()) 203 return attributes; 204 return new FilteredAttributes(indexSet, attributes); 205 } 206 207 private boolean processAttributes(Attributes attributes) throws SAXException { 208 if (currentSection.attributeProcessing == Mode.ATTRIBUTE_PROCESSING_NONE 209 || attributes.getLength() == 0) 210 return false; 211 attributeNamespaceIndexSets.clear(); 212 for (int i = 0, len = attributes.getLength(); i < len; i++) { 213 String ns = attributes.getURI(i); 214 IntSet indexSet = (IntSet)attributeNamespaceIndexSets.get(ns); 215 if (indexSet == null) { 216 indexSet = new IntSet(); 217 attributeNamespaceIndexSets.put(ns, indexSet); 218 } 219 indexSet.add(i); 220 } 221 if (currentSection.attributeProcessing == Mode.ATTRIBUTE_PROCESSING_QUALIFIED 222 && attributeNamespaceIndexSets.size() == 1 223 && attributeNamespaceIndexSets.get("") != null) 224 return false; 225 Vector handlerModes = currentSection.activeHandlersAttributeModeUsage; 226 activeHandlersAttributeIndexSets.setSize(handlerModes.size()); 227 for (int i = 0, len = handlerModes.size(); i < len; i++) 228 activeHandlersAttributeIndexSets.setElementAt(new IntSet(), i); 229 boolean transform = false; 230 Vector validationModes = currentSection.attributeValidationModeUsages; 231 for (Enumeration e = attributeNamespaceIndexSets.keys(); e.hasMoreElements();) { 232 String ns = (String )e.nextElement(); 233 IntSet indexSet = (IntSet)attributeNamespaceIndexSets.get(ns); 234 attributeSchemas.clear(); 235 filteredAttributes = null; 236 attributeNamespaceRejected = false; 237 for (int i = 0, len = handlerModes.size(); i < len; i++) { 238 ModeUsage modeUsage = (ModeUsage)handlerModes.elementAt(i); 239 AttributeActionSet actions = processAttributeSection(modeUsage, ns, indexSet, attributes); 240 if (actions.getAttach()) 241 ((IntSet)activeHandlersAttributeIndexSets.get(i)).addAll(indexSet); 242 else 243 transform = true; 244 } 245 for (int i = 0, len = validationModes.size(); i < len; i++) { 246 ModeUsage modeUsage = (ModeUsage)validationModes.elementAt(i); 247 processAttributeSection(modeUsage, ns, indexSet, attributes); 248 } 249 } 250 return transform; 251 } 252 253 private AttributeActionSet processAttributeSection(ModeUsage modeUsage, 254 String ns, 255 IntSet indexSet, 256 Attributes attributes) 257 throws SAXException { 258 Mode mode = modeUsage.getMode(currentSection.context); 259 AttributeActionSet actions = mode.getAttributeActions(ns); 260 if (actions.getReject() && !attributeNamespaceRejected) { 261 attributeNamespaceRejected = true; 262 if (eh != null) 263 eh.error(new SAXParseException (localizer.message("reject_attribute", ns), 264 locator)); 265 } 266 Schema[] schemas = actions.getSchemas(); 267 for (int j = 0; j < schemas.length; j++) { 268 if (attributeSchemas.contains(schemas[j])) 269 continue; 270 attributeSchemas.add(schemas[j]); 271 if (filteredAttributes == null) 272 filteredAttributes = filterAttributes(indexSet, attributes); 273 validateAttributes(schemas[j], filteredAttributes); 274 } 275 return actions; 276 } 277 278 private void validateAttributes(Schema schema, Attributes attributes) throws SAXException { 279 Validator validator = createValidator(schema); 280 ContentHandler ch = validator.getContentHandler(); 281 initHandler(ch); 282 ch.startElement(BEARER_URI, BEARER_LOCAL_NAME, BEARER_LOCAL_NAME, attributes); 283 ch.endElement(BEARER_URI, BEARER_LOCAL_NAME, BEARER_LOCAL_NAME); 284 cleanupHandler(ch); 285 releaseValidator(schema, validator); 286 } 287 288 private void startSection(String uri) throws SAXException { 289 Section section = new Section(uri, currentSection); 290 Vector childPrograms = currentSection.childPrograms; 291 noResultActions.clear(); 292 for (int i = 0, len = childPrograms.size(); i < len; i++) { 293 Program program = (Program)childPrograms.elementAt(i); 294 ActionSet actions = program.modeUsage.getMode(currentSection.context).getElementActions(uri); 295 ResultAction resultAction = actions.getResultAction(); 296 if (resultAction != null) 297 resultAction.perform(program.handler, section); 298 NoResultAction[] nra = actions.getNoResultActions(); 299 for (int j = 0; j < nra.length; j++) { 300 NoResultAction tem = nra[j]; 301 if (!noResultActions.contains(tem)) { 302 nra[j].perform(section); 303 noResultActions.add(tem); 304 } 305 } 306 } 307 for (int i = 0, len = section.validators.size(); i < len; i++) 308 initHandler(((Validator)section.validators.elementAt(i)).getContentHandler()); 309 currentSection = section; 310 } 311 312 private void initHandler(ContentHandler ch) throws SAXException { 313 if (locator != null) 314 ch.setDocumentLocator(locator); 315 ch.startDocument(); 316 for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent) 317 ch.startPrefixMapping(pm.prefix, pm.uri); 318 } 319 320 public void endElement(String uri, String localName, String qName) 321 throws SAXException { 322 for (int i = 0, len = currentSection.activeHandlers.size(); i < len; i++) 323 ((ContentHandler )(currentSection.activeHandlers.elementAt(i))).endElement(uri, localName, qName); 324 currentSection.depth--; 325 if (currentSection.contextDependent) 326 currentSection.context.pop(); 327 if (currentSection.depth == 0) 328 endSection(); 329 } 330 331 private void endSection() throws SAXException { 332 for (int i = 0, len = currentSection.validators.size(); i < len; i++) { 333 Validator validator = (Validator)currentSection.validators.elementAt(i); 334 cleanupHandler(validator.getContentHandler()); 335 releaseValidator((Schema)currentSection.schemas.elementAt(i), validator); 336 currentSection.validators.setElementAt(null, i); 339 } 340 currentSection = currentSection.parent; 341 } 342 343 private void cleanupHandler(ContentHandler vh) throws SAXException { 344 for (PrefixMapping pm = prefixMapping; pm != null; pm = pm.parent) 345 vh.endPrefixMapping(pm.prefix); 346 vh.endDocument(); 347 } 348 349 public void endDocument() 350 throws SAXException { 351 } 352 353 public void startPrefixMapping(String prefix, String uri) 354 throws SAXException { 355 super.startPrefixMapping(prefix, uri); 356 prefixMapping = new PrefixMapping(prefix, uri, prefixMapping); 357 } 358 359 public void endPrefixMapping(String prefix) 360 throws SAXException { 361 super.endPrefixMapping(prefix); 362 prefixMapping = prefixMapping.parent; 363 } 364 365 private Validator createValidator(Schema schema) { 366 Stack stack = (Stack )validatorHandlerCache.get(schema); 367 if (stack == null) { 368 stack = new Stack (); 369 validatorHandlerCache.put(schema, stack); 370 } 371 if (stack.empty()) 372 return schema.createValidator(properties); 373 return (Validator)stack.pop(); 374 } 375 376 private void releaseValidator(Schema schema, Validator vh) { 377 if (vh == null) 378 return; 379 vh.reset(); 380 ((Stack )validatorHandlerCache.get(schema)).push(vh); 381 } 382 383 public void reset() { 384 for (; currentSection != null; currentSection = currentSection.parent) { 385 for (int i = 0, len = currentSection.validators.size(); i < len; i++) 386 releaseValidator((Schema)currentSection.schemas.elementAt(i), 387 (Validator)currentSection.validators.elementAt(i)); 388 } 389 initCurrentSection(); 390 } 391 392 public ContentHandler getContentHandler() { 393 return this; 394 } 395 396 public DTDHandler getDTDHandler() { 397 return this; 398 } 399 } 400 | Popular Tags |