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