Pack200.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.compress.java.util.jar;

  18. import java.beans.PropertyChangeListener;
  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.io.OutputStream;
  23. import java.security.AccessController;
  24. import java.security.PrivilegedAction;
  25. import java.util.Objects;
  26. import java.util.SortedMap;
  27. import java.util.jar.JarFile;
  28. import java.util.jar.JarInputStream;
  29. import java.util.jar.JarOutputStream;

  30. import org.apache.commons.compress.harmony.archive.internal.nls.Messages;
  31. import org.apache.commons.io.input.BoundedInputStream;

  32. /**
  33.  * Class factory for {@link Pack200.Packer} and {@link Pack200.Unpacker}.
  34.  */
  35. public abstract class Pack200 {

  36.     /**
  37.      * The interface defining the API for converting a JAR file to an output stream in the Pack200 format.
  38.      */
  39.     public interface Packer {

  40.         /**
  41.          * The format of a class attribute name.
  42.          */
  43.         String CLASS_ATTRIBUTE_PFX = "pack.class.attribute."; //$NON-NLS-1$

  44.         /**
  45.          * The format of a code attribute name.
  46.          */
  47.         String CODE_ATTRIBUTE_PFX = "pack.code.attribute."; //$NON-NLS-1$

  48.         /**
  49.          * The deflation hint to set in the output archive.
  50.          */
  51.         String DEFLATE_HINT = "pack.deflate.hint"; //$NON-NLS-1$

  52.         /**
  53.          * The indicated amount of effort to use in compressing the archive.
  54.          */
  55.         String EFFORT = "pack.effort"; //$NON-NLS-1$

  56.         /**
  57.          * a String representation for {@code error}.
  58.          */
  59.         String ERROR = "error"; //$NON-NLS-1$

  60.         /**
  61.          * a String representation of {@code false}.
  62.          */
  63.         String FALSE = "false"; //$NON-NLS-1$

  64.         /**
  65.          * The format of a field attribute name.
  66.          */
  67.         String FIELD_ATTRIBUTE_PFX = "pack.field.attribute."; //$NON-NLS-1$

  68.         /**
  69.          * The String representation for {@code keep}.
  70.          */
  71.         String KEEP = "keep"; //$NON-NLS-1$

  72.         /**
  73.          * Decide if all elements shall transmit in their original order.
  74.          */
  75.         String KEEP_FILE_ORDER = "pack.keep.file.order"; //$NON-NLS-1$

  76.         /**
  77.          * The String representation for {@code latest}.
  78.          */
  79.         String LATEST = "latest"; //$NON-NLS-1$

  80.         /**
  81.          * The format of a method attribute name.
  82.          */
  83.         String METHOD_ATTRIBUTE_PFX = "pack.method.attribute."; //$NON-NLS-1$

  84.         /**
  85.          * If it shall attempt to determine the latest modification time if this is set to {@code LATEST}.
  86.          */
  87.         String MODIFICATION_TIME = "pack.modification.time"; //$NON-NLS-1$

  88.         /**
  89.          * The String representation of {@code pass}.
  90.          */
  91.         String PASS = "pass"; //$NON-NLS-1$

  92.         /**
  93.          * The file that will not be compressed.
  94.          */
  95.         String PASS_FILE_PFX = "pack.pass.file."; //$NON-NLS-1$

  96.         /**
  97.          * Packer progress as a percentage.
  98.          */
  99.         String PROGRESS = "pack.progress"; //$NON-NLS-1$

  100.         /**
  101.          * The number of bytes of each archive segment.
  102.          */
  103.         String SEGMENT_LIMIT = "pack.segment.limit"; //$NON-NLS-1$

  104.         /**
  105.          * The String representation of {@code strip}.
  106.          */
  107.         String STRIP = "strip"; //$NON-NLS-1$

  108.         /**
  109.          * The String representation of {@code true}.
  110.          */
  111.         String TRUE = "true"; //$NON-NLS-1$

  112.         /**
  113.          * The action to take if an unknown attribute is encountered.
  114.          */
  115.         String UNKNOWN_ATTRIBUTE = "pack.unknown.attribute"; //$NON-NLS-1$

  116.         /**
  117.          * Adds a listener for PropertyChange events
  118.          *
  119.          * @param listener the listener to listen if PropertyChange events occurs
  120.          */
  121.         void addPropertyChangeListener(PropertyChangeListener listener);

  122.         /**
  123.          * Packs the specified JAR file to the specified output stream.
  124.          *
  125.          * @param in  JAR file to be compressed.
  126.          * @param out stream of compressed data.
  127.          * @throws IOException if I/O exception occurs.
  128.          */
  129.         void pack(JarFile in, OutputStream out) throws IOException;

  130.         /**
  131.          * Packs the data from the specified jar input stream to the specified output stream.
  132.          *
  133.          * @param in  stream of uncompressed JAR data.
  134.          * @param out stream of compressed data.
  135.          * @throws IOException if I/O exception occurs.
  136.          */
  137.         void pack(JarInputStream in, OutputStream out) throws IOException;

  138.         /**
  139.          * Gets a sorted map of the properties of this packer.
  140.          *
  141.          * @return the properties of the packer.
  142.          */
  143.         SortedMap<String, String> properties();

  144.         /**
  145.          * Removes a listener
  146.          *
  147.          * @param listener listener to remove
  148.          */
  149.         void removePropertyChangeListener(PropertyChangeListener listener);
  150.     }

  151.     /**
  152.      * The interface defining the API for converting a packed stream in the Pack200 format to a JAR file.
  153.      */
  154.     public interface Unpacker {

  155.         /**
  156.          * The String indicating if the unpacker should ignore all transmitted values, can be replaced by either {@code true} or {@code false}.
  157.          */
  158.         String DEFLATE_HINT = "unpack.deflate.hint"; //$NON-NLS-1$

  159.         /**
  160.          * a String representation of {@code false}.
  161.          */
  162.         String FALSE = "false"; //$NON-NLS-1$

  163.         /**
  164.          * a String representation of {@code keep}.
  165.          */
  166.         String KEEP = "keep"; //$NON-NLS-1$

  167.         /**
  168.          * The progress as a {@code percentage}.
  169.          */
  170.         String PROGRESS = "unpack.progress"; //$NON-NLS-1$

  171.         /**
  172.          * a String representation of {@code true}.
  173.          */
  174.         String TRUE = "true"; //$NON-NLS-1$

  175.         /**
  176.          * Adds a listener for {@code PropertyChange} events.
  177.          *
  178.          * @param listener the listener to listen if {@code PropertyChange} events occurs.
  179.          */
  180.         void addPropertyChangeListener(PropertyChangeListener listener);

  181.         /**
  182.          * Gets a sorted map of the properties of this unpacker.
  183.          *
  184.          * @return the properties of unpacker.
  185.          */
  186.         SortedMap<String, String> properties();

  187.         /**
  188.          * Removes a listener.
  189.          *
  190.          * @param listener listener to remove.
  191.          */
  192.         void removePropertyChangeListener(PropertyChangeListener listener);

  193.         /**
  194.          * Unpacks the contents of the specified {@code File} to the specified JAR output stream.
  195.          *
  196.          * @param in  file to uncompress.
  197.          * @param out JAR output stream of uncompressed data.
  198.          * @throws IOException if I/O exception occurs.
  199.          */
  200.         void unpack(File in, JarOutputStream out) throws IOException;

  201.         /**
  202.          * Unpacks the specified stream to the specified JAR output stream.
  203.          *
  204.          * @param in  stream to uncompress, preferably a {@link BoundedInputStream}.
  205.          * @param out JAR output stream of uncompressed data.
  206.          * @throws IOException if I/O exception occurs.
  207.          */
  208.         void unpack(InputStream in, JarOutputStream out) throws IOException;

  209.     }

  210.     /**
  211.      * System property key.
  212.      */
  213.     private static final String SYSTEM_PROPERTY_PACKER = "java.util.jar.Pack200.Packer"; //$NON-NLS-1$

  214.     /**
  215.      * System property key.
  216.      */
  217.     private static final String SYSTEM_PROPERTY_UNPACKER = "java.util.jar.Pack200.Unpacker"; //$NON-NLS-1$

  218.     static Object newInstance(final String systemProperty, final String defaultClassName) {
  219.         return AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  220.             final String className = System.getProperty(systemProperty, defaultClassName);
  221.             try {
  222.                 // TODO Not sure if this will cause problems loading the class
  223.                 ClassLoader classLoader = Pack200.class.getClassLoader();
  224.                 if (classLoader == null) {
  225.                     classLoader = Objects.requireNonNull(ClassLoader.getSystemClassLoader(), "ClassLoader.getSystemClassLoader()");
  226.                 }
  227.                 return classLoader.loadClass(className).getConstructor().newInstance();
  228.             } catch (final Exception e) {
  229.                 throw new Error(Messages.getString("archive.3E", className), e); //$NON-NLS-1$
  230.             }
  231.         });
  232.     }

  233.     /**
  234.      * Returns a new instance of a packer engine.
  235.      * <p>
  236.      * The implementation of the packer engine is defined by the system property {@code 'java.util.jar.Pack200.Packer'}. If this system property is defined an
  237.      * instance of the specified class is returned, otherwise the system's default implementation is returned.
  238.      * </p>
  239.      *
  240.      * @return an instance of {@code Packer}
  241.      */
  242.     public static Pack200.Packer newPacker() {
  243.         return (Packer) newInstance(SYSTEM_PROPERTY_PACKER, "org.apache.commons.compress.harmony.pack200.Pack200PackerAdapter"); //$NON-NLS-1$
  244.     }

  245.     /**
  246.      * Returns a new instance of an unpacker engine.
  247.      * <p>
  248.      * The implementation of the unpacker engine is defined by the system property {@link Pack200.Unpacker}. If this system property is defined an instance of
  249.      * the specified class is returned, otherwise the system's default implementation is returned.
  250.      * </p>
  251.      *
  252.      * @return an instance of {@link Pack200.Unpacker}.
  253.      */
  254.     public static Pack200.Unpacker newUnpacker() {
  255.         return (Unpacker) newInstance(SYSTEM_PROPERTY_UNPACKER, "org.apache.commons.compress.harmony.unpack200.Pack200UnpackerAdapter"); //$NON-NLS-1$
  256.     }

  257.     /**
  258.      * Prevents this class from being instantiated.
  259.      */
  260.     private Pack200() {
  261.         // do nothing
  262.     }

  263. }