KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > javaguard > GuardDB


1 /**
2  * JavaGuard -- an obfuscation package for Java classfiles.
3  *
4  * Copyright (c) 1999 Mark Welsh (markw@retrologic.com)
5  * Copyright (c) 2002 Thorsten Heit (theit@gmx.de)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  * The author may be contacted at theit@gmx.de.
22  *
23  *
24  * $Id: GuardDB.java,v 1.19 2002/06/04 10:01:05 glurk Exp $
25  */

26 package net.sf.javaguard;
27
28
29 import java.io.*;
30 import java.util.*;
31 import java.util.jar.*;
32 import java.security.DigestOutputStream JavaDoc;
33 import java.security.MessageDigest JavaDoc;
34 import java.security.NoSuchAlgorithmException JavaDoc;
35 import net.sf.javaguard.classfile.*;
36 import net.sf.javaguard.log.*;
37
38 import org.apache.oro.text.MalformedCachePatternException;
39 import org.apache.oro.text.regex.MalformedPatternException;
40
41
42 /** Classfile database for obfuscation.
43  *
44  * @author <a HREF="mailto:theit@gmx.de">Thorsten Heit</a>
45  * @author <a HREF="mailto:markw@retrologic.com">Mark Welsh</a>
46  */

47 public class GuardDB implements ClassConstants {
48   /** The file name of the manifest file. */
49   private static final String JavaDoc STREAM_NAME_MANIFEST = "META-INF/MANIFEST.MF";
50   /** Signature directory name. */
51   private static final String JavaDoc SIGNATURE_PREFIX = "META-INF/";
52   /** Signature file name extension. */
53   private static final String JavaDoc SIGNATURE_EXT = ".SF";
54   
55   
56   /** Holds a list of input Jar files to obfuscate. */
57   private Vector inputJars = null;
58   /** Holds a list of input directories with files to obfuscate. The vector
59    * must have exact the same number of elements as the {@link #inputFileFilters}
60    * vector.
61    */

62   private Vector inputDirs = null;
63   /** Holds a list of file filter expressions for the input directories. The
64    * vector must have exact the same number of elements as the {@link #inputDirs}
65    * vector.
66    */

67   private Vector inputFileFilters = null;
68   /** Holds a list of output containers that each manage the output name of
69    * the obfuscated Jar file and the file containers that are used as input for
70    * the obfuscator.
71    */

72   private Vector outputContainers = null;
73   /** Holds the output file. */
74   private File outputFile;
75   /** Holds the tree of packages, classes, methods and fields. */
76   private ClassTree classTree = null;
77   /** Holds script file to use for the obfuscation. */
78   private ScriptFile scriptFile;
79   /** Holds the package, class, method and field mapping entries from the
80    * script file. */

81   private Vector mappings = null;
82   
83   /** Holds the log file to use. */
84   private FileLogger logfile;
85   /** Holds the system logger. */
86   private ScreenLogger logger;
87   
88   
89   
90   
91   /** Default constructor. Builds a classfile database for obfuscation.
92    */

93   public GuardDB() {
94     logfile = FileLogger.getInstance();
95     logger = ScreenLogger.getInstance();
96     setScriptFile(null);
97   }
98   
99   
100   
101   
102   /** Stores the script file to use for the obfuscation.
103    * @param scriptFile the script file to use for the obfuscation
104    */

105   public void setScriptFile(ScriptFile scriptFile) {
106     this.scriptFile = scriptFile;
107   }
108   
109   
110   /** Returns the script file to use for the obfuscation.
111    * @return script file; may be null
112    * @see #setScriptFile
113    */

114   private ScriptFile getScriptFile() {
115     return scriptFile;
116   }
117   
118   
119   
120   
121   /** Sets the list of input Jar files and directories files to obfuscate.
122    * @param jars a vector that holds the list of input Jar files to obfuscate
123    * @param dirs a vector that holds a list of input directories; must have the
124    * same size number of elements as the file filter vector
125    * @param filters a vector that holds a list of file filter expressions; must
126    * have the same number of elements as the directories vector
127    * @throws IllegalArgumentException if the directory and file filter vectors
128    * don't have the same size
129    */

130   public void setInput(Vector jars, Vector dirs, Vector filters)
131   throws IllegalArgumentException JavaDoc {
132     inputJars = jars;
133     if ( (null==dirs && null!=filters) || (null!=dirs && null==filters)
134       || (null!=dirs && null!=filters && dirs.size()!=filters.size())) {
135       throw new IllegalArgumentException JavaDoc("Directory and file filter vectors must have the same size");
136     }
137     inputDirs = dirs;
138     inputFileFilters = filters;
139   }
140   
141   
142   
143   
144   /** Returns the list of input Jar files to obfuscate.
145    * @return list of input Jar files; always a valid vector (may be empty)
146    * @see #setInput
147    */

148   private Vector getInputJars() {
149     if (null == inputJars) {
150       inputJars = new Vector();
151     }
152     return inputJars;
153   }
154   
155   
156   /** Returns the list of input directories that contain files to obfuscate.
157    * @return list of directories; always a valid vector (may be empty)
158    * @see #setInput
159    */

160   private Vector getInputDirs() {
161     if (null == inputDirs) {
162       inputDirs = new Vector();
163     }
164     return inputDirs;
165   }
166   
167   
168   /** Returns the list of file filter expressions for the input directories.
169    * @return list of file filter expressions; always a valid vector (may be
170    * empty)
171    * @see #setInput
172    */

173   private Vector getInputFileFilters() {
174     if (null == inputFileFilters) {
175       inputFileFilters = new Vector();
176     }
177     return inputFileFilters;
178   }
179   
180   
181   
182   
183   /** Sets the output Jar file.
184    * @param file the output Jar file; must not be null
185    */

186   public void setOutputFile(File file) {
187     outputFile = file;
188   }
189   
190   
191   /** Returns the output Jar file.
192    * @return output Jar file; may be null
193    * @see #setOutputFile
194    */

195   private File getOutputFile() {
196     return outputFile;
197   }
198   
199   
200   
201   
202   /** Reads all class files from the Jar files and the local directories and
203    * builds the classfile database.
204    * @param dump true if the parsed class tree should be dumped to the console
205    * before it is obfuscated; false else
206    * @throws IOException if an I/O error occurs
207    * @throws MalformedPatternException if an error occurs during the compilation
208    * of regular expressions
209    */

210   public void obfuscate(boolean dump)
211   throws IOException, MalformedPatternException {
212     logger.log("Building the file containers...");
213     
214     // first create the output container
215
OutputContainer oc = new OutputContainer(getOutputFile());
216     
217     // add the file containers for all Jar files
218
Vector jars = getInputJars();
219     for (int i=0; i<jars.size(); i++) {
220       FileContainer fc = new JarFileContainer( new JarFile( (File) jars.elementAt(i)) );
221       oc.addFileContainer(fc);
222     }
223     
224     // add the file containers for all local directories
225
Vector dirs = getInputDirs();
226     Vector fileFilters = getInputFileFilters();
227     for (int i=0; i<dirs.size(); i++) {
228       FileContainer fc = new LocalDirectoryFileContainer((File) dirs.elementAt(i), (String JavaDoc) fileFilters.elementAt(i));
229       oc.addFileContainer(fc);
230     }
231     
232     // walk through all file sets and remove duplicate entries
233
Vector vec = oc.getFileContainers();
234     for (int i=0; i<vec.size(); i++) {
235       FileContainer fc = (FileContainer) vec.elementAt(i);
236       for (int j=i+1; j<vec.size(); j++) {
237         FileContainer other = (FileContainer) vec.elementAt(j);
238         other.removeDuplicates(fc);
239       }
240     }
241     
242     addOutputContainer(oc);
243     startObfuscate(getOutputContainers(), dump);
244   }
245   
246   
247   
248   
249   /** Starts the obfuscation process for the given list of output containers.
250    * @param vec a vector that holds output containers; may not be null
251    * @param dump true if the parsed class tree should be dumped to the console
252    * before it is obfuscated; false else
253    * @throws IOException if an I/O error occurs
254    * @throws MalformedPatternException if an error occurs during the compilation
255    * of regular expressions
256    */

257   private void startObfuscate(Vector vec, boolean dump)
258   throws IOException, MalformedPatternException {
259     // obfuscate each output container
260
Iterator iter = vec.iterator();
261     while (iter.hasNext()) {
262       // first build a new class tree
263
ClassTree classTree = new ClassTree();
264       ClassFile.resetDangerHeader();
265       parseScriptFile(classTree);
266       
267       OutputContainer oc = (OutputContainer) iter.next();
268       // add all classes from the file containers to the class tree
269
Vector fileContainers = oc.getFileContainers();
270       logger.log("Building the class tree...");
271       for (int j=0; j<fileContainers.size(); j++) {
272         FileContainer fc = (FileContainer) fileContainers.elementAt(j);
273         logger.log(Log.INFO, "Reading the contents from '" + fc.getName() + "'");
274         addClasses(classTree, fc, dump);
275       }
276       
277       // write out a log header
278
writeLogHeader(getOutputFile().getName(), fileContainers);
279       // generate the mapping table for the class tree
280
generateMappingTable(classTree);
281       // log the mapping table to the log file
282
writeMappingTable(classTree);
283       
284       // create the output stream for the obfuscated Jar file
285
JarOutputStream jos = new JarOutputStream(new BufferedOutputStream(
286       new FileOutputStream(oc.getOutputFile())));
287       jos.setComment(Version.getJarComment());
288       
289       // obfuscate all entries in the file containers
290
for (int j=0; j<fileContainers.size(); j++) {
291         FileContainer fc = (FileContainer) fileContainers.elementAt(j);
292         obfuscateFiles(jos, classTree, fc, oc.getManifestContainer());
293       }
294       
295       // Finally, write the new manifest file
296
JarEntry outEntry = new JarEntry(STREAM_NAME_MANIFEST);
297       jos.putNextEntry(outEntry);
298       DataOutputStream manifest = new DataOutputStream(new BufferedOutputStream(jos));
299       oc.getManifestContainer().write(manifest);
300       jos.closeEntry();
301       
302       // finally close the output Jar file
303
jos.close();
304       
305       // finally print warnings
306
logfile.printMethodWarnings();
307       logfile.printWarnings();
308     }
309   }
310   
311   
312   
313   
314   /** Go through database marking certain entities for retention, while
315    * maintaining polymorphic integrity.
316    * @param classTree the class tree to which the script file entries are
317    * applied
318    * @throws MalformedPatternException if an error occurs during the compilation
319    * of regular expressions
320    * @throws IllegalArgumentException if a script entry contains an illegal type
321    */

322   public void parseScriptFile(ClassTree classTree)
323   throws MalformedPatternException, IllegalArgumentException JavaDoc {
324     if (null != getScriptFile()) {
325       Iterator iterator = getScriptFile().iterator();
326       // Enumerate the entries in the script file
327
while (iterator.hasNext()) {
328         ScriptEntry entry = (ScriptEntry) iterator.next();
329         
330         switch (entry.getType()) {
331           case ScriptConstants.TYPE_ATTRIBUTE:
332           case ScriptConstants.TYPE_RENAME:
333           case ScriptConstants.TYPE_PRESERVE:
334             classTree.retainAttribute(entry);
335             break;
336             
337           case ScriptConstants.TYPE_PACKAGE:
338           case ScriptConstants.TYPE_PACKAGE_MAP:
339           case ScriptConstants.TYPE_CLASS:
340           case ScriptConstants.TYPE_CLASS_MAP:
341           case ScriptConstants.TYPE_METHOD:
342           case ScriptConstants.TYPE_METHOD_MAP:
343           case ScriptConstants.TYPE_FIELD:
344           case ScriptConstants.TYPE_FIELD_MAP:
345             addMapping(entry);
346             break;
347             
348           case ScriptConstants.TYPE_IGNORE:
349             classTree.addIgnoreDefaultRegex(entry.getName());
350             break;
351             
352           case ScriptConstants.TYPE_IGNORE_PACKAGE:
353             classTree.addIgnorePackageRegex(entry.getName());
354             break;
355             
356           case ScriptConstants.TYPE_IGNORE_CLASS:
357             classTree.addIgnoreClassRegex(entry.getName());
358             break;
359             
360           case ScriptConstants.TYPE_IGNORE_METHOD:
361             classTree.addIgnoreMethodRegex(entry);
362             break;
363             
364           case ScriptConstants.TYPE_IGNORE_FIELD:
365             classTree.addIgnoreFieldRegex(entry);
366             break;
367             
368           case ScriptConstants.TYPE_OBFUSCATE:
369             classTree.addObfuscateDefaultRegex(entry.getName());
370             break;
371             
372           case ScriptConstants.TYPE_OBFUSCATE_PACKAGE:
373             classTree.addObfuscatePackageRegex(entry.getName());
374             break;
375             
376           case ScriptConstants.TYPE_OBFUSCATE_CLASS:
377             classTree.addObfuscateClassRegex(entry.getName());
378             break;
379             
380           case ScriptConstants.TYPE_OBFUSCATE_METHOD:
381             classTree.addObfuscateMethodRegex(entry);
382             break;
383             
384           case ScriptConstants.TYPE_OBFUSCATE_FIELD:
385             classTree.addObfuscateFieldRegex(entry);
386             break;
387             
388           default:
389             // should never happen because we've already parsed the script
390
throw new IllegalArgumentException JavaDoc("Illegal type in script file");
391         }
392       }
393     }
394   }
395   
396   
397   
398   
399   /** Adds the files from the given file container to the internal class
400    * database.
401    * @param classTree the class tree to which the available classes from the
402    * file container may be added
403    * @param fc the file container
404    * @param dump true if the parsed class tree should be dumped to the console
405    */

406   private void addClasses(ClassTree classTree, FileContainer fc, boolean dump) {
407     Enumeration enumeration = fc.enumeration();
408     while (enumeration.hasMoreElements()) {
409       FileEntry entry = (FileEntry) enumeration.nextElement();
410       // only add the next entry if it is a class file
411
if (entry.isClassFile()) {
412         DataInputStream dis = entry.getInputStream();
413         ClassFile cf = null;
414         try {
415           cf = ClassFile.create(classTree, dis);
416         } catch (IOException ioex) {
417           logger.println("Error: " + ioex.getMessage());
418           logger.printStackTrace(ioex);
419           logfile.println("# ERROR - corrupt class file: " + entry.getName());
420           logfile.printStackTrace(ioex);
421         } finally {
422           try {
423             dis.close();
424           } catch (IOException ioex) {
425             // ignored here
426
}
427         }
428         
429         // Check the class file for references to "dangerous" methods
430
cf.logDangerousMethods();
431         classTree.addClassFile(cf);
432         if (dump) {
433           PrintWriter pw = new PrintWriter(System.out);
434           cf.dump(pw);
435           //pw.close();
436
}
437       }
438     }
439   }
440   
441   
442   
443   
444   /** Generates the mapping table for the obfuscation step.
445    * @param classTree the class tree for which the mapping table should be
446    * generated
447    * @throws MalformedPatternException If the compiled expression does not
448    * conform to the grammar understood by the PatternCompiler or if some other
449    * error in the expression is encountered.
450    */

451   private void generateMappingTable(ClassTree classTree)
452   throws MalformedPatternException {
453     logger.log("Generating the mapping table for the whole class tree...");
454     
455     // before we generate obfuscated names we check which classes, fields etc.
456
// must be obfuscated and which should be ignored.
457
classTree.parseObfuscateAndIgnoreList();
458     
459     // now try to retain remote classes (if specified)
460
classTree.markRemoteClasses();
461     
462     // retain all marked mappings
463
classTree.retainMappings(getMappings());
464     
465     // retain additional fields, methods and classes
466
classTree.retainHardcodedReferences();
467     classTree.retainSerializableElements();
468     
469     // Traverse the class tree, generating obfuscated names within
470
// package and class namespaces
471
classTree.generateNames();
472     
473     // rename classes that need special treatment
474
classTree.retainRemoteClasses();
475     
476     // Resolve the polymorphic dependencies of each class, generating
477
// non-private method and field names for each namespace
478
classTree.resolveClasses();
479   }
480   
481   
482   
483   
484   /** Obfuscate all entries in the file container.
485    * @param jos the Jar file output stream
486    * @param classTree the class tree the file container belongs to
487    * @param fileContainer the file container that holds all input files
488    * @param manifestContainer the manifest container that manages the Manifest
489    * file
490    * @throws IOException if an I/O error occurs
491    */

492   private void obfuscateFiles(JarOutputStream jos, ClassTree classTree,
493   FileContainer fileContainer, ManifestContainer manifestContainer)
494   throws IOException {
495     logger.log(Log.INFO, "Obfuscating the entries in the file container: " + fileContainer.getName());
496     
497     // Go through the file container, remove attributes and rename the constant
498
// pool for each class file. Other files are renamed only if the user
499
// wishes to do so, but apart from this they are copied through unchanged.
500
// Manifest and signature files are deleted, and a new Manifest file is
501
// generated.
502
Enumeration enumeration = fileContainer.enumeration();
503     while (enumeration.hasMoreElements()) {
504       FileEntry entry = (FileEntry) enumeration.nextElement();
505       // Open the entry and prepare to process it
506
DataInputStream inStream = entry.getInputStream();
507       try {
508         if (entry.isClassFile()) {
509           // Write the obfuscated version of the class to the output Jar
510
ClassFile cf = ClassFile.create(classTree, inStream);
511           cf.remap(classTree);
512           logger.log(Log.DEBUG, "Reading: " + entry.getName());
513           logger.log(Log.DEBUG, " -> writing " + cf.getName() + CLASS_EXT);
514           JarEntry outEntry = new JarEntry(cf.getName() + CLASS_EXT);
515           jos.putNextEntry(outEntry);
516           
517           // Create an OutputStream piped through a number of digest generators for the manifest
518
MessageDigest JavaDoc shaDigest = MessageDigest.getInstance("SHA-1");
519           MessageDigest JavaDoc md5Digest = MessageDigest.getInstance("MD5");
520           DataOutputStream classOutputStream = new DataOutputStream(
521           new DigestOutputStream JavaDoc(
522           new BufferedOutputStream(
523           new DigestOutputStream JavaDoc(jos, shaDigest)),
524           md5Digest));
525           
526           // Dump the classfile, while creating the digests
527
cf.write(classOutputStream);
528           classOutputStream.flush();
529           jos.closeEntry();
530           
531           // Now update the manifest entry for the class with new name and new digests
532
MessageDigest JavaDoc[] digests = {shaDigest, md5Digest};
533           manifestContainer.updateManifest(entry.getName(), cf.getName() + CLASS_EXT, digests);
534         } else {
535           // Copy the non-class entry (resource file)
536
long size = entry.getSize();
537           if (size != -1) {
538             byte[] bytes = new byte[(int)size];
539             inStream.readFully(bytes);
540             String JavaDoc outName = classTree.getOutputFileName(entry.getName());
541             if (!entry.getName().equals(outName)) {
542               logfile.log(Log.VERBOSE, "# renaming resource: " + entry.getName() + " -> " + outName);
543             }
544             logger.log(Log.DEBUG, "Reading: " + entry.getName());
545             logger.log(Log.DEBUG, " -> writing " + outName);
546             JarEntry outEntry = new JarEntry(outName);
547             jos.putNextEntry(outEntry);
548             
549             // Create an OutputStream piped through a number of digest generators for the manifest
550
MessageDigest JavaDoc shaDigest = MessageDigest.getInstance("SHA");
551             MessageDigest JavaDoc md5Digest = MessageDigest.getInstance("MD5");
552             DataOutputStream dataOutputStream = new DataOutputStream(
553             new DigestOutputStream JavaDoc(
554             new BufferedOutputStream(
555             new DigestOutputStream JavaDoc(jos, shaDigest)),
556             md5Digest));
557             
558             // Dump the data, while creating the digests
559
dataOutputStream.write(bytes, 0, bytes.length);
560             dataOutputStream.flush();
561             jos.closeEntry();
562             
563             // Now update the manifest entry for the entry with new name and new digests
564
MessageDigest JavaDoc[] digests = {shaDigest, md5Digest};
565             manifestContainer.updateManifest(entry.getName(), outName, digests);
566           }
567         }
568       } catch (NoSuchAlgorithmException JavaDoc nae) {
569         logger.println("Cannot find message digest algorithm:");
570         logger.println(nae.getMessage());
571         logger.printStackTrace(nae);
572         // ignore that
573
} finally {
574         if (inStream != null) {
575           inStream.close();
576         }
577       }
578     }
579   }
580   
581   
582   
583   
584   /** Writes a header out to the log file.
585    * @param outName the name of the output Jar file
586    * @param vec a vector containing the file containers used for the obfuscation
587    */

588   private void writeLogHeader(String JavaDoc outName, Vector vec) {
589     logger.log(Log.INFO, "Writing log header...");
590     logfile.println("# If this log is to be used for incremental obfuscation / patch generation, ");
591     logfile.println("# add any '.class', '.method', '.field' and '.attribute' restrictions here:");
592     logfile.println();
593     logfile.println();
594     logfile.println("#-DO-NOT-EDIT-BELOW-THIS-LINE------------------DO-NOT-EDIT-BELOW-THIS-LINE--");
595     logfile.println("#");
596     logfile.println("# JavaGuard Bytecode Obfuscator, version " + Version.getVersion());
597     logfile.println("#");
598     logfile.println("# Logfile created on " + new Date().toString());
599     logfile.println("#");
600     if (null != vec) {
601       for (int i=0; i<vec.size(); i++) {
602         FileContainer fc = (FileContainer) vec.elementAt(i);
603         logfile.println("# Input taken for obfuscation: " + fc.getName());
604       }
605     }
606     logfile.println("# Output Jar file: " + outName);
607     logfile.println("# JavaGuard script file used: "
608     + (null!=getScriptFile() ? getScriptFile().getName() : "(none, defaults used)"));
609     logfile.println("#");
610     logfile.println();
611   }
612   
613   
614   
615   
616   /** Write the obfuscation steps to the log file.
617    * @param classTree the class tree whose mapping table should be written
618    * @see ClassTree#dump
619    */

620   private void writeMappingTable(ClassTree classTree) {
621     // Write the memory usage at this point to the log file
622
Runtime JavaDoc rt = Runtime.getRuntime();
623     rt.gc();
624     logfile.println();
625     logfile.println("#");
626     logfile.println("# Memory in use after class data structure built: " + Long.toString(rt.totalMemory() - rt.freeMemory()) + " bytes");
627     logfile.println("# Total memory available : " + Long.toString(rt.totalMemory()) + " bytes");
628     logfile.println("#");
629     
630     // Write the name frequency and name mapping table to the log file
631
logfile.println();
632     classTree.dump();
633   }
634   
635   
636   
637   
638   /** Returns the vector that holds the package, class, method and field
639    * mapping entries from the script file.
640    * @return vector that contains the script file entries; always non-null
641    */

642   private Vector getMappings() {
643     if (null == mappings) {
644       mappings = new Vector();
645     }
646     return mappings;
647   }
648   
649   
650   /** Adds an element to the list of mapping entries.
651    * @param entry the entry from the script file
652    * @see #getMappings
653    */

654   private void addMapping(ScriptEntry entry) {
655     getMappings().addElement(entry);
656   }
657   
658   
659   
660   
661   /** Returns the vector that stores all output containers.
662    * @return vector with output containers; always non-null
663    * @see #addOutputContainer
664    */

665   private Vector getOutputContainers() {
666     if (null == outputContainers) {
667       outputContainers = new Vector();
668     }
669     return outputContainers;
670   }
671   
672   
673   /** Adds a new output container to the list of all available output
674    * containers.
675    * @param oc the output container to add
676    * @see #getOutputContainers
677    */

678   private void addOutputContainer(OutputContainer oc) {
679     getOutputContainers().addElement(oc);
680   }
681   
682   
683   
684   
685   /** A manager class for output containers. Each output container holds a list
686    * of file containers (that manage which input files may be put into the
687    * output file), a manifest container (that maintains the Manifest file for
688    * the output Jar file) and the assigned output file.
689    */

690   private static class OutputContainer {
691     /** A vector that stores all assigned file containes. */
692     private Vector fileContainers = new Vector();
693     /** Manages the Manifest file. */
694     private ManifestContainer manifestContainer = new ManifestContainer();
695     /** Holds the output file. */
696     private File outputFile;
697     
698     
699     /** Creates a new output container and assignes it to the given output
700      * Jar file.
701      * @param file the output Jar file
702      */

703     OutputContainer(File file) {
704       this.outputFile = file;
705     }
706     
707     
708     /** Adds a new file container to the internal list of file containers.
709      * @param fc the file container to add
710      * @see #getFileContainers
711      * @throws IOException if an I/O error occurs
712      */

713     void addFileContainer(FileContainer fc)
714     throws IOException {
715       getFileContainers().addElement(fc);
716       getManifestContainer().addManifest(fc.getManifest());
717     }
718     
719     
720     /** Returns the vector that contains all assigned file containers.
721      * @return vector with file containers
722      * @see #addFileContainer
723      */

724     Vector getFileContainers() {
725       return fileContainers;
726     }
727     
728     
729     /** Returns the manifest container assigned to this object.
730      * @return manifest container
731      */

732     ManifestContainer getManifestContainer() {
733       return manifestContainer;
734     }
735     
736     
737     /** Returns the output file assigned to this object.
738      * @return the output file assigned to this object
739      */

740     File getOutputFile() {
741       return outputFile;
742     }
743   }
744 }
745
Popular Tags