    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.compress.java.util.jar;
    018
    019import java.beans.PropertyChangeListener;
    020import java.io.File;
    021import java.io.IOException;
    022import java.io.InputStream;
    023import java.io.OutputStream;
    024import java.security.AccessController;
    025import java.security.PrivilegedAction;
    026import java.util.SortedMap;
    027import java.util.jar.JarFile;
    028import java.util.jar.JarInputStream;
    029import java.util.jar.JarOutputStream;
    030
    031import org.apache.commons.compress.harmony.archive.internal.nls.Messages;
    032
    033/**
    034 * Class factory for {@link Pack200.Packer} and {@link Pack200.Unpacker}.
    035 */
    036public abstract class Pack200 {
    037
    038    /**
    039     * The interface defining the API for converting a JAR file to an output
    040     * stream in the Pack200 format.
    041     */
    042    public interface Packer {
    043
    044        /**
    045         * the format of a class attribute name.
    046         */
    047        String CLASS_ATTRIBUTE_PFX = "pack.class.attribute."; //$NON-NLS-1$
    048
    049        /**
    050         * the format of a code attribute name.
    051         */
    052        String CODE_ATTRIBUTE_PFX = "pack.code.attribute."; //$NON-NLS-1$
    053
    054        /**
    055         * the deflation hint to set in the output archive.
    056         */
    057        String DEFLATE_HINT = "pack.deflate.hint";//$NON-NLS-1$
    058
    059        /**
    060         * the indicated amount of effort to use in compressing the archive.
    061         */
    062        String EFFORT = "pack.effort";//$NON-NLS-1$
    063
    064        /**
    065         * a String representation for {@code error}.
    066         */
    067        String ERROR = "error";//$NON-NLS-1$
    068
    069        /**
    070         * a String representation of {@code false}.
    071         */
    072        String FALSE = "false";//$NON-NLS-1$
    073
    074        /**
    075         * the format of a field attribute name.
    076         */
    077        String FIELD_ATTRIBUTE_PFX = "pack.field.attribute.";//$NON-NLS-1$
    078
    079        /**
    080         * a String representation for {@code keep}.
    081         */
    082        String KEEP = "keep";//$NON-NLS-1$
    083
    084        /**
    085         * decide if all elements shall transmit in their original order.
    086         */
    087        String KEEP_FILE_ORDER = "pack.keep.file.order";//$NON-NLS-1$
    088
    089        /**
    090         * a String representation for {@code latest}.
    091         */
    092        String LATEST = "latest";//$NON-NLS-1$
    093
    094        /**
    095         * the format of a method attribute name.
    096         */
    097        String METHOD_ATTRIBUTE_PFX = "pack.method.attribute.";//$NON-NLS-1$
    098
    099        /**
    100         * if it shall attempt to determine the latest modification time if this
    101         * is set to {@code LATEST}.
    102         */
    103        String MODIFICATION_TIME = "pack.modification.time";//$NON-NLS-1$
    104
    105        /**
    106         * a String representation of {@code pass}.
    107         */
    108        String PASS = "pass";//$NON-NLS-1$
    109
    110        /**
    111         * the file that will not be compressed.
    112         */
    113        String PASS_FILE_PFX = "pack.pass.file.";//$NON-NLS-1$
    114
    115        /**
    116         * packer progress as a percentage.
    117         */
    118        String PROGRESS = "pack.progress";//$NON-NLS-1$
    119
    120        /**
    121         * The number of bytes of each archive segment.
    122         */
    123        String SEGMENT_LIMIT = "pack.segment.limit";//$NON-NLS-1$
    124
    125        /**
    126         * a String representation of {@code strip}.
    127         */
    128        String STRIP = "strip";//$NON-NLS-1$
    129
    130        /**
    131         * a String representation of {@code true}.
    132         */
    133        String TRUE = "true";//$NON-NLS-1$
    134
    135        /**
    136         * the action to take if an unknown attribute is encountered.
    137         */
    138        String UNKNOWN_ATTRIBUTE = "pack.unknown.attribute";//$NON-NLS-1$
    139
    140        /**
    141         * add a listener for PropertyChange events
    142         *
    143         * @param listener
    144         *            the listener to listen if PropertyChange events occurs
    145         */
    146        void addPropertyChangeListener(PropertyChangeListener listener);
    147
    148        /**
    149         * Pack the specified JAR file to the specified output stream.
    150         *
    151         * @param in
    152         *            JAR file to be compressed.
    153         * @param out
    154         *            stream of compressed data.
    155         * @throws IOException
    156         *             if I/O exception occurs.
    157         */
    158        void pack(JarFile in, OutputStream out) throws IOException;
    159
    160        /**
    161         * Pack the data from the specified jar input stream to the specified
    162         * output stream.
    163         *
    164         * @param in
    165         *            stream of uncompressed JAR data.
    166         * @param out
    167         *            stream of compressed data.
    168         * @throws IOException
    169         *             if I/O exception occurs.
    170         */
    171        void pack(JarInputStream in, OutputStream out) throws IOException;
    172
    173        /**
    174         * Returns a sorted map of the properties of this packer.
    175         *
    176         * @return the properties of the packer.
    177         */
    178        SortedMap<String, String> properties();
    179
    180        /**
    181         * remove a listener
    182         *
    183         * @param listener
    184         *            listener to remove
    185         */
    186        void removePropertyChangeListener(PropertyChangeListener listener);
    187    }
    188
    189    /**
    190     * The interface defining the API for converting a packed stream in the
    191     * Pack200 format to a JAR file.
    192     */
    193    public interface Unpacker {
    194
    195        /**
    196         * The String indicating if the unpacker should ignore all transmitted
    197         * values, can be replaced by either {@code true} or {@code false}.
    198         */
    199        String DEFLATE_HINT = "unpack.deflate.hint";//$NON-NLS-1$
    200
    201        /**
    202         * a String representation of {@code false}.
    203         */
    204        String FALSE = "false";//$NON-NLS-1$
    205
    206        /**
    207         * a String representation of {@code keep}.
    208         */
    209        String KEEP = "keep";//$NON-NLS-1$
    210
    211        /**
    212         * the progress as a {@code percentage}.
    213         */
    214        String PROGRESS = "unpack.progress";//$NON-NLS-1$
    215
    216        /**
    217         * a String representation of {@code true}.
    218         */
    219        String TRUE = "true";//$NON-NLS-1$
    220
    221        /**
    222         * add a listener for {@code PropertyChange} events.
    223         *
    224         * @param listener
    225         *            the listener to listen if {@code PropertyChange} events
    226         *            occurs.
    227         */
    228        void addPropertyChangeListener(PropertyChangeListener listener);
    229
    230        /**
    231         * Returns a sorted map of the properties of this unpacker.
    232         *
    233         * @return the properties of unpacker.
    234         */
    235        SortedMap<String, String> properties();
    236
    237        /**
    238         * remove a listener.
    239         *
    240         * @param listener
    241         *            listener to remove.
    242         */
    243        void removePropertyChangeListener(PropertyChangeListener listener);
    244
    245        /**
    246         * Unpack the contents of the specified {@code File} to the specified
    247         * JAR output stream.
    248         *
    249         * @param in
    250         *            file to be uncompressed.
    251         * @param out
    252         *            JAR output stream of uncompressed data.
    253         * @throws IOException
    254         *             if I/O exception occurs.
    255         */
    256        void unpack(File in, JarOutputStream out) throws IOException;
    257
    258        /**
    259         * Unpack the specified stream to the specified JAR output stream.
    260         *
    261         * @param in
    262         *            stream to uncompressed.
    263         * @param out
    264         *            JAR output stream of uncompressed data.
    265         * @throws IOException
    266         *             if I/O exception occurs.
    267         */
    268        void unpack(InputStream in, JarOutputStream out) throws IOException;
    269    }
    270
    271    private static final String SYSTEM_PROPERTY_PACKER = "java.util.jar.Pack200.Packer"; //$NON-NLS-1$
    272
    273    private static final String SYSTEM_PROPERTY_UNPACKER = "java.util.jar.Pack200.Unpacker"; //$NON-NLS-1$
    274
    275    static Object newInstance(final String systemProperty, final String defaultClassName) {
    276        return AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    277            final String className = System.getProperty(systemProperty, defaultClassName);
    278            try {
    279                // TODO Not sure if this will cause problems loading the class
    280                return Pack200.class.getClassLoader().loadClass(className).getConstructor().newInstance();
    281            } catch (final Exception e) {
    282                throw new Error(Messages.getString("archive.3E", className), e); //$NON-NLS-1$
    283            }
    284        });
    285    }
    286
    287    /**
    288     * Returns a new instance of a packer engine.
    289     * <p>
    290     * The implementation of the packer engine is defined by the system property
    291     * {@code 'java.util.jar.Pack200.Packer'}. If this system property is
    292     * defined an instance of the specified class is returned, otherwise the
    293     * system's default implementation is returned.
    294     *
    295     * @return an instance of {@code Packer}
    296     */
    297    public static Pack200.Packer newPacker() {
    298        return (Packer) newInstance(SYSTEM_PROPERTY_PACKER, "org.apache.commons.compress.harmony.pack200.Pack200PackerAdapter"); //$NON-NLS-1$
    299    }
    300
    301    /**
    302     * Returns a new instance of an unpacker engine.
    303     * <p>
    304     * The implementation of the unpacker engine is defined by the system
    305     * property {@link Pack200.Unpacker}. If this system
    306     * property is defined an instance of the specified class is returned,
    307     * otherwise the system's default implementation is returned.
    308     *
    309     * @return an instance of {@link Pack200.Unpacker}.
    310     */
    311    public static Pack200.Unpacker newUnpacker() {
    312        return (Unpacker) newInstance(SYSTEM_PROPERTY_UNPACKER, "org.apache.commons.compress.harmony.unpack200.Pack200UnpackerAdapter"); //$NON-NLS-1$
    313    }
    314
    315    /**
    316     * Prevent this class from being instantiated.
    317     */
    318    private Pack200() {
    319        // do nothing
    320    }
    321
    322}