sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1515873 - in /sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven: BundleCreator.java PackOutput.java Packer.java
Date Tue, 20 Aug 2013 16:55:18 GMT
Author: desruisseaux
Date: Tue Aug 20 16:55:17 2013
New Revision: 1515873

URL: http://svn.apache.org/r1515873
Log:
Simplify the Pack200 plugin by removing the support for various profiles.
If profiles are wanted in a future SIS version, we will try to handle them in an other way.

Modified:
    sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/BundleCreator.java
    sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackOutput.java
    sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Packer.java

Modified: sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/BundleCreator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/BundleCreator.java?rev=1515873&r1=1515872&r2=1515873&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/BundleCreator.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/BundleCreator.java
[UTF-8] Tue Aug 20 16:55:17 2013
@@ -20,6 +20,7 @@ import java.io.File;
 import java.io.IOException;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
 
 
 /**
@@ -41,16 +42,13 @@ import org.apache.maven.plugin.MojoExecu
  */
 public class BundleCreator extends AbstractMojo {
     /**
-     * The Apache SIS version, without branch name.
-     */
-    private static final String VERSION = "0.4";
-
-    /**
-     * The Apache SIS branch for which this plugin is creating a bundle, prefixed by {@code
'-'}.
-     * This is declared as a separated constant in order to make easier to update {@link
#VERSION}
-     * without creating conflicts during branch merges.
+     * Project information (name, version, URL).
+     *
+     * @parameter default-value="${project}"
+     * @required
+     * @readonly
      */
-    private static final String BRANCH = "-jdk7";
+    private MavenProject project;
 
     /**
      * The root directory (without the "<code>target/binaries</code>" sub-directory)
where JARs
@@ -73,15 +71,8 @@ public class BundleCreator extends Abstr
             throw new MojoExecutionException("Directory not found: " + targetDirectory);
         }
         try {
-            final String fullVersion = VERSION + BRANCH;
-            final Packer packer = new Packer(targetDirectory, fullVersion);
-            packer.addPack("apache-sis-" + fullVersion + ".jar");
-            try {
-                packer.createJars();
-            } finally {
-                packer.close();
-            }
-            packer.pack();
+            final Packer packer = new Packer(project.getName(), project.getUrl(), project.getVersion(),
targetDirectory);
+            packer.createPack200("sis.jar");
         } catch (IOException e) {
             throw new MojoExecutionException(e.getLocalizedMessage(), e);
         }

Modified: sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackOutput.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackOutput.java?rev=1515873&r1=1515872&r2=1515873&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackOutput.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/PackOutput.java
[UTF-8] Tue Aug 20 16:55:17 2013
@@ -19,12 +19,13 @@ package org.apache.sis.internal.maven;
 import java.util.Map;
 import java.util.Set;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
+import java.util.Iterator;
 import java.util.Enumeration;
 import java.util.jar.*;
 import java.io.File;
 import java.io.Closeable;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.FileOutputStream;
 import java.util.zip.GZIPOutputStream;
@@ -37,7 +38,7 @@ import static java.util.jar.Pack200.Pack
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.00)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 final class PackOutput implements Closeable {
@@ -47,21 +48,15 @@ final class PackOutput implements Closea
     private static final String CLASS = ".class";
 
     /**
-     * The packer that created this object. Will be used in order to fetch
-     * additional informations like the version to declare in the pom.xml file.
+     * The output file path.
      */
-    private final Packer packer;
+    private final File outputJAR;
 
     /**
-     * The output file.
+     * The stream where to write the JAR.
+     * Created only when {@link #open(File)} is invoked.
      */
-    private File file;
-
-    /**
-     * The stream where to write the JAR. Will be created
-     * only when {@link #open} will be invoked.
-     */
-    private JarOutputStream out;
+    private JarOutputStream outputStream;
 
     /**
      * The manifest attribute value, or {@code null} if none. We will set this field to the
@@ -71,88 +66,44 @@ final class PackOutput implements Closea
     private String mainClass, splashScreen;
 
     /**
-     * The JAR to be used as inputs.
-     */
-    private final Set<File> inputs;
-
-    /**
-     * The entries which were already done by previous invocation of {@link #getInputStream}.
+     * The JAR to be used as inputs. The elements in this map will be removed by the
+     * {@link #write()} method as we are done copying the content of JAR files.
      */
-    private final Set<String> entriesDone = new HashSet<>();
+    private final Map<File,PackInput> inputJARs;
 
     /**
-     * Creates an output jar.
+     * The entries which were already written in the output JAR file.
+     * There is two kind of entries which need this check:
      *
-     * @param packer    The packer that created this object.
-     * @param parent    The parent, or {@code null} if none.
-     * @param jars      The JAR filenames.
-     */
-    PackOutput(final Packer packer, final PackOutput parent, final String[] jars) {
-        this.packer = packer;
-        if (parent != null) {
-            inputs = new LinkedHashSet<>(parent.inputs);
-        } else {
-            inputs = new LinkedHashSet<>(jars.length * 4/3);
-        }
-        for (final String jar : jars) {
-            File file = new File(jar);
-            if (!file.isAbsolute()) {
-                file = new File(packer.jarDirectory, jar);
-            }
-            if (!file.isFile()) {
-                throw new IllegalArgumentException("Not a file: " + file);
-            }
-            if (!inputs.add(file)) {
-                throw new IllegalArgumentException("Duplicated JAR: " + file);
-            }
-        }
-    }
-
-    /**
-     * Returns {@code true} if this pack contains the given JAR file.
+     * <ul>
+     *   <li>Directories, which may be duplicated in different JAR files.</li>
+     *   <li>{@code META-INF/services} files which were merged in a single file.</li>
+     * </ul>
      *
-     * @param  file The JAR file to check for inclusion.
-     * @return {@code true} if this pack contains the given JAR file.
+     * @see #isMergeAllowed(String)
      */
-    boolean contains(final File file) {
-        return inputs.contains(file);
-    }
+    private final Set<String> entriesDone = new HashSet<>();
 
     /**
-     * Copies the entries from the given {@code mapping} to the given {@code actives} map,
but
-     * only those having a key included in the set of input files used by this {@code PackOutput}.
+     * Returns {@code true} if entries of the given name are allowed to be concatenated
+     * when they appear in more than one input JAR files.
      *
-     * @param mapping The mapping from {@link File} to {@link PackInput}.
-     * @param actives Where to store the {@link PackInput} required for
-     *        input by this {@code PackOutput}.
-     */
-    void copyInputs(final Map<File,PackInput> mapping, final Map<File,PackInput>
actives) {
-        for (final File file : inputs) {
-            final PackInput input = mapping.get(file);
-            if (input != null) {
-                final PackInput old = actives.put(file, input);
-                if (old != null && old != input) {
-                    throw new AssertionError("Inconsistent mapping.");
-                }
-            }
-        }
+     * @see #entriesDone
+     */
+    private static boolean isMergeAllowed(final String name) {
+        return name.startsWith(PackInput.SERVICES);
     }
 
     /**
-     * Opens the JAR files that were not already opens and store them in the given map.
+     * Creates an output jar.
      *
-     * @param  inputs The map where to store the opened JAR files.
-     * @throws IOException If a file can not be open.
+     * @param inputJARs The input JAR filenames together with their {@code PackInput} helpers.
+     * @param outputJAR The output JAR filename.
      */
-    void createPackInputs(final Map<File,PackInput> inputs) throws IOException {
-        for (final File jar : this.inputs) {
-            PackInput in = inputs.get(jar);
-            if (in == null) {
-                in = new PackInput(jar);
-                if (inputs.put(jar, in) != null) {
-                    throw new AssertionError(jar);
-                }
-            }
+    PackOutput(final Map<File,PackInput> inputJARs, final File outputJAR) {
+        this.inputJARs = inputJARs;
+        this.outputJAR = outputJAR;
+        for (final PackInput in : inputJARs.values()) {
             if (in.mainClass != null) {
                 mainClass = in.mainClass;
             }
@@ -163,23 +114,30 @@ final class PackOutput implements Closea
     }
 
     /**
-     * Opens the given JAR file for writing
+     * Opens the given JAR file for writing and creates its manifest.
      *
-     * @param  file The file to open.
+     * @param  projectName The project name, or {@code null} if none.
+     * @param  projectURL  The project URL, or {@code null} if none.
+     * @param  version     The project version, or {@code null} if none.
      * @throws IOException if the file can't be open.
      */
-    void open(final File file) throws IOException {
-        this.file = file;
+    void open(final String projectName, final String projectURL, final String version) throws
IOException {
         final Manifest manifest = new Manifest();
         Attributes attributes = manifest.getMainAttributes();
-        attributes.put(Attributes.Name.MANIFEST_VERSION,       "1.0");
-        attributes.put(Attributes.Name.SPECIFICATION_TITLE,    "Apache SIS");
-        attributes.put(Attributes.Name.SPECIFICATION_VENDOR,   "Apache SIS");
-        attributes.put(Attributes.Name.SPECIFICATION_VERSION,  packer.version);
-        attributes.put(Attributes.Name.IMPLEMENTATION_TITLE,   "Apache SIS");
-        attributes.put(Attributes.Name.IMPLEMENTATION_VENDOR,  "Apache SIS");
-        attributes.put(Attributes.Name.IMPLEMENTATION_VERSION, packer.version);
-        attributes.put(Attributes.Name.IMPLEMENTATION_URL,     "http://sis.apache.org");
+        attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+        if (projectName != null) {
+            attributes.put(Attributes.Name.SPECIFICATION_TITLE,    projectName);
+            attributes.put(Attributes.Name.SPECIFICATION_VENDOR,   projectName);
+            attributes.put(Attributes.Name.IMPLEMENTATION_TITLE,   projectName);
+            attributes.put(Attributes.Name.IMPLEMENTATION_VENDOR,  projectName);
+        }
+        if (projectURL != null) {
+            attributes.put(Attributes.Name.IMPLEMENTATION_URL, projectURL);
+        }
+        if (version != null) {
+            attributes.put(Attributes.Name.SPECIFICATION_VERSION,  version);
+            attributes.put(Attributes.Name.IMPLEMENTATION_VERSION, version);
+        }
         if (mainClass != null) {
             attributes.put(Attributes.Name.MAIN_CLASS, mainClass);
         }
@@ -187,9 +145,9 @@ final class PackOutput implements Closea
             attributes.put(PackInput.SPLASH_SCREEN, splashScreen);
         }
         /*
-         * Add the manifest of every dependencies.
+         * Add the package-level manifest of every dependencies.
          */
-        for (final File input : inputs) {
+        for (final File input : inputJARs.keySet()) {
             if (!input.getName().startsWith("sis-")) {
                 String packageName = null;
                 try (JarFile jar = new JarFile(input, false)) {
@@ -234,13 +192,15 @@ final class PackOutput implements Closea
         /*
          * Open the output stream for the big JAR file.
          */
-        out = new JarOutputStream(new FileOutputStream(file), manifest);
-        out.setLevel(1); // Use a cheap compression level since this JAR file is temporary.
+        outputStream = new JarOutputStream(new FileOutputStream(outputJAR), manifest);
+        outputStream.setLevel(1); // Use a cheap compression level since this JAR file is
temporary.
     }
 
     /**
      * Copies the value of the given attribute from a source {@code Attributes} to a target
-     * {@code Attributes} object.
+     * {@code Attributes} object. This is used for copying the package-level attributes.
+     *
+     * @return {@code true} if the attribute has been copied.
      */
     private static boolean copy(final Attributes src, final Attributes dst, final Attributes.Name
name) {
         String value = (String) src.get(name);
@@ -252,49 +212,57 @@ final class PackOutput implements Closea
     }
 
     /**
-     * Returns {@code true} if entries of the given name are allowed to be concatenated
-     * if they appear in more than one input JAR files.
+     * Iterates through the individual jars and merge them in single, bigger JAR file.
+     * This method closes the input JAR files as they are done.
      */
-    static boolean mergeAllowed(final String name) {
-        return name.startsWith(PackInput.SERVICES);
-    }
-
-    /**
-     * Begins writing a new JAR entry.
-     *
-     * @param  entry The new entry to write.
-     * @return {@code true} if the entry is ready to write, or {@code false} if it should
be skipped.
-     * @throws IOException If a failure occurs while creating the entry.
-     */
-    boolean putNextEntry(final JarEntry entry) throws IOException {
-        final String name = entry.getName();
-        if (entry.isDirectory() || mergeAllowed(name)) {
-            if (!entriesDone.add(name)) {
-                return false;
+    final void writeContent() throws IOException {
+        final byte[] buffer = new byte[64 * 1024];
+        for (final Iterator<Map.Entry<File,PackInput>> it = inputJARs.entrySet().iterator();
it.hasNext();) {
+            final Map.Entry<File,PackInput> inputJAR = it.next();
+            it.remove(); // Needs to be removed before the inner loop below.
+            try (PackInput input = inputJAR.getValue()) {
+                for (JarEntry entry; (entry = input.nextEntry()) != null;) {
+                    final String name = entry.getName();
+                    boolean isMergeAllowed = false;
+                    if (entry.isDirectory() || (isMergeAllowed = isMergeAllowed(name))) {
+                        if (!entriesDone.add(name)) {
+                            continue;
+                        }
+                    }
+                    outputStream.putNextEntry(entry);
+                    copy(input.getInputStream(), buffer);
+                    /*
+                     * From that points, the entry has been copied to the target JAR. Now
look in
+                     * following input JARs to see if there is some META-INF/services files
to merge.
+                     */
+                    if (isMergeAllowed) {
+                        for (final Map.Entry<File,PackInput> continuing : inputJARs.entrySet())
{
+                            final InputStream in = continuing.getValue().getInputStream(name);
+                            if (in != null) {
+                                copy(in, buffer);
+                            }
+                        }
+                    }
+                    outputStream.closeEntry();
+                }
             }
         }
-        out.putNextEntry(entry);
-        return true;
     }
 
     /**
-     * Writes the given number of bytes.
+     * Copies fully the given input stream to the given destination.
+     * The given input stream is closed after the copy.
      *
-     * @param  buffer The buffer containing the bytes to write.
-     * @param  n The number of bytes to write.
-     * @throws IOException if an exception occurred while writing the bytes.
-     */
-    void write(final byte[] buffer, final int n) throws IOException {
-        out.write(buffer, 0, n);
-    }
-
-    /**
-     * Close the current entry.
-     *
-     * @throws IOException If an error occurred while closing the entry.
-     */
-    void closeEntry() throws IOException {
-        out.closeEntry();
+     * @param  in     The input stream from which to get the the content to copy.
+     * @param  buffer Temporary buffer to reuse at each method call.
+     * @throws IOException If an error occurred during the copy.
+     */
+    void copy(final InputStream in, final byte[] buffer) throws IOException {
+        int n;
+        while ((n = in.read(buffer)) >= 0) {
+            outputStream.write(buffer, 0, n);
+        }
+        in.close();
     }
 
     /**
@@ -304,22 +272,22 @@ final class PackOutput implements Closea
      */
     @Override
     public void close() throws IOException {
-        if (out != null) {
-            out.close();
+        if (outputStream != null) {
+            outputStream.close();
         }
-        out = null;
+        outputStream = null;
     }
 
     /**
-     * Packs the output JAR.
+     * Creates a Pack200 file from the output JAR, then delete the JAR.
      *
      * @throws IOException if an error occurred while packing the JAR.
      */
     void pack() throws IOException {
-        if (out != null) {
+        if (outputStream != null) {
             throw new IllegalStateException("JAR output stream not closed.");
         }
-        final File inputFile = file;
+        final File inputFile = outputJAR;
         String filename = inputFile.getName();
         final int ext = filename.lastIndexOf('.');
         if (ext > 0) {
@@ -328,7 +296,7 @@ final class PackOutput implements Closea
         filename += ".pack.gz";
         final File outputFile = new File(inputFile.getParent(), filename);
         if (outputFile.equals(inputFile)) {
-            throw new IOException("Input file is already a packed: " + inputFile);
+            throw new IOException("Input file is already packed: " + inputFile);
         }
         /*
          * Now process to the compression.

Modified: sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Packer.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Packer.java?rev=1515873&r1=1515872&r2=1515873&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Packer.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/maven/Packer.java
[UTF-8] Tue Aug 20 16:55:17 2013
@@ -19,163 +19,112 @@ package org.apache.sis.internal.maven;
 import java.util.Map;
 import java.util.Set;
 import java.util.Arrays;
-import java.util.Objects;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
-import java.util.jar.*;
 import java.io.File;
 import java.io.FilenameFilter;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStream;
 
 
 /**
- * Creates PAC200 files from the JAR builds by Maven. This tools needs the JAR files to be
either provided
- * in the {@code target/binaries} directory, or listed in the {@code target/binaries/content.txt}
file.
- *
- * <p><b>Usage:</b> If {@code rootDirectory} is the directory containing
the root {@code pom.xml} file,
- * then this class can be used as below (replace {@code "1.0"} by the actual version number
and
- * {@code "sis-1.0.jar"} by any filename of your choice):</p>
- *
- * <blockquote><pre> Packer packer = new Packer(new File(rootDirectory, "target"),
"1.0");
- * packer.addPack("sis-1.0.jar");
- * packer.createJars();
- * packer.close();
- * packer.pack();</pre></blockquote>
+ * Creates a PACK200 files from the JAR in the {@code target/binaries} directory.
+ * This tools needs the JAR files to be either copied or linked in the {@code target/binaries}
directory,
+ * or listed in the {@code target/binaries/content.txt} file.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.00)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 final class Packer implements FilenameFilter {
     /**
-     * The sub-directory containing pack files. This directory
-     * will be automatically created if it doesn't already exist.
-     */
-    private static final String PACK_DIRECTORY = "bundles";
-
-    /**
-     * The Maven target directory. Should contains the {@code "binaries"} sub-directory,
-     * which should contains all JAR files collected by {@code sis-build-helper} plugin.
-     */
-    private final File targetDirectory;
-
-    /**
-     * The directory of JAR files. Shall be {@code "target/binaries"}.
+     * The {@code target} sub-directory containing pack files.
+     * This directory will be automatically created if it does not already exist.
      */
-    final File jarDirectory;
+    private static final String PACK_DIRECTORY = "distribution";
 
     /**
-     * The JAR files to read, by input filename.
+     * The project name, URL and version to declare in the manifest file, or {@code null}
if none.
      */
-    private final Map<File,PackInput> inputs = new LinkedHashMap<>();
+    private final String projectName, projectURL, version;
 
     /**
-     * The JAR and PACK files to create, by output name.
+     * The Maven target directory. Shall contain the {@code "binaries"} sub-directory,
+     * which shall contains all JAR files collected by {@code sis-build-helper} plugin.
      */
-    private final Map<String,PackOutput> outputs = new LinkedHashMap<>();
+    private final File targetDirectory;
 
     /**
-     * The version to declare in the manifest file.
+     * The directory of input JAR files. Shall be {@code "target/binaries"}.
      */
-    final String version;
+    private final File binariesDirectory;
 
     /**
      * Creates a packer.
      *
-     * @param targetDirectory The Maven target directory.
-     * @param version The version to declare in the manifest file.
+     * @param  projectName     The project name to declare in the manifest file, or {@code
null} if none.
+     * @param  projectURL      The project URL to declare in the manifest file, or {@code
null} if none.
+     * @param  version         The project version to declare in the manifest file, or {@code
null} if none.
+     * @param  targetDirectory The Maven target directory.
+     * @throws FileNotFoundException if the {@code target/binaries} directory is not found.
      */
-    Packer(final File targetDirectory, final String version) throws FileNotFoundException
{
-        this.version = version;
+    Packer(final String projectName, final String projectURL, final String version,
+           final File targetDirectory) throws FileNotFoundException
+    {
+        this.projectName = projectName;
+        this.projectURL  = projectURL;
+        this.version     = version;
         this.targetDirectory = targetDirectory;
-        this.jarDirectory = new File(targetDirectory, JarCollector.SUB_DIRECTORY);
-        if (!jarDirectory.isDirectory()) {
-            throw new FileNotFoundException("Directory not found: " + jarDirectory);
+        this.binariesDirectory = new File(targetDirectory, JarCollector.SUB_DIRECTORY);
+        if (!binariesDirectory.isDirectory()) {
+            throw new FileNotFoundException("Directory not found: " + binariesDirectory);
         }
     }
 
     /**
-     * Adds a pack which will contain every JAR files in the target directory.
-     * The given {@code pack} name is the name of the JAR file to create before to be packed.
-     * This filename shall ends with the "{@code .jar}" suffix. That suffix will be replaced
-     * by {@code ".pack.gz"} at Pack200 creation time.
+     * Filter the input JAR files. This is for internal usage by {@link #createOutputJAR(String)}
only.
      *
-     * @param  pack The name of the JAR file to create before the Pack200 creation.
-     * @throws IOException If an error occurred while collecting the target directory content.
+     * @param  directory The directory (ignored).
+     * @param  name The filename.
+     * @return {@code true} if the given filename ends with {@code ".jar"}.
      */
-    public void addPack(final String pack) throws IOException {
-        final Set<String> list = JarCollector.loadDependencyList(new File(jarDirectory,
JarCollector.CONTENT_FILE));
-        list.addAll(Arrays.asList(jarDirectory.list(this)));
-        addPack(null, pack, list.toArray(new String[list.size()]));
+    @Override
+    public boolean accept(final File directory, final String name) {
+        return name.endsWith(".jar");
     }
 
     /**
-     * Adds the given JAR files for the given pack. This method can be invoked when we want
to
-     * create a Pack200 file containing only a subset of all available JAR files, or when
some
-     * JAR files to include are specified by a previously created Pack200 file.
-     *
-     * <p>The filenames in the given {@code jars} array can contains the {@code '*'}
wildcards.
-     * However at most one entry can match, otherwise an exception will be thrown. This limited
-     * wildcards support is mostly a convenience for avoiding to specify the version number
of
-     * JAR files.</p>
-     *
-     * @param  parent The pack from which to inherit the JAR files, or {@code null} if none.
-     * @param  pack   The name of the JAR file to create before the Pack200 creation.
-     * @param  jars   The list of JAR files in this pack file. Filenames can contain the
{@code '*'} wildcards.
-     * @throws IOException If an error occurred while collecting the target directory content.
+     * Returns the list of input JAR files, together with a helper class for copying the
data in the Pack200 file.
+     * All input JAR files are opened by this method. They will need to be closed by {@link
PackInput#close()}.
      */
-    public void addPack(final String parent, final String pack, final String[] jars) throws
IOException {
-        Objects.requireNonNull("pack", pack);
-        PackOutput p = null;
-        if (parent != null) {
-            p = outputs.get(parent);
-            if (p == null) {
-                throw new IllegalArgumentException("Non-existant pack: " + parent);
+    private Map<File,PackInput> getInputJARs() throws IOException {
+        final Set<String> filenames = JarCollector.loadDependencyList(new File(binariesDirectory,
JarCollector.CONTENT_FILE));
+        filenames.addAll(Arrays.asList(binariesDirectory.list(this)));
+        final Map<File,PackInput> inputJARs = new LinkedHashMap<>(filenames.size()
* 4/3);
+        for (final String filename : filenames) {
+            File file = new File(filename);
+            if (!file.isAbsolute()) {
+                file = new File(binariesDirectory, filename);
             }
-        }
-        /*
-         * If there is wildcard, replace the wildcard by the full name.
-         * We allows only one name (the wildcard should be used for the
-         * version number only, and we don't allow many versions of the
-         * same file).
-         */
-        for (int i=0; i<jars.length; i++) {
-            final String jarFile = jars[i];
-            final int w = jarFile.lastIndexOf('*');
-            if (w >= 0) {
-                final String prefix = jarFile.substring(0, w);
-                final String suffix = jarFile.substring(w+1);
-                final String[] f = jarDirectory.list(new FilenameFilter() {
-                    @Override public boolean accept(final File directory, final String name)
{
-                        return name.startsWith(prefix) && name.endsWith(suffix);
-                    }
-                });
-                if (f == null) {
-                    throw new FileNotFoundException("Directory not found: " + jarDirectory);
-                }
-                switch (f.length) {
-                    case 1:  jars[i] = f[0]; break;
-                    case 0:  throw new IllegalArgumentException("No file found for pattern:
" + jarFile);
-                    default: throw new IllegalArgumentException("Duplicated files: " + f[0]
+ " and " + f[1]);
-                }
+            if (!file.isFile() || !file.canRead()) {
+                throw new IllegalArgumentException("Not a file or can not read: " + file);
+            }
+            if (inputJARs.put(file, new PackInput(file)) != null) {
+                throw new IllegalArgumentException("Duplicated JAR: " + file);
             }
         }
-        p = new PackOutput(this, p, jars);
-        if (outputs.put(pack, p) != null) {
-            throw new IllegalArgumentException("Duplicated pack: " + pack);
-        }
+        return inputJARs;
     }
 
     /**
-     * Creates the JAR files from the packages declared with {@link #addPack}.
+     * Creates the Pack 200 file which will contain every JAR files in the {@code target/binaries}
directory.
+     * The given {@code outputJAR} name is the name of the JAR file to create before to be
packed.
+     * This filename shall end with the "{@code .jar}" suffix.
      *
-     * @throws IOException if an error occurred while reading existing JAR files
-     *         or writing to the packed files.
+     * @param  outputJAR The name of the JAR file to create before the Pack200 creation.
+     * @throws IOException If an error occurred while collecting the target directory content.
      */
-    public void createJars() throws IOException {
+    public void createPack200(final String outputJAR) throws IOException {
         /*
          * Creates the output directory. We do that first in order to avoid the
          * costly opening of all JAR files if we can't create this directory.
@@ -186,143 +135,11 @@ final class Packer implements FilenameFi
                 throw new IOException("Can't create the \"" + PACK_DIRECTORY + "\" directory.");
             }
         }
-        /*
-         * Opens all input JAR files in read-only mode, and create the initially empty output
JAR
-         * file. We need to open all input files in order to check for duplicate entries
before we
-         * start the writing process. Files in the META-INF/services directory need to be
merged.
-         */
-        for (final Map.Entry<String,PackOutput> entry : outputs.entrySet()) {
-            final String name = entry.getKey();
-            final PackOutput pack = entry.getValue();
-            pack.createPackInputs(inputs);
-            pack.open(new File(outDirectory, name));
-        }
-        /*
-         * Iterates through the individual jars and merge them in single, bigger JAR file.
-         * During each iteration we get the array of output streams where a particular file
-         * need to be copied - all those "active" output streams will be filled in parallel.
-         */
-        final byte[] buffer = new byte[64*1024];
-        final Map<File,PackInput> activeInputs = new LinkedHashMap<>(inputs.size()
* 4/3);
-        final PackOutput[] activesForFile      = new PackOutput[outputs.size()];
-        final PackOutput[] activesForEntry     = new PackOutput[activesForFile.length];
-        final PackOutput[] activesForFollow    = new PackOutput[activesForFile.length];
-        for (final Iterator<Map.Entry<File,PackInput>> it = inputs.entrySet().iterator();
it.hasNext();) {
-            final Map.Entry<File,PackInput> fileInputPair = it.next();
-            final File  inputFile = fileInputPair.getKey();
-            try (PackInput input = fileInputPair.getValue()) {
-                it.remove(); // Needs to be before next usage of "inputs" below.
-                int countForFile = 0;
-                for (final PackOutput candidate : outputs.values()) {
-                    if (candidate.contains(inputFile)) {
-                        activesForFile[countForFile++] = candidate;
-                        candidate.copyInputs(inputs, activeInputs);
-                    }
-                }
-                /*
-                 * "activesForFile" now contains the list of PackOutput we need to care about
-                 * for the current PackInput (i.e. a whole input JAR). Copies every entries
-                 * found in that JAR.
-                 */
-                for (JarEntry entry; (entry = input.nextEntry()) != null;) {
-                    int countForEntry = 0;
-                    for (int i=0; i<countForFile; i++) {
-                        final PackOutput candidate = activesForFile[i];
-                        if (candidate.putNextEntry(entry)) {
-                            activesForEntry[countForEntry++] = candidate;
-                        }
-                    }
-                    copy(input.getInputStream(), activesForEntry, countForEntry, buffer);
-                    /*
-                     * From that points, the entry has been copied to all target JARs. Now
looks in
-                     * following input JARs to see if there is some META-INF/services files
to merge.
-                     */
-                    final String name = entry.getName();
-                    if (PackOutput.mergeAllowed(name)) {
-                        for (final Map.Entry<File,PackInput> continuing : activeInputs.entrySet())
{
-                            final InputStream in = continuing.getValue().getInputStream(name);
-                            if (in != null) {
-                                final File file = continuing.getKey();
-                                int countForFollow = 0;
-                                for (int i=0; i<countForEntry; i++) {
-                                    final PackOutput candidate = activesForEntry[i];
-                                    if (candidate.contains(file)) {
-                                        activesForFollow[countForFollow++] = candidate;
-                                    }
-                                }
-                                copy(in, activesForFollow, countForFollow, buffer);
-                                Arrays.fill(activesForFollow, null);
-                            }
-                        }
-                    }
-                    for (int i=0; i<countForEntry; i++) {
-                        activesForEntry[i].closeEntry();
-                    }
-                    Arrays.fill(activesForEntry, null);
-                }
-                Arrays.fill(activesForFile, null);
-                activeInputs.clear();
-            }
-        }
-        close();
-    }
-
-    /**
-     * Copies fully the given input stream to the given destination.
-     * The given input stream is closed after the copy.
-     *
-     * @param  in     The input stream from which to get the the content to copy.
-     * @param  out    Where to copy the input stream content.
-     * @param  count  Number of valid entries in the {@code out} array.
-     * @param  buffer Temporary buffer to reuse at each method call.
-     * @throws IOException If an error occurred during the copy.
-     */
-    private static void copy(final InputStream in, final PackOutput[] out, final int count,
-                             final byte[] buffer) throws IOException
-    {
-        int n;
-        while ((n = in.read(buffer)) >= 0) {
-            for (int i=0; i<count; i++) {
-                out[i].write(buffer, n);
-            }
-        }
-        in.close();
-    }
-
-    /**
-     * Closes all streams.
-     *
-     * @throws IOException If an error occurred while closing the stream.
-     */
-    public void close() throws IOException {
-        for (final PackOutput jar : outputs.values()) {
-            jar.close();
-        }
-        for (final PackInput jar : inputs.values()) {
-            jar.close();
-        }
-    }
-
-    /**
-     * Launch Pack200 after output JAR files have been created.
-     *
-     * @throws IOException If an error occurred while creating the PACK200 file.
-     */
-    public void pack() throws IOException {
-        for (final PackOutput jar : outputs.values()) {
-            jar.pack();
-        }
-    }
-
-    /**
-     * Filter the JAR files.
-     *
-     * @param  directory The directory (ignored).
-     * @param  name The filename.
-     * @return {@code true} if the given filename ends with {@code ".jar"}.
-     */
-    @Override
-    public boolean accept(final File directory, final String name) {
-        return name.endsWith(".jar");
+        final PackOutput output;
+        output = new PackOutput(getInputJARs(), new File(outDirectory, outputJAR));
+        output.open(projectName, projectURL, version);
+        output.writeContent();
+        output.close();
+        output.pack();
     }
 }



Mime
View raw message