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    private static final String SYSTEM_PROPERTY_PACKER = "java.util.jar.Pack200.Packer"; //$NON-NLS-1$
039
040    private static final String SYSTEM_PROPERTY_UNPACKER = "java.util.jar.Pack200.Unpacker"; //$NON-NLS-1$
041
042    /**
043     * Prevent this class from being instantiated.
044     */
045    private Pack200() {
046        // do nothing
047    }
048
049    /**
050     * Returns a new instance of a packer engine.
051     * <p>
052     * The implementation of the packer engine is defined by the system property
053     * {@code 'java.util.jar.Pack200.Packer'}. If this system property is
054     * defined an instance of the specified class is returned, otherwise the
055     * system's default implementation is returned.
056     *
057     * @return an instance of {@code Packer}
058     */
059    public static Pack200.Packer newPacker() {
060        return (Packer) AccessController
061                .doPrivileged(new PrivilegedAction<Object>() {
062                    public Object run() {
063                        String className = System
064                                .getProperty(SYSTEM_PROPERTY_PACKER,
065                                        "org.apache.commons.compress.harmony.pack200.Pack200PackerAdapter"); //$NON-NLS-1$
066                        try {
067                            // TODO Not sure if this will cause problems with
068                            // loading the packer
069                            return ClassLoader.getSystemClassLoader()
070                                    .loadClass(className).newInstance();
071                        } catch (Exception e) {
072                            throw new Error(Messages.getString("archive.3E",className), e); //$NON-NLS-1$
073                        }
074                    }
075                });
076
077    }
078
079    /**
080     * Returns a new instance of a unpacker engine.
081     * <p>
082     * The implementation of the unpacker engine is defined by the system
083     * property {@code 'java.util.jar.Pack200.Unpacker'}. If this system
084     * property is defined an instance of the specified class is returned,
085     * otherwise the system's default implementation is returned.
086     *
087     * @return a instance of {@code Unpacker}.
088     */
089    public static Pack200.Unpacker newUnpacker() {
090        return (Unpacker) AccessController
091                .doPrivileged(new PrivilegedAction<Object>() {
092                    public Object run() {
093                        String className = System
094                                .getProperty(SYSTEM_PROPERTY_UNPACKER,
095                                        "org.apache.commons.compress.harmony.unpack200.Pack200UnpackerAdapter");//$NON-NLS-1$
096                        try {
097                            return ClassLoader.getSystemClassLoader()
098                                    .loadClass(className).newInstance();
099                        } catch (Exception e) {
100                            throw new Error(Messages.getString("archive.3E",className), e); //$NON-NLS-1$
101                        }
102                    }
103                });
104    }
105
106    /**
107     * The interface defining the API for converting a JAR file to an output
108     * stream in the Pack200 format.
109     */
110    public static interface Packer {
111
112        /**
113         * the format of a class attribute name.
114         */
115        static final String CLASS_ATTRIBUTE_PFX = "pack.class.attribute."; //$NON-NLS-1$
116
117        /**
118         * the format of a code attribute name.
119         */
120        static final String CODE_ATTRIBUTE_PFX = "pack.code.attribute."; //$NON-NLS-1$
121
122        /**
123         * the deflation hint to set in the output archive.
124         */
125        static final String DEFLATE_HINT = "pack.deflate.hint";//$NON-NLS-1$
126
127        /**
128         * the indicated amount of effort to use in compressing the archive.
129         */
130        static final String EFFORT = "pack.effort";//$NON-NLS-1$
131
132        /**
133         * a String representation for {@code error}.
134         */
135        static final String ERROR = "error";//$NON-NLS-1$
136
137        /**
138         * a String representation of {@code false}.
139         */
140        static final String FALSE = "false";//$NON-NLS-1$
141
142        /**
143         * the format of a field attribute name.
144         */
145        static final String FIELD_ATTRIBUTE_PFX = "pack.field.attribute.";//$NON-NLS-1$
146
147        /**
148         * a String representation for {@code keep}.
149         */
150        static final String KEEP = "keep";//$NON-NLS-1$
151
152        /**
153         * decide if all elements shall transmit in their original order.
154         */
155        static final String KEEP_FILE_ORDER = "pack.keep.file.order";//$NON-NLS-1$
156
157        /**
158         * a String representation for {@code latest}.
159         */
160        static final String LATEST = "latest";//$NON-NLS-1$
161
162        /**
163         * the format of a method attribute name.
164         */
165        static final String METHOD_ATTRIBUTE_PFX = "pack.method.attribute.";//$NON-NLS-1$
166
167        /**
168         * if it shall attempt to determine the latest modification time if this
169         * is set to {@code LATEST}.
170         */
171        static final String MODIFICATION_TIME = "pack.modification.time";//$NON-NLS-1$
172
173        /**
174         * a String representation of {@code pass}.
175         */
176        static final String PASS = "pass";//$NON-NLS-1$
177
178        /**
179         * the file that will not be compressed.
180         */
181        static final String PASS_FILE_PFX = "pack.pass.file.";//$NON-NLS-1$
182
183        /**
184         * packer progress as a percentage.
185         */
186        static final String PROGRESS = "pack.progress";//$NON-NLS-1$
187
188        /**
189         * The number of bytes of each archive segment.
190         */
191        static final String SEGMENT_LIMIT = "pack.segment.limit";//$NON-NLS-1$
192
193        /**
194         * a String representation of {@code strip}.
195         */
196        static final String STRIP = "strip";//$NON-NLS-1$
197
198        /**
199         * a String representation of {@code true}.
200         */
201        static final String TRUE = "true";//$NON-NLS-1$
202
203        /**
204         * the action to take if an unknown attribute is encountered.
205         */
206        static final String UNKNOWN_ATTRIBUTE = "pack.unknown.attribute";//$NON-NLS-1$
207
208        /**
209         * Returns a sorted map of the properties of this packer.
210         *
211         * @return the properties of the packer.
212         */
213        SortedMap<String, String> properties();
214
215        /**
216         * Pack the specified JAR file to the specified output stream.
217         *
218         * @param in
219         *            JAR file to be compressed.
220         * @param out
221         *            stream of compressed data.
222         * @throws IOException
223         *             if I/O exception occurs.
224         */
225        void pack(JarFile in, OutputStream out) throws IOException;
226
227        /**
228         * Pack the data from the specified jar input stream to the specified
229         * output stream.
230         *
231         * @param in
232         *            stream of uncompressed JAR data.
233         * @param out
234         *            stream of compressed data.
235         * @throws IOException
236         *             if I/O exception occurs.
237         */
238        void pack(JarInputStream in, OutputStream out) throws IOException;
239
240        /**
241         * add a listener for PropertyChange events
242         *
243         * @param listener
244         *            the listener to listen if PropertyChange events occurs
245         */
246        void addPropertyChangeListener(PropertyChangeListener listener);
247
248        /**
249         * remove a listener
250         *
251         * @param listener
252         *            listener to remove
253         */
254        void removePropertyChangeListener(PropertyChangeListener listener);
255    }
256
257    /**
258     * The interface defining the API for converting a packed stream in the
259     * Pack200 format to a JAR file.
260     */
261    public static interface Unpacker {
262
263        /**
264         * The String indicating if the unpacker should ignore all transmitted
265         * values,can be replaced by either {@code true} or {@code false}.
266         */
267        static final String DEFLATE_HINT = "unpack.deflate.hint";//$NON-NLS-1$
268
269        /**
270         * a String representation of {@code false}.
271         */
272        static final String FALSE = "false";//$NON-NLS-1$
273
274        /**
275         * a String representation of {@code keep}.
276         */
277        static final String KEEP = "keep";//$NON-NLS-1$
278
279        /**
280         * the progress as a {@code percentage}.
281         */
282        static final String PROGRESS = "unpack.progress";//$NON-NLS-1$
283
284        /**
285         * a String representation of {@code true}.
286         */
287        static final String TRUE = "true";//$NON-NLS-1$
288
289        /**
290         * Returns a sorted map of the properties of this unpacker.
291         *
292         * @return the properties of unpacker.
293         */
294        SortedMap<String, String> properties();
295
296        /**
297         * Unpack the specified stream to the specified JAR output stream.
298         *
299         * @param in
300         *            stream to uncompressed.
301         * @param out
302         *            JAR output stream of uncompressed data.
303         * @throws IOException
304         *             if I/O exception occurs.
305         */
306        void unpack(InputStream in, JarOutputStream out) throws IOException;
307
308        /**
309         * Unpack the contents of the specified {@code File} to the specified
310         * JAR output stream.
311         *
312         * @param in
313         *            file to be uncompressed.
314         * @param out
315         *            JAR output stream of uncompressed data.
316         * @throws IOException
317         *             if I/O exception occurs.
318         */
319        void unpack(File in, JarOutputStream out) throws IOException;
320
321        /**
322         * add a listener for {@code PropertyChange} events.
323         *
324         * @param listener
325         *            the listener to listen if {@code PropertyChange} events
326         *            occurs.
327         */
328        void addPropertyChangeListener(PropertyChangeListener listener);
329
330        /**
331         * remove a listener.
332         *
333         * @param listener
334         *            listener to remove.
335         */
336        void removePropertyChangeListener(PropertyChangeListener listener);
337    }
338
339}