001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.commons.compress.java.util.jar; 020 021import java.beans.PropertyChangeListener; 022import java.io.File; 023import java.io.IOException; 024import java.io.InputStream; 025import java.io.OutputStream; 026import java.security.AccessController; 027import java.security.PrivilegedAction; 028import java.util.Objects; 029import java.util.SortedMap; 030import java.util.jar.JarFile; 031import java.util.jar.JarInputStream; 032import java.util.jar.JarOutputStream; 033 034import org.apache.commons.compress.harmony.archive.internal.nls.Messages; 035import org.apache.commons.io.input.BoundedInputStream; 036 037/** 038 * Class factory for {@link Pack200.Packer} and {@link Pack200.Unpacker}. 039 */ 040public abstract class Pack200 { 041 042 /** 043 * The interface defining the API for converting a JAR file to an output stream in the Pack200 format. 044 */ 045 public interface Packer { 046 047 /** 048 * The format of a class attribute name. 049 */ 050 String CLASS_ATTRIBUTE_PFX = "pack.class.attribute."; //$NON-NLS-1$ 051 052 /** 053 * The format of a code attribute name. 054 */ 055 String CODE_ATTRIBUTE_PFX = "pack.code.attribute."; //$NON-NLS-1$ 056 057 /** 058 * The deflation hint to set in the output archive. 059 */ 060 String DEFLATE_HINT = "pack.deflate.hint"; //$NON-NLS-1$ 061 062 /** 063 * The indicated amount of effort to use in compressing the archive. 064 */ 065 String EFFORT = "pack.effort"; //$NON-NLS-1$ 066 067 /** 068 * a String representation for {@code error}. 069 */ 070 String ERROR = "error"; //$NON-NLS-1$ 071 072 /** 073 * a String representation of {@code false}. 074 */ 075 String FALSE = "false"; //$NON-NLS-1$ 076 077 /** 078 * The format of a field attribute name. 079 */ 080 String FIELD_ATTRIBUTE_PFX = "pack.field.attribute."; //$NON-NLS-1$ 081 082 /** 083 * The String representation for {@code keep}. 084 */ 085 String KEEP = "keep"; //$NON-NLS-1$ 086 087 /** 088 * Decide if all elements shall transmit in their original order. 089 */ 090 String KEEP_FILE_ORDER = "pack.keep.file.order"; //$NON-NLS-1$ 091 092 /** 093 * The String representation for {@code latest}. 094 */ 095 String LATEST = "latest"; //$NON-NLS-1$ 096 097 /** 098 * The format of a method attribute name. 099 */ 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}