• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2003,2010, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package java.util.jar;
26 
27 import java.util.SortedMap;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.io.File;
31 import java.io.IOException;
32 import java.beans.PropertyChangeListener;
33 
34 
35 
36 
37 /**
38  * Transforms a JAR file to or from a packed stream in Pack200 format.
39  * Please refer to Network Transfer Format JSR 200 Specification at
40  * <a href=http://jcp.org/aboutJava/communityprocess/review/jsr200/index.html>http://jcp.org/aboutJava/communityprocess/review/jsr200/index.html</a>
41  * <p>
42  * Typically the packer engine is used by application developers
43  * to deploy or host JAR files on a website.
44  * The unpacker  engine is used by deployment applications to
45  * transform the byte-stream back to JAR format.
46  * <p>
47  * Here is an example using  packer and unpacker:<p>
48  * <blockquote><pre>
49  *    import java.util.jar.Pack200;
50  *    import java.util.jar.Pack200.*;
51  *    ...
52  *    // Create the Packer object
53  *    Packer packer = Pack200.newPacker();
54  *
55  *    // Initialize the state by setting the desired properties
56  *    Map p = packer.properties();
57  *    // take more time choosing codings for better compression
58  *    p.put(Packer.EFFORT, "7");  // default is "5"
59  *    // use largest-possible archive segments (>10% better compression).
60  *    p.put(Packer.SEGMENT_LIMIT, "-1");
61  *    // reorder files for better compression.
62  *    p.put(Packer.KEEP_FILE_ORDER, Packer.FALSE);
63  *    // smear modification times to a single value.
64  *    p.put(Packer.MODIFICATION_TIME, Packer.LATEST);
65  *    // ignore all JAR deflation requests,
66  *    // transmitting a single request to use "store" mode.
67  *    p.put(Packer.DEFLATE_HINT, Packer.FALSE);
68  *    // discard debug attributes
69  *    p.put(Packer.CODE_ATTRIBUTE_PFX+"LineNumberTable", Packer.STRIP);
70  *    // throw an error if an attribute is unrecognized
71  *    p.put(Packer.UNKNOWN_ATTRIBUTE, Packer.ERROR);
72  *    // pass one class file uncompressed:
73  *    p.put(Packer.PASS_FILE_PFX+0, "mutants/Rogue.class");
74  *    try {
75  *        JarFile jarFile = new JarFile("/tmp/testref.jar");
76  *        FileOutputStream fos = new FileOutputStream("/tmp/test.pack");
77  *        // Call the packer
78  *        packer.pack(jarFile, fos);
79  *        jarFile.close();
80  *        fos.close();
81  *
82  *        File f = new File("/tmp/test.pack");
83  *        FileOutputStream fostream = new FileOutputStream("/tmp/test.jar");
84  *        JarOutputStream jostream = new JarOutputStream(fostream);
85  *        Unpacker unpacker = Pack200.newUnpacker();
86  *        // Call the unpacker
87  *        unpacker.unpack(f, jostream);
88  *        // Must explicitly close the output.
89  *        jostream.close();
90  *    } catch (IOException ioe) {
91  *        ioe.printStackTrace();
92  *    }
93  * </pre></blockquote>
94  * <p>
95  * A Pack200 file compressed with gzip can be hosted on HTTP/1.1 web servers.
96  * The deployment applications can use "Accept-Encoding=pack200-gzip". This
97  * indicates to the server that the client application desires a version of
98  * the file encoded with Pack200 and further compressed with gzip. Please
99  * refer to  <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/deployment/deployment-guide/pack200.html">Java Deployment Guide</a> for more details and
100  * techniques.
101  * <p>
102  * Unless otherwise noted, passing a <tt>null</tt> argument to a constructor or
103  * method in this class will cause a {@link NullPointerException} to be thrown.
104  *
105  * @author John Rose
106  * @author Kumar Srinivasan
107  * @since 1.5
108  */
109 public abstract class Pack200 {
Pack200()110     private Pack200() {} //prevent instantiation
111 
112     // Static methods of the Pack200 class.
113     /**
114      * Obtain new instance of a class that implements Packer.
115      *
116      * <li><p>If the system property <tt>java.util.jar.Pack200.Packer</tt>
117      * is defined, then the value is taken to be the fully-qualified name
118      * of a concrete implementation class, which must implement Packer.
119      * This class is loaded and instantiated.  If this process fails
120      * then an unspecified error is thrown.</p></li>
121      *
122      * <li><p>If an implementation has not been specified with the system
123      * property, then the system-default implementation class is instantiated,
124      * and the result is returned.</p></li>
125      *
126      * <p>Note:  The returned object is not guaranteed to operate
127      * correctly if multiple threads use it at the same time.
128      * A multi-threaded application should either allocate multiple
129      * packer engines, or else serialize use of one engine with a lock.
130      *
131      * @return  A newly allocated Packer engine.
132      */
newPacker()133     public synchronized static Packer newPacker() {
134         return (Packer) newInstance(PACK_PROVIDER);
135     }
136 
137 
138     /**
139      * Obtain new instance of a class that implements Unpacker.
140      *
141      * <li><p>If the system property <tt>java.util.jar.Pack200.Unpacker</tt>
142      * is defined, then the value is taken to be the fully-qualified
143      * name of a concrete implementation class, which must implement Unpacker.
144      * The class is loaded and instantiated.  If this process fails
145      * then an unspecified error is thrown.</p></li>
146      *
147      * <li><p>If an implementation has not been specified with the
148      * system property, then the system-default implementation class
149      * is instantiated, and the result is returned.</p></li>
150      *
151      * <p>Note:  The returned object is not guaranteed to operate
152      * correctly if multiple threads use it at the same time.
153      * A multi-threaded application should either allocate multiple
154      * unpacker engines, or else serialize use of one engine with a lock.
155      *
156      * @return  A newly allocated Unpacker engine.
157      */
158 
newUnpacker()159     public static Unpacker newUnpacker() {
160         return (Unpacker) newInstance(UNPACK_PROVIDER);
161     }
162 
163     // Interfaces
164     /**
165      * The packer engine applies various transformations to the input JAR file,
166      * making the pack stream highly compressible by a compressor such as
167      * gzip or zip. An instance of the engine can be obtained
168      * using {@link #newPacker}.
169 
170      * The high degree of compression is achieved
171      * by using a number of techniques described in the JSR 200 specification.
172      * Some of the techniques are sorting, re-ordering and co-location of the
173      * constant pool.
174      * <p>
175      * The pack engine is initialized to an initial state as described
176      * by their properties below.
177      * The initial state can be manipulated by getting the
178      * engine properties (using {@link #properties}) and storing
179      * the modified properties on the map.
180      * The resource files will be passed through with no changes at all.
181      * The class files will not contain identical bytes, since the unpacker
182      * is free to change minor class file features such as constant pool order.
183      * However, the class files will be semantically identical,
184      * as specified in
185      * <cite>The Java&trade; Virtual Machine Specification</cite>.
186      * <p>
187      * By default, the packer does not change the order of JAR elements.
188      * Also, the modification time and deflation hint of each
189      * JAR element is passed unchanged.
190      * (Any other ZIP-archive information, such as extra attributes
191      * giving Unix file permissions, are lost.)
192      * <p>
193      * Note that packing and unpacking a JAR will in general alter the
194      * bytewise contents of classfiles in the JAR.  This means that packing
195      * and unpacking will in general invalidate any digital signatures
196      * which rely on bytewise images of JAR elements.  In order both to sign
197      * and to pack a JAR, you must first pack and unpack the JAR to
198      * "normalize" it, then compute signatures on the unpacked JAR elements,
199      * and finally repack the signed JAR.
200      * Both packing steps should
201      * use precisely the same options, and the segment limit may also
202      * need to be set to "-1", to prevent accidental variation of segment
203      * boundaries as class file sizes change slightly.
204      * <p>
205      * (Here's why this works:  Any reordering the packer does
206      * of any classfile structures is idempotent, so the second packing
207      * does not change the orderings produced by the first packing.
208      * Also, the unpacker is guaranteed by the JSR 200 specification
209      * to produce a specific bytewise image for any given transmission
210      * ordering of archive elements.)
211      * <p>
212      * In order to maintain backward compatibility, the pack file's version is
213      * set to accommodate the class files present in the input JAR file. In
214      * other words, the pack file version will be the latest, if the class files
215      * are the latest and conversely the pack file version will be the oldest
216      * if the class file versions are also the oldest. For intermediate class
217      * file versions the corresponding pack file version will be used.
218      * For example:
219      *    If the input JAR-files are solely comprised of 1.5  (or  lesser)
220      * class files, a 1.5 compatible pack file is  produced. This will also be
221      * the case for archives that have no class files.
222      *    If the input JAR-files contains a 1.6 class file, then the pack file
223      * version will be set to 1.6.
224      * <p>
225      * Note: Unless otherwise noted, passing a <tt>null</tt> argument to a
226      * constructor or method in this class will cause a {@link NullPointerException}
227      * to be thrown.
228      * <p>
229      * @since 1.5
230      */
231     public interface Packer {
232         /**
233          * This property is a numeral giving the estimated target size N
234          * (in bytes) of each archive segment.
235          * If a single input file requires more than N bytes,
236          * it will be given its own archive segment.
237          * <p>
238          * As a special case, a value of -1 will produce a single large
239          * segment with all input files, while a value of 0 will
240          * produce one segment for each class.
241          * Larger archive segments result in less fragmentation and
242          * better compression, but processing them requires more memory.
243          * <p>
244          * The size of each segment is estimated by counting the size of each
245          * input file to be transmitted in the segment, along with the size
246          * of its name and other transmitted properties.
247          * <p>
248          * The default is -1, which means the packer will always create a single
249          * segment output file. In cases where extremely large output files are
250          * generated, users are strongly encouraged to use segmenting or break
251          * up the input file into smaller JARs.
252          * <p>
253          * A 10Mb JAR packed without this limit will
254          * typically pack about 10% smaller, but the packer may require
255          * a larger Java heap (about ten times the segment limit).
256          */
257         String SEGMENT_LIMIT    = "pack.segment.limit";
258 
259         /**
260          * If this property is set to {@link #TRUE}, the packer will transmit
261          * all elements in their original order within the source archive.
262          * <p>
263          * If it is set to {@link #FALSE}, the packer may reorder elements,
264          * and also remove JAR directory entries, which carry no useful
265          * information for Java applications.
266          * (Typically this enables better compression.)
267          * <p>
268          * The default is {@link #TRUE}, which preserves the input information,
269          * but may cause the transmitted archive to be larger than necessary.
270          */
271         String KEEP_FILE_ORDER = "pack.keep.file.order";
272 
273 
274         /**
275          * If this property is set to a single decimal digit, the packer will
276          * use the indicated amount of effort in compressing the archive.
277          * Level 1 may produce somewhat larger size and faster compression speed,
278          * while level 9 will take much longer but may produce better compression.
279          * <p>
280          * The special value 0 instructs the packer to copy through the
281          * original JAR file directly, with no compression.  The JSR 200
282          * standard requires any unpacker to understand this special case
283          * as a pass-through of the entire archive.
284          * <p>
285          * The default is 5, investing a modest amount of time to
286          * produce reasonable compression.
287          */
288         String EFFORT           = "pack.effort";
289 
290         /**
291          * If this property is set to {@link #TRUE} or {@link #FALSE}, the packer
292          * will set the deflation hint accordingly in the output archive, and
293          * will not transmit the individual deflation hints of archive elements.
294          * <p>
295          * If this property is set to the special string {@link #KEEP}, the packer
296          * will attempt to determine an independent deflation hint for each
297          * available element of the input archive, and transmit this hint separately.
298          * <p>
299          * The default is {@link #KEEP}, which preserves the input information,
300          * but may cause the transmitted archive to be larger than necessary.
301          * <p>
302          * It is up to the unpacker implementation
303          * to take action upon the hint to suitably compress the elements of
304          * the resulting unpacked jar.
305          * <p>
306          * The deflation hint of a ZIP or JAR element indicates
307          * whether the element was deflated or stored directly.
308          */
309         String DEFLATE_HINT     = "pack.deflate.hint";
310 
311         /**
312          * If this property is set to the special string {@link #LATEST},
313          * the packer will attempt to determine the latest modification time,
314          * among all the available entries in the original archive or the latest
315          * modification time of all the available entries in each segment.
316          * This single value will be transmitted as part of the segment and applied
317          * to all the entries in each segment, {@link #SEGMENT_LIMIT}.
318          * <p>
319          * This can marginally decrease the transmitted size of the
320          * archive, at the expense of setting all installed files to a single
321          * date.
322          * <p>
323          * If this property is set to the special string {@link #KEEP},
324          * the packer transmits a separate modification time for each input
325          * element.
326          * <p>
327          * The default is {@link #KEEP}, which preserves the input information,
328          * but may cause the transmitted archive to be larger than necessary.
329          * <p>
330          * It is up to the unpacker implementation to take action to suitably
331          * set the modification time of each element of its output file.
332          * @see #SEGMENT_LIMIT
333          */
334         String MODIFICATION_TIME        = "pack.modification.time";
335 
336         /**
337          * Indicates that a file should be passed through bytewise, with no
338          * compression.  Multiple files may be specified by specifying
339          * additional properties with distinct strings appended, to
340          * make a family of properties with the common prefix.
341          * <p>
342          * There is no pathname transformation, except
343          * that the system file separator is replaced by the JAR file
344          * separator '/'.
345          * <p>
346          * The resulting file names must match exactly as strings with their
347          * occurrences in the JAR file.
348          * <p>
349          * If a property value is a directory name, all files under that
350          * directory will be passed also.
351          * <p>
352          * Examples:
353          * <pre><code>
354          *     Map p = packer.properties();
355          *     p.put(PASS_FILE_PFX+0, "mutants/Rogue.class");
356          *     p.put(PASS_FILE_PFX+1, "mutants/Wolverine.class");
357          *     p.put(PASS_FILE_PFX+2, "mutants/Storm.class");
358          *     # Pass all files in an entire directory hierarchy:
359          *     p.put(PASS_FILE_PFX+3, "police/");
360          * </pre></code>.
361          */
362         String PASS_FILE_PFX            = "pack.pass.file.";
363 
364         /// Attribute control.
365 
366         /**
367          * Indicates the action to take when a class-file containing an unknown
368          * attribute is encountered.  Possible values are the strings {@link #ERROR},
369          * {@link #STRIP}, and {@link #PASS}.
370          * <p>
371          * The string {@link #ERROR} means that the pack operation
372          * as a whole will fail, with an exception of type <code>IOException</code>.
373          * The string
374          * {@link #STRIP} means that the attribute will be dropped.
375          * The string
376          * {@link #PASS} means that the whole class-file will be passed through
377          * (as if it were a resource file) without compression, with  a suitable warning.
378          * This is the default value for this property.
379          * <p>
380          * Examples:
381          * <pre><code>
382          *     Map p = pack200.getProperties();
383          *     p.put(UNKNOWN_ATTRIBUTE, ERROR);
384          *     p.put(UNKNOWN_ATTRIBUTE, STRIP);
385          *     p.put(UNKNOWN_ATTRIBUTE, PASS);
386          * </pre></code>
387          */
388         String UNKNOWN_ATTRIBUTE        = "pack.unknown.attribute";
389 
390         /**
391          * When concatenated with a class attribute name,
392          * indicates the format of that attribute,
393          * using the layout language specified in the JSR 200 specification.
394          * <p>
395          * For example, the effect of this option is built in:
396          * <code>pack.class.attribute.SourceFile=RUH</code>.
397          * <p>
398          * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS} are
399          * also allowed, with the same meaning as {@link #UNKNOWN_ATTRIBUTE}.
400          * This provides a way for users to request that specific attributes be
401          * refused, stripped, or passed bitwise (with no class compression).
402          * <p>
403          * Code like this might be used to support attributes for JCOV:
404          * <pre><code>
405          *     Map p = packer.properties();
406          *     p.put(CODE_ATTRIBUTE_PFX+"CoverageTable",       "NH[PHHII]");
407          *     p.put(CODE_ATTRIBUTE_PFX+"CharacterRangeTable", "NH[PHPOHIIH]");
408          *     p.put(CLASS_ATTRIBUTE_PFX+"SourceID",           "RUH");
409          *     p.put(CLASS_ATTRIBUTE_PFX+"CompilationID",      "RUH");
410          * </code></pre>
411          * <p>
412          * Code like this might be used to strip debugging attributes:
413          * <pre><code>
414          *     Map p = packer.properties();
415          *     p.put(CODE_ATTRIBUTE_PFX+"LineNumberTable",    STRIP);
416          *     p.put(CODE_ATTRIBUTE_PFX+"LocalVariableTable", STRIP);
417          *     p.put(CLASS_ATTRIBUTE_PFX+"SourceFile",        STRIP);
418          * </code></pre>
419          */
420         String CLASS_ATTRIBUTE_PFX      = "pack.class.attribute.";
421 
422         /**
423          * When concatenated with a field attribute name,
424          * indicates the format of that attribute.
425          * For example, the effect of this option is built in:
426          * <code>pack.field.attribute.Deprecated=</code>.
427          * The special strings {@link #ERROR}, {@link #STRIP}, and
428          * {@link #PASS} are also allowed.
429          * @see #CLASS_ATTRIBUTE_PFX
430          */
431         String FIELD_ATTRIBUTE_PFX      = "pack.field.attribute.";
432 
433         /**
434          * When concatenated with a method attribute name,
435          * indicates the format of that attribute.
436          * For example, the effect of this option is built in:
437          * <code>pack.method.attribute.Exceptions=NH[RCH]</code>.
438          * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS}
439          * are also allowed.
440          * @see #CLASS_ATTRIBUTE_PFX
441          */
442         String METHOD_ATTRIBUTE_PFX     = "pack.method.attribute.";
443 
444         /**
445          * When concatenated with a code attribute name,
446          * indicates the format of that attribute.
447          * For example, the effect of this option is built in:
448          * <code>pack.code.attribute.LocalVariableTable=NH[PHOHRUHRSHH]</code>.
449          * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS}
450          * are also allowed.
451          * @see #CLASS_ATTRIBUTE_PFX
452          */
453         String CODE_ATTRIBUTE_PFX       = "pack.code.attribute.";
454 
455         /**
456          * The unpacker's progress as a percentage, as periodically
457          * updated by the unpacker.
458          * Values of 0 - 100 are normal, and -1 indicates a stall.
459          * Observe this property with a {@link PropertyChangeListener}.
460          * <p>
461          * At a minimum, the unpacker must set progress to 0
462          * at the beginning of a packing operation, and to 100
463          * at the end.
464          * @see  #addPropertyChangeListener
465          */
466         String PROGRESS                 = "pack.progress";
467 
468         /** The string "keep", a possible value for certain properties.
469          * @see #DEFLATE_HINT
470          * @see #MODIFICATION_TIME
471          */
472         String KEEP  = "keep";
473 
474         /** The string "pass", a possible value for certain properties.
475          * @see #UNKNOWN_ATTRIBUTE
476          * @see #CLASS_ATTRIBUTE_PFX
477          * @see #FIELD_ATTRIBUTE_PFX
478          * @see #METHOD_ATTRIBUTE_PFX
479          * @see #CODE_ATTRIBUTE_PFX
480          */
481         String PASS  = "pass";
482 
483         /** The string "strip", a possible value for certain properties.
484          * @see #UNKNOWN_ATTRIBUTE
485          * @see #CLASS_ATTRIBUTE_PFX
486          * @see #FIELD_ATTRIBUTE_PFX
487          * @see #METHOD_ATTRIBUTE_PFX
488          * @see #CODE_ATTRIBUTE_PFX
489          */
490         String STRIP = "strip";
491 
492         /** The string "error", a possible value for certain properties.
493          * @see #UNKNOWN_ATTRIBUTE
494          * @see #CLASS_ATTRIBUTE_PFX
495          * @see #FIELD_ATTRIBUTE_PFX
496          * @see #METHOD_ATTRIBUTE_PFX
497          * @see #CODE_ATTRIBUTE_PFX
498          */
499         String ERROR = "error";
500 
501         /** The string "true", a possible value for certain properties.
502          * @see #KEEP_FILE_ORDER
503          * @see #DEFLATE_HINT
504          */
505         String TRUE = "true";
506 
507         /** The string "false", a possible value for certain properties.
508          * @see #KEEP_FILE_ORDER
509          * @see #DEFLATE_HINT
510          */
511         String FALSE = "false";
512 
513         /** The string "latest", a possible value for certain properties.
514          * @see #MODIFICATION_TIME
515          */
516         String LATEST = "latest";
517 
518         /**
519          * Get the set of this engine's properties.
520          * This set is a "live view", so that changing its
521          * contents immediately affects the Packer engine, and
522          * changes from the engine (such as progress indications)
523          * are immediately visible in the map.
524          *
525          * <p>The property map may contain pre-defined implementation
526          * specific and default properties.  Users are encouraged to
527          * read the information and fully understand the implications,
528          * before modifying pre-existing properties.
529          * <p>
530          * Implementation specific properties are prefixed with a
531          * package name associated with the implementor, beginning
532          * with <tt>com.</tt> or a similar prefix.
533          * All property names beginning with <tt>pack.</tt> and
534          * <tt>unpack.</tt> are reserved for use by this API.
535          * <p>
536          * Unknown properties may be ignored or rejected with an
537          * unspecified error, and invalid entries may cause an
538          * unspecified error to be thrown.
539          *
540          * <p>
541          * The returned map implements all optional {@link SortedMap} operations
542          * @return A sorted association of property key strings to property
543          * values.
544          */
properties()545         SortedMap<String,String> properties();
546 
547         /**
548          * Takes a JarFile and converts it into a Pack200 archive.
549          * <p>
550          * Closes its input but not its output.  (Pack200 archives are appendable.)
551          * @param in a JarFile
552          * @param out an OutputStream
553          * @exception IOException if an error is encountered.
554          */
pack(JarFile in, OutputStream out)555         void pack(JarFile in, OutputStream out) throws IOException ;
556 
557         /**
558          * Takes a JarInputStream and converts it into a Pack200 archive.
559          * <p>
560          * Closes its input but not its output.  (Pack200 archives are appendable.)
561          * <p>
562          * The modification time and deflation hint attributes are not available,
563          * for the JAR manifest file and its containing directory.
564          *
565          * @see #MODIFICATION_TIME
566          * @see #DEFLATE_HINT
567          * @param in a JarInputStream
568          * @param out an OutputStream
569          * @exception IOException if an error is encountered.
570          */
pack(JarInputStream in, OutputStream out)571         void pack(JarInputStream in, OutputStream out) throws IOException ;
572 
573         /**
574          * Registers a listener for PropertyChange events on the properties map.
575          * This is typically used by applications to update a progress bar.
576          *
577          * @see #properties
578          * @see #PROGRESS
579          * @param listener  An object to be invoked when a property is changed.
580          */
addPropertyChangeListener(PropertyChangeListener listener)581         void addPropertyChangeListener(PropertyChangeListener listener) ;
582 
583         /**
584          * Remove a listener for PropertyChange events, added by
585          * the {@link #addPropertyChangeListener}.
586          *
587          * @see #addPropertyChangeListener
588          * @param listener  The PropertyChange listener to be removed.
589          */
removePropertyChangeListener(PropertyChangeListener listener)590         void removePropertyChangeListener(PropertyChangeListener listener);
591 
592     }
593 
594     /**
595      * The unpacker engine converts the packed stream to a JAR file.
596      * An instance of the engine can be obtained
597      * using {@link #newUnpacker}.
598      * <p>
599      * Every JAR file produced by this engine will include the string
600      * "<tt>PACK200</tt>" as a zip file comment.
601      * This allows a deployer to detect if a JAR archive was packed and unpacked.
602      * <p>
603      * Note: Unless otherwise noted, passing a <tt>null</tt> argument to a
604      * constructor or method in this class will cause a {@link NullPointerException}
605      * to be thrown.
606      * <p>
607      * This version of the unpacker is compatible with all previous versions.
608      * @since 1.5
609      */
610     public interface Unpacker {
611 
612         /** The string "keep", a possible value for certain properties.
613          * @see #DEFLATE_HINT
614          */
615         String KEEP  = "keep";
616 
617         /** The string "true", a possible value for certain properties.
618          * @see #DEFLATE_HINT
619          */
620         String TRUE = "true";
621 
622         /** The string "false", a possible value for certain properties.
623          * @see #DEFLATE_HINT
624          */
625         String FALSE = "false";
626 
627         /**
628          * Property indicating that the unpacker should
629          * ignore all transmitted values for DEFLATE_HINT,
630          * replacing them by the given value, {@link #TRUE} or {@link #FALSE}.
631          * The default value is the special string {@link #KEEP},
632          * which asks the unpacker to preserve all transmitted
633          * deflation hints.
634          */
635         String DEFLATE_HINT      = "unpack.deflate.hint";
636 
637 
638 
639         /**
640          * The unpacker's progress as a percentage, as periodically
641          * updated by the unpacker.
642          * Values of 0 - 100 are normal, and -1 indicates a stall.
643          * Observe this property with a {@link PropertyChangeListener}.
644          * <p>
645          * At a minimum, the unpacker must set progress to 0
646          * at the beginning of a packing operation, and to 100
647          * at the end.
648          * @see #addPropertyChangeListener
649          */
650         String PROGRESS         = "unpack.progress";
651 
652         /**
653          * Get the set of this engine's properties. This set is
654          * a "live view", so that changing its
655          * contents immediately affects the Packer engine, and
656          * changes from the engine (such as progress indications)
657          * are immediately visible in the map.
658          *
659          * <p>The property map may contain pre-defined implementation
660          * specific and default properties.  Users are encouraged to
661          * read the information and fully understand the implications,
662          * before modifying pre-existing properties.
663          * <p>
664          * Implementation specific properties are prefixed with a
665          * package name associated with the implementor, beginning
666          * with <tt>com.</tt> or a similar prefix.
667          * All property names beginning with <tt>pack.</tt> and
668          * <tt>unpack.</tt> are reserved for use by this API.
669          * <p>
670          * Unknown properties may be ignored or rejected with an
671          * unspecified error, and invalid entries may cause an
672          * unspecified error to be thrown.
673          *
674          * @return A sorted association of option key strings to option values.
675          */
properties()676         SortedMap<String,String> properties();
677 
678         /**
679          * Read a Pack200 archive, and write the encoded JAR to
680          * a JarOutputStream.
681          * The entire contents of the input stream will be read.
682          * It may be more efficient to read the Pack200 archive
683          * to a file and pass the File object, using the alternate
684          * method described below.
685          * <p>
686          * Closes its input but not its output.  (The output can accumulate more elements.)
687          * @param in an InputStream.
688          * @param out a JarOutputStream.
689          * @exception IOException if an error is encountered.
690          */
unpack(InputStream in, JarOutputStream out)691         void unpack(InputStream in, JarOutputStream out) throws IOException;
692 
693         /**
694          * Read a Pack200 archive, and write the encoded JAR to
695          * a JarOutputStream.
696          * <p>
697          * Does not close its output.  (The output can accumulate more elements.)
698          * @param in a File.
699          * @param out a JarOutputStream.
700          * @exception IOException if an error is encountered.
701          */
unpack(File in, JarOutputStream out)702         void unpack(File in, JarOutputStream out) throws IOException;
703 
704         /**
705          * Registers a listener for PropertyChange events on the properties map.
706          * This is typically used by applications to update a progress bar.
707          *
708          * @see #properties
709          * @see #PROGRESS
710          * @param listener  An object to be invoked when a property is changed.
711          */
addPropertyChangeListener(PropertyChangeListener listener)712         void addPropertyChangeListener(PropertyChangeListener listener) ;
713 
714         /**
715          * Remove a listener for PropertyChange events, added by
716          * the {@link #addPropertyChangeListener}.
717          *
718          * @see #addPropertyChangeListener
719          * @param listener  The PropertyChange listener to be removed.
720          */
removePropertyChangeListener(PropertyChangeListener listener)721         void removePropertyChangeListener(PropertyChangeListener listener);
722     }
723 
724     // Private stuff....
725 
726     private static final String PACK_PROVIDER = "java.util.jar.Pack200.Packer";
727     private static final String UNPACK_PROVIDER = "java.util.jar.Pack200.Unpacker";
728 
729     private static Class packerImpl;
730     private static Class unpackerImpl;
731 
newInstance(String prop)732     private synchronized static Object newInstance(String prop) {
733         String implName = "(unknown)";
734         try {
735             Class impl = (PACK_PROVIDER.equals(prop))? packerImpl: unpackerImpl;
736             if (impl == null) {
737                 // The first time, we must decide which class to use.
738                 implName = java.security.AccessController.doPrivileged(
739                     new sun.security.action.GetPropertyAction(prop,""));
740                 if (implName != null && !implName.equals(""))
741                     impl = Class.forName(implName);
742                 // Android changed : Remove default Packer Impl.
743                 //
744                 // else if (PACK_PROVIDER.equals(prop))
745                 //     impl = com.sun.java.util.jar.pack.PackerImpl.class;
746                 // else
747                 //    impl = com.sun.java.util.jar.pack.UnpackerImpl.class;
748             }
749             // We have a class.  Now instantiate it.
750             return impl.newInstance();
751         } catch (ClassNotFoundException e) {
752             throw new Error("Class not found: " + implName +
753                                 ":\ncheck property " + prop +
754                                 " in your properties file.", e);
755         } catch (InstantiationException e) {
756             throw new Error("Could not instantiate: " + implName +
757                                 ":\ncheck property " + prop +
758                                 " in your properties file.", e);
759         } catch (IllegalAccessException e) {
760             throw new Error("Cannot access class: " + implName +
761                                 ":\ncheck property " + prop +
762                                 " in your properties file.", e);
763         }
764     }
765 
766 }
767