You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by co...@apache.org on 2001/07/30 13:15:17 UTC
cvs commit: jakarta-ant/src/main/org/apache/tools/ant/taskdefs ManifestException.java Jar.java Manifest.java Zip.java
conor 01/07/30 04:15:17
Modified: src/main/org/apache/tools/ant/taskdefs Jar.java
Manifest.java Zip.java
Added: src/main/org/apache/tools/ant/taskdefs
ManifestException.java
Log:
Manifest is no longer in a fileset and so needs an uptodate check of its own
Also now log warnings about malformed manifests
Revision Changes Path
1.20 +73 -21 jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Jar.java
Index: Jar.java
===================================================================
RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Jar.java,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -r1.19 -r1.20
--- Jar.java 2001/07/28 14:11:41 1.19
+++ Jar.java 2001/07/30 11:15:17 1.20
@@ -59,6 +59,7 @@
import org.apache.tools.zip.*;
import java.io.*;
+import java.util.Enumeration;
/**
* Creates a JAR archive.
@@ -67,6 +68,7 @@
*/
public class Jar extends Zip {
+ private File manifestFile;
private Manifest manifest;
private Manifest execManifest;
@@ -86,6 +88,8 @@
throw new BuildException("Manifest file: " + manifestFile + " does not exist.",
getLocation());
}
+
+ this.manifestFile = manifestFile;
InputStream is = null;
try {
@@ -96,6 +100,10 @@
}
manifest.merge(newManifest);
}
+ catch (ManifestException e) {
+ log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
+ throw new BuildException("Invalid Manifest: " + manifestFile, e, getLocation());
+ }
catch (IOException e) {
throw new BuildException("Unable to read manifest file: " + manifestFile, e);
}
@@ -120,25 +128,39 @@
protected void initZipOutputStream(ZipOutputStream zOut)
throws IOException, BuildException
{
- // If no manifest is specified, add the default one.
- if (manifest == null) {
- execManifest = null;
- }
- else {
- execManifest = new Manifest();
- execManifest.merge(manifest);
+ try {
+ // If no manifest is specified, add the default one.
+ if (manifest == null) {
+ execManifest = null;
+ }
+ else {
+ execManifest = new Manifest();
+ execManifest.merge(manifest);
+ }
+ zipDir(null, zOut, "META-INF/");
+ super.initZipOutputStream(zOut);
+ }
+ catch (ManifestException e) {
+ log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
+ throw new BuildException("Invalid Manifest", e, getLocation());
}
- zipDir(null, zOut, "META-INF/");
- super.initZipOutputStream(zOut);
}
-
- private Manifest getDefaultManifest() throws IOException {
- String s = "/org/apache/tools/ant/defaultManifest.mf";
- InputStream in = this.getClass().getResourceAsStream(s);
- if (in == null) {
- throw new BuildException("Could not find: " + s);
+
+ private Manifest getDefaultManifest() {
+ try {
+ String s = "/org/apache/tools/ant/defaultManifest.mf";
+ InputStream in = this.getClass().getResourceAsStream(s);
+ if (in == null) {
+ throw new BuildException("Could not find default manifest: " + s);
+ }
+ return new Manifest(in);
+ }
+ catch (ManifestException e) {
+ throw new BuildException("Default manifest is invalid !!");
}
- return new Manifest(in);
+ catch (IOException e) {
+ throw new BuildException("Unable to read default manifest", e);
+ }
}
protected void finalizeZipOutputStream(ZipOutputStream zOut)
@@ -147,6 +169,10 @@
if (execManifest == null) {
execManifest = getDefaultManifest();
}
+
+ for (Enumeration e = execManifest.getWarnings(); e.hasMoreElements(); ) {
+ log("Manifest warning: " + (String)e.nextElement(), Project.MSG_WARN);
+ }
// time to write the manifest
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -157,7 +183,6 @@
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
super.zipFile(bais, zOut, "META-INF/MANIFEST.MF", System.currentTimeMillis());
super.finalizeZipOutputStream(zOut);
-
}
/**
@@ -169,11 +194,17 @@
* and not the old one from the JAR we are updating
*/
private void zipManifestEntry(InputStream is) throws IOException {
- if (execManifest == null) {
- execManifest = new Manifest(is);
+ try {
+ if (execManifest == null) {
+ execManifest = new Manifest(is);
+ }
+ else if (isAddingNewFiles()) {
+ execManifest.merge(new Manifest(is));
+ }
}
- else if (isAddingNewFiles()) {
- execManifest.merge(new Manifest(is));
+ catch (ManifestException e) {
+ log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
+ throw new BuildException("Invalid Manifest", e, getLocation());
}
}
@@ -223,6 +254,27 @@
}
}
+ /**
+ * Check whether the archive is up-to-date;
+ * @param scanners list of prepared scanners containing files to archive
+ * @param zipFile intended archive file (may or may not exist)
+ * @return true if nothing need be done (may have done something already); false if
+ * archive creation should proceed
+ * @exception BuildException if it likes
+ */
+ protected boolean isUpToDate(FileScanner[] scanners, File zipFile) throws BuildException {
+ // need to handle manifest as a special check
+ if (manifestFile != null && manifestFile.lastModified() > zipFile.lastModified()) {
+ return false;
+ }
+ return super.isUpToDate(scanners, zipFile);
+ }
+
+ protected boolean createEmptyZip(File zipFile) {
+ // Jar files always contain a manifest and can never be empty
+ return false;
+ }
+
/**
* Make sure we don't think we already have a MANIFEST next time this task
* gets executed.
1.3 +226 -42 jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Manifest.java
Index: Manifest.java
===================================================================
RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Manifest.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- Manifest.java 2001/07/29 13:57:13 1.2
+++ Manifest.java 2001/07/30 11:15:17 1.3
@@ -63,64 +63,132 @@
* @author <a href="mailto:conor@apache.org">Conor MacNeill</a>
*/
public class Manifest {
- static public final String ATTR_MANIFEST_VERSION = "Manifest-Version";
- static public final String ATTR_SIGNATURE_VERSION = "Signature-Version";
- static public final String ATTR_NAME = "Name";
- static public final String ATTR_FROM = "From";
+ /** The standard manifest version header */
+ static public final String ATTRIBUTE_MANIFEST_VERSION = "Manifest-Version";
+
+ /** The standard Signature Version header */
+ static public final String ATTRIBUTE_SIGNATURE_VERSION = "Signature-Version";
+
+ /** The Name Attribute is the first in a named section */
+ static public final String ATTRIBUTE_NAME = "Name";
+
+ /** THe From Header is disallowed in a Manifest */
+ static public final String ATTRIBUTE_FROM = "From";
+
+ /** Default Manifest version if one is not specified */
static public final String DEFAULT_MANIFEST_VERSION = "1.0";
+
+ /** The max length of a line in a Manifest */
static public final int MAX_LINE_LENGTH = 70;
/**
* Class to hold manifest attributes
*/
- static private class Attribute {
+ private class Attribute {
/** The attribute's name */
private String name = null;
/** The attribute's value */
private String value = null;
+ /**
+ * Construct an empty attribute */
public Attribute() {
}
- public Attribute(String line) throws IOException {
+ /**
+ * 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;
this.value = value;
}
- public void parse(String line) throws IOException {
+ /**
+ * 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 IOException("Manifest line \"" + line + "\" is not valid");
+ throw new ManifestException("Manifest line \"" + line + "\" is not valid");
}
name = line.substring(0, index);
value = line.substring(index + 2);
}
+ /**
+ * Set the Attribute's name
+ *
+ * @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;
}
+ /**
+ * Set the Attribute's value
+ *
+ * @param value the attribute's value
+ */
public void setValue(String value) {
this.value = value;
}
+ /**
+ * Get the Attribute's value
+ *
+ * @return the attribute's value.
+ */
public String getValue() {
return value;
}
+ /**
+ * 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.
+ */
public void addContinuation(String line) {
value += 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 attribte value cannot be written
+ */
public void write(PrintWriter writer) throws IOException {
String line = name + ": " + value;
while (line.getBytes().length > MAX_LINE_LENGTH) {
@@ -143,22 +211,46 @@
/**
* Class to represent an individual section in the
- * Manifest
+ * Manifest. A section consists of a set of attribute values,
+ * separated from other sections by a blank line.
*/
- static private class Section {
+ private class Section {
+ /** 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();
+ /**
+ * Set the Section's name
+ *
+ * @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;
}
- public String read(BufferedReader reader) throws IOException {
+ /**
+ * 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();
@@ -168,29 +260,31 @@
if (line.charAt(0) == ' ') {
// continuation line
if (attribute == null) {
- throw new IOException("Can't start an attribute with a continuation line " + line);
+ throw new ManifestException("Can't start an attribute with a continuation line " + line);
}
attribute.addContinuation(line);
}
else {
attribute = new Attribute(line);
- if (attribute.getName().equalsIgnoreCase(ATTR_NAME)) {
- return attribute.getValue();
+ String nameReadAhead = addAttribute(attribute);
+ if (nameReadAhead != null) {
+ return nameReadAhead;
}
-
- if (attribute.getName().toLowerCase().startsWith(ATTR_FROM.toLowerCase())) {
- throw new IOException("Attribute names may not start with " + ATTR_FROM);
- }
-
- addAttribute(attribute);
}
}
}
- public void merge(Section section) throws IOException {
+ /**
+ * 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 IOException("Unable to merge sections with different names");
+ throw new ManifestException("Unable to merge sections with different names");
}
for (Enumeration e = section.attributes.keys(); e.hasMoreElements();) {
@@ -200,9 +294,16 @@
}
}
+ /**
+ * 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(ATTR_NAME, name);
+ Attribute nameAttr = new Attribute(ATTRIBUTE_NAME, name);
nameAttr.write(writer);
}
for (Enumeration e = attributes.elements(); e.hasMoreElements();) {
@@ -212,6 +313,14 @@
writer.println();
}
+ /**
+ * 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 = (Attribute)attributes.get(attributeName.toLowerCase());
if (attribute == null) {
@@ -219,25 +328,61 @@
}
return attribute.getValue();
}
-
+
+ /**
+ * Remove tge given attribute from the section
+ *
+ * @param attributeName the name of the attribute to be removed.
+ */
public void removeAttribute(String attributeName) {
attributes.remove(attributeName.toLowerCase());
}
- public void addAttribute(Attribute attribute) throws IOException {
- if (attributes.containsKey(attribute.getName().toLowerCase())) {
- throw new IOException("The attribute \"" + attribute.getName() + "\" may not occur more than" +
- " once in the same section");
+ /**
+ * 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
+ *
+ * @throws ManifestException if the attribute already exists in this section.
+ */
+ public String addAttribute(Attribute attribute) throws ManifestException {
+ if (attribute.getName().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.getName().toLowerCase().startsWith(ATTRIBUTE_FROM.toLowerCase())) {
+ warnings.addElement("Manifest attributes should not start with \"" +
+ ATTRIBUTE_FROM + "\" in \"" +attribute.getName() + ": " + attribute.getValue() + "\"");
+ }
+ else if (attributes.containsKey(attribute.getName().toLowerCase())) {
+ throw new ManifestException("The attribute \"" + attribute.getName() + "\" may not " +
+ "occur more than once in the same section");
+ }
+ else {
+ attributes.put(attribute.getName().toLowerCase(), attribute);
}
- attributes.put(attribute.getName().toLowerCase(), attribute);
+ return null;
}
}
-
+ /** 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();
+ /** Warnings for this manifest file */
+ private Vector warnings = new Vector();
+
+ /** Construct an empty manifest */
public Manifest() {
}
@@ -245,8 +390,11 @@
* Read a manifest file from the given input stream
*
* @param is the input stream 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(InputStream is) throws IOException {
+ public Manifest(InputStream is) throws ManifestException, IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = reader.readLine();
if (line == null) {
@@ -255,10 +403,10 @@
// This should be the manifest version
String nextSectionName = mainSection.read(reader);
- String readManifestVersion = mainSection.getAttributeValue(ATTR_MANIFEST_VERSION);
+ String readManifestVersion = mainSection.getAttributeValue(ATTRIBUTE_MANIFEST_VERSION);
if (readManifestVersion != null) {
manifestVersion = readManifestVersion;
- mainSection.removeAttribute(ATTR_MANIFEST_VERSION);
+ mainSection.removeAttribute(ATTRIBUTE_MANIFEST_VERSION);
}
while ((line = reader.readLine()) != null) {
@@ -269,9 +417,9 @@
Section section = new Section();
if (nextSectionName == null) {
Attribute sectionName = new Attribute(line);
- if (!sectionName.getName().equalsIgnoreCase(ATTR_NAME)) {
- throw new IOException("Manifest sections should start with a \"" + ATTR_NAME +
- "\" attribute and not \"" + sectionName.getName() + "\"");
+ 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();
}
@@ -291,8 +439,13 @@
/**
* 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 manfest according
+ * to the Manifest spec.
*/
- public void merge(Manifest other) throws IOException {
+ public void merge(Manifest other) throws ManifestException {
manifestVersion = other.manifestVersion;
mainSection.merge(other.mainSection);
for (Enumeration e = other.sections.keys(); e.hasMoreElements();) {
@@ -306,18 +459,35 @@
ourSection.merge(otherSection);
}
}
+
+ // add in the warnings
+ for (Enumeration e = other.warnings.elements(); e.hasMoreElements();) {
+ warnings.addElement(e.nextElement());
+ }
}
+ /**
+ * 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.println(ATTR_MANIFEST_VERSION + ": " + manifestVersion);
- String signatureVersion = mainSection.getAttributeValue(ATTR_SIGNATURE_VERSION);
+ writer.println(ATTRIBUTE_MANIFEST_VERSION + ": " + manifestVersion);
+ String signatureVersion = mainSection.getAttributeValue(ATTRIBUTE_SIGNATURE_VERSION);
if (signatureVersion != null) {
- writer.println(ATTR_SIGNATURE_VERSION + ": " + signatureVersion);
- mainSection.removeAttribute(ATTR_SIGNATURE_VERSION);
+ writer.println(ATTRIBUTE_SIGNATURE_VERSION + ": " + signatureVersion);
+ mainSection.removeAttribute(ATTRIBUTE_SIGNATURE_VERSION);
}
mainSection.write(writer);
if (signatureVersion != null) {
- mainSection.addAttribute(new Attribute(ATTR_SIGNATURE_VERSION, signatureVersion));
+ try {
+ mainSection.addAttribute(new Attribute(ATTRIBUTE_SIGNATURE_VERSION, signatureVersion));
+ }
+ catch (ManifestException e) {
+ // shouldn't happen - ignore
+ }
}
for (Enumeration e = sections.elements(); e.hasMoreElements();) {
@@ -326,6 +496,11 @@
}
}
+ /**
+ * 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 {
@@ -335,5 +510,14 @@
return null;
}
return sw.toString();
+ }
+
+ /**
+ * Get the warnings for this manifest.
+ *
+ * @return an enumeration of warning strings
+ */
+ public Enumeration getWarnings() {
+ return warnings.elements();
}
}
1.44 +33 -23 jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Zip.java
Index: Zip.java
===================================================================
RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Zip.java,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -r1.43 -r1.44
--- Zip.java 2001/07/28 14:11:41 1.43
+++ Zip.java 2001/07/30 11:15:17 1.44
@@ -431,7 +431,39 @@
throws IOException, BuildException
{
}
+
/**
+ * Create an empty zip file
+ *
+ * @return true if the file is then considered up to date.
+ */
+ protected boolean createEmptyZip(File zipFile) {
+ // In this case using java.util.zip will not work
+ // because it does not permit a zero-entry archive.
+ // Must create it manually.
+ log("Note: creating empty "+archiveType+" archive " + zipFile, Project.MSG_INFO);
+ try {
+ OutputStream os = new FileOutputStream(zipFile);
+ try {
+ // Cf. PKZIP specification.
+ byte[] empty = new byte[22];
+ empty[0] = 80; // P
+ empty[1] = 75; // K
+ empty[2] = 5;
+ empty[3] = 6;
+ // remainder zeros
+ os.write(empty);
+ } finally {
+ os.close();
+ }
+ } catch (IOException ioe) {
+ throw new BuildException("Could not create empty ZIP archive", ioe, location);
+ }
+ return true;
+ }
+
+
+ /**
* Check whether the archive is up-to-date; and handle behavior for empty archives.
* @param scanners list of prepared scanners containing files to archive
* @param zipFile intended archive file (may or may not exist)
@@ -453,29 +485,7 @@
": no files were included.", location);
} else {
// Create.
- if (zipFile.exists()) return true;
- // In this case using java.util.zip will not work
- // because it does not permit a zero-entry archive.
- // Must create it manually.
- log("Note: creating empty "+archiveType+" archive " + zipFile, Project.MSG_INFO);
- try {
- OutputStream os = new FileOutputStream(zipFile);
- try {
- // Cf. PKZIP specification.
- byte[] empty = new byte[22];
- empty[0] = 80; // P
- empty[1] = 75; // K
- empty[2] = 5;
- empty[3] = 6;
- // remainder zeros
- os.write(empty);
- } finally {
- os.close();
- }
- } catch (IOException ioe) {
- throw new BuildException("Could not create empty ZIP archive", ioe, location);
- }
- return true;
+ return createEmptyZip(zipFile);
}
} else {
for (int i = 0; i < files.length; ++i) {
1.1 jakarta-ant/src/main/org/apache/tools/ant/taskdefs/ManifestException.java
Index: ManifestException.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Ant", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.tools.ant.taskdefs;
import java.io.*;
/**
* Exception thrown indicating problems in a JAR Manifest
*
* @author <a href="mailto:conor@apache.org">Conor MacNeill</a>
*/
public class ManifestException extends Exception {
/**
* Constructs an exception with the given descriptive message.
* @param msg Description of or information about the exception.
*/
public ManifestException(String msg) {
super(msg);
}
}