KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > groboutils > codecoverage > v2 > ant > GroboReZipTask


1 /*
2  * @(#)GroboReZipTask.java
3  *
4  * Copyright (C) 2004 Matt Albrecht
5  * groboclown@users.sourceforge.net
6  * http://groboutils.sourceforge.net
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  */

26
27 package net.sourceforge.groboutils.codecoverage.v2.ant;
28
29 import java.io.ByteArrayInputStream JavaDoc;
30 import java.io.ByteArrayOutputStream JavaDoc;
31 import java.io.File JavaDoc;
32 import java.io.FileInputStream JavaDoc;
33 import java.io.FileOutputStream JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.io.InputStream JavaDoc;
36 import java.util.Enumeration JavaDoc;
37 import java.util.Stack JavaDoc;
38 import java.util.Vector JavaDoc;
39 import java.util.zip.CRC32 JavaDoc;
40
41 import org.apache.tools.ant.BuildException;
42 import org.apache.tools.ant.DirectoryScanner;
43 import org.apache.tools.ant.Project;
44 import org.apache.tools.ant.Task;
45 import org.apache.tools.ant.types.FileSet;
46 import org.apache.tools.ant.types.PatternSet;
47 //import org.apache.tools.ant.types.Resource;
48
import org.apache.tools.ant.util.FileUtils;
49
50 // We have to use the Ant ZipScanner due to the Reference type.
51
// But it's easy to avoid this...
52
//import org.apache.tools.ant.types.ZipScanner;
53

54 // use our own re-packaging of the Apache zip utility
55
import net.sourceforge.groboutils.codecoverage.v2.ant.zip.ZipEntry;
56 import net.sourceforge.groboutils.codecoverage.v2.ant.zip.ZipOutputStream;
57 import net.sourceforge.groboutils.codecoverage.v2.ant.zip.ZipFile;
58 import net.sourceforge.groboutils.codecoverage.v2.ant.zip.ZipFileSet;
59
60
61 /**
62  * Similar to the Zip task, but its purpose is to modify not only
63  * one zip file, but possibly many containing zip files as well.
64  * Also, should have meta-inf support for modifying the classpath to
65  * add in the runtime jar file.
66  *
67  * @author Matt Albrecht <a HREF="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
68  * @version $Date: 2004/07/08 05:29:19 $
69  * @since March 23, 2004
70  */

