1 17 package org.objectweb.jonas.ant; 18 19 import java.io.File ; 20 import java.io.FileInputStream ; 21 import java.io.FileOutputStream ; 22 import java.io.IOException ; 23 import java.io.InputStream ; 24 import java.util.ArrayList ; 25 import java.util.Enumeration ; 26 import java.util.Hashtable ; 27 import java.util.Iterator ; 28 import java.util.List ; 29 import java.util.jar.JarOutputStream ; 30 import java.util.jar.Manifest ; 31 import java.util.zip.ZipEntry ; 32 import javax.xml.parsers.SAXParser ; 33 import org.apache.tools.ant.BuildException; 34 import org.apache.tools.ant.DirectoryScanner; 35 import org.apache.tools.ant.Location; 36 import org.apache.tools.ant.Project; 37 import org.apache.tools.ant.Task; 38 import org.apache.tools.ant.types.FileSet; 39 import org.apache.tools.ant.types.Path; 40 import org.apache.tools.ant.util.depend.DependencyAnalyzer; 41 import org.xml.sax.InputSource ; 42 import org.xml.sax.SAXException ; 43 44 45 54 55 56 62 63 public class GenericDeploymentTool implements EJBDeploymentTool { 64 65 protected static final String META_DIR = "META-INF/"; 66 67 68 protected static final String MANIFEST = META_DIR + "MANIFEST.MF"; 69 70 71 protected static final String EJB_DD = "ejb-jar.xml"; 72 73 74 public static final String ANALYZER_SUPER = "super"; 75 76 public static final String ANALYZER_FULL = "full"; 77 78 public static final String ANALYZER_NONE = "none"; 79 80 81 public static final String DEFAULT_ANALYZER = ANALYZER_SUPER; 82 83 84 public static final String ANALYZER_CLASS_SUPER 85 = "org.apache.tools.ant.util.depend.bcel.AncestorAnalyzer"; 86 87 public static final String ANALYZER_CLASS_FULL 88 = "org.apache.tools.ant.util.depend.bcel.FullAnalyzer"; 89 90 95 private EjbJar.Config config; 96 97 98 private File destDir; 99 100 102 private Path classpath; 103 104 105 private String genericJarSuffix = "-generic.jar"; 106 107 111 private Task task; 112 113 117 private ClassLoader classpathLoader = null; 118 119 122 private List addedfiles; 123 124 127 private DescriptorHandler handler; 128 129 132 private DependencyAnalyzer dependencyAnalyzer; 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 324 protected void addFileToJar(JarOutputStream jStream, 325 File inputFile, 326 String logicalFilename) 327 throws BuildException { 328 FileInputStream iStream = null; 329 try { 330 if (!addedfiles.contains(logicalFilename)) { 331 iStream = new FileInputStream (inputFile); 332 ZipEntry zipEntry = new ZipEntry (logicalFilename.replace('\\', '/')); 334 jStream.putNextEntry(zipEntry); 335 336 byte[] byteBuffer = new byte[2 * 1024]; 339 int count = 0; 340 do { 341 jStream.write(byteBuffer, 0, count); 342 count = iStream.read(byteBuffer, 0, byteBuffer.length); 343 } while (count != -1); 344 345 addedfiles.add(logicalFilename); 347 } 348 } catch (IOException ioe) { 349 log("WARNING: IOException while adding entry " 350 + logicalFilename + " to jarfile from " 351 + inputFile.getPath() + " " + ioe.getClass().getName() 352 + "-" + ioe.getMessage(), Project.MSG_WARN); 353 } finally { 354 if (iStream != null) { 356 try { 357 iStream.close(); 358 } catch (IOException closeException) { 359 } 361 } 362 } 363 } 364 365 protected DescriptorHandler getDescriptorHandler(File srcDir) { 366 DescriptorHandler handler = new DescriptorHandler(getTask(), srcDir); 367 368 registerKnownDTDs(handler); 369 370 for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) { 372 EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next(); 373 handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation()); 374 } 375 return handler; 376 } 377 378 384 protected void registerKnownDTDs(DescriptorHandler handler) { 385 } 387 388 public void processDescriptor(String descriptorFileName, SAXParser saxParser) { 389 390 checkConfiguration(descriptorFileName, saxParser); 391 392 try { 393 handler = getDescriptorHandler(config.srcDir); 394 395 Hashtable ejbFiles = parseEjbFiles(descriptorFileName, saxParser); 397 398 addSupportClasses(ejbFiles); 400 401 String baseName = getJarBaseName(descriptorFileName); 403 404 String ddPrefix = getVendorDDPrefix(baseName, descriptorFileName); 405 406 File manifestFile = getManifestFile(ddPrefix); 407 if (manifestFile != null) { 408 ejbFiles.put(MANIFEST, manifestFile); 409 } 410 411 412 413 ejbFiles.put(META_DIR + EJB_DD, 415 new File (config.descriptorDir, descriptorFileName)); 416 417 addVendorFiles(ejbFiles, ddPrefix); 419 420 checkAndAddDependants(ejbFiles); 422 423 if (config.flatDestDir && baseName.length() != 0) { 426 int startName = baseName.lastIndexOf(File.separator); 427 if (startName == -1) { 428 startName = 0; 429 } 430 431 int endName = baseName.length(); 432 baseName = baseName.substring(startName, endName); 433 } 434 435 File jarFile = getVendorOutputJarFile(baseName); 436 437 438 if (needToRebuild(ejbFiles, jarFile)) { 440 log("building " 442 + jarFile.getName() 443 + " with " 444 + String.valueOf(ejbFiles.size()) 445 + " files", 446 Project.MSG_INFO); 447 448 String publicId = getPublicId(); 450 writeJar(baseName, jarFile, ejbFiles, publicId, true); 451 452 } else { 453 log(jarFile.toString() + " is up to date.", 455 Project.MSG_VERBOSE); 456 } 457 458 } catch (SAXException se) { 459 String msg = "SAXException while parsing '" 460 + descriptorFileName.toString() 461 + "'. This probably indicates badly-formed XML." 462 + " Details: " 463 + se.getMessage(); 464 throw new BuildException(msg, se); 465 } catch (IOException ioe) { 466 String msg = "IOException while parsing'" 467 + descriptorFileName.toString() 468 + "'. This probably indicates that the descriptor" 469 + " doesn't exist. Details: " 470 + ioe.getMessage(); 471 throw new BuildException(msg, ioe); 472 } 473 } 474 475 487 protected void checkConfiguration(String descriptorFileName, 488 SAXParser saxParser) throws BuildException { 489 490 495 } 496 497 512 protected Hashtable parseEjbFiles(String descriptorFileName, SAXParser saxParser) 513 throws IOException , SAXException { 514 FileInputStream descriptorStream = null; 515 Hashtable ejbFiles = null; 516 517 try { 518 519 523 descriptorStream 524 = new FileInputStream (new File (config.descriptorDir, descriptorFileName)); 525 saxParser.parse(new InputSource (descriptorStream), handler); 526 527 ejbFiles = handler.getFiles(); 528 529 } finally { 530 if (descriptorStream != null) { 531 try { 532 descriptorStream.close(); 533 } catch (IOException closeException) { 534 } 536 } 537 } 538 539 return ejbFiles; 540 } 541 542 549 protected void addSupportClasses(Hashtable ejbFiles) { 550 Project project = task.getProject(); 552 for (Iterator i = config.supportFileSets.iterator(); i.hasNext();) { 553 FileSet supportFileSet = (FileSet) i.next(); 554 File supportBaseDir = supportFileSet.getDir(project); 555 DirectoryScanner supportScanner = supportFileSet.getDirectoryScanner(project); 556 supportScanner.scan(); 557 String [] supportFiles = supportScanner.getIncludedFiles(); 558 for (int j = 0; j < supportFiles.length; ++j) { 559 ejbFiles.put(supportFiles[j], new File (supportBaseDir, supportFiles[j])); 560 } 561 } 562 } 563 564 565 575 protected String getJarBaseName(String descriptorFileName) { 576 577 String baseName = ""; 578 579 if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.BASEJARNAME)) { 581 String canonicalDescriptor = descriptorFileName.replace('\\', '/'); 582 int index = canonicalDescriptor.lastIndexOf('/'); 583 if (index != -1) { 584 baseName = descriptorFileName.substring(0, index + 1); 585 } 586 baseName += config.baseJarName; 587 } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) { 588 int lastSeparatorIndex = descriptorFileName.lastIndexOf(File.separator); 589 int endBaseName = -1; 590 if (lastSeparatorIndex != -1) { 591 endBaseName = descriptorFileName.indexOf(config.baseNameTerminator, 592 lastSeparatorIndex); 593 } else { 594 endBaseName = descriptorFileName.indexOf(config.baseNameTerminator); 595 } 596 597 if (endBaseName != -1) { 598 baseName = descriptorFileName.substring(0, endBaseName); 599 } else { 600 throw new BuildException("Unable to determine jar name " 601 + "from descriptor \"" + descriptorFileName + "\""); 602 } 603 } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DIRECTORY)) { 604 File descriptorFile = new File (config.descriptorDir, descriptorFileName); 605 String path = descriptorFile.getAbsolutePath(); 606 int lastSeparatorIndex 607 = path.lastIndexOf(File.separator); 608 if (lastSeparatorIndex == -1) { 609 throw new BuildException("Unable to determine directory name holding descriptor"); 610 } 611 String dirName = path.substring(0, lastSeparatorIndex); 612 int dirSeparatorIndex = dirName.lastIndexOf(File.separator); 613 if (dirSeparatorIndex != -1) { 614 dirName = dirName.substring(dirSeparatorIndex + 1); 615 } 616 617 baseName = dirName; 618 } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.EJB_NAME)) { 619 baseName = handler.getEjbName(); 620 } 621 return baseName; 622 } 623 624 630 public String getVendorDDPrefix(String baseName, String descriptorFileName) { 631 String ddPrefix = null; 632 633 if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) { 634 ddPrefix = baseName + config.baseNameTerminator; 635 } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.BASEJARNAME) 636 || config.namingScheme.getValue().equals(EjbJar.NamingScheme.EJB_NAME) 637 || config.namingScheme.getValue().equals(EjbJar.NamingScheme.DIRECTORY)) { 638 String canonicalDescriptor = descriptorFileName.replace('\\', '/'); 639 int index = canonicalDescriptor.lastIndexOf('/'); 640 if (index == -1) { 641 ddPrefix = ""; 642 } else { 643 ddPrefix = descriptorFileName.substring(0, index + 1); 644 } 645 } 646 return ddPrefix; 647 } 648 649 653 protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) { 654 } 656 657 658 662 File getVendorOutputJarFile(String baseName) { 663 return new File (destDir, baseName + genericJarSuffix); 664 } 665 666 681 protected boolean needToRebuild(Hashtable ejbFiles, File jarFile) { 682 if (jarFile.exists()) { 683 long lastBuild = jarFile.lastModified(); 684 685 Iterator fileIter = ejbFiles.values().iterator(); 686 687 while (fileIter.hasNext()) { 690 File currentFile = (File ) fileIter.next(); 691 if (lastBuild < currentFile.lastModified()) { 692 log("Build needed because " + currentFile.getPath() + " is out of date", 693 Project.MSG_VERBOSE); 694 return true; 695 } 696 } 697 return false; 698 } 699 700 return true; 701 } 702 703 710 protected String getPublicId() { 711 return handler.getPublicId(); 712 } 713 714 725 protected File getManifestFile(String prefix) { 726 File manifestFile 727 = new File (getConfig().descriptorDir, prefix + "manifest.mf"); 728 if (manifestFile.exists()) { 729 return manifestFile; 730 } 731 732 if (config.manifest != null) { 733 return config.manifest; 734 } 735 return null; 736 } 737 738 744 protected void writeJar(String baseName, File jarfile, Hashtable files, 745 String publicId, boolean includeInnerClasses) throws BuildException { 746 747 JarOutputStream jarStream = null; 748 try { 749 addedfiles = new ArrayList (); 751 752 757 if (jarfile.exists()) { 758 jarfile.delete(); 759 } 760 jarfile.getParentFile().mkdirs(); 761 jarfile.createNewFile(); 762 763 InputStream in = null; 764 Manifest manifest = null; 765 try { 766 File manifestFile = (File ) files.get(MANIFEST); 767 if (manifestFile != null && manifestFile.exists()) { 768 in = new FileInputStream (manifestFile); 769 } else { 770 String defaultManifest = "/org/apache/tools/ant/defaultManifest.mf"; 771 in = this.getClass().getResourceAsStream(defaultManifest); 772 if (in == null) { 773 throw new BuildException("Could not find " 774 + "default manifest: " + defaultManifest); 775 } 776 } 777 778 manifest = new Manifest (in); 779 } catch (IOException e) { 780 throw new BuildException ("Unable to read manifest", e, getLocation()); 781 } finally { 782 if (in != null) { 783 in.close(); 784 } 785 } 786 787 789 jarStream = new JarOutputStream (new FileOutputStream (jarfile), manifest); 790 jarStream.setMethod(JarOutputStream.DEFLATED); 791 792 for (Iterator entryIterator = files.keySet().iterator(); entryIterator.hasNext();) { 794 String entryName = (String ) entryIterator.next(); 795 if (entryName.equals(MANIFEST)) { 796 continue; 797 } 798 799 File entryFile = (File ) files.get(entryName); 800 801 log("adding file '" + entryName + "'", 802 Project.MSG_VERBOSE); 803 804 addFileToJar(jarStream, entryFile, entryName); 805 806 InnerClassFilenameFilter flt = new InnerClassFilenameFilter(entryFile.getName()); 808 File entryDir = entryFile.getParentFile(); 809 String [] innerfiles = entryDir.list(flt); 810 if (innerfiles != null && includeInnerClasses) { 811 for (int i = 0, n = innerfiles.length; i < n; i++) { 812 813 int entryIndex = entryName.lastIndexOf(entryFile.getName()) - 1; 815 if (entryIndex < 0) { 816 entryName = innerfiles[i]; 817 } else { 818 entryName = entryName.substring(0, entryIndex) 819 + File.separatorChar + innerfiles[i]; 820 } 821 entryFile = new File (config.srcDir, entryName); 823 824 log("adding innerclass file '" + entryName + "'", 825 Project.MSG_VERBOSE); 826 827 addFileToJar(jarStream, entryFile, entryName); 828 829 } 830 } 831 } 832 } catch (IOException ioe) { 833 String msg = "IOException while processing ejb-jar file '" 834 + jarfile.toString() 835 + "'. Details: " 836 + ioe.getMessage(); 837 throw new BuildException(msg, ioe); 838 } finally { 839 if (jarStream != null) { 840 try { 841 jarStream.close(); 842 } catch (IOException closeException) { 843 } 845 } 846 } 847 } 849 850 854 protected void checkAndAddDependants(Hashtable checkEntries) 855 throws BuildException { 856 857 if (dependencyAnalyzer == null) { 858 return; 859 } 860 861 dependencyAnalyzer.reset(); 862 863 Iterator i = checkEntries.keySet().iterator(); 864 while (i.hasNext()) { 865 String entryName = (String ) i.next(); 866 if (entryName.endsWith(".class")) { 867 String className = entryName.substring(0, 868 entryName.length() - ".class".length()); 869 className = className.replace(File.separatorChar, '/'); 870 className = className.replace('/', '.'); 871 872 dependencyAnalyzer.addRootClass(className); 873 } 874 } 875 876 Enumeration e = dependencyAnalyzer.getClassDependencies(); 877 878 while (e.hasMoreElements()) { 879 String classname = (String ) e.nextElement(); 880 String location 881 = classname.replace('.', File.separatorChar) + ".class"; 882 File classFile = new File (config.srcDir, location); 883 if (classFile.exists()) { 884 checkEntries.put(location, classFile); 885 log("dependent class: " + classname + " - " + classFile, 886 Project.MSG_VERBOSE); 887 } 888 } 889 } 890 891 892 898 protected ClassLoader getClassLoaderForBuild() { 899 if (classpathLoader != null) { 900 return classpathLoader; 901 } 902 903 Path combinedClasspath = getCombinedClasspath(); 904 905 if (combinedClasspath == null) { 907 classpathLoader = getClass().getClassLoader(); 908 } else { 909 classpathLoader 910 = getTask().getProject().createClassLoader(combinedClasspath); 911 } 912 913 return classpathLoader; 914 } 915 916 922 public void validateConfigured() throws BuildException { 923 if ((destDir == null) || (!destDir.isDirectory())) { 924 String msg = "A valid destination directory must be specified " 925 + "using the \"destdir\" attribute."; 926 throw new BuildException(msg, getLocation()); 927 } 928 } 929 } 930 | Popular Tags |