diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Attribute.java b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Attribute.java
new file mode 100644
index 000000000..7c7bb5514
--- /dev/null
+++ b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Attribute.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.tools.ant.taskdefs.manifest;
+
+import java.io.PrintWriter;
+import java.io.IOException;
+
+/**
+ * Class to hold manifest attributes
+ *
+ * @author Conor MacNeill
+ * @author Stefan Bodewig
+ * @author Peter Donald
+ * @version $Revision$ $Date$
+ */
+public class Attribute
+{
+ /**
+ * The attribute's name
+ */
+ private String m_name;
+
+ /**
+ * The attribute's value
+ */
+ private String m_value;
+
+ /**
+ * Construct an empty attribute
+ */
+ public Attribute()
+ {
+ }
+
+ /**
+ * Construct a manifest by specifying its name and value
+ *
+ * @param name the attribute's name
+ * @param value the Attribute's value
+ */
+ public Attribute( final String name, final String value )
+ {
+ m_name = name;
+ m_value = value;
+ }
+
+ /**
+ * Set the Attribute's name
+ *
+ * @param name the attribute's name
+ */
+ public void setName( final String name )
+ {
+ m_name = name;
+ }
+
+ /**
+ * Set the Attribute's value
+ *
+ * @param value the attribute's value
+ */
+ public void setValue( final String value )
+ {
+ m_value = value;
+ }
+
+ /**
+ * Get the Attribute's name
+ *
+ * @return the attribute's name.
+ */
+ public String getName()
+ {
+ return m_name;
+ }
+
+ /**
+ * Get the Attribute's value
+ *
+ * @return the attribute's value.
+ */
+ public String getValue()
+ {
+ return m_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.
+ *
+ * @param line The feature to be added to the Continuation attribute
+ */
+ public void addContinuation( final String line )
+ {
+ m_value += line.substring( 1 );
+ }
+
+ public boolean equals( Object object )
+ {
+ if( !( object instanceof Attribute ) )
+ {
+ return false;
+ }
+
+ final Attribute other = (Attribute)object;
+ return
+ ( null != m_name && null != other.m_name &&
+ m_name.toLowerCase().equals( other.m_name.toLowerCase() ) &&
+ m_value != null && m_value.equals( other.m_value ) );
+ }
+
+}
diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Manifest.java b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Manifest.java
index 5cf5289a5..b531ad3bf 100644
--- a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Manifest.java
+++ b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Manifest.java
@@ -25,24 +25,18 @@ import java.util.Iterator;
import java.util.jar.Attributes;
import org.apache.myrmidon.api.AbstractTask;
import org.apache.myrmidon.api.TaskException;
-import org.apache.tools.ant.types.EnumeratedAttribute;
/**
* Class to manage Manifest information
*
+ * @author Peter Donald
* @author Conor MacNeill
* @author Stefan Bodewig
- * @author Peter Donald
* @version $Revision$ $Date$
*/
public class Manifest
extends AbstractTask
{
- /**
- * The standard manifest version header
- */
- public final static String ATTRIBUTE_MANIFEST_VERSION = Attributes.Name.MANIFEST_VERSION.toString();
-
/**
* The standard Signature Version header
*/
@@ -119,11 +113,11 @@ public class Manifest
BufferedReader reader = new BufferedReader( r );
// This should be the manifest version
String nextSectionName = m_mainSection.read( reader );
- String readManifestVersion = m_mainSection.getAttributeValue( ATTRIBUTE_MANIFEST_VERSION );
+ String readManifestVersion = m_mainSection.getAttributeValue( Attributes.Name.MANIFEST_VERSION.toString() );
if( readManifestVersion != null )
{
m_manifestVersion = readManifestVersion;
- m_mainSection.removeAttribute( ATTRIBUTE_MANIFEST_VERSION );
+ m_mainSection.removeAttribute( Attributes.Name.MANIFEST_VERSION.toString() );
}
String line = null;
@@ -137,7 +131,7 @@ public class Manifest
Section section = new Section();
if( nextSectionName == null )
{
- Attribute sectionName = new Attribute( line );
+ Attribute sectionName = ManifestUtil.buildAttribute( line );
if( !sectionName.getName().equalsIgnoreCase( ATTRIBUTE_NAME ) )
{
throw new ManifestException( "Manifest sections should start with a \"" + ATTRIBUTE_NAME +
@@ -150,7 +144,7 @@ public class Manifest
// 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 );
+ Attribute firstAttribute = ManifestUtil.buildAttribute( line );
section.addAttributeAndCheck( firstAttribute );
}
@@ -438,7 +432,7 @@ public class Manifest
public void write( PrintWriter writer )
throws IOException, TaskException
{
- writer.println( ATTRIBUTE_MANIFEST_VERSION + ": " + m_manifestVersion );
+ writer.println( Attributes.Name.MANIFEST_VERSION + ": " + m_manifestVersion );
String signatureVersion = m_mainSection.getAttributeValue( ATTRIBUTE_SIGNATURE_VERSION );
if( signatureVersion != null )
{
@@ -465,493 +459,4 @@ public class Manifest
}
}
- /**
- * Class to hold manifest attributes
- *
- * @author RT
- */
- public static class Attribute
- {
- /**
- * The attribute's name
- */
- private String name = null;
-
- /**
- * The attribute's value
- */
- private String value = null;
-
- /**
- * 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
- * @exception ManifestException Description of Exception
- * @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;
- }
-
- /**
- * Set the Attribute's name
- *
- * @param name the attribute's name
- */
- public void setName( String name )
- {
- this.name = name;
- }
-
- /**
- * Set the Attribute's value
- *
- * @param value the attribute's value
- */
- public void setValue( String value )
- {
- this.value = value;
- }
-
- /**
- * Get the Attribute's name
- *
- * @return the attribute's name.
- */
- public String getName()
- {
- return name;
- }
-
- /**
- * 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.
- *
- * @param line The feature to be added to the Continuation attribute
- */
- public void addContinuation( String line )
- {
- value += line.substring( 1 );
- }
-
- public boolean equals( Object rhs )
- {
- if( !( rhs instanceof Attribute ) )
- {
- return false;
- }
-
- Attribute rhsAttribute = (Attribute)rhs;
- return ( name != null && rhsAttribute.name != null &&
- name.toLowerCase().equals( rhsAttribute.name.toLowerCase() ) &&
- value != null && value.equals( rhsAttribute.value ) );
- }
-
- /**
- * 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 );
- value = line.substring( index + 2 );
- }
-
- /**
- * 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 )
- {
- // try to find a MAX_LINE_LENGTH byte section
- int breakIndex = MAX_LINE_LENGTH;
- String section = line.substring( 0, breakIndex );
- while( section.getBytes().length > MAX_LINE_LENGTH && breakIndex > 0 )
- {
- breakIndex--;
- section = line.substring( 0, breakIndex );
- }
- if( breakIndex == 0 )
- {
- throw new IOException( "Unable to write manifest line " + name + ": " + value );
- }
- writer.println( section );
- line = " " + line.substring( breakIndex );
- }
- writer.println( line );
- }
- }
-
- /**
- * Helper class for Manifest's mode attribute.
- */
- public static class ManifestMode extends EnumeratedAttribute
- {
- public String[] getValues()
- {
- return new String[]{"update", "replace"};
- }
- }
-
- /**
- * Class to represent an individual section in the Manifest. A section
- * consists of a set of attribute values, separated from other sections by a
- * blank line.
- *
- * @author RT
- */
- public static class Section
- {
- private ArrayList warnings = new ArrayList();
-
- /**
- * 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 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 )
- {
- Object attribute = attributes.get( attributeName.toLowerCase() );
- if( attribute == null )
- {
- return null;
- }
- if( attribute instanceof Attribute )
- {
- return ( (Attribute)attribute ).getValue();
- }
- else
- {
- String value = "";
- for( Iterator e = ( (ArrayList)attribute ).iterator(); e.hasNext(); )
- {
- Attribute classpathAttribute = (Attribute)e.next();
- value += classpathAttribute.getValue() + " ";
- }
- return value.trim();
- }
- }
-
- /**
- * Get the Section's name
- *
- * @return the section's name.
- */
- public String getName()
- {
- return name;
- }
-
- public Iterator getWarnings()
- {
- return warnings.iterator();
- }
-
- /**
- * 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 addAttributeAndCheck( Attribute attribute )
- throws ManifestException, TaskException
- {
- if( attribute.getName() == null || attribute.getValue() == null )
- {
- throw new TaskException( "Attributes must have name and value" );
- }
- if( attribute.getName().equalsIgnoreCase( ATTRIBUTE_NAME ) )
- {
- warnings.add( "\"" + 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.add( "Manifest attributes should not start with \"" +
- ATTRIBUTE_FROM + "\" in \"" + attribute.getName() + ": " + attribute.getValue() + "\"" );
- }
- else
- {
- // classpath attributes go into a vector
- String attributeName = attribute.getName().toLowerCase();
- if( attributeName.equals( ATTRIBUTE_CLASSPATH ) )
- {
- ArrayList classpathAttrs = (ArrayList)attributes.get( attributeName );
- if( classpathAttrs == null )
- {
- classpathAttrs = new ArrayList();
- attributes.put( attributeName, classpathAttrs );
- }
- classpathAttrs.add( attribute );
- }
- else if( attributes.containsKey( attributeName ) )
- {
- throw new ManifestException( "The attribute \"" + attribute.getName() + "\" may not " +
- "occur more than once in the same section" );
- }
- else
- {
- attributes.put( attributeName, attribute );
- }
- }
- return null;
- }
-
- public void addAttribute( Attribute attribute )
- throws ManifestException, TaskException
- {
- String check = addAttributeAndCheck( attribute );
- if( check != null )
- {
- throw new TaskException( "Specify the section name using the \"name\" attribute of the element rather " +
- "than using a \"Name\" manifest attribute" );
- }
- }
-
- public boolean equals( Object rhs )
- {
- if( !( rhs instanceof Section ) )
- {
- return false;
- }
-
- Section rhsSection = (Section)rhs;
- if( attributes.size() != rhsSection.attributes.size() )
- {
- return false;
- }
-
- for( Enumeration e = attributes.elements(); e.hasMoreElements(); )
- {
- Attribute attribute = (Attribute)e.nextElement();
- Attribute rshAttribute = (Attribute)rhsSection.attributes.get( attribute.getName().toLowerCase() );
- if( !attribute.equals( rshAttribute ) )
- {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * 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" );
- }
-
- for( Enumeration e = section.attributes.keys(); e.hasMoreElements(); )
- {
- String attributeName = (String)e.nextElement();
- if( attributeName.equals( ATTRIBUTE_CLASSPATH ) &&
- attributes.containsKey( attributeName ) )
- {
- // classpath entries are vetors which are merged
- ArrayList classpathAttrs = (ArrayList)section.attributes.get( attributeName );
- ArrayList ourClasspathAttrs = (ArrayList)attributes.get( attributeName );
- for( Iterator e2 = classpathAttrs.iterator(); e2.hasNext(); )
- {
- ourClasspathAttrs.add( e2.next() );
- }
- }
- else
- {
- // the merge file always wins
- attributes.put( attributeName, section.attributes.get( attributeName ) );
- }
- }
-
- // add in the warnings
- for( Iterator e = section.warnings.iterator(); e.hasNext(); )
- {
- warnings.add( e.next() );
- }
- }
-
- /**
- * 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, TaskException
- {
- 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 );
- if( nameReadAhead != null )
- {
- return nameReadAhead;
- }
- }
- }
- }
-
- /**
- * 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() );
- }
-
- /**
- * 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 );
- }
- for( Enumeration e = attributes.elements(); e.hasMoreElements(); )
- {
- Object object = e.nextElement();
- if( object instanceof Attribute )
- {
- Attribute attribute = (Attribute)object;
- attribute.write( writer );
- }
- else
- {
- ArrayList attrList = (ArrayList)object;
- for( Iterator e2 = attrList.iterator(); e2.hasNext(); )
- {
- Attribute attribute = (Attribute)e2.next();
- attribute.write( writer );
- }
- }
- }
- writer.println();
- }
- }
-
}
diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/ManifestMode.java b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/ManifestMode.java
new file mode 100644
index 000000000..a551bd1ef
--- /dev/null
+++ b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/ManifestMode.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.tools.ant.taskdefs.manifest;
+
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * Helper class for Manifest's mode attribute.
+ *
+ * @author Conor MacNeill
+ * @author Stefan Bodewig
+ * @author Peter Donald
+ * @version $Revision$ $Date$
+ */
+public class ManifestMode
+ extends EnumeratedAttribute
+{
+ public String[] getValues()
+ {
+ return new String[]{"update", "replace"};
+ }
+}
diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/ManifestUtil.java b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/ManifestUtil.java
new file mode 100644
index 000000000..8a2a46809
--- /dev/null
+++ b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/ManifestUtil.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.tools.ant.taskdefs.manifest;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Utility methods for manifest stuff.
+ *
+ * @author Conor MacNeill
+ * @author Stefan Bodewig
+ * @author Peter Donald
+ * @version $Revision$ $Date$
+ */
+public final class ManifestUtil
+{
+ public static Attribute buildAttribute( final String line )
+ throws ManifestException
+ {
+ final Attribute attribute = new Attribute();
+ parse( attribute, line );
+ return attribute;
+ }
+
+ /**
+ * 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 static void parse( final Attribute attribute, final String line )
+ throws ManifestException
+ {
+ final 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 ': ' " );
+ }
+ final String name = line.substring( 0, index );
+ final String value = line.substring( index + 2 );
+ attribute.setName( name );
+ attribute.setValue( value );
+ }
+
+ public static void write( final Attribute attribute, final PrintWriter writer )
+ throws IOException
+ {
+ final String name = attribute.getName();
+ final String value = attribute.getValue();
+ String line = name + ": " + value;
+ while( line.getBytes().length > Manifest.MAX_LINE_LENGTH )
+ {
+ // try to find a MAX_LINE_LENGTH byte section
+ int breakIndex = Manifest.MAX_LINE_LENGTH;
+ String section = line.substring( 0, breakIndex );
+ while( section.getBytes().length > Manifest.MAX_LINE_LENGTH && breakIndex > 0 )
+ {
+ breakIndex--;
+ section = line.substring( 0, breakIndex );
+ }
+ if( breakIndex == 0 )
+ {
+ throw new IOException( "Unable to write manifest line " + name + ": " + value );
+ }
+ writer.println( section );
+ line = " " + line.substring( breakIndex );
+ }
+ writer.println( line );
+ }
+}
diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Section.java b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Section.java
new file mode 100644
index 000000000..a15b51b19
--- /dev/null
+++ b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Section.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.tools.ant.taskdefs.manifest;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import org.apache.myrmidon.api.TaskException;
+
+/**
+ * Class to represent an individual section in the Manifest. A section
+ * consists of a set of attribute values, separated from other sections by a
+ * blank line.
+ *
+ * @author Conor MacNeill
+ * @author Stefan Bodewig
+ * @author Peter Donald
+ * @version $Revision$ $Date$
+ */
+public class Section
+{
+ private ArrayList warnings = new ArrayList();
+
+ /**
+ * 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 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 )
+ {
+ Object attribute = attributes.get( attributeName.toLowerCase() );
+ if( attribute == null )
+ {
+ return null;
+ }
+ if( attribute instanceof Attribute )
+ {
+ return ( (Attribute)attribute ).getValue();
+ }
+ else
+ {
+ String value = "";
+ for( Iterator e = ( (ArrayList)attribute ).iterator(); e.hasNext(); )
+ {
+ Attribute classpathAttribute = (Attribute)e.next();
+ value += classpathAttribute.getValue() + " ";
+ }
+ return value.trim();
+ }
+ }
+
+ /**
+ * Get the Section's name
+ *
+ * @return the section's name.
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ public Iterator getWarnings()
+ {
+ return warnings.iterator();
+ }
+
+ /**
+ * 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 addAttributeAndCheck( Attribute attribute )
+ throws ManifestException, TaskException
+ {
+ if( attribute.getName() == null || attribute.getValue() == null )
+ {
+ throw new TaskException( "Attributes must have name and value" );
+ }
+ if( attribute.getName().equalsIgnoreCase( Manifest.ATTRIBUTE_NAME ) )
+ {
+ warnings.add( "\"" + Manifest.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( Manifest.ATTRIBUTE_FROM.toLowerCase() ) )
+ {
+ warnings.add( "Manifest attributes should not start with \"" +
+ Manifest.ATTRIBUTE_FROM + "\" in \"" + attribute.getName() + ": " + attribute.getValue() + "\"" );
+ }
+ else
+ {
+ // classpath attributes go into a vector
+ String attributeName = attribute.getName().toLowerCase();
+ if( attributeName.equals( Manifest.ATTRIBUTE_CLASSPATH ) )
+ {
+ ArrayList classpathAttrs = (ArrayList)attributes.get( attributeName );
+ if( classpathAttrs == null )
+ {
+ classpathAttrs = new ArrayList();
+ attributes.put( attributeName, classpathAttrs );
+ }
+ classpathAttrs.add( attribute );
+ }
+ else if( attributes.containsKey( attributeName ) )
+ {
+ throw new ManifestException( "The attribute \"" + attribute.getName() + "\" may not " +
+ "occur more than once in the same section" );
+ }
+ else
+ {
+ attributes.put( attributeName, attribute );
+ }
+ }
+ return null;
+ }
+
+ public void addAttribute( Attribute attribute )
+ throws ManifestException, TaskException
+ {
+ String check = addAttributeAndCheck( attribute );
+ if( check != null )
+ {
+ throw new TaskException( "Specify the section name using the \"name\" attribute of the element rather " +
+ "than using a \"Name\" manifest attribute" );
+ }
+ }
+
+ public boolean equals( Object rhs )
+ {
+ if( !( rhs instanceof Section ) )
+ {
+ return false;
+ }
+
+ Section rhsSection = (Section)rhs;
+ if( attributes.size() != rhsSection.attributes.size() )
+ {
+ return false;
+ }
+
+ for( Enumeration e = attributes.elements(); e.hasMoreElements(); )
+ {
+ Attribute attribute = (Attribute)e.nextElement();
+ Attribute rshAttribute = (Attribute)rhsSection.attributes.get( attribute.getName().toLowerCase() );
+ if( !attribute.equals( rshAttribute ) )
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * 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" );
+ }
+
+ for( Enumeration e = section.attributes.keys(); e.hasMoreElements(); )
+ {
+ String attributeName = (String)e.nextElement();
+ if( attributeName.equals( Manifest.ATTRIBUTE_CLASSPATH ) &&
+ attributes.containsKey( attributeName ) )
+ {
+ // classpath entries are vetors which are merged
+ ArrayList classpathAttrs = (ArrayList)section.attributes.get( attributeName );
+ ArrayList ourClasspathAttrs = (ArrayList)attributes.get( attributeName );
+ for( Iterator e2 = classpathAttrs.iterator(); e2.hasNext(); )
+ {
+ ourClasspathAttrs.add( e2.next() );
+ }
+ }
+ else
+ {
+ // the merge file always wins
+ attributes.put( attributeName, section.attributes.get( attributeName ) );
+ }
+ }
+
+ // add in the warnings
+ for( Iterator e = section.warnings.iterator(); e.hasNext(); )
+ {
+ warnings.add( e.next() );
+ }
+ }
+
+ /**
+ * 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, TaskException
+ {
+ 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 = ManifestUtil.buildAttribute( line );
+ String nameReadAhead = addAttributeAndCheck( attribute );
+ if( nameReadAhead != null )
+ {
+ return nameReadAhead;
+ }
+ }
+ }
+ }
+
+ /**
+ * 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() );
+ }
+
+ /**
+ * 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( Manifest.ATTRIBUTE_NAME, name );
+ ManifestUtil.write( nameAttr, writer );
+ }
+ for( Enumeration e = attributes.elements(); e.hasMoreElements(); )
+ {
+ Object object = e.nextElement();
+ if( object instanceof Attribute )
+ {
+ Attribute attribute = (Attribute)object;
+ ManifestUtil.write( attribute, writer );
+ }
+ else
+ {
+ ArrayList attrList = (ArrayList)object;
+ for( Iterator e2 = attrList.iterator(); e2.hasNext(); )
+ {
+ Attribute attribute = (Attribute)e2.next();
+ ManifestUtil.write( attribute, writer );
+ }
+ }
+ }
+ writer.println();
+ }
+}
diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Attribute.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Attribute.java
new file mode 100644
index 000000000..7c7bb5514
--- /dev/null
+++ b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Attribute.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.tools.ant.taskdefs.manifest;
+
+import java.io.PrintWriter;
+import java.io.IOException;
+
+/**
+ * Class to hold manifest attributes
+ *
+ * @author Conor MacNeill
+ * @author Stefan Bodewig
+ * @author Peter Donald
+ * @version $Revision$ $Date$
+ */
+public class Attribute
+{
+ /**
+ * The attribute's name
+ */
+ private String m_name;
+
+ /**
+ * The attribute's value
+ */
+ private String m_value;
+
+ /**
+ * Construct an empty attribute
+ */
+ public Attribute()
+ {
+ }
+
+ /**
+ * Construct a manifest by specifying its name and value
+ *
+ * @param name the attribute's name
+ * @param value the Attribute's value
+ */
+ public Attribute( final String name, final String value )
+ {
+ m_name = name;
+ m_value = value;
+ }
+
+ /**
+ * Set the Attribute's name
+ *
+ * @param name the attribute's name
+ */
+ public void setName( final String name )
+ {
+ m_name = name;
+ }
+
+ /**
+ * Set the Attribute's value
+ *
+ * @param value the attribute's value
+ */
+ public void setValue( final String value )
+ {
+ m_value = value;
+ }
+
+ /**
+ * Get the Attribute's name
+ *
+ * @return the attribute's name.
+ */
+ public String getName()
+ {
+ return m_name;
+ }
+
+ /**
+ * Get the Attribute's value
+ *
+ * @return the attribute's value.
+ */
+ public String getValue()
+ {
+ return m_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.
+ *
+ * @param line The feature to be added to the Continuation attribute
+ */
+ public void addContinuation( final String line )
+ {
+ m_value += line.substring( 1 );
+ }
+
+ public boolean equals( Object object )
+ {
+ if( !( object instanceof Attribute ) )
+ {
+ return false;
+ }
+
+ final Attribute other = (Attribute)object;
+ return
+ ( null != m_name && null != other.m_name &&
+ m_name.toLowerCase().equals( other.m_name.toLowerCase() ) &&
+ m_value != null && m_value.equals( other.m_value ) );
+ }
+
+}
diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Manifest.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Manifest.java
index 5cf5289a5..b531ad3bf 100644
--- a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Manifest.java
+++ b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Manifest.java
@@ -25,24 +25,18 @@ import java.util.Iterator;
import java.util.jar.Attributes;
import org.apache.myrmidon.api.AbstractTask;
import org.apache.myrmidon.api.TaskException;
-import org.apache.tools.ant.types.EnumeratedAttribute;
/**
* Class to manage Manifest information
*
+ * @author Peter Donald
* @author Conor MacNeill
* @author Stefan Bodewig
- * @author Peter Donald
* @version $Revision$ $Date$
*/
public class Manifest
extends AbstractTask
{
- /**
- * The standard manifest version header
- */
- public final static String ATTRIBUTE_MANIFEST_VERSION = Attributes.Name.MANIFEST_VERSION.toString();
-
/**
* The standard Signature Version header
*/
@@ -119,11 +113,11 @@ public class Manifest
BufferedReader reader = new BufferedReader( r );
// This should be the manifest version
String nextSectionName = m_mainSection.read( reader );
- String readManifestVersion = m_mainSection.getAttributeValue( ATTRIBUTE_MANIFEST_VERSION );
+ String readManifestVersion = m_mainSection.getAttributeValue( Attributes.Name.MANIFEST_VERSION.toString() );
if( readManifestVersion != null )
{
m_manifestVersion = readManifestVersion;
- m_mainSection.removeAttribute( ATTRIBUTE_MANIFEST_VERSION );
+ m_mainSection.removeAttribute( Attributes.Name.MANIFEST_VERSION.toString() );
}
String line = null;
@@ -137,7 +131,7 @@ public class Manifest
Section section = new Section();
if( nextSectionName == null )
{
- Attribute sectionName = new Attribute( line );
+ Attribute sectionName = ManifestUtil.buildAttribute( line );
if( !sectionName.getName().equalsIgnoreCase( ATTRIBUTE_NAME ) )
{
throw new ManifestException( "Manifest sections should start with a \"" + ATTRIBUTE_NAME +
@@ -150,7 +144,7 @@ public class Manifest
// 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 );
+ Attribute firstAttribute = ManifestUtil.buildAttribute( line );
section.addAttributeAndCheck( firstAttribute );
}
@@ -438,7 +432,7 @@ public class Manifest
public void write( PrintWriter writer )
throws IOException, TaskException
{
- writer.println( ATTRIBUTE_MANIFEST_VERSION + ": " + m_manifestVersion );
+ writer.println( Attributes.Name.MANIFEST_VERSION + ": " + m_manifestVersion );
String signatureVersion = m_mainSection.getAttributeValue( ATTRIBUTE_SIGNATURE_VERSION );
if( signatureVersion != null )
{
@@ -465,493 +459,4 @@ public class Manifest
}
}
- /**
- * Class to hold manifest attributes
- *
- * @author RT
- */
- public static class Attribute
- {
- /**
- * The attribute's name
- */
- private String name = null;
-
- /**
- * The attribute's value
- */
- private String value = null;
-
- /**
- * 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
- * @exception ManifestException Description of Exception
- * @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;
- }
-
- /**
- * Set the Attribute's name
- *
- * @param name the attribute's name
- */
- public void setName( String name )
- {
- this.name = name;
- }
-
- /**
- * Set the Attribute's value
- *
- * @param value the attribute's value
- */
- public void setValue( String value )
- {
- this.value = value;
- }
-
- /**
- * Get the Attribute's name
- *
- * @return the attribute's name.
- */
- public String getName()
- {
- return name;
- }
-
- /**
- * 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.
- *
- * @param line The feature to be added to the Continuation attribute
- */
- public void addContinuation( String line )
- {
- value += line.substring( 1 );
- }
-
- public boolean equals( Object rhs )
- {
- if( !( rhs instanceof Attribute ) )
- {
- return false;
- }
-
- Attribute rhsAttribute = (Attribute)rhs;
- return ( name != null && rhsAttribute.name != null &&
- name.toLowerCase().equals( rhsAttribute.name.toLowerCase() ) &&
- value != null && value.equals( rhsAttribute.value ) );
- }
-
- /**
- * 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 );
- value = line.substring( index + 2 );
- }
-
- /**
- * 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 )
- {
- // try to find a MAX_LINE_LENGTH byte section
- int breakIndex = MAX_LINE_LENGTH;
- String section = line.substring( 0, breakIndex );
- while( section.getBytes().length > MAX_LINE_LENGTH && breakIndex > 0 )
- {
- breakIndex--;
- section = line.substring( 0, breakIndex );
- }
- if( breakIndex == 0 )
- {
- throw new IOException( "Unable to write manifest line " + name + ": " + value );
- }
- writer.println( section );
- line = " " + line.substring( breakIndex );
- }
- writer.println( line );
- }
- }
-
- /**
- * Helper class for Manifest's mode attribute.
- */
- public static class ManifestMode extends EnumeratedAttribute
- {
- public String[] getValues()
- {
- return new String[]{"update", "replace"};
- }
- }
-
- /**
- * Class to represent an individual section in the Manifest. A section
- * consists of a set of attribute values, separated from other sections by a
- * blank line.
- *
- * @author RT
- */
- public static class Section
- {
- private ArrayList warnings = new ArrayList();
-
- /**
- * 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 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 )
- {
- Object attribute = attributes.get( attributeName.toLowerCase() );
- if( attribute == null )
- {
- return null;
- }
- if( attribute instanceof Attribute )
- {
- return ( (Attribute)attribute ).getValue();
- }
- else
- {
- String value = "";
- for( Iterator e = ( (ArrayList)attribute ).iterator(); e.hasNext(); )
- {
- Attribute classpathAttribute = (Attribute)e.next();
- value += classpathAttribute.getValue() + " ";
- }
- return value.trim();
- }
- }
-
- /**
- * Get the Section's name
- *
- * @return the section's name.
- */
- public String getName()
- {
- return name;
- }
-
- public Iterator getWarnings()
- {
- return warnings.iterator();
- }
-
- /**
- * 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 addAttributeAndCheck( Attribute attribute )
- throws ManifestException, TaskException
- {
- if( attribute.getName() == null || attribute.getValue() == null )
- {
- throw new TaskException( "Attributes must have name and value" );
- }
- if( attribute.getName().equalsIgnoreCase( ATTRIBUTE_NAME ) )
- {
- warnings.add( "\"" + 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.add( "Manifest attributes should not start with \"" +
- ATTRIBUTE_FROM + "\" in \"" + attribute.getName() + ": " + attribute.getValue() + "\"" );
- }
- else
- {
- // classpath attributes go into a vector
- String attributeName = attribute.getName().toLowerCase();
- if( attributeName.equals( ATTRIBUTE_CLASSPATH ) )
- {
- ArrayList classpathAttrs = (ArrayList)attributes.get( attributeName );
- if( classpathAttrs == null )
- {
- classpathAttrs = new ArrayList();
- attributes.put( attributeName, classpathAttrs );
- }
- classpathAttrs.add( attribute );
- }
- else if( attributes.containsKey( attributeName ) )
- {
- throw new ManifestException( "The attribute \"" + attribute.getName() + "\" may not " +
- "occur more than once in the same section" );
- }
- else
- {
- attributes.put( attributeName, attribute );
- }
- }
- return null;
- }
-
- public void addAttribute( Attribute attribute )
- throws ManifestException, TaskException
- {
- String check = addAttributeAndCheck( attribute );
- if( check != null )
- {
- throw new TaskException( "Specify the section name using the \"name\" attribute of the element rather " +
- "than using a \"Name\" manifest attribute" );
- }
- }
-
- public boolean equals( Object rhs )
- {
- if( !( rhs instanceof Section ) )
- {
- return false;
- }
-
- Section rhsSection = (Section)rhs;
- if( attributes.size() != rhsSection.attributes.size() )
- {
- return false;
- }
-
- for( Enumeration e = attributes.elements(); e.hasMoreElements(); )
- {
- Attribute attribute = (Attribute)e.nextElement();
- Attribute rshAttribute = (Attribute)rhsSection.attributes.get( attribute.getName().toLowerCase() );
- if( !attribute.equals( rshAttribute ) )
- {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * 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" );
- }
-
- for( Enumeration e = section.attributes.keys(); e.hasMoreElements(); )
- {
- String attributeName = (String)e.nextElement();
- if( attributeName.equals( ATTRIBUTE_CLASSPATH ) &&
- attributes.containsKey( attributeName ) )
- {
- // classpath entries are vetors which are merged
- ArrayList classpathAttrs = (ArrayList)section.attributes.get( attributeName );
- ArrayList ourClasspathAttrs = (ArrayList)attributes.get( attributeName );
- for( Iterator e2 = classpathAttrs.iterator(); e2.hasNext(); )
- {
- ourClasspathAttrs.add( e2.next() );
- }
- }
- else
- {
- // the merge file always wins
- attributes.put( attributeName, section.attributes.get( attributeName ) );
- }
- }
-
- // add in the warnings
- for( Iterator e = section.warnings.iterator(); e.hasNext(); )
- {
- warnings.add( e.next() );
- }
- }
-
- /**
- * 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, TaskException
- {
- 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 );
- if( nameReadAhead != null )
- {
- return nameReadAhead;
- }
- }
- }
- }
-
- /**
- * 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() );
- }
-
- /**
- * 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 );
- }
- for( Enumeration e = attributes.elements(); e.hasMoreElements(); )
- {
- Object object = e.nextElement();
- if( object instanceof Attribute )
- {
- Attribute attribute = (Attribute)object;
- attribute.write( writer );
- }
- else
- {
- ArrayList attrList = (ArrayList)object;
- for( Iterator e2 = attrList.iterator(); e2.hasNext(); )
- {
- Attribute attribute = (Attribute)e2.next();
- attribute.write( writer );
- }
- }
- }
- writer.println();
- }
- }
-
}
diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/ManifestMode.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/ManifestMode.java
new file mode 100644
index 000000000..a551bd1ef
--- /dev/null
+++ b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/ManifestMode.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.tools.ant.taskdefs.manifest;
+
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * Helper class for Manifest's mode attribute.
+ *
+ * @author Conor MacNeill
+ * @author Stefan Bodewig
+ * @author Peter Donald
+ * @version $Revision$ $Date$
+ */
+public class ManifestMode
+ extends EnumeratedAttribute
+{
+ public String[] getValues()
+ {
+ return new String[]{"update", "replace"};
+ }
+}
diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/ManifestUtil.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/ManifestUtil.java
new file mode 100644
index 000000000..8a2a46809
--- /dev/null
+++ b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/ManifestUtil.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.tools.ant.taskdefs.manifest;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Utility methods for manifest stuff.
+ *
+ * @author Conor MacNeill
+ * @author Stefan Bodewig
+ * @author Peter Donald
+ * @version $Revision$ $Date$
+ */
+public final class ManifestUtil
+{
+ public static Attribute buildAttribute( final String line )
+ throws ManifestException
+ {
+ final Attribute attribute = new Attribute();
+ parse( attribute, line );
+ return attribute;
+ }
+
+ /**
+ * 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 static void parse( final Attribute attribute, final String line )
+ throws ManifestException
+ {
+ final 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 ': ' " );
+ }
+ final String name = line.substring( 0, index );
+ final String value = line.substring( index + 2 );
+ attribute.setName( name );
+ attribute.setValue( value );
+ }
+
+ public static void write( final Attribute attribute, final PrintWriter writer )
+ throws IOException
+ {
+ final String name = attribute.getName();
+ final String value = attribute.getValue();
+ String line = name + ": " + value;
+ while( line.getBytes().length > Manifest.MAX_LINE_LENGTH )
+ {
+ // try to find a MAX_LINE_LENGTH byte section
+ int breakIndex = Manifest.MAX_LINE_LENGTH;
+ String section = line.substring( 0, breakIndex );
+ while( section.getBytes().length > Manifest.MAX_LINE_LENGTH && breakIndex > 0 )
+ {
+ breakIndex--;
+ section = line.substring( 0, breakIndex );
+ }
+ if( breakIndex == 0 )
+ {
+ throw new IOException( "Unable to write manifest line " + name + ": " + value );
+ }
+ writer.println( section );
+ line = " " + line.substring( breakIndex );
+ }
+ writer.println( line );
+ }
+}
diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Section.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Section.java
new file mode 100644
index 000000000..a15b51b19
--- /dev/null
+++ b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Section.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ */
+package org.apache.tools.ant.taskdefs.manifest;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import org.apache.myrmidon.api.TaskException;
+
+/**
+ * Class to represent an individual section in the Manifest. A section
+ * consists of a set of attribute values, separated from other sections by a
+ * blank line.
+ *
+ * @author Conor MacNeill
+ * @author Stefan Bodewig
+ * @author Peter Donald
+ * @version $Revision$ $Date$
+ */
+public class Section
+{
+ private ArrayList warnings = new ArrayList();
+
+ /**
+ * 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 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 )
+ {
+ Object attribute = attributes.get( attributeName.toLowerCase() );
+ if( attribute == null )
+ {
+ return null;
+ }
+ if( attribute instanceof Attribute )
+ {
+ return ( (Attribute)attribute ).getValue();
+ }
+ else
+ {
+ String value = "";
+ for( Iterator e = ( (ArrayList)attribute ).iterator(); e.hasNext(); )
+ {
+ Attribute classpathAttribute = (Attribute)e.next();
+ value += classpathAttribute.getValue() + " ";
+ }
+ return value.trim();
+ }
+ }
+
+ /**
+ * Get the Section's name
+ *
+ * @return the section's name.
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ public Iterator getWarnings()
+ {
+ return warnings.iterator();
+ }
+
+ /**
+ * 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 addAttributeAndCheck( Attribute attribute )
+ throws ManifestException, TaskException
+ {
+ if( attribute.getName() == null || attribute.getValue() == null )
+ {
+ throw new TaskException( "Attributes must have name and value" );
+ }
+ if( attribute.getName().equalsIgnoreCase( Manifest.ATTRIBUTE_NAME ) )
+ {
+ warnings.add( "\"" + Manifest.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( Manifest.ATTRIBUTE_FROM.toLowerCase() ) )
+ {
+ warnings.add( "Manifest attributes should not start with \"" +
+ Manifest.ATTRIBUTE_FROM + "\" in \"" + attribute.getName() + ": " + attribute.getValue() + "\"" );
+ }
+ else
+ {
+ // classpath attributes go into a vector
+ String attributeName = attribute.getName().toLowerCase();
+ if( attributeName.equals( Manifest.ATTRIBUTE_CLASSPATH ) )
+ {
+ ArrayList classpathAttrs = (ArrayList)attributes.get( attributeName );
+ if( classpathAttrs == null )
+ {
+ classpathAttrs = new ArrayList();
+ attributes.put( attributeName, classpathAttrs );
+ }
+ classpathAttrs.add( attribute );
+ }
+ else if( attributes.containsKey( attributeName ) )
+ {
+ throw new ManifestException( "The attribute \"" + attribute.getName() + "\" may not " +
+ "occur more than once in the same section" );
+ }
+ else
+ {
+ attributes.put( attributeName, attribute );
+ }
+ }
+ return null;
+ }
+
+ public void addAttribute( Attribute attribute )
+ throws ManifestException, TaskException
+ {
+ String check = addAttributeAndCheck( attribute );
+ if( check != null )
+ {
+ throw new TaskException( "Specify the section name using the \"name\" attribute of the element rather " +
+ "than using a \"Name\" manifest attribute" );
+ }
+ }
+
+ public boolean equals( Object rhs )
+ {
+ if( !( rhs instanceof Section ) )
+ {
+ return false;
+ }
+
+ Section rhsSection = (Section)rhs;
+ if( attributes.size() != rhsSection.attributes.size() )
+ {
+ return false;
+ }
+
+ for( Enumeration e = attributes.elements(); e.hasMoreElements(); )
+ {
+ Attribute attribute = (Attribute)e.nextElement();
+ Attribute rshAttribute = (Attribute)rhsSection.attributes.get( attribute.getName().toLowerCase() );
+ if( !attribute.equals( rshAttribute ) )
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * 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" );
+ }
+
+ for( Enumeration e = section.attributes.keys(); e.hasMoreElements(); )
+ {
+ String attributeName = (String)e.nextElement();
+ if( attributeName.equals( Manifest.ATTRIBUTE_CLASSPATH ) &&
+ attributes.containsKey( attributeName ) )
+ {
+ // classpath entries are vetors which are merged
+ ArrayList classpathAttrs = (ArrayList)section.attributes.get( attributeName );
+ ArrayList ourClasspathAttrs = (ArrayList)attributes.get( attributeName );
+ for( Iterator e2 = classpathAttrs.iterator(); e2.hasNext(); )
+ {
+ ourClasspathAttrs.add( e2.next() );
+ }
+ }
+ else
+ {
+ // the merge file always wins
+ attributes.put( attributeName, section.attributes.get( attributeName ) );
+ }
+ }
+
+ // add in the warnings
+ for( Iterator e = section.warnings.iterator(); e.hasNext(); )
+ {
+ warnings.add( e.next() );
+ }
+ }
+
+ /**
+ * 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, TaskException
+ {
+ 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 = ManifestUtil.buildAttribute( line );
+ String nameReadAhead = addAttributeAndCheck( attribute );
+ if( nameReadAhead != null )
+ {
+ return nameReadAhead;
+ }
+ }
+ }
+ }
+
+ /**
+ * 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() );
+ }
+
+ /**
+ * 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( Manifest.ATTRIBUTE_NAME, name );
+ ManifestUtil.write( nameAttr, writer );
+ }
+ for( Enumeration e = attributes.elements(); e.hasMoreElements(); )
+ {
+ Object object = e.nextElement();
+ if( object instanceof Attribute )
+ {
+ Attribute attribute = (Attribute)object;
+ ManifestUtil.write( attribute, writer );
+ }
+ else
+ {
+ ArrayList attrList = (ArrayList)object;
+ for( Iterator e2 = attrList.iterator(); e2.hasNext(); )
+ {
+ Attribute attribute = (Attribute)e2.next();
+ ManifestUtil.write( attribute, writer );
+ }
+ }
+ }
+ writer.println();
+ }
+}