71 public class GroboReZipTask extends Task
72 {
73     private boolean failOnError = true;
74     private Vector JavaDoc zips = new Vector JavaDoc();
75     
76     private static final int BUFFER_SIZE = 8 * 1024;
77     private static final int DELETE_RETRY_SLEEP_MILLIS = 10;
78     
79     private static final FileUtils FILEUTILS = FileUtils.newFileUtils();
80     private static final long EMPTY_CRC = new CRC32 JavaDoc ().getValue ();
81     
82     
83     public static class ReZipFileSet extends ZipFileSet
84     {
85         private boolean replaceOnly = false;
86         
87         public ReZipFileSet()
88         {
89             super();
90         }
91         
92         public ReZipFileSet( FileSet fs )
93         {
94             super( fs );
95         }
96         
97         public ReZipFileSet( ZipFileSet zfs )
98         {
99             super( zfs );
100         }
101         
102         public ReZipFileSet( ReZipFileSet rzfs )
103         {
104             super( (ZipFileSet)rzfs );
105             this.replaceOnly = rzfs.replaceOnly;
106         }
107         
108         /**
109          * If this is set to true, then only the files in this fileset
110          * that already exist in the owning zip file will be added, all
111          * others in this fileset will be ignored.
112          */

113         public void setReplaceOnly( boolean replace )
114         {
115             this.replaceOnly = replace;
116         }
117         
118         public boolean getReplaceOnly( Project p )
119         {
120             if (isReference())
121             {
122                 return ((ReZipFileSet)getRef( p )).getReplaceOnly( p );
123             }
124             return this.replaceOnly;
125         }
126     }
127     
128     
129     /** the base type for altering a zip file. */
130     public static class AlterZip
131     {
132         private Vector JavaDoc subZip = new Vector JavaDoc();
133         private Vector JavaDoc fileSets = new Vector JavaDoc();
134         private Vector JavaDoc alter = new Vector JavaDoc();
135         private String JavaDoc srcFile;
136         private String JavaDoc destFile;
137         String JavaDoc encoding;
138         boolean doCompress = true;
139         
140         public void setSrc( String JavaDoc f )
141         {
142             this.srcFile = f;
143         }
144         
145         public void setDest( String JavaDoc f )
146         {
147             this.destFile = f;
148         }
149         
150         public void addFileSet( ReZipFileSet zfs )
151         {
152             if (zfs != null)
153             {
154                 this.fileSets.addElement( zfs );
155             }
156         }
157         
158         public void addZipFileSet( ReZipFileSet zfs )
159         {
160             if (zfs != null)
161             {
162                 this.fileSets.addElement( zfs );
163             }
164         }
165         
166         public void addAlterZip( AlterZip z )
167         {
168             if (z != null)
169             {
170                 this.subZip.addElement( z );
171             }
172         }
173         
174         public void addAlterWar( AlterWar z )
175         {
176             if (z != null)
177             {
178                 this.subZip.addElement( z );
179             }
180         }
181         
182         public void addAlterEar( AlterEar z )
183         {
184             if (z != null)
185             {
186                 this.subZip.addElement( z );
187             }
188         }
189         
190         public void addAlterJar( AlterJar z )
191         {
192             if (z != null)
193             {
194                 this.subZip.addElement( z );
195             }
196         }
197         
198         protected void _addModifyEntry( ModifyEntry me )
199         {
200             if (me != null)
201             {
202                 this.alter.addElement( me );
203             }
204         }
205         
206         public File JavaDoc getAbsoluteSrc( Project p )
207         {
208             return p.resolveFile( this.srcFile );
209         }
210         
211         public File JavaDoc getAbsoluteDest( Project p )
212         {
213             return p.resolveFile( this.destFile );
214         }
215         
216         public String JavaDoc getSrc()
217         {
218             return this.srcFile;
219         }
220         
221         public String JavaDoc getDest()
222         {
223             return this.destFile;
224         }
225         
226         public boolean hasDest()
227         {
228             return (this.destFile != null);
229         }
230         
231         public AlterZip[] getSubZips()
232         {
233             AlterZip az[] = new AlterZip[ this.subZip.size() ];
234             this.subZip.copyInto( az );
235             return az;
236         }
237         
238         public FileSet[] getFileSets()
239         {
240             FileSet fs[] = new FileSet[ this.fileSets.size() ];
241             this.fileSets.copyInto( fs );
242             return fs;
243         }
244         
245         public ModifyEntry[] getModifyEntries()
246         {
247             Vector JavaDoc entries = new Vector JavaDoc();
248             Enumeration JavaDoc e = this.alter.elements();
249             while (e.hasMoreElements())
250             {
251                 entries.addElement( e.nextElement() );
252             }
253             e = this.subZip.elements();
254             while (e.hasMoreElements())
255             {
256                 AlterZip az = (AlterZip)e.nextElement();
257                 entries.addElement( new AlterZipModifyEntry( az ) );
258             }
259             ModifyEntry me[] = new ModifyEntry[ entries.size() ];
260             entries.copyInto( me );
261             return me;
262         }
263     
264     
265         public ModifyEntry shouldModify( String JavaDoc r )
266         {
267             ModifyEntry[] me = getModifyEntries();
268             for (int i = 0; i < me.length; ++i)
269             {
270                 if (me[i].shouldModify( r ))
271                 {
272                     return me[i];
273                 }
274             }
275             return null;
276         }
277     }
278     
279     
280     /**
281      * Tells the processing system that a particular file needs to
282      * be modified.
283      */

284     public static abstract class ModifyEntry
285     {
286         private String JavaDoc filename;
287         public ModifyEntry( String JavaDoc src )
288         {
289             this.filename = src;
290         }
291         
292         public boolean shouldModify( String JavaDoc r )
293         {
294             return (this.filename.equals( r ) );
295         }
296         
297         public abstract void modify( GroboReZipTask grze,
298                 InputStream JavaDoc in, File JavaDoc outfile )
299                 throws IOException JavaDoc;
300     }
301     
302     
303     /**
304      * Recursively alter the inner zip file, by writing its contents
305      * to temporary files.
306      */

307     public static class AlterZipModifyEntry extends ModifyEntry
308     {
309         private AlterZip az;
310         public AlterZipModifyEntry( AlterZip az )
311         {
312             super( az.srcFile );
313             this.az = az;
314         }
315         
316         public void modify( GroboReZipTask grze,
317                 InputStream JavaDoc in, File JavaDoc outfile )
318                 throws IOException JavaDoc
319         {
320             File JavaDoc src = FILEUTILS.createTempFile( "z", ".zip", null );
321             src.deleteOnExit();
322             FileOutputStream JavaDoc fos = new FileOutputStream JavaDoc( src );
323             byte buff[] = new byte[ BUFFER_SIZE ];
324             try
325             {
326                 int size = in.read( buff, 0, BUFFER_SIZE );
327                 while (size > 0)
328                 {
329                     fos.write( buff, 0, size );
330                     size = in.read( buff, 0, BUFFER_SIZE );
331                 }
332             }
333             finally
334             {
335                 fos.close();
336             }
337             
338             try
339             {
340                 grze.processZip( this.az, src, outfile );
341             }
342             finally
343             {
344                 delete( src );
345             }
346         }
347     }
348     
349     
350     public static class AlterEar extends AlterZip
351     {
352         // currently, this is exactly the same.
353
// we may want to alter the application.xml file
354
// in the future.
355
}
356     
357     
358     public static class AlterJar extends AlterZip
359     {
360         // currently, this is exactly the same.
361
// we may want to alter the MANIFEST.MF file
362
// in the future, to possibly append the classpath entry.
363
// This should be based on a 'addLib' like syntax.
364
}
365     
366     
367     public static class AlterWar extends AlterZip
368     {
369         public void addClasses( ReZipFileSet zfs )
370         {
371             zfs.setPrefix( "WEB-INF/classes/" );
372             zfs.setReplaceOnly( true );
373             addZipFileSet( zfs );
374         }
375         
376         public void addLib( ReZipFileSet zfs )
377         {
378             zfs.setPrefix( "WEB-INF/lib/" );
379             addZipFileSet( zfs );
380         }
381     }
382     
383     
384     
385     //------------------------------------------------------------------
386

387     public void addAlterZip( AlterZip z )
388     {
389         if (z != null)
390         {
391             this.zips.addElement( z );
392         }
393     }
394     
395     public void addAlterWar( AlterWar z )
396     {
397         if (z != null)
398         {
399             this.zips.addElement( z );
400         }
401     }
402     
403     public void addAlterEar( AlterEar z )
404     {
405         if (z != null)
406         {
407             this.zips.addElement( z );
408         }
409     }
410     
411     public void addAlterJar( AlterJar z )
412     {
413         if (z != null)
414         {
415             this.zips.addElement( z );
416         }
417     }
418     
419     
420     //------------------------------------------------------------------
421

422     public void execute()
423             throws BuildException
424     {
425         // the top level zips act a bit differently than the rest -
426
// their files are absolute.
427

428         Enumeration JavaDoc e = this.zips.elements();
429         while (e.hasMoreElements())
430         {
431             AlterZip az = (AlterZip)e.nextElement();
432             File JavaDoc src = az.getAbsoluteSrc( getProject() );
433             if (src == null)
434             {
435                 String JavaDoc msg = "No source specified for zip.";
436                 if (this.failOnError)
437                 {
438                     throw new BuildException( msg );
439                 }
440                 else
441                 {
442                     log( msg, Project.MSG_WARN );
443                 }
444             }
445             File JavaDoc dest = null;
446             boolean isTemp = false;
447             if (az.hasDest())
448             {
449                 dest = az.getAbsoluteDest( getProject() );
450                 if (dest.equals( src ))
451                 {
452                     // replacing the original file...
453
dest = null;
454                 }
455             }
456             if (dest == null)
457             {
458                 isTemp = true;
459                 dest = FILEUTILS.createTempFile( "z", ".zip", null );
460                 dest.deleteOnExit();
461             }
462             
463             log( "Altering ["+src.getAbsolutePath()+"] into ["+
464                 dest.getAbsolutePath()+"]", Project.MSG_INFO );
465             
466             try
467             {
468                 processZip( az, src, dest );
469                 
470                 if (isTemp)
471                 {
472                     // replace the original file.
473
FILEUTILS.copyFile( dest, src );
474                     System.gc();
475                     System.runFinalization();
476                     delete( dest );
477                 }
478             }
479             catch (SecurityException JavaDoc se)
480             {
481                 throw new BuildException(
482                     "Not allowed to rename temporary file to old file ("
483                     + src.getAbsolutePath()
484                     + ")" );
485             }
486             catch (IOException JavaDoc ioe)
487             {
488                 String JavaDoc msg = "Problem processing zip file "+
489                     src.getAbsolutePath()+": "+
490                     ioe.getMessage();
491                 if (this.failOnError)
492                 {
493                     throw new BuildException( msg, ioe );
494                 }
495                 else
496                 {
497                     log( msg, Project.MSG_WARN );
498                 }
499             }
500             catch (BuildException be)
501             {
502                 if (this.failOnError)
503                 {
504                     throw be;
505                 }
506                 else
507                 {
508                     log( be.getMessage(), Project.MSG_WARN );
509                 }
510             }
511         }
512     }
513     
514     
515     //------------------------------------------------------------------
516

517     
518     public void processZip( AlterZip az, File JavaDoc src, File JavaDoc dest )
519             throws BuildException, IOException JavaDoc
520     {
521         ZipFile inzip = new ZipFile( src );
522         az.encoding = inzip.getEncoding();
523         Vector JavaDoc originalFiles = new Vector JavaDoc();
524         Enumeration JavaDoc entries = inzip.getEntries();
525         while (entries.hasMoreElements())
526         {
527             ZipEntry ze = (ZipEntry)entries.nextElement();
528             originalFiles.addElement( ze.getName() );
529         }
530         entries = null;
531         inzip.close();
532         inzip = null;
533         
534         ZipOutputStream zOut = new ZipOutputStream(
535             new FileOutputStream JavaDoc( dest ) );
536         zOut.setEncoding( az.encoding );
537         
538         Vector JavaDoc addedFiles = new Vector JavaDoc();
539         addFiles( zOut, az.getFileSets(), az, addedFiles, originalFiles );
540         
541         log( "Adding contents of original zip ["+src.getAbsolutePath()+"]",
542             Project.MSG_VERBOSE );
543         ReZipFileSet oldFiles = new ReZipFileSet();
544         oldFiles.setProject( getProject() );
545         oldFiles.setSrc( src );
546         oldFiles.setReplaceOnly( false );
547         /*
548         Enumeration af = addedFiles.elements();
549         while (af.hasMoreElements())
550         {
551             PatternSet.NameEntry ne = oldFiles.createExclude();
552             ne.setName( (String)af.nextElement() );
553         }
554         */

555         addFiles( zOut, oldFiles, az, addedFiles, originalFiles );
556         
557         finalizeZipOutputStream(zOut);
558     }
559     
560     
561     private void addFiles( ZipOutputStream zOut, FileSet[] filesets,
562             AlterZip az, Vector JavaDoc addedFiles, Vector JavaDoc originalFiles )
563             throws IOException JavaDoc, BuildException
564     {
565         for (int i = 0; i < filesets.length; ++i)
566         {
567             addFiles( zOut, filesets[i], az, addedFiles, originalFiles );
568         }
569     }
570     
571     
572     private void addFiles( ZipOutputStream zOut, FileSet fileset,
573             AlterZip az, Vector JavaDoc addedFiles, Vector JavaDoc originalFiles )
574             throws IOException JavaDoc, BuildException
575     {
576         DirectoryScanner ds =
577             fileset.getDirectoryScanner( getProject() );
578         //if (ds instanceof ZipScanner)
579
//{
580
// ((ZipScanner) ds).setEncoding( az.encoding );
581
//}
582
ds.scan();
583         String JavaDoc[] f = ds.getIncludedFiles();
584         if (f.length > 0)
585         {
586             addResources( az, fileset, f, false, zOut, addedFiles, originalFiles );
587         }
588
589         String JavaDoc[] d = ds.getIncludedDirectories();
590         if (d.length > 0)
591         {
592             addResources( az, fileset, d, true, zOut, addedFiles, originalFiles );
593         }
594     }
595     
596     
597     /**
598      * Add the given resources. Ripped from Ant's Zip task.
599      *
600      * @param fileset may give additional information like fullpath or
601      * permissions.
602      * @param resources the resources to add
603      * @param zOut the stream to write to
604      *
605      * @since Ant 1.5.2
606      */

607     protected final void addResources( AlterZip az,
608             FileSet fileset, String JavaDoc[] resources, boolean areDirs,
609             ZipOutputStream zOut, Vector JavaDoc addedFiles, Vector JavaDoc originalFiles )
610             throws IOException JavaDoc
611     {
612         String JavaDoc prefix = "";
613         String JavaDoc fullpath = "";
614         int dirMode = ZipFileSet.DEFAULT_DIR_MODE;
615         int fileMode = ZipFileSet.DEFAULT_FILE_MODE;
616         boolean replaceOnly = false;
617
618         ZipFileSet zfs = null;
619         if (fileset instanceof ZipFileSet)
620         {
621             zfs = (ZipFileSet) fileset;
622             prefix = zfs.getPrefix(getProject());
623             fullpath = zfs.getFullpath(getProject());
624             dirMode = zfs.getDirMode(getProject());
625             fileMode = zfs.getFileMode(getProject());
626             if (fileset instanceof ReZipFileSet)
627             {
628                 replaceOnly = ((ReZipFileSet)fileset).getReplaceOnly(getProject());
629             }
630             log( "Processing resources from ZipFileSet: prefix=["+
631                 prefix+"]; fullpath=["+fullpath+"]; dirMode=["+
632                 dirMode+"]; fileMode=["+fileMode+"]; replaceOnly=["+
633                 replaceOnly+"]", Project.MSG_DEBUG );
634         }
635
636         if (prefix.length() > 0 && fullpath.length() > 0)
637         {
638             throw new BuildException("Both prefix and fullpath attributes must"
639                                      + " not be set on the same fileset.");
640         }
641
642         if (resources.length != 1 && fullpath.length() > 0)
643         {
644             throw new BuildException("fullpath attribute may only be specified"
645                                      + " for filesets that specify a single"
646                                      + " file.");
647         }
648
649         if (prefix.length() > 0)
650         {
651             if (!prefix.endsWith("/") && !prefix.endsWith("\\"))
652             {
653                 prefix += "/";
654             }
655             addParentDirs( null, prefix, zOut, "", dirMode, addedFiles,
656                 replaceOnly );
657         }
658
659         ZipFile zf = null;
660         try
661         {
662             boolean dealingWithFiles = false;
663             File JavaDoc base = null;
664             if (zfs == null || zfs.getSrc( getProject() ) == null)
665             {
666                 dealingWithFiles = true;
667                 base = fileset.getDir( getProject() );
668                 log( "Dealing with files (base=["+base+"])",
669                     Project.MSG_DEBUG );
670             }
671             else
672             {
673                 File JavaDoc src = zfs.getSrc( getProject() );
674                 zf = new ZipFile( src, az.encoding );
675                 log( "Dealing with zipFile (src=["+src.getAbsolutePath()+"])",
676                     Project.MSG_DEBUG );
677             }
678             
679             for (int i = 0; i < resources.length; i++)
680             {
681                 log("Processing resource ["+resources[i]+"]",
682                     Project.MSG_DEBUG );
683                 String JavaDoc name = null;
684                 if (fullpath.length() > 0)
685                 {
686                     name = fullpath;
687                 }
688                 else
689                 {
690                     name = resources[i];
691                 }
692                 name = name.replace(File.separatorChar, '/');
693                 
694                 if ("".equals(name))
695                 {
696                     log("Empty name - continuing.",
697                         Project.MSG_DEBUG );
698                     continue;
699                 }
700                 if (areDirs && !name.endsWith("/"))
701                 {
702                     name = name + "/";
703                 }
704                 String JavaDoc prefixName = prefix + name;
705                 log("Output Zip entry name = ["+prefixName+"]",
706                     Project.MSG_DEBUG );
707                 
708                 if (replaceOnly && !originalFiles.contains( prefixName ))
709                 {
710                     // only add the file when the original Zip contains it.
711
log( prefixName + " not in original zip, so skip it.",
712                         Project.MSG_VERBOSE );
713                     continue;
714                 }
715                 
716                 if (!dealingWithFiles
717                     && areDirs
718                     && !zfs.hasDirModeBeenSet())
719                 {
720                     log("Adding directory's path into zip", Project.MSG_DEBUG);
721                     int nextToLastSlash = name.lastIndexOf( "/",
722                         name.length() - 2 );
723                     if (nextToLastSlash != -1)
724                     {
725                         addParentDirs( base, name.substring( 0,
726                             nextToLastSlash + 1 ),
727                             zOut, prefix, dirMode, addedFiles,
728                             replaceOnly );
729                     }
730                     ZipEntry ze = zf.getEntry( resources[i] );
731                     addParentDirs( base, name, zOut, prefix, ze.getUnixMode(),
732                         addedFiles, replaceOnly );
733                 }
734                 else
735                 {
736                     log("Adding file's path into zip", Project.MSG_DEBUG);
737                     addParentDirs( base, name, zOut, prefix, dirMode,
738                         addedFiles, replaceOnly );
739                 }
740                 
741                 if (!areDirs)
742                 {
743                     if (dealingWithFiles)
744                     {
745                         File JavaDoc f = FILEUTILS.resolveFile(base,
746                             resources[i]);
747                         // only modify files that already exist in the
748
// zip file.
749
zipFile( az, f, zOut, prefixName, fileMode,
750                             addedFiles );
751                     }
752                     else
753                     {
754                         ZipEntry ze = zf.getEntry( resources[i] );
755                         
756                         if (ze != null)
757                         {
758                             log("Inserting zip entry ["+resources[i]+
759                                 "]", Project.MSG_DEBUG);
760                             boolean oldCompress = az.doCompress;
761                             az.doCompress =
762                                 (ze.getMethod() == ZipEntry.DEFLATED);
763                             ModifyEntry me = az.shouldModify( resources[i] );
764                             try
765                             {
766                                 zipFile( az, me,
767                                     zf.getInputStream(ze), zOut, prefixName,
768                                     ze.getTime(), zfs.getSrc( getProject() ),
769                                     zfs.hasFileModeBeenSet() ? fileMode
770                                     : ze.getUnixMode(), addedFiles );
771                             }
772                             finally
773                             {
774                                 az.doCompress = oldCompress;
775                             }
776                         }
777                     }
778                 }
779             }
780         }
781         finally
782         {
783             if (zf != null)
784             {
785                 zf.close();
786             }
787         }
788     }
789
790     
791
792     /**
793      * Ripped from Ant's Zip task.
794      *
795      * Ensure all parent dirs of a given entry have been added.
796      *
797      * @since Ant 1.5.2
798      */

799     protected final void addParentDirs( File JavaDoc baseDir, String JavaDoc entry,
800             ZipOutputStream zOut, String JavaDoc prefix, int dirMode,
801             Vector JavaDoc addedFiles, boolean replaceOnly )
802             throws IOException JavaDoc
803     {
804         // note: if replaceOnly == true, then any directories added would
805
// mean that for them to be added, they must already exist in
806
// the original zip file. If that's the case, then the directory
807
// will be added anyway. Therefore we don't need to add the
808
// directory if replaceOnly == true.
809
if (replaceOnly)
810         {
811             return;
812         }
813         
814         
815         Stack JavaDoc directories = new Stack JavaDoc();
816         int slashPos = entry.length();
817
818         while ((slashPos = entry.lastIndexOf( '/', slashPos - 1 )) != -1)
819         {
820             String JavaDoc dir = entry.substring( 0, slashPos + 1 );
821             if (addedFiles.contains( prefix + dir )) {
822                 break;
823             }
824             directories.push(dir);
825         }
826
827         while (!directories.isEmpty())
828         {
829             String JavaDoc dir = (String JavaDoc) directories.pop();
830             File JavaDoc f = null;
831             if (baseDir != null) {
832                 f = new File JavaDoc(baseDir, dir);
833             } else {
834                 f = new File JavaDoc(dir);
835             }
836             
837             zipDir( f, zOut, prefix + dir, dirMode, addedFiles );
838         }
839     }
840     
841     /**
842      * Ripped from Ant's Zip task.
843      *
844      * @since Ant 1.5.2
845      */

846     protected void zipDir( File JavaDoc dir, ZipOutputStream zOut, String JavaDoc vPath,
847             int mode, Vector JavaDoc addedFiles )
848             throws IOException JavaDoc
849     {
850         if (addedFiles.contains(vPath))
851         {
852             // don't add directories we've already added.
853
// no warning if we try, it is harmless in and of itself
854
return;
855         }
856
857         log( "adding directory " + vPath, Project.MSG_VERBOSE );
858         addedFiles.addElement( vPath );
859
860         ZipEntry ze = new ZipEntry(vPath);
861         if (dir != null && dir.exists()) {
862             // ZIPs store time with a granularity of 2 seconds, round up
863
ze.setTime(dir.lastModified() + 1999);
864         } else {
865             // ZIPs store time with a granularity of 2 seconds, round up
866
ze.setTime(System.currentTimeMillis() + 1999);
867         }
868         ze.setSize( 0 );
869         ze.setMethod( ZipEntry.STORED );
870         // This is faintly ridiculous:
871
ze.setCrc( EMPTY_CRC );
872         ze.setUnixMode(mode);
873
874         zOut.putNextEntry( ze );
875     }
876     
877     
878     /**
879      * Ripped from Ant's Zip task.
880      * Method that gets called when adding from java.io.File instances.
881      *
882      * <p>This implementation delegates to the six-arg version.</p>
883      *
884      * @param file the file to add to the archive
885      * @param zOut the stream to write to
886      * @param vPath the name this entry shall have in the archive
887      * @param mode the Unix permissions to set.
888      *
889      * @since Ant 1.5.2
890      */

891     protected void zipFile( AlterZip az, File JavaDoc file,
892             ZipOutputStream zOut, String JavaDoc vPath, int mode, Vector JavaDoc addedFiles )
893             throws IOException JavaDoc
894     {
895         /*
896         if (file.equals(zipFile))
897         {
898             throw new BuildException("A zip file cannot include itself",
899                                      getLocation());
900         }
901         */

902         log("zipFile( vPath = ["+vPath+"]; file = ["+file.getAbsolutePath()+"] )",
903             Project.MSG_DEBUG );
904         FileInputStream JavaDoc fIn = new FileInputStream JavaDoc(file);
905         try
906         {
907             // ZIPs store time with a granularity of 2 seconds, round up
908
zipFile( az, null, fIn, zOut, vPath, file.lastModified() + 1999,
909                 null, mode, addedFiles );
910         }
911         finally
912         {
913             fIn.close();
914         }
915     }
916     
917     
918     /**
919      * Ripped from Ant's Zip task.
920      *
921      * Adds a new entry to the archive, takes care of duplicates as well.
922      *
923      * @param in the stream to read data for the entry from.
924      * @param zOut the stream to write to.
925      * @param vPath the name this entry shall have in the archive.
926      * @param lastModified last modification time for the entry.
927      * @param fromArchive the original archive we are copying this
928      * entry from, will be null if we are not copying from an archive.
929      * @param mode the Unix permissions to set.
930      *
931      * @since Ant 1.5.2
932      */

933     protected void zipFile( AlterZip az, ModifyEntry me, InputStream JavaDoc in,
934             ZipOutputStream zOut, String JavaDoc vPath,
935             long lastModified, File JavaDoc fromArchive, int mode, Vector JavaDoc addedFiles )
936             throws IOException JavaDoc
937     {
938         if (addedFiles.contains(vPath))
939         {
940             log( vPath + " already added, skipping", Project.MSG_VERBOSE );
941             return;
942             /*
943             if (duplicate.equals("preserve")) {
944                 log(vPath + " already added, skipping", Project.MSG_INFO);
945                 return;
946             } else if (duplicate.equals("fail")) {
947                 throw new BuildException("Duplicate file " + vPath
948                                          + " was found and the duplicate "
949                                          + "attribute is 'fail'.");
950             } else {
951                 // duplicate equal to add, so we continue
952                 log("duplicate file " + vPath
953                     + " found, adding.", Project.MSG_VERBOSE);
954             }
955             */

956         }
957         else
958         {
959             log( "adding entry " + vPath, Project.MSG_VERBOSE );
960         }
961         
962         ZipEntry ze = new ZipEntry( vPath );
963         ze.setTime( lastModified );
964         ze.setMethod( az.doCompress ? ZipEntry.DEFLATED : ZipEntry.STORED );
965         
966         // should this zip file be modified?
967
File JavaDoc tmpFile = null;
968         try
969         {
970             if (me != null)
971             {
972                 tmpFile = FILEUTILS.createTempFile( "z", ".tmp", null );
973                 tmpFile.deleteOnExit();
974                 
975                 me.modify( this, in, tmpFile );
976                 
977                 in = new FileInputStream JavaDoc( tmpFile );
978             }
979             
980             /*
981             * ZipOutputStream.putNextEntry expects the ZipEntry to
982             * know its size and the CRC sum before you start writing
983             * the data when using STORED mode - unless it is seekable.
984             *
985             * This forces us to process the data twice.
986             */

987             if (!zOut.isSeekable() && !az.doCompress)
988             {
989                 long size = 0;
990                 CRC32 JavaDoc cal = new CRC32 JavaDoc();
991                 if (!in.markSupported())
992                 {
993                     // Store data into a byte[]
994
ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
995     
996                     byte[] buffer = new byte[8 * 1024];
997                     int count = 0;
998                     do {
999                         size += count;
1000                        cal.update(buffer, 0, count);
1001                        bos.write(buffer, 0, count);
1002                        count = in.read(buffer, 0, buffer.length);
1003                    } while (count != -1);
1004                    in = new ByteArrayInputStream JavaDoc(bos.toByteArray());
1005                }
1006                else
1007                {
1008                    in.mark(Integer.MAX_VALUE);
1009                    byte[] buffer = new byte[8 * 1024];
1010                    int count = 0;
1011                    do
1012                    {
1013                        size += count;
1014                        cal.update(buffer, 0, count);
1015                        count = in.read(buffer, 0, buffer.length);
1016                    } while (count != -1);
1017                    in.reset();
1018                }
1019                ze.setSize(size);
1020                ze.setCrc(cal.getValue());
1021            }
1022            
1023            ze.setUnixMode(mode);
1024            zOut.putNextEntry(ze);
1025            
1026            byte[] buffer = new byte[BUFFER_SIZE];
1027            int count = 0;
1028            do
1029            {
1030                if (count != 0)
1031                {
1032                    zOut.write(buffer, 0, count);
1033                }
1034                count = in.read(buffer, 0, BUFFER_SIZE);
1035            } while (count != -1);
1036            
1037            addedFiles.addElement(vPath);
1038        }
1039        finally
1040        {
1041            // close the input stream before deleting the temp file.
1042
if (in != null)
1043            {
1044                in.close();
1045            }
1046            
1047            if (tmpFile != null)
1048            {
1049                delete( tmpFile );
1050            }
1051        }
1052    }
1053    
1054    
1055    
1056    /**
1057     * method for subclasses to override
1058     */

1059    protected void initZipOutputStream(ZipOutputStream zOut)
1060            throws IOException JavaDoc, BuildException
1061    {
1062    }
1063
1064    /**
1065     * method for subclasses to override
1066     */

1067    protected void finalizeZipOutputStream(ZipOutputStream zOut)
1068            throws IOException JavaDoc, BuildException
1069    {
1070        zOut.finish();
1071    }
1072    
1073    /**
1074     * (pulled from the ant Delete task)
1075     * Attempt to fix possible race condition when deleting
1076     * files on WinXP. If the delete does not work,
1077     * wait a little and try again.
1078     */

1079    private static boolean delete(File JavaDoc f)
1080    {
1081        if (!f.delete())
1082        {
1083            try
1084            {
1085                Thread.sleep( DELETE_RETRY_SLEEP_MILLIS );
1086            }
1087            catch (InterruptedException JavaDoc ex)
1088            {
1089                // ignore
1090
}
1091            return f.delete();
1092        }
1093        return true;
1094    }
1095}
1096
1097
Popular Tags