1 18 package org.apache.tools.ant.taskdefs.optional.ejb; 19 20 import java.io.File ; 21 import java.io.FileInputStream ; 22 import java.io.FileOutputStream ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.util.Enumeration ; 26 import java.util.HashSet ; 27 import java.util.Hashtable ; 28 import java.util.Iterator ; 29 import java.util.Set ; 30 import java.util.jar.JarOutputStream ; 31 import java.util.jar.Manifest ; 32 import java.util.zip.ZipEntry ; 33 34 import javax.xml.parsers.SAXParser ; 35 36 import org.apache.tools.ant.BuildException; 37 import org.apache.tools.ant.DirectoryScanner; 38 import org.apache.tools.ant.Location; 39 import org.apache.tools.ant.Project; 40 import org.apache.tools.ant.Task; 41 import org.apache.tools.ant.types.FileSet; 42 import org.apache.tools.ant.types.Path; 43 import org.apache.tools.ant.util.depend.DependencyAnalyzer; 44 import org.xml.sax.InputSource ; 45 import org.xml.sax.SAXException ; 46 47 48 57 public class GenericDeploymentTool implements EJBDeploymentTool { 58 59 public static final int DEFAULT_BUFFER_SIZE = 1024; 60 61 public static final int JAR_COMPRESS_LEVEL = 9; 62 63 64 protected static final String META_DIR = "META-INF/"; 65 66 67 protected static final String MANIFEST = META_DIR + "MANIFEST.MF"; 68 69 70 protected static final String EJB_DD = "ejb-jar.xml"; 71 72 73 public static final String ANALYZER_SUPER = "super"; 74 75 public static final String ANALYZER_FULL = "full"; 76 77 public static final String ANALYZER_NONE = "none"; 78 79 80 public static final String DEFAULT_ANALYZER = ANALYZER_SUPER; 81 82 83 public static final String ANALYZER_CLASS_SUPER 84 = "org.apache.tools.ant.util.depend.bcel.AncestorAnalyzer"; 85 86 public static final String ANALYZER_CLASS_FULL 87 = "org.apache.tools.ant.util.depend.bcel.FullAnalyzer"; 88 89 94 private EjbJar.Config config; 95 96 97 private File destDir; 98 99 101 private Path classpath; 102 103 104 private String genericJarSuffix = "-generic.jar"; 105 106 110 private Task task; 111 112 116 private ClassLoader classpathLoader = null; 117 118 121 private Set addedfiles; 122 123 126 private DescriptorHandler handler; 127 128 131 private DependencyAnalyzer dependencyAnalyzer; 132 133 134 public GenericDeploymentTool() { 135 } 136 137 138 142 public void setDestdir(File inDir) { 143 this.destDir = inDir; 144 } 145 146 151 protected File getDestDir() { 152 return destDir; 153 } 154 155 156 161 public void setTask(Task task) { 162 this.task = task; 163 } 164 165 170 protected Task getTask() { 171 return task; 172 } 173 174 179 protected EjbJar.Config getConfig() { 180 return config; 181 } 182 183 189 protected boolean usingBaseJarName() { 190 return config.baseJarName != null; 191 } 192 193 197 public void setGenericJarSuffix(String inString) { 198 this.genericJarSuffix = inString; 199 } 200 201 206 public Path createClasspath() { 207 if (classpath == null) { 208 classpath = new Path(task.getProject()); 209 } 210 return classpath.createPath(); 211 } 212 213 218 public void setClasspath(Path classpath) { 219 this.classpath = classpath; 220 } 221 222 228 protected Path getCombinedClasspath() { 229 Path combinedPath = classpath; 230 if (config.classpath != null) { 231 if (combinedPath == null) { 232 combinedPath = config.classpath; 233 } else { 234 combinedPath.append(config.classpath); 235 } 236 } 237 238 return combinedPath; 239 } 240 241 247 protected void log(String message, int level) { 248 getTask().log(message, level); 249 } 250 251 256 protected Location getLocation() { 257 return getTask().getLocation(); 258 } 259 260 private void createAnalyzer() { 261 String analyzer = config.analyzer; 262 if (analyzer == null) { 263 analyzer = DEFAULT_ANALYZER; 264 } 265 266 if (analyzer.equals(ANALYZER_NONE)) { 267 return; 268 } 269 270 String analyzerClassName = null; 271 if (analyzer.equals(ANALYZER_SUPER)) { 272 analyzerClassName = ANALYZER_CLASS_SUPER; 273 } else if (analyzer.equals(ANALYZER_FULL)) { 274 analyzerClassName = ANALYZER_CLASS_FULL; 275 } else { 276 analyzerClassName = analyzer; 277 } 278 279 try { 280 Class analyzerClass = Class.forName(analyzerClassName); 281 dependencyAnalyzer 282 = (DependencyAnalyzer) analyzerClass.newInstance(); 283 dependencyAnalyzer.addClassPath(new Path(task.getProject(), 284 config.srcDir.getPath())); 285 dependencyAnalyzer.addClassPath(config.classpath); 286 } catch (NoClassDefFoundError e) { 287 dependencyAnalyzer = null; 288 task.log("Unable to load dependency analyzer: " + analyzerClassName 289 + " - dependent class not found: " + e.getMessage(), 290 Project.MSG_WARN); 291 } catch (Exception e) { 292 dependencyAnalyzer = null; 293 task.log("Unable to load dependency analyzer: " + analyzerClassName 294 + " - exception: " + e.getMessage(), 295 Project.MSG_WARN); 296 } 297 } 298 299 300 305 public void configure(EjbJar.Config config) { 306 this.config = config; 307 308 createAnalyzer(); 309 classpathLoader = null; 310 } 311 312 325 protected void addFileToJar(JarOutputStream jStream, 326 File inputFile, 327 String logicalFilename) 328 throws BuildException { 329 FileInputStream iStream = null; 330 try { 331 if (!addedfiles.contains(logicalFilename)) { 332 iStream = new FileInputStream (inputFile); 333 ZipEntry zipEntry = new ZipEntry (logicalFilename.replace('\\', '/')); 335 jStream.putNextEntry(zipEntry); 336 337 byte[] byteBuffer = new byte[2 * DEFAULT_BUFFER_SIZE]; 340 int count = 0; 341 do { 342 jStream.write(byteBuffer, 0, count); 343 count = iStream.read(byteBuffer, 0, byteBuffer.length); 344 } while (count != -1); 345 346 addedfiles.add(logicalFilename); 348 } 349 } catch (IOException ioe) { 350 log("WARNING: IOException while adding entry " 351 + logicalFilename + " to jarfile from " 352 + inputFile.getPath() + " " + ioe.getClass().getName() 353 + "-" + ioe.getMessage(), Project.MSG_WARN); 354 } finally { 355 if (iStream != null) { 357 try { 358 iStream.close(); 359 } catch (IOException closeException) { 360 } 362 } 363 } 364 } 365 366 371 protected DescriptorHandler getDescriptorHandler(File srcDir) { 372 DescriptorHandler h = new DescriptorHandler(getTask(), srcDir); 373 374 registerKnownDTDs(h); 375 376 for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) { 378 EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next(); 379 h.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation()); 380 } 381 return h; 382 } 383 384 391 protected void registerKnownDTDs(DescriptorHandler handler) { 392 } 394 395 396 public void processDescriptor(String descriptorFileName, SAXParser saxParser) { 397 398 checkConfiguration(descriptorFileName, saxParser); 399 400 try { 401 handler = getDescriptorHandler(config.srcDir); 402 403 Hashtable ejbFiles = parseEjbFiles(descriptorFileName, saxParser); 405 406 addSupportClasses(ejbFiles); 408 409 String baseName = getJarBaseName(descriptorFileName); 411 412 String ddPrefix = getVendorDDPrefix(baseName, descriptorFileName); 413 414 File manifestFile = getManifestFile(ddPrefix); 415 if (manifestFile != null) { 416 ejbFiles.put(MANIFEST, manifestFile); 417 } 418 419 420 421 ejbFiles.put(META_DIR + EJB_DD, 423 new File (config.descriptorDir, descriptorFileName)); 424 425 addVendorFiles(ejbFiles, ddPrefix); 427 428 checkAndAddDependants(ejbFiles); 430 431 if (config.flatDestDir && baseName.length() != 0) { 434 int startName = baseName.lastIndexOf(File.separator); 435 if (startName == -1) { 436 startName = 0; 437 } 438 439 int endName = baseName.length(); 440 baseName = baseName.substring(startName, endName); 441 } 442 443 File jarFile = getVendorOutputJarFile(baseName); 444 445 446 if (needToRebuild(ejbFiles, jarFile)) { 448 log("building " 450 + jarFile.getName() 451 + " with " 452 + String.valueOf(ejbFiles.size()) 453 + " files", 454 Project.MSG_INFO); 455 456 String publicId = getPublicId(); 458 writeJar(baseName, jarFile, ejbFiles, publicId); 459 460 } else { 461 log(jarFile.toString() + " is up to date.", 463 Project.MSG_VERBOSE); 464 } 465 466 } catch (SAXException se) { 467 String msg = "SAXException while parsing '" 468 + descriptorFileName 469 + "'. This probably indicates badly-formed XML." 470 + " Details: " 471 + se.getMessage(); 472 throw new BuildException(msg, se); 473 } catch (IOException ioe) { 474 String msg = "IOException while parsing'" 475 + descriptorFileName.toString() 476 + "'. This probably indicates that the descriptor" 477 + " doesn't exist. Details: " 478 + ioe.getMessage(); 479 throw new BuildException(msg, ioe); 480 } 481 } 482 483 495 protected void checkConfiguration(String descriptorFileName, 496 SAXParser saxParser) throws BuildException { 497 498 503 } 504 505 520 protected Hashtable parseEjbFiles(String descriptorFileName, SAXParser saxParser) 521 throws IOException , SAXException { 522 FileInputStream descriptorStream = null; 523 Hashtable ejbFiles = null; 524 525 try { 526 527 531 descriptorStream 532 = new FileInputStream (new File (config.descriptorDir, descriptorFileName)); 533 saxParser.parse(new InputSource (descriptorStream), handler); 534 535 ejbFiles = handler.getFiles(); 536 537 } finally { 538 if (descriptorStream != null) { 539 try { 540 descriptorStream.close(); 541 } catch (IOException closeException) { 542 } 544 } 545 } 546 547 return ejbFiles; 548 } 549 550 557 protected void addSupportClasses(Hashtable ejbFiles) { 558 Project project = task.getProject(); 560 for (Iterator i = config.supportFileSets.iterator(); i.hasNext();) { 561 FileSet supportFileSet = (FileSet) i.next(); 562 File supportBaseDir = supportFileSet.getDir(project); 563 DirectoryScanner supportScanner = supportFileSet.getDirectoryScanner(project); 564 supportScanner.scan(); 565 String [] supportFiles = supportScanner.getIncludedFiles(); 566 for (int j = 0; j < supportFiles.length; ++j) { 567 ejbFiles.put(supportFiles[j], new File (supportBaseDir, supportFiles[j])); 568 } 569 } 570 } 571 572 573 583 protected String getJarBaseName(String descriptorFileName) { 584 585 String baseName = ""; 586 587 if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.BASEJARNAME)) { 589 String canonicalDescriptor = descriptorFileName.replace('\\', '/'); 590 int index = canonicalDescriptor.lastIndexOf('/'); 591 if (index != -1) { 592 baseName = descriptorFileName.substring(0, index + 1); 593 } 594 baseName += config.baseJarName; 595 } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) { 596 int lastSeparatorIndex = descriptorFileName.lastIndexOf(File.separator); 597 int endBaseName = -1; 598 if (lastSeparatorIndex != -1) { 599 endBaseName = descriptorFileName.indexOf(config.baseNameTerminator, 600 lastSeparatorIndex); 601 } else { 602 endBaseName = descriptorFileName.indexOf(config.baseNameTerminator); 603 } 604 605 if (endBaseName != -1) { 606 baseName = descriptorFileName.substring(0, endBaseName); 607 } else { 608 throw new BuildException("Unable to determine jar name " 609 + "from descriptor \"" + descriptorFileName + "\""); 610 } 611 } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DIRECTORY)) { 612 File descriptorFile = new File (config.descriptorDir, descriptorFileName); 613 String path = descriptorFile.getAbsolutePath(); 614 int lastSeparatorIndex 615 = path.lastIndexOf(File.separator); 616 if (lastSeparatorIndex == -1) { 617 throw new BuildException("Unable to determine directory name holding descriptor"); 618 } 619 String dirName = path.substring(0, lastSeparatorIndex); 620 int dirSeparatorIndex = dirName.lastIndexOf(File.separator); 621 if (dirSeparatorIndex != -1) { 622 dirName = dirName.substring(dirSeparatorIndex + 1); 623 } 624 625 baseName = dirName; 626 } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.EJB_NAME)) { 627 baseName = handler.getEjbName(); 628 } 629 return baseName; 630 } 631 632 641 public String getVendorDDPrefix(String baseName, String descriptorFileName) { 642 String ddPrefix = null; 643 644 if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) { 645 ddPrefix = baseName + config.baseNameTerminator; 646 } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.BASEJARNAME) 647 || config.namingScheme.getValue().equals(EjbJar.NamingScheme.EJB_NAME) 648 || config.namingScheme.getValue().equals(EjbJar.NamingScheme.DIRECTORY)) { 649 String canonicalDescriptor = descriptorFileName.replace('\\', '/'); 650 int index = canonicalDescriptor.lastIndexOf('/'); 651 if (index == -1) { 652 ddPrefix = ""; 653 } else { 654 ddPrefix = descriptorFileName.substring(0, index + 1); 655 } 656 } 657 return ddPrefix; 658 } 659 660 666 protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) { 667 } 669 670 671 676 File getVendorOutputJarFile(String baseName) { 677 return new File (destDir, baseName + genericJarSuffix); 678 } 679 680 695 protected boolean needToRebuild(Hashtable ejbFiles, File jarFile) { 696 if (jarFile.exists()) { 697 long lastBuild = jarFile.lastModified(); 698 699 Iterator fileIter = ejbFiles.values().iterator(); 700 701 while (fileIter.hasNext()) { 704 File currentFile = (File ) fileIter.next(); 705 if (lastBuild < currentFile.lastModified()) { 706 log("Build needed because " + currentFile.getPath() + " is out of date", 707 Project.MSG_VERBOSE); 708 return true; 709 } 710 } 711 return false; 712 } 713 714 return true; 715 } 716 717 724 protected String getPublicId() { 725 return handler.getPublicId(); 726 } 727 728 739 protected File getManifestFile(String prefix) { 740 File manifestFile 741 = new File (getConfig().descriptorDir, prefix + "manifest.mf"); 742 if (manifestFile.exists()) { 743 return manifestFile; 744 } 745 746 if (config.manifest != null) { 747 return config.manifest; 748 } 749 return null; 750 } 751 752 762 protected void writeJar(String baseName, File jarfile, Hashtable files, 763 String publicId) throws BuildException { 764 765 JarOutputStream jarStream = null; 766 try { 767 if (addedfiles == null) { 769 addedfiles = new HashSet (); 770 } else { 771 addedfiles.clear(); 772 } 773 774 779 if (jarfile.exists()) { 780 jarfile.delete(); 781 } 782 jarfile.getParentFile().mkdirs(); 783 jarfile.createNewFile(); 784 785 InputStream in = null; 786 Manifest manifest = null; 787 try { 788 File manifestFile = (File ) files.get(MANIFEST); 789 if (manifestFile != null && manifestFile.exists()) { 790 in = new FileInputStream (manifestFile); 791 } else { 792 String defaultManifest = "/org/apache/tools/ant/defaultManifest.mf"; 793 in = this.getClass().getResourceAsStream(defaultManifest); 794 if (in == null) { 795 throw new BuildException("Could not find " 796 + "default manifest: " + defaultManifest); 797 } 798 } 799 800 manifest = new Manifest (in); 801 } catch (IOException e) { 802 throw new BuildException ("Unable to read manifest", e, getLocation()); 803 } finally { 804 if (in != null) { 805 in.close(); 806 } 807 } 808 809 811 jarStream = new JarOutputStream (new FileOutputStream (jarfile), manifest); 812 jarStream.setMethod(JarOutputStream.DEFLATED); 813 814 for (Iterator entryIterator = files.keySet().iterator(); entryIterator.hasNext();) { 816 String entryName = (String ) entryIterator.next(); 817 if (entryName.equals(MANIFEST)) { 818 continue; 819 } 820 821 File entryFile = (File ) files.get(entryName); 822 823 log("adding file '" + entryName + "'", 824 Project.MSG_VERBOSE); 825 826 addFileToJar(jarStream, entryFile, entryName); 827 828 InnerClassFilenameFilter flt = new InnerClassFilenameFilter(entryFile.getName()); 830 File entryDir = entryFile.getParentFile(); 831 String [] innerfiles = entryDir.list(flt); 832 if (innerfiles != null) { 833 for (int i = 0, n = innerfiles.length; i < n; i++) { 834 835 int entryIndex = entryName.lastIndexOf(entryFile.getName()) - 1; 837 if (entryIndex < 0) { 838 entryName = innerfiles[i]; 839 } else { 840 entryName = entryName.substring(0, entryIndex) 841 + File.separatorChar + innerfiles[i]; 842 } 843 entryFile = new File (config.srcDir, entryName); 845 846 log("adding innerclass file '" + entryName + "'", 847 Project.MSG_VERBOSE); 848 849 addFileToJar(jarStream, entryFile, entryName); 850 851 } 852 } 853 } 854 } catch (IOException ioe) { 855 String msg = "IOException while processing ejb-jar file '" 856 + jarfile.toString() 857 + "'. Details: " 858 + ioe.getMessage(); 859 throw new BuildException(msg, ioe); 860 } finally { 861 if (jarStream != null) { 862 try { 863 jarStream.close(); 864 } catch (IOException closeException) { 865 } 867 } 868 } 869 } 871 872 877 protected void checkAndAddDependants(Hashtable checkEntries) 878 throws BuildException { 879 880 if (dependencyAnalyzer == null) { 881 return; 882 } 883 884 dependencyAnalyzer.reset(); 885 886 Iterator i = checkEntries.keySet().iterator(); 887 while (i.hasNext()) { 888 String entryName = (String ) i.next(); 889 if (entryName.endsWith(".class")) { 890 String className = entryName.substring(0, 891 entryName.length() - ".class".length()); 892 className = className.replace(File.separatorChar, '/'); 893 className = className.replace('/', '.'); 894 895 dependencyAnalyzer.addRootClass(className); 896 } 897 } 898 899 Enumeration e = dependencyAnalyzer.getClassDependencies(); 900 901 while (e.hasMoreElements()) { 902 String classname = (String ) e.nextElement(); 903 String location 904 = classname.replace('.', File.separatorChar) + ".class"; 905 File classFile = new File (config.srcDir, location); 906 if (classFile.exists()) { 907 checkEntries.put(location, classFile); 908 log("dependent class: " + classname + " - " + classFile, 909 Project.MSG_VERBOSE); 910 } 911 } 912 } 913 914 915 921 protected ClassLoader getClassLoaderForBuild() { 922 if (classpathLoader != null) { 923 return classpathLoader; 924 } 925 926 Path combinedClasspath = getCombinedClasspath(); 927 928 if (combinedClasspath == null) { 930 classpathLoader = getClass().getClassLoader(); 931 } else { 932 classpathLoader 933 = getTask().getProject().createClassLoader(combinedClasspath); 934 } 935 936 return classpathLoader; 937 } 938 939 945 public void validateConfigured() throws BuildException { 946 if ((destDir == null) || (!destDir.isDirectory())) { 947 String msg = "A valid destination directory must be specified " 948 + "using the \"destdir\" attribute."; 949 throw new BuildException(msg, getLocation()); 950 } 951 } 952 } 953 | Popular Tags |