001 package com.thaiopensource.validate.xerces; 002 003 import com.thaiopensource.util.PropertyMap; 004 import com.thaiopensource.validate.ValidateProperty; 005 import com.thaiopensource.validate.Validator; 006 007 import org.apache.xerces.impl.XMLEntityManager; 008 import org.apache.xerces.impl.XMLErrorReporter; 009 import org.apache.xerces.impl.validation.EntityState; 010 import org.apache.xerces.impl.validation.ValidationManager; 011 import org.apache.xerces.impl.xs.XMLSchemaValidator; 012 import org.apache.xerces.util.NamespaceSupport; 013 import org.apache.xerces.util.ParserConfigurationSettings; 014 import org.apache.xerces.util.SymbolTable; 015 import org.apache.xerces.util.XMLAttributesImpl; 016 import org.apache.xerces.util.XMLSymbols; 017 import org.apache.xerces.util.ErrorHandlerWrapper; 018 import org.apache.xerces.xni.NamespaceContext; 019 import org.apache.xerces.xni.QName; 020 import org.apache.xerces.xni.XMLAttributes; 021 import org.apache.xerces.xni.XMLLocator; 022 import org.apache.xerces.xni.XMLResourceIdentifier; 023 import org.apache.xerces.xni.XMLString; 024 import org.apache.xerces.xni.XNIException; 025 import org.apache.xerces.xni.grammars.XMLGrammarPool; 026 import org.apache.xerces.xni.parser.XMLComponent; 027 import org.apache.xerces.xni.parser.XMLEntityResolver; 028 import org.apache.xerces.xni.parser.XMLInputSource; 029 import org.apache.xerces.xni.parser.XMLParseException; 030 import org.apache.xerces.xni.parser.XMLErrorHandler; 031 import org.xml.sax.Attributes; 032 import org.xml.sax.Locator; 033 import org.xml.sax.SAXException; 034 import org.xml.sax.SAXParseException; 035 import org.xml.sax.DTDHandler; 036 import org.xml.sax.ContentHandler; 037 038 import java.io.IOException; 039 import java.util.Hashtable; 040 041 class ValidatorImpl extends ParserConfigurationSettings implements Validator, ContentHandler, DTDHandler, XMLLocator, XMLEntityResolver, EntityState { 042 043 private final XMLSchemaValidator schemaValidator = new XMLSchemaValidator(); 044 private final XMLErrorReporter errorReporter = new XMLErrorReporter(); 045 private final XMLEntityManager entityManager = new XMLEntityManager(); 046 private final ValidationManager validationManager = new ValidationManager(); 047 private final NamespaceContext namespaceContext = new NamespaceSupport(); 048 private final XMLAttributes attributes = new XMLAttributesImpl(); 049 private final SymbolTable symbolTable; 050 private final XMLComponent[] components; 051 private Locator locator; 052 private final Hashtable entityTable = new Hashtable(); 053 private boolean pushedContext = false; 054 055 // JC deal with baseURI 056 057 static private final String[] recognizedFeatures = { 058 Features.SCHEMA_AUGMENT_PSVI, 059 Features.SCHEMA_FULL_CHECKING, 060 Features.VALIDATION, 061 Features.SCHEMA_VALIDATION, 062 }; 063 064 static private final String[] recognizedProperties = { 065 Properties.XMLGRAMMAR_POOL, 066 Properties.SYMBOL_TABLE, 067 Properties.ERROR_REPORTER, 068 Properties.ERROR_HANDLER, 069 Properties.VALIDATION_MANAGER, 070 Properties.ENTITY_MANAGER, 071 Properties.ENTITY_RESOLVER, 072 }; 073 074 ValidatorImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool, PropertyMap properties) { 075 this.symbolTable = symbolTable; 076 XMLErrorHandler errorHandlerWrapper = new ErrorHandlerWrapper(ValidateProperty.ERROR_HANDLER.get(properties)); 077 components = new XMLComponent[] { errorReporter, schemaValidator, entityManager }; 078 for (int i = 0; i < components.length; i++) { 079 addRecognizedFeatures(components[i].getRecognizedFeatures()); 080 addRecognizedProperties(components[i].getRecognizedProperties()); 081 } 082 addRecognizedFeatures(recognizedFeatures); 083 addRecognizedProperties(recognizedProperties); 084 setFeature(Features.SCHEMA_AUGMENT_PSVI, false); 085 setFeature(Features.SCHEMA_FULL_CHECKING, true); 086 setFeature(Features.VALIDATION, true); 087 setFeature(Features.SCHEMA_VALIDATION, true); 088 setProperty(Properties.XMLGRAMMAR_POOL, grammarPool); 089 setProperty(Properties.SYMBOL_TABLE, symbolTable); 090 errorReporter.setDocumentLocator(this); 091 setProperty(Properties.ERROR_REPORTER, errorReporter); 092 setProperty(Properties.ERROR_HANDLER, errorHandlerWrapper); 093 setProperty(Properties.VALIDATION_MANAGER, validationManager); 094 // In Xerces 2.4.0, XMLSchemaValidator uses ENTITY_MANAGER when 095 // it should use ENTITY_RESOLVER 096 097 // George: comment out the next line, otherwise 098 // with newwe versions of Xerces we got a CCE if I remember right... 099 100 setProperty(Properties.ENTITY_MANAGER, entityManager); 101 102 setProperty(Properties.ENTITY_RESOLVER, this); 103 reset(); 104 } 105 106 public void reset() { 107 validationManager.reset(); 108 namespaceContext.reset(); 109 for (int i = 0; i < components.length; i++) 110 components[i].reset(this); 111 validationManager.setEntityState(this); 112 } 113 114 public ContentHandler getContentHandler() { 115 return this; 116 } 117 118 public DTDHandler getDTDHandler() { 119 return this; 120 } 121 122 public void setDocumentLocator(Locator locator) { 123 this.locator = locator; 124 } 125 126 public void notationDecl(String name, 127 String publicId, 128 String systemId) { 129 // nothing needed 130 } 131 132 public void unparsedEntityDecl(String name, 133 String publicId, 134 String systemId, 135 String notationName) { 136 entityTable.put(name, name); 137 } 138 139 public boolean isEntityDeclared(String name) { 140 return entityTable.get(name) != null; 141 } 142 143 public boolean isEntityUnparsed(String name) { 144 return entityTable.get(name) != null; 145 } 146 147 public void startDocument() 148 throws SAXException { 149 try { 150 schemaValidator.startDocument(locator == null ? null : this, null, namespaceContext, null); 151 } 152 catch (XNIException e) { 153 throw toSAXException(e); 154 } 155 } 156 157 public void endDocument() 158 throws SAXException { 159 try { 160 schemaValidator.endDocument(null); 161 } 162 catch (XNIException e) { 163 throw toSAXException(e); 164 } 165 } 166 167 public void startElement(String namespaceURI, String localName, 168 String qName, Attributes atts) 169 throws SAXException { 170 try { 171 if (!pushedContext) 172 namespaceContext.pushContext(); 173 else 174 pushedContext = false; 175 for (int i = 0, len = atts.getLength(); i < len; i++) 176 attributes.addAttribute(makeQName(atts.getURI(i), atts.getLocalName(i), atts.getQName(i)), 177 symbolTable.addSymbol(atts.getType(i)), 178 atts.getValue(i)); 179 schemaValidator.startElement(makeQName(namespaceURI, localName, qName), attributes, null); 180 attributes.removeAllAttributes(); 181 } 182 catch (XNIException e) { 183 throw toSAXException(e); 184 } 185 } 186 187 public void endElement(String namespaceURI, String localName, 188 String qName) 189 throws SAXException { 190 try { 191 schemaValidator.endElement(makeQName(namespaceURI, localName, qName), null); 192 namespaceContext.popContext(); 193 } 194 catch (XNIException e) { 195 throw toSAXException(e); 196 } 197 } 198 199 public void startPrefixMapping(String prefix, String uri) 200 throws SAXException { 201 try { 202 if (!pushedContext) { 203 namespaceContext.pushContext(); 204 pushedContext = true; 205 } 206 if (prefix == null) 207 prefix = XMLSymbols.EMPTY_STRING; 208 else 209 prefix = symbolTable.addSymbol(prefix); 210 if (uri != null) { 211 if (uri.equals("")) 212 uri = null; 213 else 214 uri = symbolTable.addSymbol(uri); 215 } 216 namespaceContext.declarePrefix(prefix, uri); 217 } 218 catch (XNIException e) { 219 throw toSAXException(e); 220 } 221 } 222 223 public void endPrefixMapping(String prefix) 224 throws SAXException { 225 // do nothing 226 } 227 228 public void characters(char ch[], int start, int length) 229 throws SAXException { 230 try { 231 schemaValidator.characters(new XMLString(ch, start, length), null); 232 } 233 catch (XNIException e) { 234 throw toSAXException(e); 235 } 236 } 237 238 public void ignorableWhitespace(char ch[], int start, int length) 239 throws SAXException { 240 try { 241 schemaValidator.ignorableWhitespace(new XMLString(ch, start, length), null); 242 } 243 catch (XNIException e) { 244 throw toSAXException(e); 245 } 246 } 247 248 public void processingInstruction(String target, String data) 249 throws SAXException { 250 // do nothing 251 } 252 253 public void skippedEntity(String name) 254 throws SAXException { 255 // do nothing 256 } 257 258 private QName makeQName(String namespaceURI, String localName, String qName) { 259 localName = symbolTable.addSymbol(localName); 260 String prefix; 261 if (namespaceURI.equals("")) { 262 namespaceURI = null; 263 prefix = XMLSymbols.EMPTY_STRING; 264 qName = localName; 265 } 266 else { 267 namespaceURI = symbolTable.addSymbol(namespaceURI); 268 if (qName.equals("")) { 269 prefix = namespaceContext.getPrefix(namespaceURI); 270 if (prefix == XMLSymbols.EMPTY_STRING) 271 qName = localName; 272 else if (prefix == null) 273 qName = localName; // JC what to do? 274 else 275 qName = symbolTable.addSymbol(prefix + ":" + localName); 276 } 277 else { 278 qName = symbolTable.addSymbol(qName); 279 int colon = qName.indexOf(':'); 280 if (colon > 0) 281 prefix = symbolTable.addSymbol(qName.substring(0, colon)); 282 else 283 prefix = XMLSymbols.EMPTY_STRING; 284 } 285 } 286 return new QName(prefix, localName, qName, namespaceURI); 287 } 288 289 public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) 290 throws XNIException, IOException { 291 return null; 292 } 293 294 public String getPublicId() { 295 return locator.getPublicId(); 296 } 297 298 public String getEncoding() { 299 return null; 300 } 301 302 public String getBaseSystemId() { 303 return null; 304 } 305 306 public String getLiteralSystemId() { 307 return null; 308 } 309 310 public String getExpandedSystemId() { 311 return locator.getSystemId(); 312 } 313 314 public int getLineNumber() { 315 return locator.getLineNumber(); 316 } 317 318 public int getColumnNumber() { 319 return locator.getColumnNumber(); 320 } 321 322 static SAXException toSAXException(XNIException e) { 323 if (e instanceof XMLParseException) { 324 XMLParseException pe = (XMLParseException)e; 325 return new SAXParseException(pe.getMessage(), 326 pe.getPublicId(), 327 pe.getExpandedSystemId(), 328 pe.getLineNumber(), 329 pe.getColumnNumber(), 330 pe.getException()); 331 } 332 Exception nested = e.getException(); 333 if (nested == null) 334 return new SAXException(e.getMessage()); 335 if (nested instanceof SAXException) 336 return (SAXException)nested; 337 if (nested instanceof RuntimeException) 338 throw (RuntimeException)nested; 339 return new SAXException(nested); 340 } 341 342 /** 343 * This is needed by the Xerces 2.7.0 - we do not include it yet 344 * as it is not yet released but made an integration from CVS some 345 * time ago. When reverting to 2.6.2 the method remained here as we 346 * will neet it when we will get back to 2.7.0. 347 * 348 * @see org.apache.xerces.xni.XMLLocator#getCharacterOffset() 349 */ 350 public int getCharacterOffset() { 351 return 0; 352 } 353 354 /** 355 * This is needed by the Xerces 2.7.0 - we do not include it yet 356 * as it is not yet released but made an integration from CVS some 357 * time ago. When reverting to 2.6.2 the method remained here as we 358 * will neet it when we will get back to 2.7.0. 359 * 360 * @see org.apache.xerces.xni.XMLLocator#getXMLVersion() 361 */ 362 public String getXMLVersion() { 363 return "1.0"; 364 } 365 }