Source Code Cross Referenced for Zip.java in  » Build » ANT » org » apache » tools » ant » taskdefs » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Build » ANT » org.apache.tools.ant.taskdefs 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
0003:         *  contributor license agreements.  See the NOTICE file distributed with
0004:         *  this work for additional information regarding copyright ownership.
0005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
0006:         *  (the "License"); you may not use this file except in compliance with
0007:         *  the License.  You may obtain a copy of the License at
0008:         *
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         *  Unless required by applicable law or agreed to in writing, software
0012:         *  distributed under the License is distributed on an "AS IS" BASIS,
0013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         *  See the License for the specific language governing permissions and
0015:         *  limitations under the License.
0016:         *
0017:         */
0018:        package org.apache.tools.ant.taskdefs;
0019:
0020:        import java.io.ByteArrayInputStream;
0021:        import java.io.ByteArrayOutputStream;
0022:        import java.io.File;
0023:        import java.io.FileInputStream;
0024:        import java.io.FileOutputStream;
0025:        import java.io.IOException;
0026:        import java.io.InputStream;
0027:        import java.io.OutputStream;
0028:        import java.util.ArrayList;
0029:        import java.util.Enumeration;
0030:        import java.util.Hashtable;
0031:        import java.util.Iterator;
0032:        import java.util.Stack;
0033:        import java.util.Vector;
0034:        import java.util.zip.CRC32;
0035:
0036:        import org.apache.tools.ant.BuildException;
0037:        import org.apache.tools.ant.DirectoryScanner;
0038:        import org.apache.tools.ant.FileScanner;
0039:        import org.apache.tools.ant.Project;
0040:        import org.apache.tools.ant.types.ArchiveFileSet;
0041:        import org.apache.tools.ant.types.EnumeratedAttribute;
0042:        import org.apache.tools.ant.types.FileSet;
0043:        import org.apache.tools.ant.types.PatternSet;
0044:        import org.apache.tools.ant.types.Resource;
0045:        import org.apache.tools.ant.types.ResourceCollection;
0046:        import org.apache.tools.ant.types.ZipFileSet;
0047:        import org.apache.tools.ant.types.ZipScanner;
0048:        import org.apache.tools.ant.types.resources.ArchiveResource;
0049:        import org.apache.tools.ant.types.resources.FileResource;
0050:        import org.apache.tools.ant.util.FileNameMapper;
0051:        import org.apache.tools.ant.util.FileUtils;
0052:        import org.apache.tools.ant.util.GlobPatternMapper;
0053:        import org.apache.tools.ant.util.IdentityMapper;
0054:        import org.apache.tools.ant.util.MergingMapper;
0055:        import org.apache.tools.ant.util.ResourceUtils;
0056:        import org.apache.tools.zip.ZipEntry;
0057:        import org.apache.tools.zip.ZipExtraField;
0058:        import org.apache.tools.zip.ZipFile;
0059:        import org.apache.tools.zip.ZipOutputStream;
0060:
0061:        /**
0062:         * Create a Zip file.
0063:         *
0064:         * @since Ant 1.1
0065:         *
0066:         * @ant.task category="packaging"
0067:         */
0068:        public class Zip extends MatchingTask {
0069:            // CheckStyle:VisibilityModifier OFF - bc
0070:
0071:            protected File zipFile;
0072:            // use to scan own archive
0073:            private ZipScanner zs;
0074:            private File baseDir;
0075:            protected Hashtable entries = new Hashtable();
0076:            private Vector groupfilesets = new Vector();
0077:            private Vector filesetsFromGroupfilesets = new Vector();
0078:            protected String duplicate = "add";
0079:            private boolean doCompress = true;
0080:            private boolean doUpdate = false;
0081:            // shadow of the above if the value is altered in execute
0082:            private boolean savedDoUpdate = false;
0083:            private boolean doFilesonly = false;
0084:            protected String archiveType = "zip";
0085:
0086:            // For directories:
0087:            private static final long EMPTY_CRC = new CRC32().getValue();
0088:            protected String emptyBehavior = "skip";
0089:            private Vector resources = new Vector();
0090:            protected Hashtable addedDirs = new Hashtable();
0091:            private Vector addedFiles = new Vector();
0092:
0093:            protected boolean doubleFilePass = false;
0094:            protected boolean skipWriting = false;
0095:
0096:            private static final FileUtils FILE_UTILS = FileUtils
0097:                    .getFileUtils();
0098:
0099:            // CheckStyle:VisibilityModifier ON
0100:
0101:            /**
0102:             * true when we are adding new files into the Zip file, as opposed
0103:             * to adding back the unchanged files
0104:             */
0105:            private boolean addingNewFiles = false;
0106:
0107:            /**
0108:             * Encoding to use for filenames, defaults to the platform's
0109:             * default encoding.
0110:             */
0111:            private String encoding;
0112:
0113:            /**
0114:             * Whether the original compression of entries coming from a ZIP
0115:             * archive should be kept (for example when updating an archive).
0116:             *
0117:             * @since Ant 1.6
0118:             */
0119:            private boolean keepCompression = false;
0120:
0121:            /**
0122:             * Whether the file modification times will be rounded up to the
0123:             * next even number of seconds.
0124:             *
0125:             * @since Ant 1.6.2
0126:             */
0127:            private boolean roundUp = true;
0128:
0129:            /**
0130:             * Comment for the archive.
0131:             * @since Ant 1.6.3
0132:             */
0133:            private String comment = "";
0134:
0135:            private int level = ZipOutputStream.DEFAULT_COMPRESSION;
0136:
0137:            /**
0138:             * This is the name/location of where to
0139:             * create the .zip file.
0140:             * @param zipFile the path of the zipFile
0141:             * @deprecated since 1.5.x.
0142:             *             Use setDestFile(File) instead.
0143:             * @ant.attribute ignore="true"
0144:             */
0145:            public void setZipfile(File zipFile) {
0146:                setDestFile(zipFile);
0147:            }
0148:
0149:            /**
0150:             * This is the name/location of where to
0151:             * create the file.
0152:             * @param file the path of the zipFile
0153:             * @since Ant 1.5
0154:             * @deprecated since 1.5.x.
0155:             *             Use setDestFile(File) instead.
0156:             * @ant.attribute ignore="true"
0157:             */
0158:            public void setFile(File file) {
0159:                setDestFile(file);
0160:            }
0161:
0162:            /**
0163:             * The file to create; required.
0164:             * @since Ant 1.5
0165:             * @param destFile The new destination File
0166:             */
0167:            public void setDestFile(File destFile) {
0168:                this .zipFile = destFile;
0169:            }
0170:
0171:            /**
0172:             * The file to create.
0173:             * @return the destination file
0174:             * @since Ant 1.5.2
0175:             */
0176:            public File getDestFile() {
0177:                return zipFile;
0178:            }
0179:
0180:            /**
0181:             * Directory from which to archive files; optional.
0182:             * @param baseDir the base directory
0183:             */
0184:            public void setBasedir(File baseDir) {
0185:                this .baseDir = baseDir;
0186:            }
0187:
0188:            /**
0189:             * Whether we want to compress the files or only store them;
0190:             * optional, default=true;
0191:             * @param c if true, compress the files
0192:             */
0193:            public void setCompress(boolean c) {
0194:                doCompress = c;
0195:            }
0196:
0197:            /**
0198:             * Whether we want to compress the files or only store them;
0199:             * @return true if the files are to be compressed
0200:             * @since Ant 1.5.2
0201:             */
0202:            public boolean isCompress() {
0203:                return doCompress;
0204:            }
0205:
0206:            /**
0207:             * If true, emulate Sun's jar utility by not adding parent directories;
0208:             * optional, defaults to false.
0209:             * @param f if true, emulate sun's jar by not adding parent directories
0210:             */
0211:            public void setFilesonly(boolean f) {
0212:                doFilesonly = f;
0213:            }
0214:
0215:            /**
0216:             * If true, updates an existing file, otherwise overwrite
0217:             * any existing one; optional defaults to false.
0218:             * @param c if true, updates an existing zip file
0219:             */
0220:            public void setUpdate(boolean c) {
0221:                doUpdate = c;
0222:                savedDoUpdate = c;
0223:            }
0224:
0225:            /**
0226:             * Are we updating an existing archive?
0227:             * @return true if updating an existing archive
0228:             */
0229:            public boolean isInUpdateMode() {
0230:                return doUpdate;
0231:            }
0232:
0233:            /**
0234:             * Adds a set of files.
0235:             * @param set the fileset to add
0236:             */
0237:            public void addFileset(FileSet set) {
0238:                add(set);
0239:            }
0240:
0241:            /**
0242:             * Adds a set of files that can be
0243:             * read from an archive and be given a prefix/fullpath.
0244:             * @param set the zipfileset to add
0245:             */
0246:            public void addZipfileset(ZipFileSet set) {
0247:                add(set);
0248:            }
0249:
0250:            /**
0251:             * Add a collection of resources to be archived.
0252:             * @param a the resources to archive
0253:             * @since Ant 1.7
0254:             */
0255:            public void add(ResourceCollection a) {
0256:                resources.add(a);
0257:            }
0258:
0259:            /**
0260:             * Adds a group of zip files.
0261:             * @param set the group (a fileset) to add
0262:             */
0263:            public void addZipGroupFileset(FileSet set) {
0264:                groupfilesets.addElement(set);
0265:            }
0266:
0267:            /**
0268:             * Sets behavior for when a duplicate file is about to be added -
0269:             * one of <code>add</code>, <code>preserve</code> or <code>fail</code>.
0270:             * Possible values are: <code>add</code> (keep both
0271:             * of the files); <code>preserve</code> (keep the first version
0272:             * of the file found); <code>fail</code> halt a problem
0273:             * Default for zip tasks is <code>add</code>
0274:             * @param df a <code>Duplicate</code> enumerated value
0275:             */
0276:            public void setDuplicate(Duplicate df) {
0277:                duplicate = df.getValue();
0278:            }
0279:
0280:            /**
0281:             * Possible behaviors when there are no matching files for the task:
0282:             * "fail", "skip", or "create".
0283:             */
0284:            public static class WhenEmpty extends EnumeratedAttribute {
0285:                /**
0286:                 * The string values for the enumerated value
0287:                 * @return the values
0288:                 */
0289:                public String[] getValues() {
0290:                    return new String[] { "fail", "skip", "create" };
0291:                }
0292:            }
0293:
0294:            /**
0295:             * Sets behavior of the task when no files match.
0296:             * Possible values are: <code>fail</code> (throw an exception
0297:             * and halt the build); <code>skip</code> (do not create
0298:             * any archive, but issue a warning); <code>create</code>
0299:             * (make an archive with no entries).
0300:             * Default for zip tasks is <code>skip</code>;
0301:             * for jar tasks, <code>create</code>.
0302:             * @param we a <code>WhenEmpty</code> enumerated value
0303:             */
0304:            public void setWhenempty(WhenEmpty we) {
0305:                emptyBehavior = we.getValue();
0306:            }
0307:
0308:            /**
0309:             * Encoding to use for filenames, defaults to the platform's
0310:             * default encoding.
0311:             *
0312:             * <p>For a list of possible values see <a
0313:             * href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.</p>
0314:             * @param encoding the encoding name
0315:             */
0316:            public void setEncoding(String encoding) {
0317:                this .encoding = encoding;
0318:            }
0319:
0320:            /**
0321:             * Encoding to use for filenames.
0322:             * @return the name of the encoding to use
0323:             * @since Ant 1.5.2
0324:             */
0325:            public String getEncoding() {
0326:                return encoding;
0327:            }
0328:
0329:            /**
0330:             * Whether the original compression of entries coming from a ZIP
0331:             * archive should be kept (for example when updating an archive).
0332:             * Default is false.
0333:             * @param keep if true, keep the original compression
0334:             * @since Ant 1.6
0335:             */
0336:            public void setKeepCompression(boolean keep) {
0337:                keepCompression = keep;
0338:            }
0339:
0340:            /**
0341:             * Comment to use for archive.
0342:             *
0343:             * @param comment The content of the comment.
0344:             * @since Ant 1.6.3
0345:             */
0346:            public void setComment(String comment) {
0347:                this .comment = comment;
0348:            }
0349:
0350:            /**
0351:             * Comment of the archive
0352:             *
0353:             * @return Comment of the archive.
0354:             * @since Ant 1.6.3
0355:             */
0356:            public String getComment() {
0357:                return comment;
0358:            }
0359:
0360:            /**
0361:             * Set the compression level to use.  Default is
0362:             * ZipOutputStream.DEFAULT_COMPRESSION.
0363:             * @param level compression level.
0364:             * @since Ant 1.7
0365:             */
0366:            public void setLevel(int level) {
0367:                this .level = level;
0368:            }
0369:
0370:            /**
0371:             * Get the compression level.
0372:             * @return compression level.
0373:             * @since Ant 1.7
0374:             */
0375:            public int getLevel() {
0376:                return level;
0377:            }
0378:
0379:            /**
0380:             * Whether the file modification times will be rounded up to the
0381:             * next even number of seconds.
0382:             *
0383:             * <p>Zip archives store file modification times with a
0384:             * granularity of two seconds, so the times will either be rounded
0385:             * up or down.  If you round down, the archive will always seem
0386:             * out-of-date when you rerun the task, so the default is to round
0387:             * up.  Rounding up may lead to a different type of problems like
0388:             * JSPs inside a web archive that seem to be slightly more recent
0389:             * than precompiled pages, rendering precompilation useless.</p>
0390:             * @param r a <code>boolean</code> value
0391:             * @since Ant 1.6.2
0392:             */
0393:            public void setRoundUp(boolean r) {
0394:                roundUp = r;
0395:            }
0396:
0397:            /**
0398:             * validate and build
0399:             * @throws BuildException on error
0400:             */
0401:            public void execute() throws BuildException {
0402:
0403:                if (doubleFilePass) {
0404:                    skipWriting = true;
0405:                    executeMain();
0406:                    skipWriting = false;
0407:                    executeMain();
0408:                } else {
0409:                    executeMain();
0410:                }
0411:            }
0412:
0413:            /**
0414:             * Build the zip file.
0415:             * This is called twice if doubleFilePass is true.
0416:             * @throws BuildException on error
0417:             */
0418:            public void executeMain() throws BuildException {
0419:
0420:                if (baseDir == null && resources.size() == 0
0421:                        && groupfilesets.size() == 0
0422:                        && "zip".equals(archiveType)) {
0423:                    throw new BuildException("basedir attribute must be set, "
0424:                            + "or at least one "
0425:                            + "resource collection must be given!");
0426:                }
0427:
0428:                if (zipFile == null) {
0429:                    throw new BuildException("You must specify the "
0430:                            + archiveType + " file to create!");
0431:                }
0432:
0433:                if (zipFile.exists() && !zipFile.isFile()) {
0434:                    throw new BuildException(zipFile + " is not a file.");
0435:                }
0436:
0437:                if (zipFile.exists() && !zipFile.canWrite()) {
0438:                    throw new BuildException(zipFile + " is read-only.");
0439:                }
0440:
0441:                // Renamed version of original file, if it exists
0442:                File renamedFile = null;
0443:                addingNewFiles = true;
0444:
0445:                // Whether or not an actual update is required -
0446:                // we don't need to update if the original file doesn't exist
0447:                if (doUpdate && !zipFile.exists()) {
0448:                    doUpdate = false;
0449:                    log("ignoring update attribute as " + archiveType
0450:                            + " doesn't exist.", Project.MSG_DEBUG);
0451:                }
0452:
0453:                // Add the files found in groupfileset to fileset
0454:                for (int i = 0; i < groupfilesets.size(); i++) {
0455:
0456:                    log("Processing groupfileset ", Project.MSG_VERBOSE);
0457:                    FileSet fs = (FileSet) groupfilesets.elementAt(i);
0458:                    FileScanner scanner = fs.getDirectoryScanner(getProject());
0459:                    String[] files = scanner.getIncludedFiles();
0460:                    File basedir = scanner.getBasedir();
0461:                    for (int j = 0; j < files.length; j++) {
0462:
0463:                        log("Adding file " + files[j] + " to fileset",
0464:                                Project.MSG_VERBOSE);
0465:                        ZipFileSet zf = new ZipFileSet();
0466:                        zf.setProject(getProject());
0467:                        zf.setSrc(new File(basedir, files[j]));
0468:                        add(zf);
0469:                        filesetsFromGroupfilesets.addElement(zf);
0470:                    }
0471:                }
0472:
0473:                // collect filesets to pass them to getResourcesToAdd
0474:                Vector vfss = new Vector();
0475:                if (baseDir != null) {
0476:                    FileSet fs = (FileSet) getImplicitFileSet().clone();
0477:                    fs.setDir(baseDir);
0478:                    vfss.addElement(fs);
0479:                }
0480:                for (int i = 0; i < resources.size(); i++) {
0481:                    ResourceCollection rc = (ResourceCollection) resources
0482:                            .elementAt(i);
0483:                    vfss.addElement(rc);
0484:                }
0485:
0486:                ResourceCollection[] fss = new ResourceCollection[vfss.size()];
0487:                vfss.copyInto(fss);
0488:                boolean success = false;
0489:                try {
0490:                    // can also handle empty archives
0491:                    ArchiveState state = getResourcesToAdd(fss, zipFile, false);
0492:
0493:                    // quick exit if the target is up to date
0494:                    if (!state.isOutOfDate()) {
0495:                        return;
0496:                    }
0497:
0498:                    if (!zipFile.exists() && state.isWithoutAnyResources()) {
0499:                        createEmptyZip(zipFile);
0500:                        return;
0501:                    }
0502:                    Resource[][] addThem = state.getResourcesToAdd();
0503:
0504:                    if (doUpdate) {
0505:                        renamedFile = FILE_UTILS.createTempFile("zip", ".tmp",
0506:                                zipFile.getParentFile());
0507:                        renamedFile.deleteOnExit();
0508:
0509:                        try {
0510:                            FILE_UTILS.rename(zipFile, renamedFile);
0511:                        } catch (SecurityException e) {
0512:                            throw new BuildException(
0513:                                    "Not allowed to rename old file ("
0514:                                            + zipFile.getAbsolutePath()
0515:                                            + ") to temporary file");
0516:                        } catch (IOException e) {
0517:                            throw new BuildException(
0518:                                    "Unable to rename old file ("
0519:                                            + zipFile.getAbsolutePath()
0520:                                            + ") to temporary file");
0521:                        }
0522:                    }
0523:
0524:                    String action = doUpdate ? "Updating " : "Building ";
0525:
0526:                    log(action + archiveType + ": " + zipFile.getAbsolutePath());
0527:
0528:                    ZipOutputStream zOut = null;
0529:                    try {
0530:                        if (!skipWriting) {
0531:                            zOut = new ZipOutputStream(zipFile);
0532:
0533:                            zOut.setEncoding(encoding);
0534:                            zOut
0535:                                    .setMethod(doCompress ? ZipOutputStream.DEFLATED
0536:                                            : ZipOutputStream.STORED);
0537:                            zOut.setLevel(level);
0538:                        }
0539:                        initZipOutputStream(zOut);
0540:
0541:                        // Add the explicit resource collections to the archive.
0542:                        for (int i = 0; i < fss.length; i++) {
0543:                            if (addThem[i].length != 0) {
0544:                                addResources(fss[i], addThem[i], zOut);
0545:                            }
0546:                        }
0547:
0548:                        if (doUpdate) {
0549:                            addingNewFiles = false;
0550:                            ZipFileSet oldFiles = new ZipFileSet();
0551:                            oldFiles.setProject(getProject());
0552:                            oldFiles.setSrc(renamedFile);
0553:                            oldFiles.setDefaultexcludes(false);
0554:
0555:                            for (int i = 0; i < addedFiles.size(); i++) {
0556:                                PatternSet.NameEntry ne = oldFiles
0557:                                        .createExclude();
0558:                                ne.setName((String) addedFiles.elementAt(i));
0559:                            }
0560:                            DirectoryScanner ds = oldFiles
0561:                                    .getDirectoryScanner(getProject());
0562:                            ((ZipScanner) ds).setEncoding(encoding);
0563:
0564:                            String[] f = ds.getIncludedFiles();
0565:                            Resource[] r = new Resource[f.length];
0566:                            for (int i = 0; i < f.length; i++) {
0567:                                r[i] = ds.getResource(f[i]);
0568:                            }
0569:
0570:                            if (!doFilesonly) {
0571:                                String[] d = ds.getIncludedDirectories();
0572:                                Resource[] dr = new Resource[d.length];
0573:                                for (int i = 0; i < d.length; i++) {
0574:                                    dr[i] = ds.getResource(d[i]);
0575:                                }
0576:                                Resource[] tmp = r;
0577:                                r = new Resource[tmp.length + dr.length];
0578:                                System.arraycopy(dr, 0, r, 0, dr.length);
0579:                                System.arraycopy(tmp, 0, r, dr.length,
0580:                                        tmp.length);
0581:                            }
0582:                            addResources(oldFiles, r, zOut);
0583:                        }
0584:                        if (zOut != null) {
0585:                            zOut.setComment(comment);
0586:                        }
0587:                        finalizeZipOutputStream(zOut);
0588:
0589:                        // If we've been successful on an update, delete the
0590:                        // temporary file
0591:                        if (doUpdate) {
0592:                            if (!renamedFile.delete()) {
0593:                                log("Warning: unable to delete temporary file "
0594:                                        + renamedFile.getName(),
0595:                                        Project.MSG_WARN);
0596:                            }
0597:                        }
0598:                        success = true;
0599:                    } finally {
0600:                        // Close the output stream.
0601:                        try {
0602:                            if (zOut != null) {
0603:                                zOut.close();
0604:                            }
0605:                        } catch (IOException ex) {
0606:                            // If we're in this finally clause because of an
0607:                            // exception, we don't really care if there's an
0608:                            // exception when closing the stream. E.g. if it
0609:                            // throws "ZIP file must have at least one entry",
0610:                            // because an exception happened before we added
0611:                            // any files, then we must swallow this
0612:                            // exception. Otherwise, the error that's reported
0613:                            // will be the close() error, which is not the
0614:                            // real cause of the problem.
0615:                            if (success) {
0616:                                throw ex;
0617:                            }
0618:                        }
0619:                    }
0620:                } catch (IOException ioe) {
0621:                    String msg = "Problem creating " + archiveType + ": "
0622:                            + ioe.getMessage();
0623:
0624:                    // delete a bogus ZIP file (but only if it's not the original one)
0625:                    if ((!doUpdate || renamedFile != null) && !zipFile.delete()) {
0626:                        msg += " (and the archive is probably corrupt but I could not "
0627:                                + "delete it)";
0628:                    }
0629:
0630:                    if (doUpdate && renamedFile != null) {
0631:                        try {
0632:                            FILE_UTILS.rename(renamedFile, zipFile);
0633:                        } catch (IOException e) {
0634:                            msg += " (and I couldn't rename the temporary file "
0635:                                    + renamedFile.getName() + " back)";
0636:                        }
0637:                    }
0638:
0639:                    throw new BuildException(msg, ioe, getLocation());
0640:                } finally {
0641:                    cleanUp();
0642:                }
0643:            }
0644:
0645:            /**
0646:             * Indicates if the task is adding new files into the archive as opposed to
0647:             * copying back unchanged files from the backup copy
0648:             * @return true if adding new files
0649:             */
0650:            protected final boolean isAddingNewFiles() {
0651:                return addingNewFiles;
0652:            }
0653:
0654:            /**
0655:             * Add the given resources.
0656:             *
0657:             * @param fileset may give additional information like fullpath or
0658:             * permissions.
0659:             * @param resources the resources to add
0660:             * @param zOut the stream to write to
0661:             * @throws IOException on error
0662:             *
0663:             * @since Ant 1.5.2
0664:             */
0665:            protected final void addResources(FileSet fileset,
0666:                    Resource[] resources, ZipOutputStream zOut)
0667:                    throws IOException {
0668:
0669:                String prefix = "";
0670:                String fullpath = "";
0671:                int dirMode = ArchiveFileSet.DEFAULT_DIR_MODE;
0672:                int fileMode = ArchiveFileSet.DEFAULT_FILE_MODE;
0673:
0674:                ArchiveFileSet zfs = null;
0675:                if (fileset instanceof  ArchiveFileSet) {
0676:                    zfs = (ArchiveFileSet) fileset;
0677:                    prefix = zfs.getPrefix(getProject());
0678:                    fullpath = zfs.getFullpath(getProject());
0679:                    dirMode = zfs.getDirMode(getProject());
0680:                    fileMode = zfs.getFileMode(getProject());
0681:                }
0682:
0683:                if (prefix.length() > 0 && fullpath.length() > 0) {
0684:                    throw new BuildException(
0685:                            "Both prefix and fullpath attributes must"
0686:                                    + " not be set on the same fileset.");
0687:                }
0688:
0689:                if (resources.length != 1 && fullpath.length() > 0) {
0690:                    throw new BuildException(
0691:                            "fullpath attribute may only be specified"
0692:                                    + " for filesets that specify a single"
0693:                                    + " file.");
0694:                }
0695:
0696:                if (prefix.length() > 0) {
0697:                    if (!prefix.endsWith("/") && !prefix.endsWith("\\")) {
0698:                        prefix += "/";
0699:                    }
0700:                    addParentDirs(null, prefix, zOut, "", dirMode);
0701:                }
0702:
0703:                ZipFile zf = null;
0704:                try {
0705:                    boolean dealingWithFiles = false;
0706:                    File base = null;
0707:
0708:                    if (zfs == null || zfs.getSrc(getProject()) == null) {
0709:                        dealingWithFiles = true;
0710:                        base = fileset.getDir(getProject());
0711:                    } else if (zfs instanceof  ZipFileSet) {
0712:                        zf = new ZipFile(zfs.getSrc(getProject()), encoding);
0713:                    }
0714:
0715:                    for (int i = 0; i < resources.length; i++) {
0716:                        String name = null;
0717:                        if (fullpath.length() > 0) {
0718:                            name = fullpath;
0719:                        } else {
0720:                            name = resources[i].getName();
0721:                        }
0722:                        name = name.replace(File.separatorChar, '/');
0723:
0724:                        if ("".equals(name)) {
0725:                            continue;
0726:                        }
0727:                        if (resources[i].isDirectory() && !name.endsWith("/")) {
0728:                            name = name + "/";
0729:                        }
0730:
0731:                        if (!doFilesonly && !dealingWithFiles
0732:                                && resources[i].isDirectory()
0733:                                && !zfs.hasDirModeBeenSet()) {
0734:                            int nextToLastSlash = name.lastIndexOf("/", name
0735:                                    .length() - 2);
0736:                            if (nextToLastSlash != -1) {
0737:                                addParentDirs(base, name.substring(0,
0738:                                        nextToLastSlash + 1), zOut, prefix,
0739:                                        dirMode);
0740:                            }
0741:                            if (zf != null) {
0742:                                ZipEntry ze = zf.getEntry(resources[i]
0743:                                        .getName());
0744:                                addParentDirs(base, name, zOut, prefix, ze
0745:                                        .getUnixMode());
0746:                            } else {
0747:                                ArchiveResource tr = (ArchiveResource) resources[i];
0748:                                addParentDirs(base, name, zOut, prefix, tr
0749:                                        .getMode());
0750:                            }
0751:
0752:                        } else {
0753:                            addParentDirs(base, name, zOut, prefix, dirMode);
0754:                        }
0755:
0756:                        if (!resources[i].isDirectory() && dealingWithFiles) {
0757:                            File f = FILE_UTILS.resolveFile(base, resources[i]
0758:                                    .getName());
0759:                            zipFile(f, zOut, prefix + name, fileMode);
0760:                        } else if (!resources[i].isDirectory()) {
0761:                            if (zf != null) {
0762:                                ZipEntry ze = zf.getEntry(resources[i]
0763:                                        .getName());
0764:
0765:                                if (ze != null) {
0766:                                    boolean oldCompress = doCompress;
0767:                                    if (keepCompression) {
0768:                                        doCompress = (ze.getMethod() == ZipEntry.DEFLATED);
0769:                                    }
0770:                                    try {
0771:                                        zipFile(
0772:                                                zf.getInputStream(ze),
0773:                                                zOut,
0774:                                                prefix + name,
0775:                                                ze.getTime(),
0776:                                                zfs.getSrc(getProject()),
0777:                                                zfs.hasFileModeBeenSet() ? fileMode
0778:                                                        : ze.getUnixMode());
0779:                                    } finally {
0780:                                        doCompress = oldCompress;
0781:                                    }
0782:                                }
0783:                            } else {
0784:                                ArchiveResource tr = (ArchiveResource) resources[i];
0785:                                InputStream is = null;
0786:                                try {
0787:                                    is = tr.getInputStream();
0788:                                    zipFile(is, zOut, prefix + name,
0789:                                            resources[i].getLastModified(), zfs
0790:                                                    .getSrc(getProject()),
0791:                                            zfs.hasFileModeBeenSet() ? fileMode
0792:                                                    : tr.getMode());
0793:                                } finally {
0794:                                    FileUtils.close(is);
0795:                                }
0796:                            }
0797:                        }
0798:                    }
0799:                } finally {
0800:                    if (zf != null) {
0801:                        zf.close();
0802:                    }
0803:                }
0804:            }
0805:
0806:            /**
0807:             * Add the given resources.
0808:             *
0809:             * @param rc may give additional information like fullpath or
0810:             * permissions.
0811:             * @param resources the resources to add
0812:             * @param zOut the stream to write to
0813:             * @throws IOException on error
0814:             *
0815:             * @since Ant 1.7
0816:             */
0817:            protected final void addResources(ResourceCollection rc,
0818:                    Resource[] resources, ZipOutputStream zOut)
0819:                    throws IOException {
0820:                if (rc instanceof  FileSet) {
0821:                    addResources((FileSet) rc, resources, zOut);
0822:                    return;
0823:                }
0824:                for (int i = 0; i < resources.length; i++) {
0825:                    String name = resources[i].getName().replace(
0826:                            File.separatorChar, '/');
0827:                    if ("".equals(name)) {
0828:                        continue;
0829:                    }
0830:                    if (resources[i].isDirectory() && doFilesonly) {
0831:                        continue;
0832:                    }
0833:                    File base = null;
0834:                    if (resources[i] instanceof  FileResource) {
0835:                        base = ((FileResource) resources[i]).getBaseDir();
0836:                    }
0837:                    if (resources[i].isDirectory()) {
0838:                        if (!name.endsWith("/")) {
0839:                            name = name + "/";
0840:                        }
0841:                    }
0842:
0843:                    addParentDirs(base, name, zOut, "",
0844:                            ArchiveFileSet.DEFAULT_DIR_MODE);
0845:
0846:                    if (!resources[i].isDirectory()) {
0847:                        if (resources[i] instanceof  FileResource) {
0848:                            File f = ((FileResource) resources[i]).getFile();
0849:                            zipFile(f, zOut, name,
0850:                                    ArchiveFileSet.DEFAULT_FILE_MODE);
0851:                        } else {
0852:                            InputStream is = null;
0853:                            try {
0854:                                is = resources[i].getInputStream();
0855:                                zipFile(is, zOut, name, resources[i]
0856:                                        .getLastModified(), null,
0857:                                        ArchiveFileSet.DEFAULT_FILE_MODE);
0858:                            } finally {
0859:                                FileUtils.close(is);
0860:                            }
0861:                        }
0862:                    }
0863:                }
0864:            }
0865:
0866:            /**
0867:             * method for subclasses to override
0868:             * @param zOut the zip output stream
0869:             * @throws IOException on output error
0870:             * @throws BuildException on other errors
0871:             */
0872:            protected void initZipOutputStream(ZipOutputStream zOut)
0873:                    throws IOException, BuildException {
0874:            }
0875:
0876:            /**
0877:             * method for subclasses to override
0878:             * @param zOut the zip output stream
0879:             * @throws IOException on output error
0880:             * @throws BuildException on other errors
0881:             */
0882:            protected void finalizeZipOutputStream(ZipOutputStream zOut)
0883:                    throws IOException, BuildException {
0884:            }
0885:
0886:            /**
0887:             * Create an empty zip file
0888:             * @param zipFile the zip file
0889:             * @return true for historic reasons
0890:             * @throws BuildException on error
0891:             */
0892:            protected boolean createEmptyZip(File zipFile)
0893:                    throws BuildException {
0894:                // In this case using java.util.zip will not work
0895:                // because it does not permit a zero-entry archive.
0896:                // Must create it manually.
0897:                log("Note: creating empty " + archiveType + " archive "
0898:                        + zipFile, Project.MSG_INFO);
0899:                OutputStream os = null;
0900:                try {
0901:                    os = new FileOutputStream(zipFile);
0902:                    // Cf. PKZIP specification.
0903:                    byte[] empty = new byte[22];
0904:                    empty[0] = 80; // P
0905:                    empty[1] = 75; // K
0906:                    empty[2] = 5;
0907:                    empty[3] = 6;
0908:                    // remainder zeros
0909:                    os.write(empty);
0910:                } catch (IOException ioe) {
0911:                    throw new BuildException(
0912:                            "Could not create empty ZIP archive " + "("
0913:                                    + ioe.getMessage() + ")", ioe,
0914:                            getLocation());
0915:                } finally {
0916:                    if (os != null) {
0917:                        try {
0918:                            os.close();
0919:                        } catch (IOException e) {
0920:                            //ignore
0921:                        }
0922:                    }
0923:                }
0924:                return true;
0925:            }
0926:
0927:            /**
0928:             * @since Ant 1.5.2
0929:             */
0930:            private synchronized ZipScanner getZipScanner() {
0931:                if (zs == null) {
0932:                    zs = new ZipScanner();
0933:                    zs.setEncoding(encoding);
0934:                    zs.setSrc(zipFile);
0935:                }
0936:                return zs;
0937:            }
0938:
0939:            /**
0940:             * Collect the resources that are newer than the corresponding
0941:             * entries (or missing) in the original archive.
0942:             *
0943:             * <p>If we are going to recreate the archive instead of updating
0944:             * it, all resources should be considered as new, if a single one
0945:             * is.  Because of this, subclasses overriding this method must
0946:             * call <code>super.getResourcesToAdd</code> and indicate with the
0947:             * third arg if they already know that the archive is
0948:             * out-of-date.</p>
0949:             *
0950:             * <p>This method first delegates to getNonFileSetResourceToAdd
0951:             * and then invokes the FileSet-arg version.  All this to keep
0952:             * backwards compatibility for subclasses that don't know how to
0953:             * deal with non-FileSet ResourceCollections.</p>
0954:             *
0955:             * @param rcs The resource collections to grab resources from
0956:             * @param zipFile intended archive file (may or may not exist)
0957:             * @param needsUpdate whether we already know that the archive is
0958:             * out-of-date.  Subclasses overriding this method are supposed to
0959:             * set this value correctly in their call to
0960:             * <code>super.getResourcesToAdd</code>.
0961:             * @return an array of resources to add for each fileset passed in as well
0962:             *         as a flag that indicates whether the archive is uptodate.
0963:             *
0964:             * @exception BuildException if it likes
0965:             * @since Ant 1.7
0966:             */
0967:            protected ArchiveState getResourcesToAdd(ResourceCollection[] rcs,
0968:                    File zipFile, boolean needsUpdate) throws BuildException {
0969:                ArrayList filesets = new ArrayList();
0970:                ArrayList rest = new ArrayList();
0971:                for (int i = 0; i < rcs.length; i++) {
0972:                    if (rcs[i] instanceof  FileSet) {
0973:                        filesets.add(rcs[i]);
0974:                    } else {
0975:                        rest.add(rcs[i]);
0976:                    }
0977:                }
0978:                ResourceCollection[] rc = (ResourceCollection[]) rest
0979:                        .toArray(new ResourceCollection[rest.size()]);
0980:                ArchiveState as = getNonFileSetResourcesToAdd(rc, zipFile,
0981:                        needsUpdate);
0982:
0983:                FileSet[] fs = (FileSet[]) filesets
0984:                        .toArray(new FileSet[filesets.size()]);
0985:                ArchiveState as2 = getResourcesToAdd(fs, zipFile, as
0986:                        .isOutOfDate());
0987:                if (!as.isOutOfDate() && as2.isOutOfDate()) {
0988:                    /*
0989:                     * Bad luck.
0990:                     *
0991:                     * There are resources in the filesets that make the
0992:                     * archive out of date, but not in the non-fileset
0993:                     * resources. We need to rescan the non-FileSets to grab
0994:                     * all of them now.
0995:                     */
0996:                    as = getNonFileSetResourcesToAdd(rc, zipFile, true);
0997:                }
0998:
0999:                Resource[][] toAdd = new Resource[rcs.length][];
1000:                int fsIndex = 0;
1001:                int restIndex = 0;
1002:                for (int i = 0; i < rcs.length; i++) {
1003:                    if (rcs[i] instanceof  FileSet) {
1004:                        toAdd[i] = as2.getResourcesToAdd()[fsIndex++];
1005:                    } else {
1006:                        toAdd[i] = as.getResourcesToAdd()[restIndex++];
1007:                    }
1008:                }
1009:                return new ArchiveState(as2.isOutOfDate(), toAdd);
1010:            }
1011:
1012:            /**
1013:             * Collect the resources that are newer than the corresponding
1014:             * entries (or missing) in the original archive.
1015:             *
1016:             * <p>If we are going to recreate the archive instead of updating
1017:             * it, all resources should be considered as new, if a single one
1018:             * is.  Because of this, subclasses overriding this method must
1019:             * call <code>super.getResourcesToAdd</code> and indicate with the
1020:             * third arg if they already know that the archive is
1021:             * out-of-date.</p>
1022:             *
1023:             * @param filesets The filesets to grab resources from
1024:             * @param zipFile intended archive file (may or may not exist)
1025:             * @param needsUpdate whether we already know that the archive is
1026:             * out-of-date.  Subclasses overriding this method are supposed to
1027:             * set this value correctly in their call to
1028:             * <code>super.getResourcesToAdd</code>.
1029:             * @return an array of resources to add for each fileset passed in as well
1030:             *         as a flag that indicates whether the archive is uptodate.
1031:             *
1032:             * @exception BuildException if it likes
1033:             */
1034:            protected ArchiveState getResourcesToAdd(FileSet[] filesets,
1035:                    File zipFile, boolean needsUpdate) throws BuildException {
1036:
1037:                Resource[][] initialResources = grabResources(filesets);
1038:                if (isEmpty(initialResources)) {
1039:                    if (needsUpdate && doUpdate) {
1040:                        /*
1041:                         * This is a rather hairy case.
1042:                         *
1043:                         * One of our subclasses knows that we need to update the
1044:                         * archive, but at the same time, there are no resources
1045:                         * known to us that would need to be added.  Only the
1046:                         * subclass seems to know what's going on.
1047:                         *
1048:                         * This happens if <jar> detects that the manifest has changed,
1049:                         * for example.  The manifest is not part of any resources
1050:                         * because of our support for inline <manifest>s.
1051:                         *
1052:                         * If we invoke createEmptyZip like Ant 1.5.2 did,
1053:                         * we'll loose all stuff that has been in the original
1054:                         * archive (bugzilla report 17780).
1055:                         */
1056:                        return new ArchiveState(true, initialResources);
1057:                    }
1058:
1059:                    if (emptyBehavior.equals("skip")) {
1060:                        if (doUpdate) {
1061:                            log(
1062:                                    archiveType
1063:                                            + " archive "
1064:                                            + zipFile
1065:                                            + " not updated because no new files were included.",
1066:                                    Project.MSG_VERBOSE);
1067:                        } else {
1068:                            log("Warning: skipping " + archiveType
1069:                                    + " archive " + zipFile
1070:                                    + " because no files were included.",
1071:                                    Project.MSG_WARN);
1072:                        }
1073:                    } else if (emptyBehavior.equals("fail")) {
1074:                        throw new BuildException("Cannot create " + archiveType
1075:                                + " archive " + zipFile
1076:                                + ": no files were included.", getLocation());
1077:                    } else {
1078:                        // Create.
1079:                        if (!zipFile.exists()) {
1080:                            needsUpdate = true;
1081:                        }
1082:                    }
1083:                    return new ArchiveState(needsUpdate, initialResources);
1084:                }
1085:
1086:                // initialResources is not empty
1087:
1088:                if (!zipFile.exists()) {
1089:                    return new ArchiveState(true, initialResources);
1090:                }
1091:
1092:                if (needsUpdate && !doUpdate) {
1093:                    // we are recreating the archive, need all resources
1094:                    return new ArchiveState(true, initialResources);
1095:                }
1096:
1097:                Resource[][] newerResources = new Resource[filesets.length][];
1098:
1099:                for (int i = 0; i < filesets.length; i++) {
1100:                    if (!(fileset instanceof  ZipFileSet)
1101:                            || ((ZipFileSet) fileset).getSrc(getProject()) == null) {
1102:                        File base = filesets[i].getDir(getProject());
1103:
1104:                        for (int j = 0; j < initialResources[i].length; j++) {
1105:                            File resourceAsFile = FILE_UTILS.resolveFile(base,
1106:                                    initialResources[i][j].getName());
1107:                            if (resourceAsFile.equals(zipFile)) {
1108:                                throw new BuildException(
1109:                                        "A zip file cannot include " + "itself",
1110:                                        getLocation());
1111:                            }
1112:                        }
1113:                    }
1114:                }
1115:
1116:                for (int i = 0; i < filesets.length; i++) {
1117:                    if (initialResources[i].length == 0) {
1118:                        newerResources[i] = new Resource[] {};
1119:                        continue;
1120:                    }
1121:
1122:                    FileNameMapper myMapper = new IdentityMapper();
1123:                    if (filesets[i] instanceof  ZipFileSet) {
1124:                        ZipFileSet zfs = (ZipFileSet) filesets[i];
1125:                        if (zfs.getFullpath(getProject()) != null
1126:                                && !zfs.getFullpath(getProject()).equals("")) {
1127:                            // in this case all files from origin map to
1128:                            // the fullPath attribute of the zipfileset at
1129:                            // destination
1130:                            MergingMapper fm = new MergingMapper();
1131:                            fm.setTo(zfs.getFullpath(getProject()));
1132:                            myMapper = fm;
1133:
1134:                        } else if (zfs.getPrefix(getProject()) != null
1135:                                && !zfs.getPrefix(getProject()).equals("")) {
1136:                            GlobPatternMapper gm = new GlobPatternMapper();
1137:                            gm.setFrom("*");
1138:                            String prefix = zfs.getPrefix(getProject());
1139:                            if (!prefix.endsWith("/") && !prefix.endsWith("\\")) {
1140:                                prefix += "/";
1141:                            }
1142:                            gm.setTo(prefix + "*");
1143:                            myMapper = gm;
1144:                        }
1145:                    }
1146:
1147:                    Resource[] resources = initialResources[i];
1148:                    if (doFilesonly) {
1149:                        resources = selectFileResources(resources);
1150:                    }
1151:
1152:                    newerResources[i] = ResourceUtils.selectOutOfDateSources(
1153:                            this , resources, myMapper, getZipScanner());
1154:                    needsUpdate = needsUpdate || (newerResources[i].length > 0);
1155:
1156:                    if (needsUpdate && !doUpdate) {
1157:                        // we will return initialResources anyway, no reason
1158:                        // to scan further.
1159:                        break;
1160:                    }
1161:                }
1162:
1163:                if (needsUpdate && !doUpdate) {
1164:                    // we are recreating the archive, need all resources
1165:                    return new ArchiveState(true, initialResources);
1166:                }
1167:
1168:                return new ArchiveState(needsUpdate, newerResources);
1169:            }
1170:
1171:            /**
1172:             * Collect the resources that are newer than the corresponding
1173:             * entries (or missing) in the original archive.
1174:             *
1175:             * <p>If we are going to recreate the archive instead of updating
1176:             * it, all resources should be considered as new, if a single one
1177:             * is.  Because of this, subclasses overriding this method must
1178:             * call <code>super.getResourcesToAdd</code> and indicate with the
1179:             * third arg if they already know that the archive is
1180:             * out-of-date.</p>
1181:             *
1182:             * @param rcs The filesets to grab resources from
1183:             * @param zipFile intended archive file (may or may not exist)
1184:             * @param needsUpdate whether we already know that the archive is
1185:             * out-of-date.  Subclasses overriding this method are supposed to
1186:             * set this value correctly in their call to
1187:             * <code>super.getResourcesToAdd</code>.
1188:             * @return an array of resources to add for each fileset passed in as well
1189:             *         as a flag that indicates whether the archive is uptodate.
1190:             *
1191:             * @exception BuildException if it likes
1192:             */
1193:            protected ArchiveState getNonFileSetResourcesToAdd(
1194:                    ResourceCollection[] rcs, File zipFile, boolean needsUpdate)
1195:                    throws BuildException {
1196:                /*
1197:                 * Backwards compatibility forces us to repeat the logic of
1198:                 * getResourcesToAdd(FileSet[], ...) here once again.
1199:                 */
1200:
1201:                Resource[][] initialResources = grabNonFileSetResources(rcs);
1202:                if (isEmpty(initialResources)) {
1203:                    // no emptyBehavior handling since the FileSet version
1204:                    // will take care of it.
1205:                    return new ArchiveState(needsUpdate, initialResources);
1206:                }
1207:
1208:                // initialResources is not empty
1209:
1210:                if (!zipFile.exists()) {
1211:                    return new ArchiveState(true, initialResources);
1212:                }
1213:
1214:                if (needsUpdate && !doUpdate) {
1215:                    // we are recreating the archive, need all resources
1216:                    return new ArchiveState(true, initialResources);
1217:                }
1218:
1219:                Resource[][] newerResources = new Resource[rcs.length][];
1220:
1221:                for (int i = 0; i < rcs.length; i++) {
1222:                    if (initialResources[i].length == 0) {
1223:                        newerResources[i] = new Resource[] {};
1224:                        continue;
1225:                    }
1226:
1227:                    for (int j = 0; j < initialResources[i].length; j++) {
1228:                        if (initialResources[i][j] instanceof  FileResource
1229:                                && zipFile
1230:                                        .equals(((FileResource) initialResources[i][j])
1231:                                                .getFile())) {
1232:                            throw new BuildException(
1233:                                    "A zip file cannot include " + "itself",
1234:                                    getLocation());
1235:                        }
1236:                    }
1237:
1238:                    Resource[] rs = initialResources[i];
1239:                    if (doFilesonly) {
1240:                        rs = selectFileResources(rs);
1241:                    }
1242:
1243:                    newerResources[i] = ResourceUtils.selectOutOfDateSources(
1244:                            this , rs, new IdentityMapper(), getZipScanner());
1245:                    needsUpdate = needsUpdate || (newerResources[i].length > 0);
1246:
1247:                    if (needsUpdate && !doUpdate) {
1248:                        // we will return initialResources anyway, no reason
1249:                        // to scan further.
1250:                        break;
1251:                    }
1252:                }
1253:
1254:                if (needsUpdate && !doUpdate) {
1255:                    // we are recreating the archive, need all resources
1256:                    return new ArchiveState(true, initialResources);
1257:                }
1258:
1259:                return new ArchiveState(needsUpdate, newerResources);
1260:            }
1261:
1262:            /**
1263:             * Fetch all included and not excluded resources from the sets.
1264:             *
1265:             * <p>Included directories will precede included files.</p>
1266:             * @param filesets an array of filesets
1267:             * @return the resources included
1268:             * @since Ant 1.5.2
1269:             */
1270:            protected Resource[][] grabResources(FileSet[] filesets) {
1271:                Resource[][] result = new Resource[filesets.length][];
1272:                for (int i = 0; i < filesets.length; i++) {
1273:                    boolean skipEmptyNames = true;
1274:                    if (filesets[i] instanceof  ZipFileSet) {
1275:                        ZipFileSet zfs = (ZipFileSet) filesets[i];
1276:                        skipEmptyNames = zfs.getPrefix(getProject()).equals("")
1277:                                && zfs.getFullpath(getProject()).equals("");
1278:                    }
1279:                    DirectoryScanner rs = filesets[i]
1280:                            .getDirectoryScanner(getProject());
1281:                    if (rs instanceof  ZipScanner) {
1282:                        ((ZipScanner) rs).setEncoding(encoding);
1283:                    }
1284:                    Vector resources = new Vector();
1285:                    if (!doFilesonly) {
1286:                        String[] directories = rs.getIncludedDirectories();
1287:                        for (int j = 0; j < directories.length; j++) {
1288:                            if (!"".equals(directories[j]) || !skipEmptyNames) {
1289:                                resources.addElement(rs
1290:                                        .getResource(directories[j]));
1291:                            }
1292:                        }
1293:                    }
1294:                    String[] files = rs.getIncludedFiles();
1295:                    for (int j = 0; j < files.length; j++) {
1296:                        if (!"".equals(files[j]) || !skipEmptyNames) {
1297:                            resources.addElement(rs.getResource(files[j]));
1298:                        }
1299:                    }
1300:
1301:                    result[i] = new Resource[resources.size()];
1302:                    resources.copyInto(result[i]);
1303:                }
1304:                return result;
1305:            }
1306:
1307:            /**
1308:             * Fetch all included and not excluded resources from the collections.
1309:             *
1310:             * <p>Included directories will precede included files.</p>
1311:             * @param rcs an array of resource collections
1312:             * @return the resources included
1313:             * @since Ant 1.7
1314:             */
1315:            protected Resource[][] grabNonFileSetResources(
1316:                    ResourceCollection[] rcs) {
1317:                Resource[][] result = new Resource[rcs.length][];
1318:                for (int i = 0; i < rcs.length; i++) {
1319:                    Iterator iter = rcs[i].iterator();
1320:                    ArrayList rs = new ArrayList();
1321:                    int lastDir = 0;
1322:                    while (iter.hasNext()) {
1323:                        Resource r = (Resource) iter.next();
1324:                        if (r.isExists()) {
1325:                            if (r.isDirectory()) {
1326:                                rs.add(lastDir++, r);
1327:                            } else {
1328:                                rs.add(r);
1329:                            }
1330:                        }
1331:                    }
1332:                    result[i] = (Resource[]) rs
1333:                            .toArray(new Resource[rs.size()]);
1334:                }
1335:                return result;
1336:            }
1337:
1338:            /**
1339:             * Add a directory to the zip stream.
1340:             * @param dir  the directort to add to the archive
1341:             * @param zOut the stream to write to
1342:             * @param vPath the name this entry shall have in the archive
1343:             * @param mode the Unix permissions to set.
1344:             * @throws IOException on error
1345:             * @since Ant 1.5.2
1346:             */
1347:            protected void zipDir(File dir, ZipOutputStream zOut, String vPath,
1348:                    int mode) throws IOException {
1349:                zipDir(dir, zOut, vPath, mode, null);
1350:            }
1351:
1352:            /**
1353:             * Add a directory to the zip stream.
1354:             * @param dir  the directort to add to the archive
1355:             * @param zOut the stream to write to
1356:             * @param vPath the name this entry shall have in the archive
1357:             * @param mode the Unix permissions to set.
1358:             * @param extra ZipExtraFields to add
1359:             * @throws IOException on error
1360:             * @since Ant 1.6.3
1361:             */
1362:            protected void zipDir(File dir, ZipOutputStream zOut, String vPath,
1363:                    int mode, ZipExtraField[] extra) throws IOException {
1364:                if (doFilesonly) {
1365:                    log("skipping directory " + vPath
1366:                            + " for file-only archive", Project.MSG_VERBOSE);
1367:                    return;
1368:                }
1369:                if (addedDirs.get(vPath) != null) {
1370:                    // don't add directories we've already added.
1371:                    // no warning if we try, it is harmless in and of itself
1372:                    return;
1373:                }
1374:
1375:                log("adding directory " + vPath, Project.MSG_VERBOSE);
1376:                addedDirs.put(vPath, vPath);
1377:
1378:                if (!skipWriting) {
1379:                    ZipEntry ze = new ZipEntry(vPath);
1380:                    if (dir != null && dir.exists()) {
1381:                        // ZIPs store time with a granularity of 2 seconds, round up
1382:                        ze.setTime(dir.lastModified() + (roundUp ? 1999 : 0));
1383:                    } else {
1384:                        // ZIPs store time with a granularity of 2 seconds, round up
1385:                        ze.setTime(System.currentTimeMillis()
1386:                                + (roundUp ? 1999 : 0));
1387:                    }
1388:                    ze.setSize(0);
1389:                    ze.setMethod(ZipEntry.STORED);
1390:                    // This is faintly ridiculous:
1391:                    ze.setCrc(EMPTY_CRC);
1392:                    ze.setUnixMode(mode);
1393:
1394:                    if (extra != null) {
1395:                        ze.setExtraFields(extra);
1396:                    }
1397:
1398:                    zOut.putNextEntry(ze);
1399:                }
1400:            }
1401:
1402:            /**
1403:             * Adds a new entry to the archive, takes care of duplicates as well.
1404:             *
1405:             * @param in the stream to read data for the entry from.
1406:             * @param zOut the stream to write to.
1407:             * @param vPath the name this entry shall have in the archive.
1408:             * @param lastModified last modification time for the entry.
1409:             * @param fromArchive the original archive we are copying this
1410:             * entry from, will be null if we are not copying from an archive.
1411:             * @param mode the Unix permissions to set.
1412:             *
1413:             * @since Ant 1.5.2
1414:             * @throws IOException on error
1415:             */
1416:            protected void zipFile(InputStream in, ZipOutputStream zOut,
1417:                    String vPath, long lastModified, File fromArchive, int mode)
1418:                    throws IOException {
1419:                if (entries.contains(vPath)) {
1420:
1421:                    if (duplicate.equals("preserve")) {
1422:                        log(vPath + " already added, skipping",
1423:                                Project.MSG_INFO);
1424:                        return;
1425:                    } else if (duplicate.equals("fail")) {
1426:                        throw new BuildException("Duplicate file " + vPath
1427:                                + " was found and the duplicate "
1428:                                + "attribute is 'fail'.");
1429:                    } else {
1430:                        // duplicate equal to add, so we continue
1431:                        log("duplicate file " + vPath + " found, adding.",
1432:                                Project.MSG_VERBOSE);
1433:                    }
1434:                } else {
1435:                    log("adding entry " + vPath, Project.MSG_VERBOSE);
1436:                }
1437:
1438:                entries.put(vPath, vPath);
1439:
1440:                if (!skipWriting) {
1441:                    ZipEntry ze = new ZipEntry(vPath);
1442:                    ze.setTime(lastModified);
1443:                    ze.setMethod(doCompress ? ZipEntry.DEFLATED
1444:                            : ZipEntry.STORED);
1445:
1446:                    /*
1447:                     * ZipOutputStream.putNextEntry expects the ZipEntry to
1448:                     * know its size and the CRC sum before you start writing
1449:                     * the data when using STORED mode - unless it is seekable.
1450:                     *
1451:                     * This forces us to process the data twice.
1452:                     */
1453:                    if (!zOut.isSeekable() && !doCompress) {
1454:                        long size = 0;
1455:                        CRC32 cal = new CRC32();
1456:                        if (!in.markSupported()) {
1457:                            // Store data into a byte[]
1458:                            ByteArrayOutputStream bos = new ByteArrayOutputStream();
1459:
1460:                            byte[] buffer = new byte[8 * 1024];
1461:                            int count = 0;
1462:                            do {
1463:                                size += count;
1464:                                cal.update(buffer, 0, count);
1465:                                bos.write(buffer, 0, count);
1466:                                count = in.read(buffer, 0, buffer.length);
1467:                            } while (count != -1);
1468:                            in = new ByteArrayInputStream(bos.toByteArray());
1469:
1470:                        } else {
1471:                            in.mark(Integer.MAX_VALUE);
1472:                            byte[] buffer = new byte[8 * 1024];
1473:                            int count = 0;
1474:                            do {
1475:                                size += count;
1476:                                cal.update(buffer, 0, count);
1477:                                count = in.read(buffer, 0, buffer.length);
1478:                            } while (count != -1);
1479:                            in.reset();
1480:                        }
1481:                        ze.setSize(size);
1482:                        ze.setCrc(cal.getValue());
1483:                    }
1484:
1485:                    ze.setUnixMode(mode);
1486:                    zOut.putNextEntry(ze);
1487:
1488:                    byte[] buffer = new byte[8 * 1024];
1489:                    int count = 0;
1490:                    do {
1491:                        if (count != 0) {
1492:                            zOut.write(buffer, 0, count);
1493:                        }
1494:                        count = in.read(buffer, 0, buffer.length);
1495:                    } while (count != -1);
1496:                }
1497:                addedFiles.addElement(vPath);
1498:            }
1499:
1500:            /**
1501:             * Method that gets called when adding from <code>java.io.File</code> instances.
1502:             *
1503:             * <p>This implementation delegates to the six-arg version.</p>
1504:             *
1505:             * @param file the file to add to the archive
1506:             * @param zOut the stream to write to
1507:             * @param vPath the name this entry shall have in the archive
1508:             * @param mode the Unix permissions to set.
1509:             * @throws IOException on error
1510:             *
1511:             * @since Ant 1.5.2
1512:             */
1513:            protected void zipFile(File file, ZipOutputStream zOut,
1514:                    String vPath, int mode) throws IOException {
1515:                if (file.equals(zipFile)) {
1516:                    throw new BuildException(
1517:                            "A zip file cannot include itself", getLocation());
1518:                }
1519:
1520:                FileInputStream fIn = new FileInputStream(file);
1521:                try {
1522:                    // ZIPs store time with a granularity of 2 seconds, round up
1523:                    zipFile(fIn, zOut, vPath, file.lastModified()
1524:                            + (roundUp ? 1999 : 0), null, mode);
1525:                } finally {
1526:                    fIn.close();
1527:                }
1528:            }
1529:
1530:            /**
1531:             * Ensure all parent dirs of a given entry have been added.
1532:             * @param baseDir the base directory to use (may be null)
1533:             * @param entry   the entry name to create directories from
1534:             * @param zOut    the stream to write to
1535:             * @param prefix  a prefix to place on the created entries
1536:             * @param dirMode the directory mode
1537:             * @throws IOException on error
1538:             * @since Ant 1.5.2
1539:             */
1540:            protected final void addParentDirs(File baseDir, String entry,
1541:                    ZipOutputStream zOut, String prefix, int dirMode)
1542:                    throws IOException {
1543:                if (!doFilesonly) {
1544:                    Stack directories = new Stack();
1545:                    int slashPos = entry.length();
1546:
1547:                    while ((slashPos = entry.lastIndexOf('/', slashPos - 1)) != -1) {
1548:                        String dir = entry.substring(0, slashPos + 1);
1549:                        if (addedDirs.get(prefix + dir) != null) {
1550:                            break;
1551:                        }
1552:                        directories.push(dir);
1553:                    }
1554:
1555:                    while (!directories.isEmpty()) {
1556:                        String dir = (String) directories.pop();
1557:                        File f = null;
1558:                        if (baseDir != null) {
1559:                            f = new File(baseDir, dir);
1560:                        } else {
1561:                            f = new File(dir);
1562:                        }
1563:                        zipDir(f, zOut, prefix + dir, dirMode);
1564:                    }
1565:                }
1566:            }
1567:
1568:            /**
1569:             * Do any clean up necessary to allow this instance to be used again.
1570:             *
1571:             * <p>When we get here, the Zip file has been closed and all we
1572:             * need to do is to reset some globals.</p>
1573:             *
1574:             * <p>This method will only reset globals that have been changed
1575:             * during execute(), it will not alter the attributes or nested
1576:             * child elements.  If you want to reset the instance so that you
1577:             * can later zip a completely different set of files, you must use
1578:             * the reset method.</p>
1579:             *
1580:             * @see #reset
1581:             */
1582:            protected void cleanUp() {
1583:                addedDirs.clear();
1584:                addedFiles.removeAllElements();
1585:                entries.clear();
1586:                addingNewFiles = false;
1587:                doUpdate = savedDoUpdate;
1588:                Enumeration e = filesetsFromGroupfilesets.elements();
1589:                while (e.hasMoreElements()) {
1590:                    ZipFileSet zf = (ZipFileSet) e.nextElement();
1591:                    resources.removeElement(zf);
1592:                }
1593:                filesetsFromGroupfilesets.removeAllElements();
1594:            }
1595:
1596:            /**
1597:             * Makes this instance reset all attributes to their default
1598:             * values and forget all children.
1599:             *
1600:             * @since Ant 1.5
1601:             *
1602:             * @see #cleanUp
1603:             */
1604:            public void reset() {
1605:                resources.removeAllElements();
1606:                zipFile = null;
1607:                baseDir = null;
1608:                groupfilesets.removeAllElements();
1609:                duplicate = "add";
1610:                archiveType = "zip";
1611:                doCompress = true;
1612:                emptyBehavior = "skip";
1613:                doUpdate = false;
1614:                doFilesonly = false;
1615:                encoding = null;
1616:            }
1617:
1618:            /**
1619:             * Check is the resource arrays are empty.
1620:             * @param r the arrays to check
1621:             * @return true if all individual arrays are empty
1622:             *
1623:             * @since Ant 1.5.2
1624:             */
1625:            protected static final boolean isEmpty(Resource[][] r) {
1626:                for (int i = 0; i < r.length; i++) {
1627:                    if (r[i].length > 0) {
1628:                        return false;
1629:                    }
1630:                }
1631:                return true;
1632:            }
1633:
1634:            /**
1635:             * Drops all non-file resources from the given array.
1636:             * @param orig the resources to filter
1637:             * @return the filters resources
1638:             * @since Ant 1.6
1639:             */
1640:            protected Resource[] selectFileResources(Resource[] orig) {
1641:                if (orig.length == 0) {
1642:                    return orig;
1643:                }
1644:
1645:                Vector v = new Vector(orig.length);
1646:                for (int i = 0; i < orig.length; i++) {
1647:                    if (!orig[i].isDirectory()) {
1648:                        v.addElement(orig[i]);
1649:                    } else {
1650:                        log("Ignoring directory " + orig[i].getName()
1651:                                + " as only files will be added.",
1652:                                Project.MSG_VERBOSE);
1653:                    }
1654:                }
1655:
1656:                if (v.size() != orig.length) {
1657:                    Resource[] r = new Resource[v.size()];
1658:                    v.copyInto(r);
1659:                    return r;
1660:                }
1661:                return orig;
1662:            }
1663:
1664:            /**
1665:             * Possible behaviors when a duplicate file is added:
1666:             * "add", "preserve" or "fail"
1667:             */
1668:            public static class Duplicate extends EnumeratedAttribute {
1669:                /**
1670:                 * @see EnumeratedAttribute#getValues()
1671:                 */
1672:                /** {@inheritDoc} */
1673:                public String[] getValues() {
1674:                    return new String[] { "add", "preserve", "fail" };
1675:                }
1676:            }
1677:
1678:            /**
1679:             * Holds the up-to-date status and the out-of-date resources of
1680:             * the original archive.
1681:             *
1682:             * @since Ant 1.5.3
1683:             */
1684:            public static class ArchiveState {
1685:                private boolean outOfDate;
1686:                private Resource[][] resourcesToAdd;
1687:
1688:                ArchiveState(boolean state, Resource[][] r) {
1689:                    outOfDate = state;
1690:                    resourcesToAdd = r;
1691:                }
1692:
1693:                /**
1694:                 * Return the outofdate status.
1695:                 * @return the outofdate status
1696:                 */
1697:                public boolean isOutOfDate() {
1698:                    return outOfDate;
1699:                }
1700:
1701:                /**
1702:                 * Get the resources to add.
1703:                 * @return the resources to add
1704:                 */
1705:                public Resource[][] getResourcesToAdd() {
1706:                    return resourcesToAdd;
1707:                }
1708:
1709:                /**
1710:                 * find out if there are absolutely no resources to add
1711:                 * @since Ant 1.6.3
1712:                 * @return true if there are no resources to add
1713:                 */
1714:                public boolean isWithoutAnyResources() {
1715:                    if (resourcesToAdd == null) {
1716:                        return true;
1717:                    }
1718:                    for (int counter = 0; counter < resourcesToAdd.length; counter++) {
1719:                        if (resourcesToAdd[counter] != null) {
1720:                            if (resourcesToAdd[counter].length > 0) {
1721:                                return false;
1722:                            }
1723:                        }
1724:                    }
1725:                    return true;
1726:                }
1727:            }
1728:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.