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 }