View Javadoc
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  
19  import java.beans.PropertyChangeListener;
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  import java.security.AccessController;
25  import java.security.PrivilegedAction;
26  import java.util.Objects;
27  import java.util.SortedMap;
28  import java.util.jar.JarFile;
29  import java.util.jar.JarInputStream;
30  import java.util.jar.JarOutputStream;
31  
32  import org.apache.commons.compress.harmony.archive.internal.nls.Messages;
33  import org.apache.commons.io.input.BoundedInputStream;
34  
35  /**
36   * Class factory for {@link Pack200.Packer} and {@link Pack200.Unpacker}.
37   */
38  public abstract class Pack200 {
39  
40      /**
41       * The interface defining the API for converting a JAR file to an output stream in the Pack200 format.
42       */
43      public interface Packer {
44  
45          /**
46           * The format of a class attribute name.
47           */
48          String CLASS_ATTRIBUTE_PFX = "pack.class.attribute."; //$NON-NLS-1$
49  
50          /**
51           * The format of a code attribute name.
52           */
53          String CODE_ATTRIBUTE_PFX = "pack.code.attribute."; //$NON-NLS-1$
54  
55          /**
56           * The deflation hint to set in the output archive.
57           */
58          String DEFLATE_HINT = "pack.deflate.hint";//$NON-NLS-1$
59  
60          /**
61           * The indicated amount of effort to use in compressing the archive.
62           */
63          String EFFORT = "pack.effort";//$NON-NLS-1$
64  
65          /**
66           * a String representation for {@code error}.
67           */
68          String ERROR = "error";//$NON-NLS-1$
69  
70          /**
71           * a String representation of {@code false}.
72           */
73          String FALSE = "false";//$NON-NLS-1$
74  
75          /**
76           * The format of a field attribute name.
77           */
78          String FIELD_ATTRIBUTE_PFX = "pack.field.attribute.";//$NON-NLS-1$
79  
80          /**
81           * The String representation for {@code keep}.
82           */
83          String KEEP = "keep";//$NON-NLS-1$
84  
85          /**
86           * Decide if all elements shall transmit in their original order.
87           */
88          String KEEP_FILE_ORDER = "pack.keep.file.order";//$NON-NLS-1$
89  
90          /**
91           * The String representation for {@code latest}.
92           */
93          String LATEST = "latest";//$NON-NLS-1$
94  
95          /**
96           * The format of a method attribute name.
97           */
98          String METHOD_ATTRIBUTE_PFX = "pack.method.attribute.";//$NON-NLS-1$
99  
100         /**
101          * If it shall attempt to determine the latest modification time if this is set to {@code LATEST}.
102          */
103         String MODIFICATION_TIME = "pack.modification.time";//$NON-NLS-1$
104 
105         /**
106          * The 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          * The String representation of {@code strip}.
127          */
128         String STRIP = "strip";//$NON-NLS-1$
129 
130         /**
131          * The 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          * Adds a listener for PropertyChange events
142          *
143          * @param listener the listener to listen if PropertyChange events occurs
144          */
145         void addPropertyChangeListener(PropertyChangeListener listener);
146 
147         /**
148          * Packs the specified JAR file to the specified output stream.
149          *
150          * @param in  JAR file to be compressed.
151          * @param out stream of compressed data.
152          * @throws IOException if I/O exception occurs.
153          */
154         void pack(JarFile in, OutputStream out) throws IOException;
155 
156         /**
157          * Packs the data from the specified jar input stream to the specified output stream.
158          *
159          * @param in  stream of uncompressed JAR data.
160          * @param out stream of compressed data.
161          * @throws IOException if I/O exception occurs.
162          */
163         void pack(JarInputStream in, OutputStream out) throws IOException;
164 
165         /**
166          * Gets a sorted map of the properties of this packer.
167          *
168          * @return the properties of the packer.
169          */
170         SortedMap<String, String> properties();
171 
172         /**
173          * Removes a listener
174          *
175          * @param listener listener to remove
176          */
177         void removePropertyChangeListener(PropertyChangeListener listener);
178     }
179 
180     /**
181      * The interface defining the API for converting a packed stream in the Pack200 format to a JAR file.
182      */
183     public interface Unpacker {
184 
185         /**
186          * The String indicating if the unpacker should ignore all transmitted values, can be replaced by either {@code true} or {@code false}.
187          */
188         String DEFLATE_HINT = "unpack.deflate.hint";//$NON-NLS-1$
189 
190         /**
191          * a String representation of {@code false}.
192          */
193         String FALSE = "false";//$NON-NLS-1$
194 
195         /**
196          * a String representation of {@code keep}.
197          */
198         String KEEP = "keep";//$NON-NLS-1$
199 
200         /**
201          * The progress as a {@code percentage}.
202          */
203         String PROGRESS = "unpack.progress";//$NON-NLS-1$
204 
205         /**
206          * a String representation of {@code true}.
207          */
208         String TRUE = "true";//$NON-NLS-1$
209 
210         /**
211          * Adds a listener for {@code PropertyChange} events.
212          *
213          * @param listener the listener to listen if {@code PropertyChange} events occurs.
214          */
215         void addPropertyChangeListener(PropertyChangeListener listener);
216 
217         /**
218          * Gets a sorted map of the properties of this unpacker.
219          *
220          * @return the properties of unpacker.
221          */
222         SortedMap<String, String> properties();
223 
224         /**
225          * Removes a listener.
226          *
227          * @param listener listener to remove.
228          */
229         void removePropertyChangeListener(PropertyChangeListener listener);
230 
231         /**
232          * Unpacks the contents of the specified {@code File} to the specified JAR output stream.
233          *
234          * @param in  file to uncompress.
235          * @param out JAR output stream of uncompressed data.
236          * @throws IOException if I/O exception occurs.
237          */
238         void unpack(File in, JarOutputStream out) throws IOException;
239 
240         /**
241          * Unpacks the specified stream to the specified JAR output stream.
242          *
243          * @param in  stream to uncompress, preferably a {@link BoundedInputStream}.
244          * @param out JAR output stream of uncompressed data.
245          * @throws IOException if I/O exception occurs.
246          */
247         void unpack(InputStream in, JarOutputStream out) throws IOException;
248 
249     }
250 
251     /**
252      * System property key.
253      */
254     private static final String SYSTEM_PROPERTY_PACKER = "java.util.jar.Pack200.Packer"; //$NON-NLS-1$
255 
256     /**
257      * System property key.
258      */
259     private static final String SYSTEM_PROPERTY_UNPACKER = "java.util.jar.Pack200.Unpacker"; //$NON-NLS-1$
260 
261     static Object newInstance(final String systemProperty, final String defaultClassName) {
262         return AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
263             final String className = System.getProperty(systemProperty, defaultClassName);
264             try {
265                 // TODO Not sure if this will cause problems loading the class
266                 ClassLoader classLoader = Pack200.class.getClassLoader();
267                 if (classLoader == null) {
268                     classLoader = Objects.requireNonNull(ClassLoader.getSystemClassLoader(), "ClassLoader.getSystemClassLoader()");
269                 }
270                 return classLoader.loadClass(className).getConstructor().newInstance();
271             } catch (final Exception e) {
272                 throw new Error(Messages.getString("archive.3E", className), e); //$NON-NLS-1$
273             }
274         });
275     }
276 
277     /**
278      * Returns a new instance of a packer engine.
279      * <p>
280      * 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
281      * instance of the specified class is returned, otherwise the system's default implementation is returned.
282      * </p>
283      *
284      * @return an instance of {@code Packer}
285      */
286     public static Pack200.Packer newPacker() {
287         return (Packer) newInstance(SYSTEM_PROPERTY_PACKER, "org.apache.commons.compress.harmony.pack200.Pack200PackerAdapter"); //$NON-NLS-1$
288     }
289 
290     /**
291      * Returns a new instance of an unpacker engine.
292      * <p>
293      * The implementation of the unpacker engine is defined by the system property {@link Pack200.Unpacker}. If this system property is defined an instance of
294      * the specified class is returned, otherwise the system's default implementation is returned.
295      * </p>
296      *
297      * @return an instance of {@link Pack200.Unpacker}.
298      */
299     public static Pack200.Unpacker newUnpacker() {
300         return (Unpacker) newInstance(SYSTEM_PROPERTY_UNPACKER, "org.apache.commons.compress.harmony.unpack200.Pack200UnpackerAdapter"); //$NON-NLS-1$
301     }
302 
303     /**
304      * Prevents this class from being instantiated.
305      */
306     private Pack200() {
307         // do nothing
308     }
309 
310 }