bodewig     2004/04/23 03:03:50

  Modified:    .        build.xml
               src/main/org/apache/tools/ant/taskdefs Jar.java Java.java
  Added:       src/testcases/org/apache/tools/ant/taskdefs
                        ProtectedJarMethodsTest.java
  Log:
  Implement jar index for referenced jars, PR: 14255
  
  Revision  Changes    Path
  1.417     +2 -0      ant/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/ant/build.xml,v
  retrieving revision 1.416
  retrieving revision 1.417
  diff -u -r1.416 -r1.417
  --- build.xml 15 Apr 2004 13:53:47 -0000      1.416
  +++ build.xml 23 Apr 2004 10:03:49 -0000      1.417
  @@ -1551,6 +1551,8 @@
                      unless="tests.and.ant.share.classloader"/>
             <exclude name="${ant.package}/taskdefs/ProcessDestroyerTest.java"
                      unless="tests.and.ant.share.classloader"/>
  +          <exclude 
name="${ant.package}/taskdefs/ProtectedJarMethodsTest.java"
  +                   unless="tests.and.ant.share.classloader"/>
   
             <!-- can only run if cvs is installed on your machine
                  enable by setting the property have.cvs
  
  
  
  1.86      +201 -27   ant/src/main/org/apache/tools/ant/taskdefs/Jar.java
  
  Index: Jar.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/Jar.java,v
  retrieving revision 1.85
  retrieving revision 1.86
  diff -u -r1.85 -r1.86
  --- Jar.java  9 Mar 2004 16:48:05 -0000       1.85
  +++ Jar.java  23 Apr 2004 10:03:49 -0000      1.86
  @@ -29,7 +29,15 @@
   import java.io.OutputStreamWriter;
   import java.io.PrintWriter;
   import java.io.Reader;
  +import java.util.ArrayList;
  +import java.util.Collections;
  +import java.util.Comparator;
   import java.util.Enumeration;
  +import java.util.HashSet;
  +import java.util.Iterator;
  +import java.util.List;
  +import java.util.StringTokenizer;
  +import java.util.TreeMap;
   import java.util.Vector;
   import java.util.zip.ZipEntry;
   import java.util.zip.ZipFile;
  @@ -37,10 +45,10 @@
   import org.apache.tools.ant.Project;
   import org.apache.tools.ant.types.EnumeratedAttribute;
   import org.apache.tools.ant.types.FileSet;
  +import org.apache.tools.ant.types.Path;
   import org.apache.tools.ant.types.ZipFileSet;
   import org.apache.tools.zip.ZipOutputStream;
   
  -
   /**
    * Creates a JAR archive.
    *
  @@ -115,6 +123,13 @@
        */
       private Vector rootEntries;
   
  +    /**
  +     * Path containing jars that shall be indexed in addition to this 
archive.
  +     *
  +     * @since Ant 1.7
  +     */
  +    private Path indexJars;
  +
       /** constructor */
       public Jar() {
           super();
  @@ -304,6 +319,16 @@
           super.addFileset(fs);
       }
   
  +    /**
  +     * @since Ant 1.7
  +     */
  +    public void addConfiguredIndexJars(Path p) {
  +        if (indexJars == null) {
  +            indexJars = new Path(getProject());
  +        }
  +        indexJars.append(p);
  +    }
  +
       protected void initZipOutputStream(ZipOutputStream zOut)
           throws IOException, BuildException {
   
  @@ -384,7 +409,7 @@
       /**
        * Create the index list to speed up classloading.
        * This is a JDK 1.3+ specific feature and is enabled by default. See
  -     * <a 
href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR+Index";>
  +     * <a 
href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR%20Index";>
        * the JAR index specification</a> for more details.
        *
        * @param zOut the zip stream representing the jar being built.
  @@ -404,34 +429,38 @@
           // header newline
           writer.println(zipFile.getName());
   
  -        // JarIndex is sorting the directories by ascending order.
  -        // it's painful to do in JDK 1.1 and it has no value but cosmetic
  -        // since it will be read into a hashtable by the classloader.
  -        Enumeration e = addedDirs.keys();
  -        while (e.hasMoreElements()) {
  -            String dir = (String) e.nextElement();
  +        writeIndexLikeList(new ArrayList(addedDirs.keySet()), 
  +                           rootEntries, writer);
  +        writer.println();
   
  -            // try to be smart, not to be fooled by a weird directory name
  -            // @fixme do we need to check for directories starting by ./ ?
  -            dir = dir.replace('\\', '/');
  -            int pos = dir.lastIndexOf('/');
  -            if (pos != -1) {
  -                dir = dir.substring(0, pos);
  +        if (indexJars != null) {
  +            Manifest mf = createManifest();
  +            Manifest.Attribute classpath =
  +                
mf.getMainSection().getAttribute(Manifest.ATTRIBUTE_CLASSPATH);
  +            String[] cpEntries = null;
  +            if (classpath != null) {
  +                StringTokenizer tok = new 
StringTokenizer(classpath.getValue(),
  +                                                          " ");
  +                cpEntries = new String[tok.countTokens()];
  +                int c = 0;
  +                while (tok.hasMoreTokens()) {
  +                    cpEntries[c++] = tok.nextToken();
  +                }
               }
  -
  -            // looks like nothing from META-INF should be added
  -            // and the check is not case insensitive.
  -            // see sun.misc.JarIndex
  -            if (dir.startsWith("META-INF")) {
  -                continue;
  +            String[] indexJarEntries = indexJars.list();
  +            for (int i = 0; i < indexJarEntries.length; i++) {
  +                String name = findJarName(indexJarEntries[i], cpEntries);
  +                if (name != null) {
  +                    ArrayList dirs = new ArrayList();
  +                    ArrayList files = new ArrayList();
  +                    grabFilesAndDirs(indexJarEntries[i], dirs, files);
  +                    if (dirs.size() + files.size() > 0) {
  +                        writer.println(name);
  +                        writeIndexLikeList(dirs, files, writer);
  +                        writer.println();
  +                    }
  +                }
               }
  -            // name newline
  -            writer.println(dir);
  -        }
  -
  -        e = rootEntries.elements();
  -        while (e.hasMoreElements()) {
  -            writer.println(e.nextElement());
           }
   
           writer.flush();
  @@ -670,6 +699,151 @@
       public static class FilesetManifestConfig extends EnumeratedAttribute {
           public String[] getValues() {
               return new String[] {"skip", "merge", "mergewithoutmain"};
  +        }
  +    }
  +
  +    /**
  +     * Writes the directory entries from the first and the filenames
  +     * from the second list to the given writer, one entry per line.
  +     *
  +     * @since Ant 1.7
  +     */
  +    protected final void writeIndexLikeList(List dirs, List files,
  +                                            PrintWriter writer)
  +        throws IOException {
  +        // JarIndex is sorting the directories by ascending order.
  +        // it has no value but cosmetic since it will be read into a
  +        // hashtable by the classloader, but we'll do so anyway.
  +        Collections.sort(dirs);
  +        Collections.sort(files);
  +        Iterator iter = dirs.iterator();
  +        while (iter.hasNext()) {
  +            String dir = (String) iter.next();
  +
  +            // try to be smart, not to be fooled by a weird directory name
  +            dir = dir.replace('\\', '/');
  +            if (dir.startsWith("./")) {
  +                dir = dir.substring(2);
  +            }
  +            while (dir.startsWith("/")) {
  +                dir = dir.substring(1);
  +            }
  +            int pos = dir.lastIndexOf('/');
  +            if (pos != -1) {
  +                dir = dir.substring(0, pos);
  +            }
  +
  +            // looks like nothing from META-INF should be added
  +            // and the check is not case insensitive.
  +            // see sun.misc.JarIndex
  +            if (dir.startsWith("META-INF")) {
  +                continue;
  +            }
  +            // name newline
  +            writer.println(dir);
  +        }
  +
  +        iter = files.iterator();
  +        while (iter.hasNext()) {
  +            writer.println(iter.next());
  +        }
  +    }
  +
  +    /**
  +     * try to guess the name of the given file.
  +     *
  +     * <p>If this jar has a classpath attribute in its manifest, we
  +     * can assume that it will only require an index of jars listed
  +     * there.  try to find which classpath entry is most likely the
  +     * one the given file name points to.</p>
  +     *
  +     * <p>In the absence of a classpath attribute, assume the other
  +     * files will be placed inside the same directory as this jar and
  +     * use their basename.</p>
  +     *
  +     * <p>if there is a classpath and the given file doesn't match any
  +     * of its entries, return null.</p>
  +     *
  +     * @since Ant 1.7
  +     */
  +    protected static final String findJarName(String fileName, 
  +                                              String[] classpath) {
  +        if (classpath == null) {
  +            return (new File(fileName)).getName();
  +        }
  +        fileName = fileName.replace(File.separatorChar, '/');
  +        TreeMap matches = new TreeMap(new Comparator() {
  +                // longest match comes first
  +                public int compare(Object o1, Object o2) {
  +                    if (o1 instanceof String && o2 instanceof String) {
  +                        return ((String) o2).length()
  +                            - ((String) o1).length();
  +                    }
  +                    return 0;
  +                }
  +            });
  +
  +        for (int i = 0; i < classpath.length; i++) {
  +            if (fileName.endsWith(classpath[i])) {
  +                matches.put(classpath[i], classpath[i]);
  +            } else {
  +                int slash = classpath[i].indexOf("/");
  +                String candidate = classpath[i];
  +                while (slash > -1) {
  +                    candidate = candidate.substring(slash + 1);
  +                    if (fileName.endsWith(candidate)) {
  +                        matches.put(candidate, classpath[i]);
  +                        break;
  +                    }
  +                    slash = candidate.indexOf("/");
  +                }
  +            }
  +        }
  +                        
  +        return matches.size() == 0 
  +            ? null : (String) matches.get(matches.firstKey());
  +    }
  +
  +    /**
  +     * Grab lists of all root-level files and all directories
  +     * contained in the given archive.
  +     *
  +     * @since Ant 1.7
  +     */
  +    protected static final void grabFilesAndDirs(String file, List dirs, 
  +                                                 List files)
  +        throws IOException {
  +        org.apache.tools.zip.ZipFile zf = null;
  +        try {
  +            zf = new org.apache.tools.zip.ZipFile(file, "utf-8");
  +            Enumeration entries = zf.getEntries();
  +            HashSet dirSet = new HashSet();
  +            while (entries.hasMoreElements()) {
  +                org.apache.tools.zip.ZipEntry ze = 
  +                    (org.apache.tools.zip.ZipEntry) entries.nextElement();
  +                String name = ze.getName();
  +                // META-INF would be skipped anyway, avoid index for
  +                // manifest-only jars.
  +                if (!name.startsWith("META-INF/")) {
  +                    if (ze.isDirectory()) {
  +                        dirSet.add(name);
  +                    } else if (name.indexOf("/") == -1) {
  +                        files.add(name);
  +                    } else {
  +                        // a file, not in the root
  +                        // since the jar may be one without directory
  +                        // entries, add the parent dir of this file as
  +                        // well.
  +                        dirSet.add(name.substring(0, 
  +                                                  name.lastIndexOf("/") + 
1));
  +                    }
  +                }
  +            }
  +            dirs.addAll(dirSet);
  +        } finally {
  +            if (zf != null) {
  +                zf.close();
  +            }
           }
       }
   }
  
  
  
  1.93      +1 -0      ant/src/main/org/apache/tools/ant/taskdefs/Java.java
  
  Index: Java.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/Java.java,v
  retrieving revision 1.92
  retrieving revision 1.93
  diff -u -r1.92 -r1.93
  --- Java.java 23 Apr 2004 07:33:51 -0000      1.92
  +++ Java.java 23 Apr 2004 10:03:49 -0000      1.93
  @@ -417,6 +417,7 @@
           failOnError = fail;
           incompatibleWithSpawn |= fail;
       }
  +
       /**
        * The working directory of the process
        *
  
  
  
  1.1                  
ant/src/testcases/org/apache/tools/ant/taskdefs/ProtectedJarMethodsTest.java
  
  Index: ProtectedJarMethodsTest.java
  ===================================================================
  /*
   * Copyright  2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  
  package org.apache.tools.ant.taskdefs;
  
  import java.io.File;
  import java.io.IOException;
  import java.util.ArrayList;
  import org.apache.tools.ant.BuildFileTest;
  
  /**
   */
  public class ProtectedJarMethodsTest extends BuildFileTest {
  
      private static String tempJar = "tmp.jar";
  
      public ProtectedJarMethodsTest(String name) {
          super(name);
      }
  
      public void setUp() {
          configureProject("src/etc/testcases/taskdefs/jar.xml");
      }
  
      public void tearDown() {
          executeTarget("cleanup");
      }
  
      public void testGrabFilesAndDirs() throws IOException {
          executeTarget("testIndexTests");
          String archive = getProject().resolveFile(tempJar).getAbsolutePath();
          ArrayList dirs = new ArrayList();
          ArrayList files = new ArrayList();
          String[] expectedDirs = new String[] {
              "sub/",
          };
          String[] expectedFiles = new String[] {
              "foo",
          };
          Jar.grabFilesAndDirs(archive, dirs, files);
          assertEquals(expectedDirs.length, dirs.size());
          for (int i = 0; i < expectedDirs.length; i++) {
              assertTrue("Found " + expectedDirs[i],
                         dirs.contains(expectedDirs[i]));
          }
          assertEquals(expectedFiles.length, files.size());
          for (int i = 0; i < expectedFiles.length; i++) {
              assertTrue("Found " + expectedFiles[i],
                         files.contains(expectedFiles[i]));
          }
      }
  
      public void testFindJarNameNoClasspath() {
          assertEquals("foo", Jar.findJarName("foo", null));
          assertEquals("foo", Jar.findJarName("lib" + File.separatorChar + 
"foo",
                                              null));
      }
  
      public void testFindJarNameNoMatch() {
          assertNull(Jar.findJarName("foo", new String[] {"bar"}));
      }
  
      public void testFindJarNameSimpleMatches() {
          assertEquals("foo", Jar.findJarName("foo", new String[] {"foo"}));
          assertEquals("lib/foo", Jar.findJarName("foo",
                                                  new String[] {"lib/foo"}));
          assertEquals("foo", Jar.findJarName("bar" + File.separatorChar + 
"foo",
                                              new String[] {"foo"}));
          assertEquals("lib/foo",
                       Jar.findJarName("bar" + File.separatorChar + "foo",
                                       new String[] {"lib/foo"}));
      }
  
      public void testFindJarNameLongestMatchWins() {
          assertEquals("lib/foo",
                       Jar.findJarName("lib/foo", 
                                       new String[] {"foo", "lib/foo", 
                                                     "lib/bar/foo"}));
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to