1 18 package org.apache.tools.ant.taskdefs.optional; 19 20 import java.io.File ; 21 import java.io.FileInputStream ; 22 import java.io.IOException ; 23 import java.util.Vector ; 24 25 import org.apache.tools.ant.AntClassLoader; 26 import org.apache.tools.ant.BuildException; 27 import org.apache.tools.ant.DirectoryScanner; 28 import org.apache.tools.ant.Project; 29 import org.apache.tools.ant.Task; 30 import org.apache.tools.ant.types.DTDLocation; 31 import org.apache.tools.ant.types.FileSet; 32 import org.apache.tools.ant.types.Path; 33 import org.apache.tools.ant.types.Reference; 34 import org.apache.tools.ant.types.XMLCatalog; 35 import org.apache.tools.ant.util.FileUtils; 36 import org.apache.tools.ant.util.JAXPUtils; 37 import org.apache.tools.ant.util.XmlConstants; 38 39 import org.xml.sax.EntityResolver ; 40 import org.xml.sax.ErrorHandler ; 41 import org.xml.sax.InputSource ; 42 import org.xml.sax.Parser ; 43 import org.xml.sax.SAXException ; 44 import org.xml.sax.SAXNotRecognizedException ; 45 import org.xml.sax.SAXNotSupportedException ; 46 import org.xml.sax.SAXParseException ; 47 import org.xml.sax.XMLReader ; 48 import org.xml.sax.helpers.ParserAdapter ; 49 50 57 public class XMLValidateTask extends Task { 58 59 62 private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); 63 64 protected static final String INIT_FAILED_MSG = 65 "Could not start xml validation: "; 66 67 protected boolean failOnError = true; 71 protected boolean warn = true; 72 protected boolean lenient = false; 73 protected String readerClassName = null; 74 75 76 protected File file = null; 77 78 protected Vector filesets = new Vector (); 79 protected Path classpath; 80 81 87 protected XMLReader xmlReader = null; 88 protected ValidatorErrorHandler errorHandler = new ValidatorErrorHandler(); 90 93 94 private Vector attributeList = new Vector (); 95 96 99 private final Vector propertyList = new Vector (); 100 101 private XMLCatalog xmlCatalog = new XMLCatalog(); 102 103 public static final String MESSAGE_FILES_VALIDATED 104 = " file(s) have been successfully validated."; 105 106 114 public void setFailOnError(boolean fail) { 115 failOnError = fail; 116 } 117 118 124 public void setWarn(boolean bool) { 125 warn = bool; 126 } 127 128 139 public void setLenient(boolean bool) { 140 lenient = bool; 141 } 142 143 154 public void setClassName(String className) { 155 readerClassName = className; 156 } 157 158 162 public void setClasspath(Path classpath) { 163 if (this.classpath == null) { 164 this.classpath = classpath; 165 } else { 166 this.classpath.append(classpath); 167 } 168 } 169 170 174 public Path createClasspath() { 175 if (this.classpath == null) { 176 this.classpath = new Path(getProject()); 177 } 178 return this.classpath.createPath(); 179 } 180 181 186 public void setClasspathRef(Reference r) { 187 createClasspath().setRefid(r); 188 } 189 190 194 public void setFile(File file) { 195 this.file = file; 196 } 197 198 202 public void addConfiguredXMLCatalog(XMLCatalog catalog) { 203 xmlCatalog.addConfiguredXMLCatalog(catalog); 204 } 205 206 210 public void addFileset(FileSet set) { 211 filesets.addElement(set); 212 } 213 214 224 public Attribute createAttribute() { 225 final Attribute feature = new Attribute(); 226 attributeList.addElement(feature); 227 return feature; 228 } 229 230 236 public Property createProperty() { 237 final Property prop = new Property(); 238 propertyList.addElement(prop); 239 return prop; 240 } 241 242 247 public void init() throws BuildException { 248 super.init(); 249 xmlCatalog.setProject(getProject()); 250 } 251 252 258 public DTDLocation createDTD() { 259 DTDLocation dtdLocation = new DTDLocation(); 260 xmlCatalog.addDTD(dtdLocation); 261 return dtdLocation; 262 } 263 267 protected EntityResolver getEntityResolver() { 268 return xmlCatalog; 269 } 270 271 279 protected XMLReader getXmlReader() { 280 return xmlReader; 281 } 282 283 287 public void execute() throws BuildException { 288 289 int fileProcessed = 0; 290 if (file == null && (filesets.size() == 0)) { 291 throw new BuildException( 292 "Specify at least one source - " + "a file or a fileset."); 293 } 294 295 296 297 if (file != null) { 298 if (file.exists() && file.canRead() && file.isFile()) { 299 doValidate(file); 300 fileProcessed++; 301 } else { 302 String errorMsg = "File " + file + " cannot be read"; 303 if (failOnError) { 304 throw new BuildException(errorMsg); 305 } else { 306 log(errorMsg, Project.MSG_ERR); 307 } 308 } 309 } 310 311 for (int i = 0; i < filesets.size(); i++) { 312 313 FileSet fs = (FileSet) filesets.elementAt(i); 314 DirectoryScanner ds = fs.getDirectoryScanner(getProject()); 315 String [] files = ds.getIncludedFiles(); 316 317 for (int j = 0; j < files.length; j++) { 318 File srcFile = new File (fs.getDir(getProject()), files[j]); 319 doValidate(srcFile); 320 fileProcessed++; 321 } 322 } 323 onSuccessfulValidation(fileProcessed); 324 } 325 326 330 protected void onSuccessfulValidation(int fileProcessed) { 331 log(fileProcessed + MESSAGE_FILES_VALIDATED); 332 } 333 334 340 protected void initValidator() { 341 342 xmlReader = createXmlReader(); 343 344 xmlReader.setEntityResolver(getEntityResolver()); 345 xmlReader.setErrorHandler(errorHandler); 346 347 if (!isSax1Parser()) { 348 if (!lenient) { 350 setFeature(XmlConstants.FEATURE_VALIDATION, true); 351 } 352 for (int i = 0; i < attributeList.size(); i++) { 354 Attribute feature = (Attribute) attributeList.elementAt(i); 355 setFeature(feature.getName(), feature.getValue()); 356 357 } 358 for (int i = 0; i < propertyList.size(); i++) { 360 final Property prop = (Property) propertyList.elementAt(i); 361 setProperty(prop.getName(), prop.getValue()); 362 } 363 } 364 } 365 366 370 protected boolean isSax1Parser() { 371 return (xmlReader instanceof ParserAdapter ); 372 } 373 374 382 protected XMLReader createXmlReader() { 383 Object reader = null; 384 if (readerClassName == null) { 385 reader = createDefaultReaderOrParser(); 386 } else { 387 388 Class readerClass = null; 389 try { 390 if (classpath != null) { 392 AntClassLoader loader = 393 getProject().createClassLoader(classpath); 394 readerClass = Class.forName(readerClassName, true, loader); 395 } else { 396 readerClass = Class.forName(readerClassName); 397 } 398 399 reader = readerClass.newInstance(); 400 } catch (ClassNotFoundException e) { 401 throw new BuildException(INIT_FAILED_MSG + readerClassName, e); 402 } catch (InstantiationException e) { 403 throw new BuildException(INIT_FAILED_MSG + readerClassName, e); 404 } catch (IllegalAccessException e) { 405 throw new BuildException(INIT_FAILED_MSG + readerClassName, e); 406 } 407 } 408 409 XMLReader newReader; 411 if (reader instanceof XMLReader ) { 412 newReader = (XMLReader ) reader; 413 log( 414 "Using SAX2 reader " + reader.getClass().getName(), 415 Project.MSG_VERBOSE); 416 } else { 417 418 if (reader instanceof Parser ) { 420 newReader = new ParserAdapter ((Parser ) reader); 421 log( 422 "Using SAX1 parser " + reader.getClass().getName(), 423 Project.MSG_VERBOSE); 424 } else { 425 throw new BuildException( 426 INIT_FAILED_MSG 427 + reader.getClass().getName() 428 + " implements nor SAX1 Parser nor SAX2 XMLReader."); 429 } 430 } 431 return newReader; 432 } 433 434 438 private Object createDefaultReaderOrParser() { 439 Object reader; 440 try { 441 reader = createDefaultReader(); 442 } catch (BuildException exc) { 443 reader = JAXPUtils.getParser(); 444 } 445 return reader; 446 } 447 448 455 protected XMLReader createDefaultReader() { 456 return JAXPUtils.getXMLReader(); 457 } 458 459 465 protected void setFeature(String feature, boolean value) 466 throws BuildException { 467 log("Setting feature " + feature + "=" + value, Project.MSG_DEBUG); 468 try { 469 xmlReader.setFeature(feature, value); 470 } catch (SAXNotRecognizedException e) { 471 throw new BuildException( 472 "Parser " 473 + xmlReader.getClass().getName() 474 + " doesn't recognize feature " 475 + feature, 476 e, 477 getLocation()); 478 } catch (SAXNotSupportedException e) { 479 throw new BuildException( 480 "Parser " 481 + xmlReader.getClass().getName() 482 + " doesn't support feature " 483 + feature, 484 e, 485 getLocation()); 486 } 487 } 488 489 497 protected void setProperty(String name, String value) throws BuildException { 498 if (name == null || value == null) { 500 throw new BuildException("Property name and value must be specified."); 501 } 502 503 try { 504 xmlReader.setProperty(name, value); 505 } catch (SAXNotRecognizedException e) { 506 throw new BuildException( 507 "Parser " 508 + xmlReader.getClass().getName() 509 + " doesn't recognize property " 510 + name, 511 e, 512 getLocation()); 513 } catch (SAXNotSupportedException e) { 514 throw new BuildException( 515 "Parser " 516 + xmlReader.getClass().getName() 517 + " doesn't support property " 518 + name, 519 e, 520 getLocation()); 521 } 522 } 523 524 529 protected boolean doValidate(File afile) { 530 initValidator(); 532 boolean result = true; 533 try { 534 log("Validating " + afile.getName() + "... ", Project.MSG_VERBOSE); 535 errorHandler.init(afile); 536 InputSource is = new InputSource (new FileInputStream (afile)); 537 String uri = FILE_UTILS.toURI(afile.getAbsolutePath()); 538 is.setSystemId(uri); 539 xmlReader.parse(is); 540 } catch (SAXException ex) { 541 log("Caught when validating: " + ex.toString(), Project.MSG_DEBUG); 542 if (failOnError) { 543 throw new BuildException( 544 "Could not validate document " + afile); 545 } 546 log("Could not validate document " + afile + ": " + ex.toString()); 547 result = false; 548 } catch (IOException ex) { 549 throw new BuildException( 550 "Could not validate document " + afile, 551 ex); 552 } 553 if (errorHandler.getFailure()) { 554 if (failOnError) { 555 throw new BuildException( 556 afile + " is not a valid XML document."); 557 } 558 result = false; 559 log(afile + " is not a valid XML document", Project.MSG_ERR); 560 } 561 return result; 562 } 563 564 571 protected class ValidatorErrorHandler implements ErrorHandler { 572 573 protected File currentFile = null; 575 protected String lastErrorMessage = null; 576 protected boolean failed = false; 577 582 public void init(File file) { 583 currentFile = file; 584 failed = false; 585 } 586 590 public boolean getFailure() { 591 return failed; 592 } 593 594 598 public void fatalError(SAXParseException exception) { 599 failed = true; 600 doLog(exception, Project.MSG_ERR); 601 } 602 606 public void error(SAXParseException exception) { 607 failed = true; 608 doLog(exception, Project.MSG_ERR); 609 } 610 614 public void warning(SAXParseException exception) { 615 if (warn) { 618 doLog(exception, Project.MSG_WARN); 619 } 620 } 621 622 private void doLog(SAXParseException e, int logLevel) { 623 624 log(getMessage(e), logLevel); 625 } 626 627 private String getMessage(SAXParseException e) { 628 String sysID = e.getSystemId(); 629 if (sysID != null) { 630 String name = sysID; 631 if (sysID.startsWith("file:")) { 632 try { 633 name = FILE_UTILS.fromURI(sysID); 634 } catch (Exception ex) { 635 } 637 } 638 int line = e.getLineNumber(); 639 int col = e.getColumnNumber(); 640 return name 641 + (line == -1 642 ? "" 643 : (":" + line + (col == -1 ? "" : (":" + col)))) 644 + ": " 645 + e.getMessage(); 646 } 647 return e.getMessage(); 648 } 649 } 650 651 655 public static class Attribute { 656 662 private String attributeName = null; 663 664 667 private boolean attributeValue; 668 669 673 public void setName(String name) { 674 attributeName = name; 675 } 676 680 public void setValue(boolean value) { 681 attributeValue = value; 682 } 683 684 688 public String getName() { 689 return attributeName; 690 } 691 692 696 public boolean getValue() { 697 return attributeValue; 698 } 699 } 700 701 707 public static final class Property { 708 709 private String name; 710 private String value; 711 715 public String getName() { 716 return name; 717 } 718 722 public void setName(String name) { 723 this.name = name; 724 } 725 726 730 public String getValue() { 731 return value; 732 } 733 737 public void setValue(String value) { 738 this.value = value; 739 } 740 741 } 743 744 745 } 746 | Popular Tags |