KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > izforge > izpack > compiler > MultiVolumePackager


1 /*
2  * IzPack - Copyright 2001-2007 Julien Ponge, All Rights Reserved.
3  *
4  * http://www.izforge.com/izpack/ http://developer.berlios.de/projects/izpack/
5  *
6  * Copyright 2007 Dennis Reil
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
9  * in compliance with the License. You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software distributed under the License
14  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
15  * or implied. See the License for the specific language governing permissions and limitations under
16  * the License.
17  */

18 package com.izforge.izpack.compiler;
19
20 import java.io.BufferedReader JavaDoc;
21 import java.io.File JavaDoc;
22 import java.io.FileInputStream JavaDoc;
23 import java.io.FileOutputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.ObjectOutputStream JavaDoc;
27 import java.io.OutputStream JavaDoc;
28 import java.io.StringReader JavaDoc;
29 import java.net.URL JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.HashSet JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.List JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.Properties JavaDoc;
37 import java.util.Set JavaDoc;
38 import java.util.zip.Deflater JavaDoc;
39 import java.util.zip.ZipEntry JavaDoc;
40 import java.util.zip.ZipException JavaDoc;
41 import java.util.zip.ZipFile JavaDoc;
42 import java.util.zip.ZipInputStream JavaDoc;
43 import java.util.zip.ZipOutputStream JavaDoc;
44
45 import net.n3.nanoxml.XMLElement;
46
47 import com.izforge.izpack.CustomData;
48 import com.izforge.izpack.GUIPrefs;
49 import com.izforge.izpack.Info;
50 import com.izforge.izpack.Pack;
51 import com.izforge.izpack.PackFile;
52 import com.izforge.izpack.Panel;
53 import com.izforge.izpack.XPackFile;
54 import com.izforge.izpack.compressor.PackCompressor;
55 import com.izforge.izpack.compressor.PackCompressorFactory;
56 import com.izforge.izpack.io.FileSpanningInputStream;
57 import com.izforge.izpack.io.FileSpanningOutputStream;
58 import com.izforge.izpack.util.Debug;
59
60 /**
61  * The packager class. The packager is used by the compiler to put files into an installer, and
62  * create the actual installer files.
63  *
64  * This is a packager, which packs everything into multi volumes.
65  *
66  * @author Dennis Reil, <Dennis.Reil@reddot.de>
67  */

