Source Code Cross Referenced for Jar.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:
0019:        package org.apache.tools.ant.taskdefs;
0020:
0021:        import java.io.ByteArrayInputStream;
0022:        import java.io.ByteArrayOutputStream;
0023:        import java.io.File;
0024:        import java.io.FileOutputStream;
0025:        import java.io.FileInputStream;
0026:        import java.io.IOException;
0027:        import java.io.InputStream;
0028:        import java.io.UnsupportedEncodingException;
0029:        import java.io.InputStreamReader;
0030:        import java.io.OutputStreamWriter;
0031:        import java.io.PrintWriter;
0032:        import java.io.Reader;
0033:        import java.util.ArrayList;
0034:        import java.util.Collections;
0035:        import java.util.Comparator;
0036:        import java.util.Enumeration;
0037:        import java.util.HashSet;
0038:        import java.util.Iterator;
0039:        import java.util.List;
0040:        import java.util.StringTokenizer;
0041:        import java.util.TreeMap;
0042:        import java.util.Vector;
0043:        import java.util.zip.ZipEntry;
0044:        import java.util.zip.ZipFile;
0045:        import org.apache.tools.ant.BuildException;
0046:        import org.apache.tools.ant.Project;
0047:        import org.apache.tools.ant.types.EnumeratedAttribute;
0048:        import org.apache.tools.ant.types.Path;
0049:        import org.apache.tools.ant.types.ResourceCollection;
0050:        import org.apache.tools.ant.types.ZipFileSet;
0051:        import org.apache.tools.ant.types.spi.Service;
0052:        import org.apache.tools.zip.JarMarker;
0053:        import org.apache.tools.zip.ZipExtraField;
0054:        import org.apache.tools.zip.ZipOutputStream;
0055:
0056:        /**
0057:         * Creates a JAR archive.
0058:         *
0059:         * @since Ant 1.1
0060:         *
0061:         * @ant.task category="packaging"
0062:         */
0063:        public class Jar extends Zip {
0064:            /** The index file name. */
0065:            private static final String INDEX_NAME = "META-INF/INDEX.LIST";
0066:
0067:            /** The manifest file name. */
0068:            private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
0069:
0070:            /**
0071:             * List of all known SPI Services
0072:             */
0073:            private List serviceList = new ArrayList();
0074:
0075:            /** merged manifests added through addConfiguredManifest */
0076:            private Manifest configuredManifest;
0077:            /** shadow of the above if upToDate check alters the value */
0078:            private Manifest savedConfiguredManifest;
0079:
0080:            /**  merged manifests added through filesets */
0081:            private Manifest filesetManifest;
0082:
0083:            /**
0084:             * Manifest of original archive, will be set to null if not in
0085:             * update mode.
0086:             */
0087:            private Manifest originalManifest;
0088:
0089:            /**
0090:             *  whether to merge fileset manifests;
0091:             *  value is true if filesetmanifest is 'merge' or 'mergewithoutmain'
0092:             */
0093:            private FilesetManifestConfig filesetManifestConfig;
0094:
0095:            /**
0096:             * whether to merge the main section of fileset manifests;
0097:             * value is true if filesetmanifest is 'merge'
0098:             */
0099:            private boolean mergeManifestsMain = true;
0100:
0101:            /** the manifest specified by the 'manifest' attribute **/
0102:            private Manifest manifest;
0103:
0104:            /** The encoding to use when reading in a manifest file */
0105:            private String manifestEncoding;
0106:
0107:            /**
0108:             * The file found from the 'manifest' attribute.  This can be
0109:             * either the location of a manifest, or the name of a jar added
0110:             * through a fileset.  If its the name of an added jar, the
0111:             * manifest is looked for in META-INF/MANIFEST.MF
0112:             */
0113:            private File manifestFile;
0114:
0115:            /** jar index is JDK 1.3+ only */
0116:            private boolean index = false;
0117:
0118:            /**
0119:             * whether to really create the archive in createEmptyZip, will
0120:             * get set in getResourcesToAdd.
0121:             */
0122:            private boolean createEmpty = false;
0123:
0124:            /**
0125:             * Stores all files that are in the root of the archive (i.e. that
0126:             * have a name that doesn't contain a slash) so they can get
0127:             * listed in the index.
0128:             *
0129:             * Will not be filled unless the user has asked for an index.
0130:             *
0131:             * @since Ant 1.6
0132:             */
0133:            private Vector rootEntries;
0134:
0135:            /**
0136:             * Path containing jars that shall be indexed in addition to this archive.
0137:             *
0138:             * @since Ant 1.6.2
0139:             */
0140:            private Path indexJars;
0141:
0142:            /**
0143:             * Extra fields needed to make Solaris recognize the archive as a jar file.
0144:             *
0145:             * @since Ant 1.6.3
0146:             */
0147:            private static final ZipExtraField[] JAR_MARKER = new ZipExtraField[] { JarMarker
0148:                    .getInstance() };
0149:
0150:            // CheckStyle:VisibilityModifier OFF - bc
0151:            protected String emptyBehavior = "create";
0152:
0153:            // CheckStyle:VisibilityModifier ON
0154:
0155:            /** constructor */
0156:            public Jar() {
0157:                super ();
0158:                archiveType = "jar";
0159:                emptyBehavior = "create";
0160:                setEncoding("UTF8");
0161:                rootEntries = new Vector();
0162:            }
0163:
0164:            /**
0165:             * Not used for jar files.
0166:             * @param we not used
0167:             * @ant.attribute ignore="true"
0168:             */
0169:            public void setWhenempty(WhenEmpty we) {
0170:                log(
0171:                        "JARs are never empty, they contain at least a manifest file",
0172:                        Project.MSG_WARN);
0173:            }
0174:
0175:            /**
0176:             * Indicates if a jar file should be created when it would only contain a
0177:             * manifest file.
0178:             * Possible values are: <code>fail</code> (throw an exception
0179:             * and halt the build); <code>skip</code> (do not create
0180:             * any archive, but issue a warning); <code>create</code>
0181:             * (make an archive with only a manifest file).
0182:             * Default is <code>create</code>;
0183:             * @param we a <code>WhenEmpty</code> enumerated value
0184:             */
0185:            public void setWhenmanifestonly(WhenEmpty we) {
0186:                emptyBehavior = we.getValue();
0187:            }
0188:
0189:            /**
0190:             * Set the destination file.
0191:             * @param jarFile the destination file
0192:             * @deprecated since 1.5.x.
0193:             *             Use setDestFile(File) instead.
0194:             */
0195:            public void setJarfile(File jarFile) {
0196:                setDestFile(jarFile);
0197:            }
0198:
0199:            /**
0200:             * Set whether or not to create an index list for classes.
0201:             * This may speed up classloading in some cases.
0202:             * @param flag a <code>boolean</code> value
0203:             */
0204:            public void setIndex(boolean flag) {
0205:                index = flag;
0206:            }
0207:
0208:            /**
0209:             * The character encoding to use in the manifest file.
0210:             *
0211:             * @param manifestEncoding the character encoding
0212:             */
0213:            public void setManifestEncoding(String manifestEncoding) {
0214:                this .manifestEncoding = manifestEncoding;
0215:            }
0216:
0217:            /**
0218:             * Allows the manifest for the archive file to be provided inline
0219:             * in the build file rather than in an external file.
0220:             *
0221:             * @param newManifest an embedded manifest element
0222:             * @throws ManifestException on error
0223:             */
0224:            public void addConfiguredManifest(Manifest newManifest)
0225:                    throws ManifestException {
0226:                if (configuredManifest == null) {
0227:                    configuredManifest = newManifest;
0228:                } else {
0229:                    configuredManifest.merge(newManifest);
0230:                }
0231:                savedConfiguredManifest = configuredManifest;
0232:            }
0233:
0234:            /**
0235:             * The manifest file to use. This can be either the location of a manifest,
0236:             * or the name of a jar added through a fileset. If its the name of an added
0237:             * jar, the task expects the manifest to be in the jar at META-INF/MANIFEST.MF.
0238:             *
0239:             * @param manifestFile the manifest file to use.
0240:             */
0241:            public void setManifest(File manifestFile) {
0242:                if (!manifestFile.exists()) {
0243:                    throw new BuildException("Manifest file: " + manifestFile
0244:                            + " does not exist.", getLocation());
0245:                }
0246:
0247:                this .manifestFile = manifestFile;
0248:            }
0249:
0250:            private Manifest getManifest(File manifestFile) {
0251:
0252:                Manifest newManifest = null;
0253:                FileInputStream fis = null;
0254:                InputStreamReader isr = null;
0255:                try {
0256:                    fis = new FileInputStream(manifestFile);
0257:                    if (manifestEncoding == null) {
0258:                        isr = new InputStreamReader(fis);
0259:                    } else {
0260:                        isr = new InputStreamReader(fis, manifestEncoding);
0261:                    }
0262:                    newManifest = getManifest(isr);
0263:                } catch (UnsupportedEncodingException e) {
0264:                    throw new BuildException(
0265:                            "Unsupported encoding while reading manifest: "
0266:                                    + e.getMessage(), e);
0267:                } catch (IOException e) {
0268:                    throw new BuildException("Unable to read manifest file: "
0269:                            + manifestFile + " (" + e.getMessage() + ")", e);
0270:                } finally {
0271:                    if (isr != null) {
0272:                        try {
0273:                            isr.close();
0274:                        } catch (IOException e) {
0275:                            // do nothing
0276:                        }
0277:                    }
0278:                }
0279:                return newManifest;
0280:            }
0281:
0282:            /**
0283:             * @return null if jarFile doesn't contain a manifest, the
0284:             * manifest otherwise.
0285:             * @since Ant 1.5.2
0286:             */
0287:            private Manifest getManifestFromJar(File jarFile)
0288:                    throws IOException {
0289:                ZipFile zf = null;
0290:                try {
0291:                    zf = new ZipFile(jarFile);
0292:
0293:                    // must not use getEntry as "well behaving" applications
0294:                    // must accept the manifest in any capitalization
0295:                    Enumeration e = zf.entries();
0296:                    while (e.hasMoreElements()) {
0297:                        ZipEntry ze = (ZipEntry) e.nextElement();
0298:                        if (ze.getName().equalsIgnoreCase(MANIFEST_NAME)) {
0299:                            InputStreamReader isr = new InputStreamReader(zf
0300:                                    .getInputStream(ze), "UTF-8");
0301:                            return getManifest(isr);
0302:                        }
0303:                    }
0304:                    return null;
0305:                } finally {
0306:                    if (zf != null) {
0307:                        try {
0308:                            zf.close();
0309:                        } catch (IOException e) {
0310:                            // XXX - log an error?  throw an exception?
0311:                        }
0312:                    }
0313:                }
0314:            }
0315:
0316:            private Manifest getManifest(Reader r) {
0317:
0318:                Manifest newManifest = null;
0319:                try {
0320:                    newManifest = new Manifest(r);
0321:                } catch (ManifestException e) {
0322:                    log("Manifest is invalid: " + e.getMessage(),
0323:                            Project.MSG_ERR);
0324:                    throw new BuildException("Invalid Manifest: "
0325:                            + manifestFile, e, getLocation());
0326:                } catch (IOException e) {
0327:                    throw new BuildException("Unable to read manifest file"
0328:                            + " (" + e.getMessage() + ")", e);
0329:                }
0330:                return newManifest;
0331:            }
0332:
0333:            /**
0334:             * Behavior when a Manifest is found in a zipfileset or zipgroupfileset file.
0335:             * Valid values are "skip", "merge", and "mergewithoutmain".
0336:             * "merge" will merge all of manifests together, and merge this into any
0337:             * other specified manifests.
0338:             * "mergewithoutmain" merges everything but the Main section of the manifests.
0339:             * Default value is "skip".
0340:             *
0341:             * Note: if this attribute's value is not "skip", the created jar will not
0342:             * be readable by using java.util.jar.JarInputStream
0343:             *
0344:             * @param config setting for found manifest behavior.
0345:             */
0346:            public void setFilesetmanifest(FilesetManifestConfig config) {
0347:                filesetManifestConfig = config;
0348:                mergeManifestsMain = "merge".equals(config.getValue());
0349:
0350:                if (filesetManifestConfig != null
0351:                        && !filesetManifestConfig.getValue().equals("skip")) {
0352:
0353:                    doubleFilePass = true;
0354:                }
0355:            }
0356:
0357:            /**
0358:             * Adds a zipfileset to include in the META-INF directory.
0359:             *
0360:             * @param fs zipfileset to add
0361:             */
0362:            public void addMetainf(ZipFileSet fs) {
0363:                // We just set the prefix for this fileset, and pass it up.
0364:                fs.setPrefix("META-INF/");
0365:                super .addFileset(fs);
0366:            }
0367:
0368:            /**
0369:             * Add a path to index jars.
0370:             * @param p a path
0371:             * @since Ant 1.6.2
0372:             */
0373:            public void addConfiguredIndexJars(Path p) {
0374:                if (indexJars == null) {
0375:                    indexJars = new Path(getProject());
0376:                }
0377:                indexJars.append(p);
0378:            }
0379:
0380:            /**
0381:             * A nested SPI service element.
0382:             * @param service the nested element.
0383:             * @since Ant 1.7
0384:             */
0385:            public void addConfiguredService(Service service) {
0386:                // Check if the service is configured correctly
0387:                service.check();
0388:                serviceList.add(service);
0389:            }
0390:
0391:            /**
0392:             * Write SPI Information to JAR
0393:             */
0394:            private void writeServices(ZipOutputStream zOut) throws IOException {
0395:                Iterator serviceIterator;
0396:                Service service;
0397:
0398:                serviceIterator = serviceList.iterator();
0399:                while (serviceIterator.hasNext()) {
0400:                    service = (Service) serviceIterator.next();
0401:                    //stolen from writeManifest
0402:                    super .zipFile(service.getAsStream(), zOut,
0403:                            "META-INF/service/" + service.getType(), System
0404:                                    .currentTimeMillis(), null,
0405:                            ZipFileSet.DEFAULT_FILE_MODE);
0406:                }
0407:            }
0408:
0409:            /**
0410:             * Initialize the zip output stream.
0411:             * @param zOut the zip output stream
0412:             * @throws IOException on I/O errors
0413:             * @throws BuildException on other errors
0414:             */
0415:            protected void initZipOutputStream(ZipOutputStream zOut)
0416:                    throws IOException, BuildException {
0417:
0418:                if (!skipWriting) {
0419:                    Manifest jarManifest = createManifest();
0420:                    writeManifest(zOut, jarManifest);
0421:                    writeServices(zOut);
0422:                }
0423:            }
0424:
0425:            private Manifest createManifest() throws BuildException {
0426:                try {
0427:                    Manifest finalManifest = Manifest.getDefaultManifest();
0428:
0429:                    if (manifest == null) {
0430:                        if (manifestFile != null) {
0431:                            // if we haven't got the manifest yet, attempt to
0432:                            // get it now and have manifest be the final merge
0433:                            manifest = getManifest(manifestFile);
0434:                        }
0435:                    }
0436:
0437:                    /*
0438:                     * Precedence: manifestFile wins over inline manifest,
0439:                     * over manifests read from the filesets over the original
0440:                     * manifest.
0441:                     *
0442:                     * merge with null argument is a no-op
0443:                     */
0444:
0445:                    if (isInUpdateMode()) {
0446:                        finalManifest.merge(originalManifest);
0447:                    }
0448:                    finalManifest.merge(filesetManifest);
0449:                    finalManifest.merge(configuredManifest);
0450:                    finalManifest.merge(manifest, !mergeManifestsMain);
0451:
0452:                    return finalManifest;
0453:
0454:                } catch (ManifestException e) {
0455:                    log("Manifest is invalid: " + e.getMessage(),
0456:                            Project.MSG_ERR);
0457:                    throw new BuildException("Invalid Manifest", e,
0458:                            getLocation());
0459:                }
0460:            }
0461:
0462:            private void writeManifest(ZipOutputStream zOut, Manifest manifest)
0463:                    throws IOException {
0464:                for (Enumeration e = manifest.getWarnings(); e
0465:                        .hasMoreElements();) {
0466:                    log("Manifest warning: " + (String) e.nextElement(),
0467:                            Project.MSG_WARN);
0468:                }
0469:
0470:                zipDir(null, zOut, "META-INF/", ZipFileSet.DEFAULT_DIR_MODE,
0471:                        JAR_MARKER);
0472:                // time to write the manifest
0473:                ByteArrayOutputStream baos = new ByteArrayOutputStream();
0474:                OutputStreamWriter osw = new OutputStreamWriter(baos,
0475:                        Manifest.JAR_ENCODING);
0476:                PrintWriter writer = new PrintWriter(osw);
0477:                manifest.write(writer);
0478:                writer.flush();
0479:
0480:                ByteArrayInputStream bais = new ByteArrayInputStream(baos
0481:                        .toByteArray());
0482:                super .zipFile(bais, zOut, MANIFEST_NAME, System
0483:                        .currentTimeMillis(), null,
0484:                        ZipFileSet.DEFAULT_FILE_MODE);
0485:                super .initZipOutputStream(zOut);
0486:            }
0487:
0488:            /**
0489:             * Finalize the zip output stream.
0490:             * This creates an index list if the index attribute is true.
0491:             * @param zOut the zip output stream
0492:             * @throws IOException on I/O errors
0493:             * @throws BuildException on other errors
0494:             */
0495:            protected void finalizeZipOutputStream(ZipOutputStream zOut)
0496:                    throws IOException, BuildException {
0497:
0498:                if (index) {
0499:                    createIndexList(zOut);
0500:                }
0501:            }
0502:
0503:            /**
0504:             * Create the index list to speed up classloading.
0505:             * This is a JDK 1.3+ specific feature and is enabled by default. See
0506:             * <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR%20Index">
0507:             * the JAR index specification</a> for more details.
0508:             *
0509:             * @param zOut the zip stream representing the jar being built.
0510:             * @throws IOException thrown if there is an error while creating the
0511:             * index and adding it to the zip stream.
0512:             */
0513:            private void createIndexList(ZipOutputStream zOut)
0514:                    throws IOException {
0515:                ByteArrayOutputStream baos = new ByteArrayOutputStream();
0516:                // encoding must be UTF8 as specified in the specs.
0517:                PrintWriter writer = new PrintWriter(new OutputStreamWriter(
0518:                        baos, "UTF8"));
0519:
0520:                // version-info blankline
0521:                writer.println("JarIndex-Version: 1.0");
0522:                writer.println();
0523:
0524:                // header newline
0525:                writer.println(zipFile.getName());
0526:
0527:                writeIndexLikeList(new ArrayList(addedDirs.keySet()),
0528:                        rootEntries, writer);
0529:                writer.println();
0530:
0531:                if (indexJars != null) {
0532:                    Manifest mf = createManifest();
0533:                    Manifest.Attribute classpath = mf.getMainSection()
0534:                            .getAttribute(Manifest.ATTRIBUTE_CLASSPATH);
0535:                    String[] cpEntries = null;
0536:                    if (classpath != null && classpath.getValue() != null) {
0537:                        StringTokenizer tok = new StringTokenizer(classpath
0538:                                .getValue(), " ");
0539:                        cpEntries = new String[tok.countTokens()];
0540:                        int c = 0;
0541:                        while (tok.hasMoreTokens()) {
0542:                            cpEntries[c++] = tok.nextToken();
0543:                        }
0544:                    }
0545:                    String[] indexJarEntries = indexJars.list();
0546:                    for (int i = 0; i < indexJarEntries.length; i++) {
0547:                        String name = findJarName(indexJarEntries[i], cpEntries);
0548:                        if (name != null) {
0549:                            ArrayList dirs = new ArrayList();
0550:                            ArrayList files = new ArrayList();
0551:                            grabFilesAndDirs(indexJarEntries[i], dirs, files);
0552:                            if (dirs.size() + files.size() > 0) {
0553:                                writer.println(name);
0554:                                writeIndexLikeList(dirs, files, writer);
0555:                                writer.println();
0556:                            }
0557:                        }
0558:                    }
0559:                }
0560:
0561:                writer.flush();
0562:                ByteArrayInputStream bais = new ByteArrayInputStream(baos
0563:                        .toByteArray());
0564:                super .zipFile(bais, zOut, INDEX_NAME, System
0565:                        .currentTimeMillis(), null,
0566:                        ZipFileSet.DEFAULT_FILE_MODE);
0567:            }
0568:
0569:            /**
0570:             * Overridden from Zip class to deal with manifests and index lists.
0571:             * @param is the input stream
0572:             * @param zOut the zip output stream
0573:             * @param vPath the name this entry shall have in the archive
0574:             * @param lastModified last modification time for the entry.
0575:             * @param fromArchive the original archive we are copying this
0576:             *                    entry from, will be null if we are not copying from an archive.
0577:             * @param mode the Unix permissions to set.
0578:             * @throws IOException on error
0579:             */
0580:            protected void zipFile(InputStream is, ZipOutputStream zOut,
0581:                    String vPath, long lastModified, File fromArchive, int mode)
0582:                    throws IOException {
0583:                if (MANIFEST_NAME.equalsIgnoreCase(vPath)) {
0584:                    if (!doubleFilePass || (doubleFilePass && skipWriting)) {
0585:                        filesetManifest(fromArchive, is);
0586:                    }
0587:                } else if (INDEX_NAME.equalsIgnoreCase(vPath) && index) {
0588:                    log("Warning: selected " + archiveType
0589:                            + " files include a META-INF/INDEX.LIST which will"
0590:                            + " be replaced by a newly generated one.",
0591:                            Project.MSG_WARN);
0592:                } else {
0593:                    if (index && vPath.indexOf("/") == -1) {
0594:                        rootEntries.addElement(vPath);
0595:                    }
0596:                    super .zipFile(is, zOut, vPath, lastModified, fromArchive,
0597:                            mode);
0598:                }
0599:            }
0600:
0601:            private void filesetManifest(File file, InputStream is)
0602:                    throws IOException {
0603:                if (manifestFile != null && manifestFile.equals(file)) {
0604:                    // If this is the same name specified in 'manifest', this
0605:                    // is the manifest to use
0606:                    log("Found manifest " + file, Project.MSG_VERBOSE);
0607:                    try {
0608:                        if (is != null) {
0609:                            InputStreamReader isr;
0610:                            if (manifestEncoding == null) {
0611:                                isr = new InputStreamReader(is);
0612:                            } else {
0613:                                isr = new InputStreamReader(is,
0614:                                        manifestEncoding);
0615:                            }
0616:                            manifest = getManifest(isr);
0617:                        } else {
0618:                            manifest = getManifest(file);
0619:                        }
0620:                    } catch (UnsupportedEncodingException e) {
0621:                        throw new BuildException(
0622:                                "Unsupported encoding while reading "
0623:                                        + "manifest: " + e.getMessage(), e);
0624:                    }
0625:                } else if (filesetManifestConfig != null
0626:                        && !filesetManifestConfig.getValue().equals("skip")) {
0627:                    // we add this to our group of fileset manifests
0628:                    log("Found manifest to merge in file " + file,
0629:                            Project.MSG_VERBOSE);
0630:
0631:                    try {
0632:                        Manifest newManifest = null;
0633:                        if (is != null) {
0634:                            InputStreamReader isr;
0635:                            if (manifestEncoding == null) {
0636:                                isr = new InputStreamReader(is);
0637:                            } else {
0638:                                isr = new InputStreamReader(is,
0639:                                        manifestEncoding);
0640:                            }
0641:                            newManifest = getManifest(isr);
0642:                        } else {
0643:                            newManifest = getManifest(file);
0644:                        }
0645:
0646:                        if (filesetManifest == null) {
0647:                            filesetManifest = newManifest;
0648:                        } else {
0649:                            filesetManifest.merge(newManifest);
0650:                        }
0651:                    } catch (UnsupportedEncodingException e) {
0652:                        throw new BuildException(
0653:                                "Unsupported encoding while reading "
0654:                                        + "manifest: " + e.getMessage(), e);
0655:                    } catch (ManifestException e) {
0656:                        log("Manifest in file " + file + " is invalid: "
0657:                                + e.getMessage(), Project.MSG_ERR);
0658:                        throw new BuildException("Invalid Manifest", e,
0659:                                getLocation());
0660:                    }
0661:                } else {
0662:                    // assuming 'skip' otherwise
0663:                    // don't warn if skip has been requested explicitly, warn if user
0664:                    // didn't set the attribute
0665:
0666:                    // Hide warning also as it makes no sense since
0667:                    // the filesetmanifest attribute itself has been
0668:                    // hidden
0669:
0670:                    //int logLevel = filesetManifestConfig == null ?
0671:                    //    Project.MSG_WARN : Project.MSG_VERBOSE;
0672:                    //log("File " + file
0673:                    //    + " includes a META-INF/MANIFEST.MF which will be ignored. "
0674:                    //    + "To include this file, set filesetManifest to a value other "
0675:                    //    + "than 'skip'.", logLevel);
0676:                }
0677:            }
0678:
0679:            /**
0680:             * Collect the resources that are newer than the corresponding
0681:             * entries (or missing) in the original archive.
0682:             *
0683:             * <p>If we are going to recreate the archive instead of updating
0684:             * it, all resources should be considered as new, if a single one
0685:             * is.  Because of this, subclasses overriding this method must
0686:             * call <code>super.getResourcesToAdd</code> and indicate with the
0687:             * third arg if they already know that the archive is
0688:             * out-of-date.</p>
0689:             *
0690:             * @param rcs The resource collections to grab resources from
0691:             * @param zipFile intended archive file (may or may not exist)
0692:             * @param needsUpdate whether we already know that the archive is
0693:             * out-of-date.  Subclasses overriding this method are supposed to
0694:             * set this value correctly in their call to
0695:             * super.getResourcesToAdd.
0696:             * @return an array of resources to add for each fileset passed in as well
0697:             *         as a flag that indicates whether the archive is uptodate.
0698:             *
0699:             * @exception BuildException if it likes
0700:             */
0701:            protected ArchiveState getResourcesToAdd(ResourceCollection[] rcs,
0702:                    File zipFile, boolean needsUpdate) throws BuildException {
0703:
0704:                // need to handle manifest as a special check
0705:                if (zipFile.exists()) {
0706:                    // if it doesn't exist, it will get created anyway, don't
0707:                    // bother with any up-to-date checks.
0708:
0709:                    try {
0710:                        originalManifest = getManifestFromJar(zipFile);
0711:                        if (originalManifest == null) {
0712:                            log(
0713:                                    "Updating jar since the current jar has no manifest",
0714:                                    Project.MSG_VERBOSE);
0715:                            needsUpdate = true;
0716:                        } else {
0717:                            Manifest mf = createManifest();
0718:                            if (!mf.equals(originalManifest)) {
0719:                                log(
0720:                                        "Updating jar since jar manifest has changed",
0721:                                        Project.MSG_VERBOSE);
0722:                                needsUpdate = true;
0723:                            }
0724:                        }
0725:                    } catch (Throwable t) {
0726:                        log("error while reading original manifest in file: "
0727:                                + zipFile.toString() + t.getMessage(),
0728:                                Project.MSG_WARN);
0729:                        needsUpdate = true;
0730:                    }
0731:
0732:                } else {
0733:                    // no existing archive
0734:                    needsUpdate = true;
0735:                }
0736:
0737:                createEmpty = needsUpdate;
0738:                return super .getResourcesToAdd(rcs, zipFile, needsUpdate);
0739:            }
0740:
0741:            /**
0742:             * Create an empty jar file.
0743:             * @param zipFile the file to create
0744:             * @return true for historic reasons
0745:             * @throws BuildException on error
0746:             */
0747:            protected boolean createEmptyZip(File zipFile)
0748:                    throws BuildException {
0749:                if (!createEmpty) {
0750:                    return true;
0751:                }
0752:
0753:                if (emptyBehavior.equals("skip")) {
0754:                    log("Warning: skipping " + archiveType + " archive "
0755:                            + zipFile + " because no files were included.",
0756:                            Project.MSG_WARN);
0757:                    return true;
0758:                } else if (emptyBehavior.equals("fail")) {
0759:                    throw new BuildException("Cannot create " + archiveType
0760:                            + " archive " + zipFile
0761:                            + ": no files were included.", getLocation());
0762:                }
0763:
0764:                ZipOutputStream zOut = null;
0765:                try {
0766:                    log("Building MANIFEST-only jar: "
0767:                            + getDestFile().getAbsolutePath());
0768:                    zOut = new ZipOutputStream(new FileOutputStream(
0769:                            getDestFile()));
0770:
0771:                    zOut.setEncoding(getEncoding());
0772:                    if (isCompress()) {
0773:                        zOut.setMethod(ZipOutputStream.DEFLATED);
0774:                    } else {
0775:                        zOut.setMethod(ZipOutputStream.STORED);
0776:                    }
0777:                    initZipOutputStream(zOut);
0778:                    finalizeZipOutputStream(zOut);
0779:                } catch (IOException ioe) {
0780:                    throw new BuildException(
0781:                            "Could not create almost empty JAR archive" + " ("
0782:                                    + ioe.getMessage() + ")", ioe,
0783:                            getLocation());
0784:                } finally {
0785:                    // Close the output stream.
0786:                    try {
0787:                        if (zOut != null) {
0788:                            zOut.close();
0789:                        }
0790:                    } catch (IOException ex) {
0791:                        // Ignore close exception
0792:                    }
0793:                    createEmpty = false;
0794:                }
0795:                return true;
0796:            }
0797:
0798:            /**
0799:             * Make sure we don't think we already have a MANIFEST next time this task
0800:             * gets executed.
0801:             *
0802:             * @see Zip#cleanUp
0803:             */
0804:            protected void cleanUp() {
0805:                super .cleanUp();
0806:
0807:                // we want to save this info if we are going to make another pass
0808:                if (!doubleFilePass || (doubleFilePass && !skipWriting)) {
0809:                    manifest = null;
0810:                    configuredManifest = savedConfiguredManifest;
0811:                    filesetManifest = null;
0812:                    originalManifest = null;
0813:                }
0814:                rootEntries.removeAllElements();
0815:            }
0816:
0817:            /**
0818:             * reset to default values.
0819:             *
0820:             * @see Zip#reset
0821:             *
0822:             * @since 1.44, Ant 1.5
0823:             */
0824:            public void reset() {
0825:                super .reset();
0826:                emptyBehavior = "create";
0827:                configuredManifest = null;
0828:                filesetManifestConfig = null;
0829:                mergeManifestsMain = false;
0830:                manifestFile = null;
0831:                index = false;
0832:            }
0833:
0834:            /**
0835:             * The manifest config enumerated type.
0836:             */
0837:            public static class FilesetManifestConfig extends
0838:                    EnumeratedAttribute {
0839:                /**
0840:                 * Get the list of valid strings.
0841:                 * @return the list of values - "skip", "merge" and "mergewithoutmain"
0842:                 */
0843:                public String[] getValues() {
0844:                    return new String[] { "skip", "merge", "mergewithoutmain" };
0845:                }
0846:            }
0847:
0848:            /**
0849:             * Writes the directory entries from the first and the filenames
0850:             * from the second list to the given writer, one entry per line.
0851:             *
0852:             * @param dirs a list of directories
0853:             * @param files a list of files
0854:             * @param writer the writer to write to
0855:             * @throws IOException on error
0856:             * @since Ant 1.6.2
0857:             */
0858:            protected final void writeIndexLikeList(List dirs, List files,
0859:                    PrintWriter writer) throws IOException {
0860:                // JarIndex is sorting the directories by ascending order.
0861:                // it has no value but cosmetic since it will be read into a
0862:                // hashtable by the classloader, but we'll do so anyway.
0863:                Collections.sort(dirs);
0864:                Collections.sort(files);
0865:                Iterator iter = dirs.iterator();
0866:                while (iter.hasNext()) {
0867:                    String dir = (String) iter.next();
0868:
0869:                    // try to be smart, not to be fooled by a weird directory name
0870:                    dir = dir.replace('\\', '/');
0871:                    if (dir.startsWith("./")) {
0872:                        dir = dir.substring(2);
0873:                    }
0874:                    while (dir.startsWith("/")) {
0875:                        dir = dir.substring(1);
0876:                    }
0877:                    int pos = dir.lastIndexOf('/');
0878:                    if (pos != -1) {
0879:                        dir = dir.substring(0, pos);
0880:                    }
0881:
0882:                    // looks like nothing from META-INF should be added
0883:                    // and the check is not case insensitive.
0884:                    // see sun.misc.JarIndex
0885:                    if (dir.startsWith("META-INF")) {
0886:                        continue;
0887:                    }
0888:                    // name newline
0889:                    writer.println(dir);
0890:                }
0891:
0892:                iter = files.iterator();
0893:                while (iter.hasNext()) {
0894:                    writer.println(iter.next());
0895:                }
0896:            }
0897:
0898:            /**
0899:             * try to guess the name of the given file.
0900:             *
0901:             * <p>If this jar has a classpath attribute in its manifest, we
0902:             * can assume that it will only require an index of jars listed
0903:             * there.  try to find which classpath entry is most likely the
0904:             * one the given file name points to.</p>
0905:             *
0906:             * <p>In the absence of a classpath attribute, assume the other
0907:             * files will be placed inside the same directory as this jar and
0908:             * use their basename.</p>
0909:             *
0910:             * <p>if there is a classpath and the given file doesn't match any
0911:             * of its entries, return null.</p>
0912:             *
0913:             * @param fileName the name to look for
0914:             * @param classpath the classpath to look in (may be null)
0915:             * @return the matching entry, or null if the file is not found
0916:             * @since Ant 1.6.2
0917:             */
0918:            protected static final String findJarName(String fileName,
0919:                    String[] classpath) {
0920:                if (classpath == null) {
0921:                    return (new File(fileName)).getName();
0922:                }
0923:                fileName = fileName.replace(File.separatorChar, '/');
0924:                TreeMap matches = new TreeMap(new Comparator() {
0925:                    // longest match comes first
0926:                    public int compare(Object o1, Object o2) {
0927:                        if (o1 instanceof  String && o2 instanceof  String) {
0928:                            return ((String) o2).length()
0929:                                    - ((String) o1).length();
0930:                        }
0931:                        return 0;
0932:                    }
0933:                });
0934:
0935:                for (int i = 0; i < classpath.length; i++) {
0936:                    if (fileName.endsWith(classpath[i])) {
0937:                        matches.put(classpath[i], classpath[i]);
0938:                    } else {
0939:                        int slash = classpath[i].indexOf("/");
0940:                        String candidate = classpath[i];
0941:                        while (slash > -1) {
0942:                            candidate = candidate.substring(slash + 1);
0943:                            if (fileName.endsWith(candidate)) {
0944:                                matches.put(candidate, classpath[i]);
0945:                                break;
0946:                            }
0947:                            slash = candidate.indexOf("/");
0948:                        }
0949:                    }
0950:                }
0951:
0952:                return matches.size() == 0 ? null : (String) matches
0953:                        .get(matches.firstKey());
0954:            }
0955:
0956:            /**
0957:             * Grab lists of all root-level files and all directories
0958:             * contained in the given archive.
0959:             * @param file the zip file to examine
0960:             * @param dirs where to place the directories found
0961:             * @param files where to place the files found
0962:             * @since Ant 1.7
0963:             * @throws IOException on error
0964:             */
0965:            protected static final void grabFilesAndDirs(String file,
0966:                    List dirs, List files) throws IOException {
0967:                org.apache.tools.zip.ZipFile zf = null;
0968:                try {
0969:                    zf = new org.apache.tools.zip.ZipFile(file, "utf-8");
0970:                    Enumeration entries = zf.getEntries();
0971:                    HashSet dirSet = new HashSet();
0972:                    while (entries.hasMoreElements()) {
0973:                        org.apache.tools.zip.ZipEntry ze = (org.apache.tools.zip.ZipEntry) entries
0974:                                .nextElement();
0975:                        String name = ze.getName();
0976:                        // META-INF would be skipped anyway, avoid index for
0977:                        // manifest-only jars.
0978:                        if (!name.startsWith("META-INF/")) {
0979:                            if (ze.isDirectory()) {
0980:                                dirSet.add(name);
0981:                            } else if (name.indexOf("/") == -1) {
0982:                                files.add(name);
0983:                            } else {
0984:                                // a file, not in the root
0985:                                // since the jar may be one without directory
0986:                                // entries, add the parent dir of this file as
0987:                                // well.
0988:                                dirSet.add(name.substring(0, name
0989:                                        .lastIndexOf("/") + 1));
0990:                            }
0991:                        }
0992:                    }
0993:                    dirs.addAll(dirSet);
0994:                } finally {
0995:                    if (zf != null) {
0996:                        zf.close();
0997:                    }
0998:                }
0999:            }
1000:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.