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