68 public class MultiVolumePackager implements IPackager
69 {
70
71     public static final String JavaDoc INSTALLER_PAK_NAME = "installer";
72
73     /** Path to the skeleton installer. */
74     public static final String JavaDoc SKELETON_SUBPATH = "lib/installer.jar";
75
76     /** Base file name of all jar files. This has no ".jar" suffix. */
77     private File JavaDoc baseFile = null;
78
79     /** Executable zipped output stream. First to open, last to close. */
80     private ZipOutputStream JavaDoc primaryJarStream;
81
82     /** Basic installer info. */
83     private Info info = null;
84
85     /** Gui preferences of instatller. */
86     private GUIPrefs guiPrefs = null;
87
88     /** The variables used in the project */
89     private Properties JavaDoc variables = new Properties JavaDoc();
90
91     /** The ordered panels informations. */
92     private List JavaDoc panelList = new ArrayList JavaDoc();
93
94     /** The ordered packs informations (as PackInfo objects). */
95     private List JavaDoc packsList = new ArrayList JavaDoc();
96
97     /** The ordered langpack ISO3 names. */
98     private List JavaDoc langpackNameList = new ArrayList JavaDoc();
99
100     /** The ordered custom actions informations. */
101     private List JavaDoc customDataList = new ArrayList JavaDoc();
102
103     /** The langpack URLs keyed by ISO3 name. */
104     private Map JavaDoc installerResourceURLMap = new HashMap JavaDoc();
105
106     /** Jar file URLs who's contents will be copied into the installer. */
107     private Set JavaDoc includedJarURLs = new HashSet JavaDoc();
108
109     /** Each pack is created in a separte jar if webDirURL is non-null. */
110     private boolean packJarsSeparate = false;
111
112     /** The listeners. */
113     private PackagerListener listener;
114
115     /** The compression format to be used for pack compression */
116     private PackCompressor compressor;
117
118     /** Files which are always written into the container file */
119     private HashMap JavaDoc alreadyWrittenFiles = new HashMap JavaDoc();
120     
121     private XMLElement configdata = null;
122
123     /**
124      * The constructor.
125      *
126      * @throws CompilerException
127      */

128     public MultiVolumePackager() throws CompilerException
129     {
130         this("default");
131     }
132
133     /**
134      * Extended constructor.
135      *
136      * @param compr_format Compression format to be used for packs compression format (if supported)
137      * @throws CompilerException
138      */

139     public MultiVolumePackager(String JavaDoc compr_format) throws CompilerException
140     {
141         this(compr_format, -1);
142     }
143
144     /**
145      * Extended constructor.
146      *
147      * @param compr_format Compression format to be used for packs
148      * @param compr_level Compression level to be used with the chosen compression format (if
149      * supported)
150      * @throws CompilerException
151      */

152     public MultiVolumePackager(String JavaDoc compr_format, int compr_level) throws CompilerException
153     {
154         setCompressorOptions(compr_format, compr_level);
155     }
156
157     /**
158      * Create the installer, beginning with the specified jar. If the name specified does not end in
159      * ".jar", it is appended. If secondary jars are created for packs (if the Info object added has
160      * a webDirURL set), they are created in the same directory, named sequentially by inserting
161      * ".pack#" (where '#' is the pack number) ".jar" suffix: e.g. "foo.pack1.jar". If any file
162      * exists, it is overwritten.
163      */

164     public void createInstaller(File JavaDoc primaryFile) throws Exception JavaDoc
165     {
166         // first analyze the configuration
167
this.analyzeConfigurationInformation();
168         
169         // preliminary work
170
String JavaDoc baseName = primaryFile.getName();
171         if (baseName.endsWith(".jar"))
172         {
173             baseName = baseName.substring(0, baseName.length() - 4);
174             baseFile = new File JavaDoc(primaryFile.getParentFile(), baseName);
175         }
176         else
177             baseFile = primaryFile;
178
179         info.setInstallerBase(baseFile.getName());
180         packJarsSeparate = (info.getWebDirURL() != null);
181
182         // primary (possibly only) jar. -1 indicates primary
183
primaryJarStream = getJarOutputStream(baseFile.getName() + ".jar");
184
185         sendStart();
186
187         // write the primary jar. MUST be first so manifest is not overwritten
188
// by
189
// an included jar
190
System.out.println("Writing skeleton installer.");
191         writeSkeletonInstaller();
192         writeInstallerObject("info", info);
193         writeInstallerObject("vars", variables);
194         writeInstallerObject("GUIPrefs", guiPrefs);
195         writeInstallerObject("panelsOrder", panelList);
196         writeInstallerObject("customData", customDataList);
197         writeInstallerObject("langpacks.info", langpackNameList);
198         writeInstallerResources();
199         writeIncludedJars();
200
201         // Pack File Data may be written to separate jars
202
String JavaDoc packfile = baseFile.getParent() + File.separator + INSTALLER_PAK_NAME;
203         writePacks(new File JavaDoc(packfile));
204
205         // Finish up. closeAlways is a hack for pack compressions other than
206
// default. Some of it (e.g. BZip2) closes the slave of it also.
207
// But this should not be because the jar stream should be open
208
// for the next pack. Therefore an own JarOutputStream will be used
209
// which close method will be blocked.
210
// primaryJarStream.closeAlways();
211
primaryJarStream.close();
212
213         sendStop();
214     }
215
216     /***********************************************************************************************
217      * Listener assistance
218      **********************************************************************************************/

219
220     private void analyzeConfigurationInformation()
221     {
222         String JavaDoc classname = this.getClass().getName();
223         String JavaDoc sizeprop = classname + ".volumesize";
224         String JavaDoc freespaceprop = classname + ".firstvolumefreespace";
225         if (this.configdata == null){
226             // no configdata given, set default values
227
this.variables.setProperty(sizeprop, Long.toString(FileSpanningOutputStream.DEFAULT_VOLUME_SIZE));
228             this.variables.setProperty(freespaceprop, Long.toString(FileSpanningOutputStream.DEFAULT_ADDITIONAL_FIRST_VOLUME_FREE_SPACE_SIZE));
229         }
230         else {
231             // configdata was set
232
String JavaDoc volumesize = configdata.getAttribute("volumesize", Long.toString(FileSpanningOutputStream.DEFAULT_VOLUME_SIZE));
233             String JavaDoc freespace = configdata.getAttribute("firstvolumefreespace", Long.toString(FileSpanningOutputStream.DEFAULT_ADDITIONAL_FIRST_VOLUME_FREE_SPACE_SIZE));
234             this.variables.setProperty(sizeprop, volumesize);
235             this.variables.setProperty(freespaceprop, freespace);
236         }
237     }
238
239     /**
240      * Get the PackagerListener.
241      *
242      * @return the current PackagerListener
243      */

244     public PackagerListener getPackagerListener()
245     {
246         return listener;
247     }
248
249     /**
250      * Adds a listener.
251      *
252      * @param listener The listener.
253      */

254     public void setPackagerListener(PackagerListener listener)
255     {
256         this.listener = listener;
257     }
258
259     /**
260      * Dispatches a message to the listeners.
261      *
262      * @param job The job description.
263      */

264     private void sendMsg(String JavaDoc job)
265     {
266         sendMsg(job, PackagerListener.MSG_INFO);
267     }
268
269     /**
270      * Dispatches a message to the listeners at specified priority.
271      *
272      * @param job The job description.
273      * @param priority The message priority.
274      */

275     private void sendMsg(String JavaDoc job, int priority)
276     {
277         Debug.trace(job);
278         if (listener != null) listener.packagerMsg(job, priority);
279     }
280
281     /** Dispatches a start event to the listeners. */
282     private void sendStart()
283     {
284         if (listener != null) listener.packagerStart();
285     }
286
287     /** Dispatches a stop event to the listeners. */
288     private void sendStop()
289     {
290         if (listener != null) listener.packagerStop();
291     }
292
293     /***********************************************************************************************
294      * Public methods to add data to the Installer being packed
295      **********************************************************************************************/

296
297     /**
298      * Sets the informations related to this installation.
299      *
300      * @param info The info section.
301      * @exception Exception Description of the Exception
302      */

303     public void setInfo(Info info) throws Exception JavaDoc
304     {
305         sendMsg("Setting the installer information", PackagerListener.MSG_VERBOSE);
306         this.info = info;
307         if (!getCompressor().useStandardCompression()
308                 && getCompressor().getDecoderMapperName() != null)
309         {
310             this.info.setPackDecoderClassName(getCompressor().getDecoderMapperName());
311         }
312     }
313
314     /**
315      * Sets the GUI preferences.
316      *
317      * @param prefs The new gUIPrefs value
318      */

319     public void setGUIPrefs(GUIPrefs prefs)
320     {
321         sendMsg("Setting the GUI preferences", PackagerListener.MSG_VERBOSE);
322         guiPrefs = prefs;
323     }
324
325     /**
326      * Allows access to add, remove and update the variables for the project, which are maintained
327      * in the packager.
328      *
329      * @return map of variable names to values
330      */

331     public Properties JavaDoc getVariables()
332     {
333         return variables;
334     }
335
336     /**
337      * Add a panel, where order is important. Only one copy of the class files neeed are inserted in
338      * the installer.
339      */

340     public void addPanelJar(Panel panel, URL JavaDoc jarURL)
341     {
342         panelList.add(panel); // serialized to keep order/variables correct
343
addJarContent(jarURL); // each included once, no matter how many times
344
// added
345
}
346
347     /**
348      * Add a custom data like custom actions, where order is important. Only one copy of the class
349      * files neeed are inserted in the installer.
350      *
351      * @param ca custom action object
352      * @param url the URL to include once
353      */

354     public void addCustomJar(CustomData ca, URL JavaDoc url)
355     {
356         customDataList.add(ca); // serialized to keep order/variables correct
357
addJarContent(url); // each included once, no matter how many times
358
// added
359
}
360
361     /**
362      * Adds a pack, order is mostly irrelevant.
363      *
364      * @param pack contains all the files and items that go with a pack
365      */

366     public void addPack(PackInfo pack)
367     {
368         packsList.add(pack);
369     }
370
371     /**
372      * Gets the packages list
373      */

374     public List JavaDoc getPacksList()
375     {
376         return packsList;
377     }
378
379     /**
380      * Adds a language pack.
381      *
382      * @param iso3 The ISO3 code.
383      * @param xmlURL The location of the xml local info
384      * @param flagURL The location of the flag image resource
385      */

386     public void addLangPack(String JavaDoc iso3, URL JavaDoc xmlURL, URL JavaDoc flagURL)
387     {
388         sendMsg("Adding langpack: " + iso3, PackagerListener.MSG_VERBOSE);
389         // put data & flag as entries in installer, and keep array of iso3's
390
// names
391
langpackNameList.add(iso3);
392         addResource("flag." + iso3, flagURL);
393         installerResourceURLMap.put("langpacks/" + iso3 + ".xml", xmlURL);
394     }
395
396     /**
397      * Adds a resource.
398      *
399      * @param resId The resource Id.
400      * @param url The location of the data
401      */

402     public void addResource(String JavaDoc resId, URL JavaDoc url)
403     {
404         sendMsg("Adding resource: " + resId, PackagerListener.MSG_VERBOSE);
405         installerResourceURLMap.put("res/" + resId, url);
406     }
407
408     /**
409      * Adds a native library.
410      *
411      * @param name The native library name.
412      * @param url The url to get the data from.
413      * @exception Exception Description of the Exception
414      */

415     public void addNativeLibrary(String JavaDoc name, URL JavaDoc url) throws Exception JavaDoc
416     {
417         sendMsg("Adding native library: " + name, PackagerListener.MSG_VERBOSE);
418         installerResourceURLMap.put("native/" + name, url);
419     }
420
421     /**
422      * Adds a jar file content to the installer. Package structure is maintained. Need mechanism to
423      * copy over signed entry information.
424      *
425      * @param jarURL The url of the jar to add to the installer. We use a URL so the jar may be
426      * nested within another.
427      */

428     public void addJarContent(URL JavaDoc jarURL)
429     {
430         addJarContent(jarURL, null);
431     }
432
433     /**
434      * Adds a jar file content to the installer. Package structure is maintained. Need mechanism to
435      * copy over signed entry information.
436      *
437      * @param jarURL The url of the jar to add to the installer. We use a URL so the jar may be
438      * nested within another.
439      */

440     public void addJarContent(URL JavaDoc jarURL, List JavaDoc files)
441     {
442         Object JavaDoc[] cont = { jarURL, files};
443         sendMsg("Adding content of jar: " + jarURL.getFile(), PackagerListener.MSG_VERBOSE);
444         includedJarURLs.add(cont);
445     }
446
447     /**
448      * Marks a native library to be added to the uninstaller.
449      *
450      * @param data the describing custom action data object
451      */

452     public void addNativeUninstallerLibrary(CustomData data)
453     {
454         customDataList.add(data); // serialized to keep order/variables
455
// correct
456

457     }
458
459     /***********************************************************************************************
460      * Private methods used when writing out the installer to jar files.
461      **********************************************************************************************/

462
463     /**
464      * Write skeleton installer to primary jar. It is just an included jar, except that we copy the
465      * META-INF as well.
466      */

467     private void writeSkeletonInstaller() throws IOException JavaDoc
468     {
469         sendMsg("Copying the skeleton installer", PackagerListener.MSG_VERBOSE);
470         
471         
472         InputStream JavaDoc is = MultiVolumePackager.class.getResourceAsStream("/" + SKELETON_SUBPATH);
473         if (is == null)
474         {
475             File JavaDoc skeleton = new File JavaDoc(Compiler.IZPACK_HOME, SKELETON_SUBPATH);
476             is = new FileInputStream JavaDoc(skeleton);
477         }
478         ZipInputStream JavaDoc inJarStream = new ZipInputStream JavaDoc(is);
479         
480         // copy anything except the manifest.mf
481
List JavaDoc excludes = new ArrayList JavaDoc();
482         excludes.add("META-INF.MANIFEST.MF");
483         copyZipWithoutExcludes(inJarStream, primaryJarStream,excludes);
484
485         // ugly code to modify the manifest-file to set MultiVolumeInstaller as main class
486
// reopen Stream
487
is = MultiVolumePackager.class.getResourceAsStream("/" + SKELETON_SUBPATH);
488         if (is == null)
489         {
490             File JavaDoc skeleton = new File JavaDoc(Compiler.IZPACK_HOME, SKELETON_SUBPATH);
491             is = new FileInputStream JavaDoc(skeleton);
492         }
493         inJarStream = new ZipInputStream JavaDoc(is);
494         boolean found = false;
495         ZipEntry JavaDoc ze = null;
496         String JavaDoc modifiedmanifest = null;
497         while (((ze = inJarStream.getNextEntry()) != null) && !found){
498             if ("META-INF/MANIFEST.MF".equals(ze.getName())){
499                 long size = ze.getSize();
500                 byte[] buffer = new byte[4096];
501                 int readbytes = 0;
502                 int totalreadbytes = 0;
503                 StringBuffer JavaDoc manifest = new StringBuffer JavaDoc();
504                 while (((readbytes = inJarStream.read(buffer)) > 0) && (totalreadbytes < size)){
505                     totalreadbytes += readbytes;
506                     String JavaDoc tmp = new String JavaDoc(buffer,0,readbytes,"utf-8");
507                     manifest.append(tmp);
508                 }
509                 
510                 
511                 StringReader JavaDoc stringreader = new StringReader JavaDoc(manifest.toString());
512                 BufferedReader JavaDoc reader = new BufferedReader JavaDoc(stringreader);
513                 String JavaDoc line = null;
514                 StringBuffer JavaDoc modified = new StringBuffer JavaDoc();
515                 while ((line = reader.readLine()) != null){
516                     if (line.startsWith("Main-Class:")){
517                         line = "Main-Class: com.izforge.izpack.installer.MultiVolumeInstaller";
518                     }
519                     modified.append(line);
520                     modified.append("\r\n");
521                 }
522                 reader.close();
523                 modifiedmanifest = modified.toString();
524                 /*
525                 System.out.println("Manifest:");
526                 System.out.println(manifest.toString());
527                 System.out.println("Modified Manifest:");
528                 System.out.println(modified.toString());
529                 */

530                 break;
531             }
532         }
533         
534         primaryJarStream.putNextEntry(new ZipEntry JavaDoc("META-INF/MANIFEST.MF"));
535         primaryJarStream.write(modifiedmanifest.getBytes());
536         primaryJarStream.closeEntry();
537     }
538
539     /**
540      * Write an arbitrary object to primary jar.
541      */

542     private void writeInstallerObject(String JavaDoc entryName, Object JavaDoc object) throws IOException JavaDoc
543     {
544         primaryJarStream.putNextEntry(new ZipEntry JavaDoc(entryName));
545         ObjectOutputStream JavaDoc out = new ObjectOutputStream JavaDoc(primaryJarStream);
546         out.writeObject(object);
547         out.flush();
548         primaryJarStream.closeEntry();
549     }
550
551     /** Write the data referenced by URL to primary jar. */
552     private void writeInstallerResources() throws IOException JavaDoc
553     {
554         sendMsg("Copying " + installerResourceURLMap.size() + " files into installer");
555
556         Iterator JavaDoc i = installerResourceURLMap.keySet().iterator();
557         while (i.hasNext())
558         {
559             String JavaDoc name = (String JavaDoc) i.next();
560             InputStream JavaDoc in = ((URL JavaDoc) installerResourceURLMap.get(name)).openStream();
561             primaryJarStream.putNextEntry(new ZipEntry JavaDoc(name));
562             copyStream(in, primaryJarStream);
563             primaryJarStream.closeEntry();
564             in.close();
565         }
566     }
567
568     /** Copy included jars to primary jar. */
569     private void writeIncludedJars() throws IOException JavaDoc
570     {
571         sendMsg("Merging " + includedJarURLs.size() + " jars into installer");
572
573         Iterator JavaDoc i = includedJarURLs.iterator();
574         while (i.hasNext())
575         {
576             Object JavaDoc[] current = (Object JavaDoc[]) i.next();
577             InputStream JavaDoc is = ((URL JavaDoc) current[0]).openStream();
578             ZipInputStream JavaDoc inJarStream = new ZipInputStream JavaDoc(is);
579             copyZip(inJarStream, primaryJarStream, (List JavaDoc) current[1]);
580         }
581     }
582
583     /**
584      * Write Packs to primary jar or each to a separate jar.
585      */

586     private void writePacks(File JavaDoc primaryfile) throws Exception JavaDoc
587     {
588
589         final int num = packsList.size();
590         sendMsg("Writing " + num + " Pack" + (num > 1 ? "s" : "") + " into installer");
591         Debug.trace("Writing " + num + " Pack" + (num > 1 ? "s" : "") + " into installer");
592         // Map to remember pack number and bytes offsets of back references
593
Map JavaDoc storedFiles = new HashMap JavaDoc();
594
595         // First write the serialized files and file metadata data for each pack
596
// while counting bytes.
597

598         String JavaDoc classname = this.getClass().getName();
599         String JavaDoc volumesize = this.getVariables().getProperty(classname + ".volumesize");
600         String JavaDoc extraspace = this.getVariables().getProperty(classname + ".firstvolumefreespace");
601
602         long volumesizel = FileSpanningOutputStream.DEFAULT_VOLUME_SIZE;
603         long extraspacel = FileSpanningOutputStream.DEFAULT_ADDITIONAL_FIRST_VOLUME_FREE_SPACE_SIZE;
604
605         if (volumesize != null)
606         {
607             volumesizel = Long.parseLong(volumesize);
608         }
609         if (extraspace != null)
610         {
611             extraspacel = Long.parseLong(extraspace);
612         }
613         Debug.trace("Volumesize: " + volumesizel);
614         Debug.trace("Extra space on first volume: " + extraspacel);
615         FileSpanningOutputStream fout = new FileSpanningOutputStream(primaryfile.getParent()
616                 + File.separator + primaryfile.getName() + ".pak", volumesizel);
617         fout.setFirstvolumefreespacesize(extraspacel);
618
619         int packNumber = 0;
620         Iterator JavaDoc packIter = packsList.iterator();
621         while (packIter.hasNext())
622         {
623             PackInfo packInfo = (PackInfo) packIter.next();
624             Pack pack = packInfo.getPack();
625             pack.nbytes = 0;
626
627             sendMsg("Writing Pack " + packNumber + ": " + pack.name, PackagerListener.MSG_VERBOSE);
628             Debug.trace("Writing Pack " + packNumber + ": " + pack.name);
629             ZipEntry JavaDoc entry = new ZipEntry JavaDoc("packs/pack" + packNumber);
630             // write the metadata as uncompressed object stream to primaryJarStream
631
// ByteCountingOutputStream dos = new
632
// ByteCountingOutputStream(comprStream);
633
// ByteCountingOutputStream dos = new
634
// ByteCountingOutputStream(primaryJarStream);
635
// first write a packs entry
636

637             primaryJarStream.putNextEntry(entry);
638             ObjectOutputStream JavaDoc objOut = new ObjectOutputStream JavaDoc(primaryJarStream);
639
640             // We write the actual pack files
641
objOut.writeInt(packInfo.getPackFiles().size());
642
643             Iterator JavaDoc iter = packInfo.getPackFiles().iterator();
644             while (iter.hasNext())
645             {
646                 boolean addFile = !pack.loose;
647                 XPackFile pf = new XPackFile((PackFile) iter.next());
648                 File JavaDoc file = packInfo.getFile(pf.getPackfile());
649                 Debug.trace("Next file: " + file.getAbsolutePath());
650                 // use a back reference if file was in previous pack, and in
651
// same jar
652
long[] info = (long[]) storedFiles.get(file);
653                 if (info != null && !packJarsSeparate)
654                 {
655                     Debug.trace("File already included in other pack");
656                     pf.setPreviousPackFileRef((int) info[0], info[1]);
657                     addFile = false;
658                 }
659
660                 if (addFile && !pf.isDirectory())
661                 {
662                     long pos = fout.getFilepointer();
663
664                     pf.setArchivefileposition(pos);
665
666                     // write out the filepointer
667
int volumecountbeforewrite = fout.getVolumeCount();
668
669                     FileInputStream JavaDoc inStream = new FileInputStream JavaDoc(file);
670                     long bytesWritten = copyStream(inStream, fout);
671                     fout.flush();
672
673                     long posafterwrite = fout.getFilepointer();
674                     Debug.trace("File (" + pf.sourcePath + ") " + pos + " <-> " + posafterwrite);
675
676                     if (fout.getFilepointer() != (pos + bytesWritten))
677                     {
678                         Debug.trace("file: " + file.getName());
679                         Debug.trace("(Filepos/BytesWritten/ExpectedNewFilePos/NewFilePointer) ("
680                                         + pos + "/" + bytesWritten + "/" + (pos + bytesWritten)
681                                         + "/" + fout.getFilepointer() + ")");
682                         Debug.trace("Volumecount (before/after) ("
683                                 + volumecountbeforewrite + "/" + fout.getVolumeCount() + ")");
684                         throw new IOException JavaDoc("Error new filepointer is illegal");
685                     }
686
687                     if (bytesWritten != pf.length()) { throw new IOException JavaDoc(
688                             "File size mismatch when reading " + file); }
689                     inStream.close();
690                     // keine backreferences möglich
691
// storedFiles.put(file, new long[] { packNumber, pos});
692
}
693
694                 objOut.writeObject(pf); // base info
695
objOut.flush(); // make sure it is written
696
// even if not written, it counts towards pack size
697
pack.nbytes += pf.length();
698             }
699             // Write out information about parsable files
700
objOut.writeInt(packInfo.getParsables().size());
701             iter = packInfo.getParsables().iterator();
702             while (iter.hasNext())
703                 objOut.writeObject(iter.next());
704
705             // Write out information about executable files
706
objOut.writeInt(packInfo.getExecutables().size());
707             iter = packInfo.getExecutables().iterator();
708             while (iter.hasNext())
709                 objOut.writeObject(iter.next());
710
711             // Write out information about updatecheck files
712
objOut.writeInt(packInfo.getUpdateChecks().size());
713             iter = packInfo.getUpdateChecks().iterator();
714             while (iter.hasNext())
715                 objOut.writeObject(iter.next());
716
717             // Cleanup
718
objOut.flush();
719             packNumber++;
720         }
721
722         // write metadata for reading in volumes
723
int volumes = fout.getVolumeCount();
724         Debug.trace("Written " + volumes + " volumes");
725         String JavaDoc volumename = primaryfile.getName() + ".pak";
726
727         fout.flush();
728         fout.close();
729
730         primaryJarStream.putNextEntry(new ZipEntry JavaDoc("volumes.info"));
731         ObjectOutputStream JavaDoc out = new ObjectOutputStream JavaDoc(primaryJarStream);
732         out.writeInt(volumes);
733         out.writeUTF(volumename);
734         out.flush();
735         primaryJarStream.closeEntry();
736
737         // Now that we know sizes, write pack metadata to primary jar.
738
primaryJarStream.putNextEntry(new ZipEntry JavaDoc("packs.info"));
739         out = new ObjectOutputStream JavaDoc(primaryJarStream);
740         out.writeInt(packsList.size());
741
742         Iterator JavaDoc i = packsList.iterator();
743         while (i.hasNext())
744         {
745             PackInfo pack = (PackInfo) i.next();
746             out.writeObject(pack.getPack());
747         }
748         out.flush();
749         primaryJarStream.closeEntry();
750     }
751
752     /***********************************************************************************************
753      * Stream utilites for creation of the installer.
754      **********************************************************************************************/

755
756     /** Return a stream for the next jar. */
757     private ZipOutputStream JavaDoc getJarOutputStream(String JavaDoc name) throws IOException JavaDoc
758     {
759         File JavaDoc file = new File JavaDoc(baseFile.getParentFile(), name);
760         sendMsg("Building installer jar: " + file.getAbsolutePath());
761         Debug.trace("Building installer jar: " + file.getAbsolutePath());
762         ZipOutputStream JavaDoc jar = new ZipOutputStream JavaDoc(new FileOutputStream JavaDoc(file));
763         jar.setLevel(Deflater.BEST_COMPRESSION);
764         // jar.setPreventClose(true); // Needed at using FilterOutputStreams which
765
// calls close
766
// of the slave at finalizing.
767

768         return jar;
769     }
770
771     /**
772      * Copies contents of one jar to another.
773      *
774      * <p>
775      * TODO: it would be useful to be able to keep signature information from signed jar files, can
776      * we combine manifests and still have their content signed?
777      *
778      * @see #copyStream(InputStream, OutputStream)
779      */

780     private void copyZip(ZipInputStream JavaDoc zin, ZipOutputStream JavaDoc out) throws IOException JavaDoc
781     {
782         copyZip(zin, out, null);
783     }
784
785     /**
786      * Copies specified contents of one jar to another.
787      *
788      * <p>
789      * TODO: it would be useful to be able to keep signature information from signed jar files, can
790      * we combine manifests and still have their content signed?
791      *
792      * @see #copyStream(InputStream, OutputStream)
793      */

794     private void copyZip(ZipInputStream JavaDoc zin, ZipOutputStream JavaDoc out, List JavaDoc files) throws IOException JavaDoc
795     {
796         java.util.zip.ZipEntry JavaDoc zentry;
797         if (!alreadyWrittenFiles.containsKey(out)) alreadyWrittenFiles.put(out, new HashSet JavaDoc());
798         HashSet JavaDoc currentSet = (HashSet JavaDoc) alreadyWrittenFiles.get(out);
799         while ((zentry = zin.getNextEntry()) != null)
800         {
801             String JavaDoc currentName = zentry.getName();
802             String JavaDoc testName = currentName.replace('/', '.');
803             testName = testName.replace('\\', '.');
804             if (files != null)
805             {
806                 Iterator JavaDoc i = files.iterator();
807                 boolean founded = false;
808                 while (i.hasNext())
809                 { // Make "includes" self to support regex.
810
String JavaDoc doInclude = (String JavaDoc) i.next();
811                     if (testName.matches(doInclude))
812                     {
813                         founded = true;
814                         break;
815                     }
816                 }
817                 if (!founded) continue;
818             }
819             if (currentSet.contains(currentName)) continue;
820             try
821             {
822                 out.putNextEntry(new ZipEntry JavaDoc(currentName));
823                 copyStream(zin, out);
824                 out.closeEntry();
825                 zin.closeEntry();
826                 currentSet.add(currentName);
827             }
828             catch (ZipException JavaDoc x)
829             {
830                 // This avoids any problem that can occur with duplicate
831
// directories. for instance all META-INF data in jars
832
// unfortunately this do not work with the apache ZipOutputStream...
833
}
834         }
835     }
836     
837     /**
838      * Copies specified contents of one jar to another without the specified files
839      *
840      * <p>
841      * TODO: it would be useful to be able to keep signature information from signed jar files, can
842      * we combine manifests and still have their content signed?
843      *
844      * @see #copyStream(InputStream, OutputStream)
845      */

846     private void copyZipWithoutExcludes(ZipInputStream JavaDoc zin, ZipOutputStream JavaDoc out, List JavaDoc excludes) throws IOException JavaDoc
847     {
848         java.util.zip.ZipEntry JavaDoc zentry;
849         if (!alreadyWrittenFiles.containsKey(out)) alreadyWrittenFiles.put(out, new HashSet JavaDoc());
850         HashSet JavaDoc currentSet = (HashSet JavaDoc) alreadyWrittenFiles.get(out);
851         while ((zentry = zin.getNextEntry()) != null)
852         {
853             String JavaDoc currentName = zentry.getName();
854             String JavaDoc testName = currentName.replace('/', '.');
855             testName = testName.replace('\\', '.');
856             if (excludes != null)
857             {
858                 Iterator JavaDoc i = excludes.iterator();
859                 boolean skip = false;
860                 while (i.hasNext())
861                 {
862                     // Make "excludes" self to support regex.
863
String JavaDoc doExclude = (String JavaDoc) i.next();
864                     if (testName.matches(doExclude))
865                     {
866                         skip = true;
867                         break;
868                     }
869                 }
870                 if (skip){
871                     continue;
872                 }
873             }
874             if (currentSet.contains(currentName)) continue;
875             try
876             {
877                 out.putNextEntry(new ZipEntry JavaDoc(currentName));
878                 copyStream(zin, out);
879                 out.closeEntry();
880                 zin.closeEntry();
881                 currentSet.add(currentName);
882             }
883             catch (ZipException JavaDoc x)
884             {
885                 // This avoids any problem that can occur with duplicate
886
// directories. for instance all META-INF data in jars
887
// unfortunately this do not work with the apache ZipOutputStream...
888
}
889         }
890     }
891
892     /**
893      * Copies all the data from the specified input stream to the specified output stream.
894      *
895      * @param in the input stream to read
896      * @param out the output stream to write
897      * @return the total number of bytes copied
898      * @exception IOException if an I/O error occurs
899      */

900     private long copyStream(InputStream JavaDoc in, OutputStream JavaDoc out) throws IOException JavaDoc
901     {
902         byte[] buffer = new byte[5120];
903         long bytesCopied = 0;
904         int bytesInBuffer;
905         while ((bytesInBuffer = in.read(buffer)) != -1)
906         {
907             out.write(buffer, 0, bytesInBuffer);
908             bytesCopied += bytesInBuffer;
909         }
910         return bytesCopied;
911     }
912
913     /**
914      * Returns the current pack compressor
915      *
916      * @return Returns the current pack compressor.
917      */

918     public PackCompressor getCompressor()
919     {
920         return compressor;
921     }
922
923     public void setCompressorOptions(String JavaDoc compr_format, int compr_level) throws CompilerException
924     {
925         compressor = PackCompressorFactory.get(compr_format);
926         compressor.setCompressionLevel(compr_level);
927     }
928
929     public void addConfigurationInformation(XMLElement data)
930     {
931        this.configdata = data;
932     }
933
934     public void initPackCompressor(String JavaDoc compr_format, int compr_level) throws CompilerException
935     {
936         this.setCompressorOptions(compr_format, compr_level);
937     }
938 }
Popular Tags