alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Ant example source code file (Manifest.java)

This example Ant source code file (Manifest.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Ant tags/keywords

attribute, attribute, buildexception, enumeration, enumeration, eol, io, ioexception, manifest, manifestexception, section, section, string, string, util, vector

The Manifest.java source code

/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package org.apache.tools.ant.taskdefs;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.util.FileUtils;

/**
 * Holds the data of a jar manifest.
 *
 * Manifests are processed according to the
 * {@link <a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html">Jar
 * file specification.</a>}.
 * Specifically, a manifest element consists of
 * a set of attributes and sections. These sections in turn may contain
 * attributes. Note in particular that this may result in manifest lines
 * greater than 72 bytes being wrapped and continued on the next
 * line. If an application can not handle the continuation mechanism, it
 * is a defect in the application, not this task.
 *
 *
 * @since Ant 1.4
 */
public class Manifest {
    /** The standard manifest version header */
    public static final String ATTRIBUTE_MANIFEST_VERSION
        = "Manifest-Version";

    /** The standard Signature Version header */
    public static final String ATTRIBUTE_SIGNATURE_VERSION
        = "Signature-Version";

    /** The Name Attribute is the first in a named section */
    public static final String ATTRIBUTE_NAME = "Name";

    /** The From Header is disallowed in a Manifest */
    public static final String ATTRIBUTE_FROM = "From";

    /** The Class-Path Header is special - it can be duplicated */
    public static final String ATTRIBUTE_CLASSPATH = "Class-Path";

    /** Default Manifest version if one is not specified */
    public static final  String DEFAULT_MANIFEST_VERSION = "1.0";

    /** The max length of a line in a Manifest */
    public static final int MAX_LINE_LENGTH = 72;

    /**
     * Max length of a line section which is continued. Need to allow
     * for the CRLF.
     */
    public static final int MAX_SECTION_LENGTH = MAX_LINE_LENGTH - 2;

    /** The End-Of-Line marker in manifests */
    public static final String EOL = "\r\n";
    /** Error for attributes */
    public static final String ERROR_FROM_FORBIDDEN = "Manifest attributes should not start "
                        + "with \"" + ATTRIBUTE_FROM + "\" in \"";

    /** Encoding to be used for JAR files. */
    public static final String JAR_ENCODING = "UTF-8";

    /**
     * An attribute for the manifest.
     * Those attributes that are not nested into a section will be added to the "Main" section.
     */
    public static class Attribute {

        /**
         * Maximum length of the name to have the value starting on the same
         * line as the name. This to stay under 72 bytes total line length
         * (including CRLF).
         */
        private static final int MAX_NAME_VALUE_LENGTH = 68;

        /**
         * Maximum length of the name according to the jar specification.
         * In this case the first line will have 74 bytes total line length
         * (including CRLF). This conflicts with the 72 bytes total line length
         * max, but is the only possible conclusion from the manifest specification, if
         * names with 70 bytes length are allowed, have to be on the first line, and
         * have to be followed by ": ".
         */
        private static final int MAX_NAME_LENGTH = 70;

        /** The attribute's name */
        private String name = null;

        /** The attribute's value */
        private Vector values = new Vector();

        /**
         * For multivalued attributes, this is the index of the attribute
         * currently being defined.
         */
        private int currentIndex = 0;

        /**
         * Construct an empty attribute */
        public Attribute() {
        }

        /**
         * Construct an attribute by parsing a line from the Manifest
         *
         * @param line the line containing the attribute name and value
         *
         * @throws ManifestException if the line is not valid
         */
        public Attribute(String line) throws ManifestException {
            parse(line);
        }

        /**
         * Construct a manifest by specifying its name and value
         *
         * @param name the attribute's name
         * @param value the Attribute's value
         */
        public Attribute(String name, String value) {
            this.name = name;
            setValue(value);
        }

        /**
         * @see java.lang.Object#hashCode
         * @return a hashcode based on the key and values.
         */
        public int hashCode() {
            int hashCode = 0;

            if (name != null) {
                hashCode += getKey().hashCode();
            }

            hashCode += values.hashCode();
            return hashCode;
        }

        /**
         * @param rhs the object to check for equality.
         * @see java.lang.Object#equals
         * @return true if the key and values are the same.
         */
        public boolean equals(Object rhs) {
            if (rhs == null || rhs.getClass() != getClass()) {
                return false;
            }

            if (rhs == this) {
                return true;
            }

            Attribute rhsAttribute = (Attribute) rhs;
            String lhsKey = getKey();
            String rhsKey = rhsAttribute.getKey();
            if ((lhsKey == null && rhsKey != null)
                 || (lhsKey != null && rhsKey == null)
                 || !lhsKey.equals(rhsKey)) {
                return false;
            }

            return values.equals(rhsAttribute.values);
        }

        /**
         * Parse a line into name and value pairs
         *
         * @param line the line to be parsed
         *
         * @throws ManifestException if the line does not contain a colon
         * separating the name and value
         */
        public void parse(String line) throws ManifestException {
            int index = line.indexOf(": ");
            if (index == -1) {
                throw new ManifestException("Manifest line \"" + line
                    + "\" is not valid as it does not "
                    + "contain a name and a value separated by ': ' ");
            }
            name = line.substring(0, index);
            setValue(line.substring(index + 2));
        }

        /**
         * Set the Attribute's name; required
         *
         * @param name the attribute's name
         */
        public void setName(String name) {
            this.name = name;
        }

        /**
         * Get the Attribute's name
         *
         * @return the attribute's name.
         */
        public String getName() {
            return name;
        }

        /**
         * Get the attribute's Key - its name in lower case.
         *
         * @return the attribute's key.
         */
        public String getKey() {
            if (name == null) {
                return null;
            }
            return name.toLowerCase();
        }

        /**
         * Set the Attribute's value; required
         *
         * @param value the attribute's value
         */
        public void setValue(String value) {
            if (currentIndex >= values.size()) {
                values.addElement(value);
                currentIndex = values.size() - 1;
            } else {
                values.setElementAt(value, currentIndex);
            }
        }

        /**
         * Get the Attribute's value.
         *
         * @return the attribute's value.
         */
        public String getValue() {
            if (values.size() == 0) {
                return null;
            }

            String fullValue = "";
            for (Enumeration e = getValues(); e.hasMoreElements();) {
                String value = (String) e.nextElement();
                fullValue += value + " ";
            }
            return fullValue.trim();
        }

        /**
         * Add a new value to this attribute - making it multivalued.
         *
         * @param value the attribute's additional value
         */
        public void addValue(String value) {
            currentIndex++;
            setValue(value);
        }

        /**
         * Get all the attribute's values.
         *
         * @return an enumeration of the attributes values
         */
        public Enumeration getValues() {
            return values.elements();
        }

        /**
         * Add a continuation line from the Manifest file.
         *
         * When lines are too long in a manifest, they are continued on the
         * next line by starting with a space. This method adds the continuation
         * data to the attribute value by skipping the first character.
         *
         * @param line the continuation line.
         */
        public void addContinuation(String line) {
            String currentValue = (String) values.elementAt(currentIndex);
            setValue(currentValue + line.substring(1));
        }

        /**
         * Write the attribute out to a print writer.
         *
         * @param writer the Writer to which the attribute is written
         *
         * @throws IOException if the attribute value cannot be written
         */
        public void write(PrintWriter writer) throws IOException {
            for (Enumeration e = getValues(); e.hasMoreElements();) {
                writeValue(writer, (String) e.nextElement());
            }
        }

        /**
         * Write a single attribute value out
         *
         * @param writer the Writer to which the attribute is written
         * @param value the attribute value
         *
         * @throws IOException if the attribute value cannot be written
         */
        private void writeValue(PrintWriter writer, String value)
             throws IOException {
            String line = null;
            int nameLength = name.getBytes(JAR_ENCODING).length;
            if (nameLength > MAX_NAME_VALUE_LENGTH) {
                if (nameLength > MAX_NAME_LENGTH) {
                    throw new IOException("Unable to write manifest line "
                            + name + ": " + value);
                }
                writer.print(name + ": " + EOL);
                line = " " + value;
            } else {
                line = name + ": " + value;
            }
            while (line.getBytes(JAR_ENCODING).length > MAX_SECTION_LENGTH) {
                // try to find a MAX_LINE_LENGTH byte section
                int breakIndex = MAX_SECTION_LENGTH;
                if (breakIndex >= line.length()) {
                    breakIndex = line.length() - 1;
                }
                String section = line.substring(0, breakIndex);
                while (section.getBytes(JAR_ENCODING).length > MAX_SECTION_LENGTH
                     && breakIndex > 0) {
                    breakIndex--;
                    section = line.substring(0, breakIndex);
                }
                if (breakIndex == 0) {
                    throw new IOException("Unable to write manifest line "
                        + name + ": " + value);
                }
                writer.print(section + EOL);
                line = " " + line.substring(breakIndex);
            }
            writer.print(line + EOL);
        }
    }

    /**
     * A manifest section - you can nest attribute elements into sections.
     * A section consists of a set of attribute values,
     * separated from other sections by a blank line.
     */
    public static class Section {
        /** Warnings for this section */
        private Vector warnings = new Vector();

        /**
         * The section's name if any. The main section in a
         * manifest is unnamed.
         */
        private String name = null;

        /** The section's attributes.*/
        private Hashtable attributes = new Hashtable();

        /** Index used to retain the attribute ordering */
        private Vector attributeIndex = new Vector();

        /**
         * The name of the section; optional -default is the main section.
         * @param name the section's name
         */
        public void setName(String name) {
            this.name = name;
        }

        /**
         * Get the Section's name.
         *
         * @return the section's name.
         */
        public String getName() {
            return name;
        }

        /**
         * Read a section through a reader.
         *
         * @param reader the reader from which the section is read
         *
         * @return the name of the next section if it has been read as
         *         part of this section - This only happens if the
         *         Manifest is malformed.
         *
         * @throws ManifestException if the section is not valid according
         *         to the JAR spec
         * @throws IOException if the section cannot be read from the reader.
         */
        public String read(BufferedReader reader)
             throws ManifestException, IOException {
            Attribute attribute = null;
            while (true) {
                String line = reader.readLine();
                if (line == null || line.length() == 0) {
                    return null;
                }
                if (line.charAt(0) == ' ') {
                    // continuation line
                    if (attribute == null) {
                        if (name != null) {
                            // a continuation on the first line is a
                            // continuation of the name - concatenate this
                            // line and the name
                            name += line.substring(1);
                        } else {
                            throw new ManifestException("Can't start an "
                                + "attribute with a continuation line " + line);
                        }
                    } else {
                        attribute.addContinuation(line);
                    }
                } else {
                    attribute = new Attribute(line);
                    String nameReadAhead = addAttributeAndCheck(attribute);
                    // refresh attribute in case of multivalued attributes.
                    attribute = getAttribute(attribute.getKey());
                    if (nameReadAhead != null) {
                        return nameReadAhead;
                    }
                }
            }
        }

        /**
         * Merge in another section
         *
         * @param section the section to be merged with this one.
         *
         * @throws ManifestException if the sections cannot be merged.
         */
        public void merge(Section section) throws ManifestException {
            if (name == null && section.getName() != null
                || name != null
                && !(name.equalsIgnoreCase(section.getName()))) {
                throw new ManifestException("Unable to merge sections "
                    + "with different names");
            }

            Enumeration e = section.getAttributeKeys();
            Attribute classpathAttribute = null;
            while (e.hasMoreElements()) {
                String attributeName = (String) e.nextElement();
                Attribute attribute = section.getAttribute(attributeName);
                if (attributeName.equalsIgnoreCase(ATTRIBUTE_CLASSPATH)) {
                    if (classpathAttribute == null) {
                        classpathAttribute = new Attribute();
                        classpathAttribute.setName(ATTRIBUTE_CLASSPATH);
                    }
                    Enumeration cpe = attribute.getValues();
                    while (cpe.hasMoreElements()) {
                        String value = (String) cpe.nextElement();
                        classpathAttribute.addValue(value);
                    }
                } else {
                    // the merge file always wins
                    storeAttribute(attribute);
                }
            }

            if (classpathAttribute != null) {
                // the merge file *always* wins, even for Class-Path
                storeAttribute(classpathAttribute);
            }

            // add in the warnings
            Enumeration warnEnum = section.warnings.elements();
            while (warnEnum.hasMoreElements()) {
                warnings.addElement(warnEnum.nextElement());
            }
        }

        /**
         * Write the section out to a print writer.
         *
         * @param writer the Writer to which the section is written
         *
         * @throws IOException if the section cannot be written
         */
        public void write(PrintWriter writer) throws IOException {
            if (name != null) {
                Attribute nameAttr = new Attribute(ATTRIBUTE_NAME, name);
                nameAttr.write(writer);
            }
            Enumeration e = getAttributeKeys();
            while (e.hasMoreElements()) {
                String key = (String) e.nextElement();
                Attribute attribute = getAttribute(key);
                attribute.write(writer);
            }
            writer.print(EOL);
        }

        /**
         * Get a attribute of the section
         *
         * @param attributeName the name of the attribute
         * @return a Manifest.Attribute instance if the attribute is
         *         single-valued, otherwise a Vector of Manifest.Attribute
         *         instances.
         */
        public Attribute getAttribute(String attributeName) {
            return (Attribute) attributes.get(attributeName.toLowerCase());
        }

        /**
         * Get the attribute keys.
         *
         * @return an Enumeration of Strings, each string being the lower case
         *         key of an attribute of the section.
         */
        public Enumeration getAttributeKeys() {
            return attributeIndex.elements();
        }

        /**
         * Get the value of the attribute with the name given.
         *
         * @param attributeName the name of the attribute to be returned.
         *
         * @return the attribute's value or null if the attribute does not exist
         *         in the section
         */
        public String getAttributeValue(String attributeName) {
            Attribute attribute = getAttribute(attributeName.toLowerCase());
            if (attribute == null) {
                return null;
            }
            return attribute.getValue();
        }

        /**
         * Remove the given attribute from the section
         *
         * @param attributeName the name of the attribute to be removed.
         */
        public void removeAttribute(String attributeName) {
            String key = attributeName.toLowerCase();
            attributes.remove(key);
            attributeIndex.removeElement(key);
        }

        /**
         * Add an attribute to the section.
         *
         * @param attribute the attribute to be added to the section
         *
         * @exception ManifestException if the attribute is not valid.
         */
        public void addConfiguredAttribute(Attribute attribute)
             throws ManifestException {
            String check = addAttributeAndCheck(attribute);
            if (check != null) {
                throw new BuildException("Specify the section name using "
                    + "the \"name\" attribute of the <section> element rather "
                    + "than using a \"Name\" manifest attribute");
            }
        }

        /**
         * Add an attribute to the section
         *
         * @param attribute the attribute to be added.
         *
         * @return the value of the attribute if it is a name
         *         attribute - null other wise
         *
         * @exception ManifestException if the attribute already
         *            exists in this section.
         */
        public String addAttributeAndCheck(Attribute attribute)
             throws ManifestException {
            if (attribute.getName() == null || attribute.getValue() == null) {
                throw new BuildException("Attributes must have name and value");
            }
            if (attribute.getKey().equalsIgnoreCase(ATTRIBUTE_NAME)) {
                warnings.addElement("\"" + ATTRIBUTE_NAME + "\" attributes "
                    + "should not occur in the main section and must be the "
                    + "first element in all other sections: \""
                    + attribute.getName() + ": " + attribute.getValue() + "\"");
                return attribute.getValue();
            }

            if (attribute.getKey().startsWith(ATTRIBUTE_FROM.toLowerCase())) {
                warnings.addElement(ERROR_FROM_FORBIDDEN
                    + attribute.getName() + ": " + attribute.getValue() + "\"");
            } else {
                // classpath attributes go into a vector
                String attributeKey = attribute.getKey();
                if (attributeKey.equalsIgnoreCase(ATTRIBUTE_CLASSPATH)) {
                    Attribute classpathAttribute =
                        (Attribute) attributes.get(attributeKey);

                    if (classpathAttribute == null) {
                        storeAttribute(attribute);
                    } else {
                        warnings.addElement("Multiple Class-Path attributes "
                            + "are supported but violate the Jar "
                            + "specification and may not be correctly "
                            + "processed in all environments");
                        Enumeration e = attribute.getValues();
                        while (e.hasMoreElements()) {
                            String value = (String) e.nextElement();
                            classpathAttribute.addValue(value);
                        }
                    }
                } else if (attributes.containsKey(attributeKey)) {
                    throw new ManifestException("The attribute \""
                        + attribute.getName() + "\" may not occur more "
                        + "than once in the same section");
                } else {
                    storeAttribute(attribute);
                }
            }
            return null;
        }

        /**
         * Clone this section
         *
         * @return the cloned Section
         * @since Ant 1.5.2
         */
        public Object clone() {
            Section cloned = new Section();
            cloned.setName(name);
            Enumeration e = getAttributeKeys();
            while (e.hasMoreElements()) {
                String key = (String) e.nextElement();
                Attribute attribute = getAttribute(key);
                cloned.storeAttribute(new Attribute(attribute.getName(),
                                                    attribute.getValue()));
            }
            return cloned;
        }

        /**
         * Store an attribute and update the index.
         *
         * @param attribute the attribute to be stored
         */
        private void storeAttribute(Attribute attribute) {
            if (attribute == null) {
                return;
            }
            String attributeKey = attribute.getKey();
            attributes.put(attributeKey, attribute);
            if (!attributeIndex.contains(attributeKey)) {
                attributeIndex.addElement(attributeKey);
            }
        }

        /**
         * Get the warnings for this section.
         *
         * @return an Enumeration of warning strings.
         */
        public Enumeration getWarnings() {
            return warnings.elements();
        }

        /**
         * @see java.lang.Object#hashCode
         * @return a hash value based on the attributes.
         */
        public int hashCode() {
            return attributes.hashCode();
        }

        /**
         * @see java.lang.Object#equals
         * @param rhs the object to check for equality.
         * @return true if the attributes are the same.
         */
        public boolean equals(Object rhs) {
            if (rhs == null || rhs.getClass() != getClass()) {
                return false;
            }

            if (rhs == this) {
                return true;
            }

            Section rhsSection = (Section) rhs;

            return attributes.equals(rhsSection.attributes);
        }
    }


    /** The version of this manifest */
    private String manifestVersion = DEFAULT_MANIFEST_VERSION;

    /** The main section of this manifest */
    private Section mainSection = new Section();

    /** The named sections of this manifest */
    private Hashtable sections = new Hashtable();

    /** Index of sections - used to retain order of sections in manifest */
    private Vector sectionIndex = new Vector();

    /**
     * Construct a manifest from Ant's default manifest file.
     *
     * @return the default manifest.
     * @exception BuildException if there is a problem loading the
     *            default manifest
     */
    public static Manifest getDefaultManifest() throws BuildException {
        InputStream in = null;
        InputStreamReader insr = null;
        try {
            String defManifest = "/org/apache/tools/ant/defaultManifest.mf";
            in = Manifest.class.getResourceAsStream(defManifest);
            if (in == null) {
                throw new BuildException("Could not find default manifest: "
                    + defManifest);
            }
            try {
                insr = new InputStreamReader(in, "UTF-8");
                Manifest defaultManifest = new Manifest(insr);
                Attribute createdBy = new Attribute("Created-By",
                    System.getProperty("java.vm.version") + " ("
                    + System.getProperty("java.vm.vendor") + ")");
                defaultManifest.getMainSection().storeAttribute(createdBy);
                return defaultManifest;
            } catch (UnsupportedEncodingException e) {
                insr = new InputStreamReader(in);
                return new Manifest(insr);
            }
        } catch (ManifestException e) {
            throw new BuildException("Default manifest is invalid !!", e);
        } catch (IOException e) {
            throw new BuildException("Unable to read default manifest", e);
        } finally {
            FileUtils.close(insr);
            FileUtils.close(in);
        }
    }

    /** Construct an empty manifest */
    public Manifest() {
        manifestVersion = null;
    }

    /**
     * Read a manifest file from the given reader
     *
     * @param r is the reader from which the Manifest is read
     *
     * @throws ManifestException if the manifest is not valid according
     *         to the JAR spec
     * @throws IOException if the manifest cannot be read from the reader.
     */
    public Manifest(Reader r) throws ManifestException, IOException {
        BufferedReader reader = new BufferedReader(r);
        // This should be the manifest version
        String nextSectionName = mainSection.read(reader);
        String readManifestVersion
            = mainSection.getAttributeValue(ATTRIBUTE_MANIFEST_VERSION);
        if (readManifestVersion != null) {
            manifestVersion = readManifestVersion;
            mainSection.removeAttribute(ATTRIBUTE_MANIFEST_VERSION);
        }

        String line = null;
        while ((line = reader.readLine()) != null) {
            if (line.length() == 0) {
                continue;
            }

            Section section = new Section();
            if (nextSectionName == null) {
                Attribute sectionName = new Attribute(line);
                if (!sectionName.getName().equalsIgnoreCase(ATTRIBUTE_NAME)) {
                    throw new ManifestException("Manifest sections should "
                        + "start with a \"" + ATTRIBUTE_NAME
                        + "\" attribute and not \""
                        + sectionName.getName() + "\"");
                }
                nextSectionName = sectionName.getValue();
            } else {
                // we have already started reading this section
                // this line is the first attribute. set it and then
                // let the normal read handle the rest
                Attribute firstAttribute = new Attribute(line);
                section.addAttributeAndCheck(firstAttribute);
            }

            section.setName(nextSectionName);
            nextSectionName = section.read(reader);
            addConfiguredSection(section);
        }
    }

    /**
     * Add a section to the manifest
     *
     * @param section the manifest section to be added
     *
     * @exception ManifestException if the secti0on is not valid.
     */
    public void addConfiguredSection(Section section)
         throws ManifestException {
        String sectionName = section.getName();
        if (sectionName == null) {
            throw new BuildException("Sections must have a name");
        }
        sections.put(sectionName, section);
        if (!sectionIndex.contains(sectionName)) {
            sectionIndex.addElement(sectionName);
        }
    }

    /**
     * Add an attribute to the manifest - it is added to the main section.
     *
     * @param attribute the attribute to be added.
     *
     * @exception ManifestException if the attribute is not valid.
     */
    public void addConfiguredAttribute(Attribute attribute)
         throws ManifestException {
        if (attribute.getKey() == null || attribute.getValue() == null) {
            throw new BuildException("Attributes must have name and value");
        }
        if (attribute.getKey().equalsIgnoreCase(ATTRIBUTE_MANIFEST_VERSION)) {
            manifestVersion = attribute.getValue();
        } else {
            mainSection.addConfiguredAttribute(attribute);
        }
    }

    /**
     * Merge the contents of the given manifest into this manifest
     *
     * @param other the Manifest to be merged with this one.
     *
     * @throws ManifestException if there is a problem merging the
     *         manifest according to the Manifest spec.
     */
    public void merge(Manifest other) throws ManifestException {
        merge(other, false);
    }

    /**
     * Merge the contents of the given manifest into this manifest
     *
     * @param other the Manifest to be merged with this one.
     * @param overwriteMain whether to overwrite the main section
     *        of the current manifest
     *
     * @throws ManifestException if there is a problem merging the
     *         manifest according to the Manifest spec.
     */
    public void merge(Manifest other, boolean overwriteMain)
         throws ManifestException {
        if (other != null) {
             if (overwriteMain) {
                 mainSection = (Section) other.mainSection.clone();
             } else {
                 mainSection.merge(other.mainSection);
             }

             if (other.manifestVersion != null) {
                 manifestVersion = other.manifestVersion;
             }

             Enumeration e = other.getSectionNames();
             while (e.hasMoreElements()) {
                 String sectionName = (String) e.nextElement();
                 Section ourSection = (Section) sections.get(sectionName);
                 Section otherSection
                    = (Section) other.sections.get(sectionName);
                 if (ourSection == null) {
                     if (otherSection != null) {
                         addConfiguredSection((Section) otherSection.clone());
                     }
                 } else {
                     ourSection.merge(otherSection);
                 }
             }
         }
    }

    /**
    * Write the manifest out to a print writer.
    *
    * @param writer the Writer to which the manifest is written
    *
    * @throws IOException if the manifest cannot be written
    */
    public void write(PrintWriter writer) throws IOException {
        writer.print(ATTRIBUTE_MANIFEST_VERSION + ": " + manifestVersion + EOL);
        String signatureVersion
            = mainSection.getAttributeValue(ATTRIBUTE_SIGNATURE_VERSION);
        if (signatureVersion != null) {
            writer.print(ATTRIBUTE_SIGNATURE_VERSION + ": "
                + signatureVersion + EOL);
            mainSection.removeAttribute(ATTRIBUTE_SIGNATURE_VERSION);
        }
        mainSection.write(writer);

        // add it back
        if (signatureVersion != null) {
            try {
                Attribute svAttr = new Attribute(ATTRIBUTE_SIGNATURE_VERSION,
                    signatureVersion);
                mainSection.addConfiguredAttribute(svAttr);
            } catch (ManifestException e) {
                // shouldn't happen - ignore
            }
        }

        Enumeration e = sectionIndex.elements();
        while (e.hasMoreElements()) {
            String sectionName = (String) e.nextElement();
            Section section = getSection(sectionName);
            section.write(writer);
        }
    }

    /**
     * Convert the manifest to its string representation
     *
     * @return a multiline string with the Manifest as it
     *         appears in a Manifest file.
     */
    public String toString() {
        StringWriter sw = new StringWriter();
        try {
            write(new PrintWriter(sw));
        } catch (IOException e) {
            return null;
        }
        return sw.toString();
    }

    /**
     * Get the warnings for this manifest.
     *
     * @return an enumeration of warning strings
     */
    public Enumeration getWarnings() {
        Vector warnings = new Vector();

        Enumeration warnEnum = mainSection.getWarnings();
        while (warnEnum.hasMoreElements()) {
            warnings.addElement(warnEnum.nextElement());
        }

        // create a vector and add in the warnings for all the sections
        Enumeration e = sections.elements();
        while (e.hasMoreElements()) {
            Section section = (Section) e.nextElement();
            Enumeration e2 = section.getWarnings();
            while (e2.hasMoreElements()) {
                warnings.addElement(e2.nextElement());
            }
        }

        return warnings.elements();
    }

    /**
     * @see java.lang.Object#hashCode
     * @return a hashcode based on the version, main and sections.
     */
    public int hashCode() {
        int hashCode = 0;

        if (manifestVersion != null) {
            hashCode += manifestVersion.hashCode();
        }
        hashCode += mainSection.hashCode();
        hashCode += sections.hashCode();

        return hashCode;
    }

    /**
     * @see java.lang.Object#equals
     * @param rhs the object to check for equality.
     * @return true if the version, main and sections are the same.
     */
    public boolean equals(Object rhs) {
        if (rhs == null || rhs.getClass() != getClass()) {
            return false;
        }

        if (rhs == this) {
            return true;
        }

        Manifest rhsManifest = (Manifest) rhs;
        if (manifestVersion == null) {
            if (rhsManifest.manifestVersion != null) {
                return false;
            }
        } else if (!manifestVersion.equals(rhsManifest.manifestVersion)) {
            return false;
        }

        if (!mainSection.equals(rhsManifest.mainSection)) {
            return false;
        }

        return sections.equals(rhsManifest.sections);
    }

    /**
     * Get the version of the manifest
     *
     * @return the manifest's version string
     */
    public String getManifestVersion() {
        return manifestVersion;
    }

    /**
     * Get the main section of the manifest
     *
     * @return the main section of the manifest
     */
    public Section getMainSection() {
        return mainSection;
    }

    /**
     * Get a particular section from the manifest
     *
     * @param name the name of the section desired.
     * @return the specified section or null if that section
     * does not exist in the manifest
     */
    public Section getSection(String name) {
        return (Section) sections.get(name);
    }

    /**
     * Get the section names in this manifest.
     *
     * @return an Enumeration of section names
     */
    public Enumeration getSectionNames() {
        return sectionIndex.elements();
    }
}

Other Ant examples (source code examples)

Here is a short list of links related to this Ant Manifest.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.