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).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}