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 }