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.Objects; 027import java.util.SortedMap; 028import java.util.jar.JarFile; 029import java.util.jar.JarInputStream; 030import java.util.jar.JarOutputStream; 031 032import org.apache.commons.compress.harmony.archive.internal.nls.Messages; 033import org.apache.commons.io.input.BoundedInputStream; 034 035/** 036 * Class factory for {@link Pack200.Packer} and {@link Pack200.Unpacker}. 037 */ 038public abstract class Pack200 { 039 040 /** 041 * The interface defining the API for converting a JAR file to an output stream in the Pack200 format. 042 */ 043 public interface Packer { 044 045 /** 046 * The format of a class attribute name. 047 */ 048 String CLASS_ATTRIBUTE_PFX = "pack.class.attribute."; //$NON-NLS-1$ 049 050 /** 051 * The format of a code attribute name. 052 */ 053 String CODE_ATTRIBUTE_PFX = "pack.code.attribute."; //$NON-NLS-1$ 054 055 /** 056 * The deflation hint to set in the output archive. 057 */ 058 String DEFLATE_HINT = "pack.deflate.hint"; //$NON-NLS-1$ 059 060 /** 061 * The indicated amount of effort to use in compressing the archive. 062 */ 063 String EFFORT = "pack.effort"; //$NON-NLS-1$ 064 065 /** 066 * a String representation for {@code error}. 067 */ 068 String ERROR = "error"; //$NON-NLS-1$ 069 070 /** 071 * a String representation of {@code false}. 072 */ 073 String FALSE = "false"; //$NON-NLS-1$ 074 075 /** 076 * The format of a field attribute name. 077 */ 078 String FIELD_ATTRIBUTE_PFX = "pack.field.attribute."; //$NON-NLS-1$ 079 080 /** 081 * The String representation for {@code keep}. 082 */ 083 String KEEP = "keep"; //$NON-NLS-1$ 084 085 /** 086 * Decide if all elements shall transmit in their original order. 087 */ 088 String KEEP_FILE_ORDER = "pack.keep.file.order"; //$NON-NLS-1$ 089 090 /** 091 * The String representation for {@code latest}. 092 */ 093 String LATEST = "latest"; //$NON-NLS-1$ 094 095 /** 096 * The format of a method attribute name. 097 */ 098 String METHOD_ATTRIBUTE_PFX = "pack.method.attribute."; //$NON-NLS-1$ 099 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}