1 5 package xdoclet.util; 6 7 import java.io.File ; 8 import java.io.FileReader ; 9 import java.io.IOException ; 10 import java.io.StringReader ; 11 import java.net.URL ; 12 import java.util.ArrayList ; 13 import java.util.Collection ; 14 import java.util.HashMap ; 15 16 import javax.xml.parsers.ParserConfigurationException ; 17 import javax.xml.parsers.SAXParser ; 18 import javax.xml.parsers.SAXParserFactory ; 19 import org.apache.commons.logging.Log; 20 21 import org.apache.tools.ant.AntClassLoader; 22 23 import org.xml.sax.InputSource ; 24 import org.xml.sax.Parser ; 25 import org.xml.sax.SAXException ; 26 import org.xml.sax.SAXNotRecognizedException ; 27 import org.xml.sax.SAXNotSupportedException ; 28 import org.xml.sax.SAXParseException ; 29 import org.xml.sax.XMLReader ; 30 import org.xml.sax.helpers.DefaultHandler ; 31 import org.xml.sax.helpers.ParserAdapter ; 32 import xdoclet.XDocletException; 33 import xdoclet.XDocletMessages; 34 35 44 public class XmlValidator extends DefaultHandler 45 { 46 47 50 public final static String DEFAULT_XML_READER_CLASSNAME = "org.apache.crimson.parser.XMLReaderImpl"; 51 private final static String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource"; 52 private final static String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; 53 private final static String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; 54 55 private static XmlValidator instance = new XmlValidator(null); 56 57 protected ClassLoader classLoader; 58 59 62 protected XMLReader xmlReader = null; 63 64 protected String readerClassName = DEFAULT_XML_READER_CLASSNAME; 65 66 private final HashMap _dtds = new HashMap (); 67 private final Collection _schemas = new ArrayList (); 68 69 74 public XmlValidator(ClassLoader classLoader) 75 { 76 this.classLoader = classLoader; 77 } 78 79 84 public static XmlValidator getInstance() 85 { 86 return instance; 87 } 88 89 94 public static void setInstance(XmlValidator instance) 95 { 96 XmlValidator.instance = instance; 97 } 98 99 106 public void registerDTD(String publicId, URL dtdURL) 107 { 108 Log log = LogUtil.getLog(XmlValidator.class, "registerDTD"); 109 110 if (log.isDebugEnabled()) { 111 log.debug("DTD '" + dtdURL + "' registered for public Id '" + publicId + "'."); 112 } 113 114 _dtds.put(publicId, dtdURL); 115 } 116 117 122 public void registerSchema(URL schemaURL) 123 { 124 Log log = LogUtil.getLog(XmlValidator.class, "registerSchema"); 125 126 if (log.isDebugEnabled()) { 127 log.debug("Schema '" + schemaURL + "' registered."); 128 } 129 130 _schemas.add(schemaURL.toString()); 131 } 132 133 142 public InputSource resolveEntity(String publicId, String systemId) 143 { 144 Log log = LogUtil.getLog(XmlValidator.class, "resolveEntity"); 145 146 if (log.isDebugEnabled()) { 147 log.debug("publicId=" + publicId); 148 log.debug("systemId=" + systemId); 149 } 150 151 URL dtdURL = (URL ) _dtds.get(publicId); 152 153 if (dtdURL != null) { 154 String dtd = FileManager.getURLContent(dtdURL); 155 156 if (log.isDebugEnabled()) { 157 log.debug("dtdURL != null, dtdURL=" + dtdURL); 158 log.debug("dtd.length()=" + dtd.length()); 159 } 160 161 return new InputSource (new StringReader (dtd)); 162 } 163 else { 164 log.debug("dtdURL == null"); 165 166 String msg = Translator.getString(XDocletMessages.class, XDocletMessages.COULDNT_LOAD_LOCAL_DTD, new String []{publicId}); 167 168 if (isSchemaValidation()) { 170 log.debug(msg); 171 } 172 else { 173 log.error(msg); 174 } 175 return null; 176 } 177 } 178 179 185 public void error(SAXParseException e) 186 throws SAXParseException 187 { 188 throw e; 189 } 190 191 197 public void warning(SAXParseException e) 198 throws SAXParseException 199 { 200 } 202 203 211 public void validate(File xmlFile) throws XDocletException 212 { 213 if (classLoader == null) { 214 initValidator(); 217 } 218 else { 219 initValidatorHack(); 220 } 221 doValidate(xmlFile); 222 } 223 224 227 public void reset() 228 { 229 _schemas.clear(); 230 _dtds.clear(); 231 } 232 233 238 private boolean isSchemaValidation() 239 { 240 return !_schemas.isEmpty(); 241 } 242 243 246 252 private void doValidate(File xml_file) throws XDocletException 253 { 254 Log log = LogUtil.getLog(XmlValidator.class, "doValidate"); 255 256 try { 257 if (log.isDebugEnabled()) { 258 log.debug("Validating " + xml_file.getName() + "... "); 259 } 260 261 InputSource is = new InputSource (new FileReader (xml_file)); 263 String uri = "file:" + xml_file.getAbsolutePath().replace('\\', '/'); 264 265 for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) { 266 uri = uri.substring(0, index) + "%23" + uri.substring(index + 1); 267 } 268 269 is.setSystemId(uri); 270 271 xmlReader.parse(is); 272 } 273 catch (SAXParseException e) { 274 String message = Translator.getString(XDocletUtilMessages.class, XDocletUtilMessages.GENERATED_XML_INVALID, 275 new String []{e.getSystemId(), Integer.toString(e.getLineNumber()), e.getMessage()}); 276 277 throw new XDocletException(e, message); 278 } 279 catch (SAXException e) { 280 String message = Translator.getString(XDocletUtilMessages.class, XDocletUtilMessages.PARSING_FAILED, 281 new String []{xml_file.getAbsolutePath(), e.getMessage()}); 282 283 throw new XDocletException(e, message); 284 } 285 catch (IOException e) { 286 String message = Translator.getString(XDocletUtilMessages.class, XDocletUtilMessages.PARSING_FAILED, 287 new String []{xml_file.getAbsolutePath(), e.getMessage()}); 288 289 throw new XDocletException(e, message); 290 } 291 292 } 300 301 306 private void initValidatorHack() throws XDocletException 307 { 308 Log log = LogUtil.getLog(XmlValidator.class, "initValidator"); 309 310 if (isSchemaValidation()) { 312 log.warn(Translator.getString(XDocletUtilMessages.class, XDocletUtilMessages.PARSER_DOES_NOT_SUPPORT_XSD_VALIDATION)); 313 } 314 315 try { 316 Class readerClass = null; 319 320 if (classLoader != null) { 321 readerClass = classLoader.loadClass(readerClassName); 322 AntClassLoader.initializeClass(readerClass); 323 } 324 else { 325 readerClass = Class.forName(readerClassName); 326 } 327 328 if (XMLReader .class.isAssignableFrom(readerClass)) { 330 xmlReader = (XMLReader ) readerClass.newInstance(); 331 332 if (log.isDebugEnabled()) { 333 log.debug("Using SAX2 reader " + readerClassName); 334 } 335 } 336 else { 337 if (Parser .class.isAssignableFrom(readerClass)) { 339 Parser parser = (Parser ) readerClass.newInstance(); 340 341 xmlReader = new ParserAdapter (parser); 342 343 if (log.isDebugEnabled()) { 344 log.debug("Using SAX1 parser " + readerClassName); 345 } 346 } 347 else { 348 String message = Translator.getString(XDocletUtilMessages.class, XDocletUtilMessages.INIT_FAILED, new String []{readerClassName}); 349 350 System.out.println("init_failed"); 351 352 throw new XDocletException(message); 353 } 354 } 355 } 356 catch (ClassNotFoundException e) { 357 e.printStackTrace(); 358 359 String message = Translator.getString(XDocletUtilMessages.class, XDocletUtilMessages.INIT_FAILED, new String []{readerClassName}); 360 361 throw new XDocletException(e, message); 362 } 363 catch (InstantiationException e) { 364 e.printStackTrace(); 365 366 String message = Translator.getString(XDocletUtilMessages.class, XDocletUtilMessages.INIT_FAILED, new String []{readerClassName}); 367 368 throw new XDocletException(e, message); 369 } 370 catch (IllegalAccessException e) { 371 e.printStackTrace(); 372 373 String message = Translator.getString(XDocletUtilMessages.class, XDocletUtilMessages.INIT_FAILED, new String []{readerClassName}); 374 375 throw new XDocletException(e, message); 376 } 377 378 xmlReader.setEntityResolver(this); 380 381 if (!(xmlReader instanceof ParserAdapter )) { 382 try { 384 xmlReader.setFeature("http://xml.org/sax/features/validation", true); 385 } 386 catch (SAXNotRecognizedException e) { 387 e.printStackTrace(); 388 } 389 catch (SAXNotSupportedException e) { 390 e.printStackTrace(); 391 } 392 } 393 } 394 395 private void initValidator() throws XDocletException 396 { 397 Log log = LogUtil.getLog(XmlValidator.class, "initValidator"); 398 399 try { 400 SAXParserFactory factory = SAXParserFactory.newInstance(); 401 402 factory.setValidating(true); 403 factory.setNamespaceAware(isSchemaValidation()); 404 405 SAXParser parser; 407 408 try { 409 parser = factory.newSAXParser(); 410 if (log.isDebugEnabled()) { 411 log.debug("SAX Parser crated class=" + parser.getClass()); 412 } 413 } 414 catch (ParserConfigurationException e) { 415 if (!factory.isNamespaceAware()) { 418 throw e; 419 } 420 factory.setNamespaceAware(false); 421 parser = factory.newSAXParser(); 422 log.warn(Translator.getString(XDocletUtilMessages.class, XDocletUtilMessages.NO_NAMESPACE_AWARE_SAX_PARSER)); 423 } 424 425 if (isSchemaValidation() && parser.isNamespaceAware()) { 428 try { 429 parser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); 430 parser.setProperty(JAXP_SCHEMA_SOURCE, _schemas.toArray(new String [_schemas.size()])); 431 } 432 catch (SAXException e) { 433 factory.setValidating(false); 436 parser = factory.newSAXParser(); 437 log.warn(Translator.getString(XDocletUtilMessages.class, XDocletUtilMessages.PARSER_DOES_NOT_SUPPORT_XSD_VALIDATION)); 438 log.debug("JAXP 1.2 schema validation properties not recognized", e); 439 } 440 } 441 xmlReader = parser.getXMLReader(); 442 xmlReader.setEntityResolver(this); 443 xmlReader.setErrorHandler(this); 444 445 } 446 catch (SAXException e) { 447 throw new XDocletException(e, Translator.getString(XDocletMessages.class, XDocletMessages.COULDNT_INIT_XML_PARSER)); 448 } 449 catch (ParserConfigurationException e) { 450 throw new XDocletException(e, Translator.getString(XDocletMessages.class, XDocletMessages.COULDNT_CONF_XML_PARSER)); 451 } 452 catch (NullPointerException e) { 453 throw new XDocletException(e, Translator.getString(XDocletMessages.class, XDocletMessages.COULDNT_LOAD_DTD)); 454 } 455 } 456 } 457 | Popular Tags |