Browse Source

Start to clean up the clean up the manifest task and extract the useful bits into separate classes and adaptors.

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271212 13f79535-47bb-0310-9956-ffa450edef68
master
Peter Donald 23 years ago
parent
commit
6518cd22e0
10 changed files with 1124 additions and 1002 deletions
  1. +119
    -0
      proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Attribute.java
  2. +6
    -501
      proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Manifest.java
  3. +27
    -0
      proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/ManifestMode.java
  4. +78
    -0
      proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/ManifestUtil.java
  5. +332
    -0
      proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Section.java
  6. +119
    -0
      proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Attribute.java
  7. +6
    -501
      proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Manifest.java
  8. +27
    -0
      proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/ManifestMode.java
  9. +78
    -0
      proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/ManifestUtil.java
  10. +332
    -0
      proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Section.java

+ 119
- 0
proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Attribute.java View File

@@ -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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @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 ) );
}

}

+ 6
- 501
proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Manifest.java View File

@@ -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 <a href="mailto:peter@apache.org">Peter Donald</a>
* @author <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @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 <section> 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();
}
}

}

+ 27
- 0
proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/ManifestMode.java View File

@@ -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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @version $Revision$ $Date$
*/
public class ManifestMode
extends EnumeratedAttribute
{
public String[] getValues()
{
return new String[]{"update", "replace"};
}
}

+ 78
- 0
proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/ManifestUtil.java View File

@@ -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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @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 );
}
}

+ 332
- 0
proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/manifest/Section.java View File

@@ -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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @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 <section> 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();
}
}

+ 119
- 0
proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Attribute.java View File

@@ -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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @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 ) );
}

}

+ 6
- 501
proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Manifest.java View File

@@ -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 <a href="mailto:peter@apache.org">Peter Donald</a>
* @author <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @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 <section> 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();
}
}

}

+ 27
- 0
proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/ManifestMode.java View File

@@ -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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @version $Revision$ $Date$
*/
public class ManifestMode
extends EnumeratedAttribute
{
public String[] getValues()
{
return new String[]{"update", "replace"};
}
}

+ 78
- 0
proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/ManifestUtil.java View File

@@ -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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @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 );
}
}

+ 332
- 0
proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/manifest/Section.java View File

@@ -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 <a href="mailto:conor@apache.org">Conor MacNeill</a>
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
* @author <a href="mailto:peter@apache.org">Peter Donald</a>
* @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 <section> 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();
}
}

Loading…
Cancel
Save