git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271240 13f79535-47bb-0310-9956-ffa450edef68master
@@ -18,12 +18,12 @@ import java.io.OutputStreamWriter; | |||
import java.io.PrintWriter; | |||
import java.io.Reader; | |||
import java.util.Enumeration; | |||
import java.util.Iterator; | |||
import java.util.zip.ZipFile; | |||
import org.apache.aut.zip.ZipOutputStream; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.tools.ant.taskdefs.manifest.Manifest; | |||
import org.apache.tools.ant.taskdefs.manifest.ManifestException; | |||
import org.apache.tools.ant.taskdefs.manifest.ManifestUtil; | |||
import org.apache.tools.ant.types.FileScanner; | |||
/** | |||
@@ -89,10 +89,10 @@ public class Jar | |||
try | |||
{ | |||
r = new FileReader( manifestFile ); | |||
Manifest newManifest = new Manifest( r ); | |||
Manifest newManifest = ManifestUtil.buildManifest( r ); | |||
if( m_manifest == null ) | |||
{ | |||
m_manifest = Manifest.getDefaultManifest(); | |||
m_manifest = ManifestUtil.getDefaultManifest(); | |||
} | |||
m_manifest.merge( newManifest ); | |||
} | |||
@@ -134,7 +134,7 @@ public class Jar | |||
{ | |||
if( m_manifest == null ) | |||
{ | |||
m_manifest = Manifest.getDefaultManifest(); | |||
m_manifest = ManifestUtil.getDefaultManifest(); | |||
} | |||
m_manifest.merge( newManifest ); | |||
buildFileManifest = true; | |||
@@ -172,10 +172,10 @@ public class Jar | |||
getLogger().debug( "Updating jar since the current jar has no manifest" ); | |||
return false; | |||
} | |||
Manifest currentManifest = new Manifest( new InputStreamReader( theZipFile.getInputStream( entry ) ) ); | |||
Manifest currentManifest = ManifestUtil.buildManifest( new InputStreamReader( theZipFile.getInputStream( entry ) ) ); | |||
if( m_manifest == null ) | |||
{ | |||
m_manifest = Manifest.getDefaultManifest(); | |||
m_manifest = ManifestUtil.getDefaultManifest(); | |||
} | |||
if( !currentManifest.equals( m_manifest ) ) | |||
{ | |||
@@ -231,22 +231,25 @@ public class Jar | |||
{ | |||
try | |||
{ | |||
m_execManifest = Manifest.getDefaultManifest(); | |||
m_execManifest = ManifestUtil.getDefaultManifest(); | |||
if( m_manifest != null ) | |||
{ | |||
m_execManifest.merge( m_manifest ); | |||
} | |||
/* | |||
for( Iterator e = m_execManifest.getWarnings(); e.hasNext(); ) | |||
{ | |||
getLogger().warn( "Manifest warning: " + (String)e.next() ); | |||
} | |||
*/ | |||
zipDir( null, zOut, "META-INF/" ); | |||
// time to write the manifest | |||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
PrintWriter writer = new PrintWriter( baos ); | |||
m_execManifest.write( writer ); | |||
Manifest manifest = m_execManifest; | |||
ManifestUtil.write( manifest, writer ); | |||
writer.flush(); | |||
ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() ); | |||
@@ -375,11 +378,12 @@ public class Jar | |||
{ | |||
if( m_execManifest == null ) | |||
{ | |||
m_execManifest = new Manifest( new InputStreamReader( is ) ); | |||
m_execManifest = ManifestUtil.buildManifest( new InputStreamReader( is ) ); | |||
} | |||
else if( isAddingNewFiles() ) | |||
{ | |||
m_execManifest.merge( new Manifest( new InputStreamReader( is ) ) ); | |||
final Manifest other = ManifestUtil.buildManifest( new InputStreamReader( is ) ); | |||
m_execManifest.merge( other ); | |||
} | |||
} | |||
catch( ManifestException e ) | |||
@@ -9,6 +9,7 @@ package org.apache.tools.ant.taskdefs.manifest; | |||
import java.io.PrintWriter; | |||
import java.io.IOException; | |||
import java.util.jar.Attributes; | |||
/** | |||
* Class to hold manifest attributes | |||
@@ -110,10 +111,11 @@ public class Attribute | |||
} | |||
final Attribute other = (Attribute)object; | |||
final String name = other.m_name; | |||
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 ) ); | |||
( null != m_name && null != name && | |||
m_name.toLowerCase().equals( name.toLowerCase() ) && | |||
null != m_value && m_value.equals( other.m_value ) ); | |||
} | |||
} |
@@ -7,23 +7,11 @@ | |||
*/ | |||
package org.apache.tools.ant.taskdefs.manifest; | |||
import java.io.BufferedReader; | |||
import java.io.File; | |||
import java.io.FileReader; | |||
import java.io.FileWriter; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.InputStreamReader; | |||
import java.io.PrintWriter; | |||
import java.io.Reader; | |||
import java.io.StringWriter; | |||
import java.io.UnsupportedEncodingException; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Enumeration; | |||
import java.util.Hashtable; | |||
import java.util.Iterator; | |||
import java.util.jar.Attributes; | |||
import org.apache.myrmidon.api.AbstractTask; | |||
import java.util.Set; | |||
import org.apache.myrmidon.api.TaskException; | |||
/** | |||
@@ -35,42 +23,11 @@ import org.apache.myrmidon.api.TaskException; | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class Manifest | |||
extends AbstractTask | |||
{ | |||
/** | |||
* The standard Signature Version header | |||
*/ | |||
public final static String ATTRIBUTE_SIGNATURE_VERSION = Attributes.Name.SIGNATURE_VERSION.toString(); | |||
/** | |||
* The Name Attribute is the first in a named section | |||
*/ | |||
public final static String ATTRIBUTE_NAME = "Name"; | |||
/** | |||
* The From Header is disallowed in a Manifest | |||
*/ | |||
public final static String ATTRIBUTE_FROM = "From"; | |||
/** | |||
* The Class-Path Header is special - it can be duplicated | |||
*/ | |||
public final static String ATTRIBUTE_CLASSPATH = Attributes.Name.CLASS_PATH.toString(); | |||
/** | |||
* Default Manifest version if one is not specified | |||
*/ | |||
public final static String DEFAULT_MANIFEST_VERSION = "1.0"; | |||
/** | |||
* The max length of a line in a Manifest | |||
*/ | |||
public final static int MAX_LINE_LENGTH = 70; | |||
/** | |||
* The version of this manifest | |||
*/ | |||
private String m_manifestVersion = DEFAULT_MANIFEST_VERSION; | |||
private String m_manifestVersion = ManifestUtil.DEFAULT_MANIFEST_VERSION; | |||
/** | |||
* The main section of this manifest | |||
@@ -82,211 +39,112 @@ public class Manifest | |||
*/ | |||
private Hashtable m_sections = new Hashtable(); | |||
private File m_manifestFile; | |||
private ManifestMode m_mode; | |||
/** | |||
* Construct an empty manifest | |||
*/ | |||
public Manifest() | |||
throws TaskException | |||
public void setManifestVersion( final String manifestVersion ) | |||
{ | |||
m_mode = new ManifestMode(); | |||
m_mode.setValue( "replace" ); | |||
m_manifestVersion = null; | |||
m_manifestVersion = manifestVersion; | |||
} | |||
/** | |||
* Read a manifest file from the given reader | |||
* | |||
* @param r Description of Parameter | |||
* @exception ManifestException Description of Exception | |||
* @exception IOException Description of Exception | |||
* @throws ManifestException if the manifest is not valid according to the | |||
* JAR spec | |||
* @throws IOException if the manifest cannot be read from the reader. | |||
*/ | |||
public Manifest( Reader r ) | |||
throws ManifestException, TaskException, IOException | |||
public void setMainSection( final Section mainSection ) | |||
{ | |||
BufferedReader reader = new BufferedReader( r ); | |||
// This should be the manifest version | |||
String nextSectionName = m_mainSection.read( reader ); | |||
String readManifestVersion = m_mainSection.getAttributeValue( Attributes.Name.MANIFEST_VERSION.toString() ); | |||
if( readManifestVersion != null ) | |||
{ | |||
m_manifestVersion = readManifestVersion; | |||
m_mainSection.removeAttribute( Attributes.Name.MANIFEST_VERSION.toString() ); | |||
} | |||
String line = null; | |||
while( ( line = reader.readLine() ) != null ) | |||
{ | |||
if( line.length() == 0 ) | |||
{ | |||
continue; | |||
} | |||
Section section = new Section(); | |||
if( nextSectionName == null ) | |||
{ | |||
Attribute sectionName = ManifestUtil.buildAttribute( line ); | |||
if( !sectionName.getName().equalsIgnoreCase( ATTRIBUTE_NAME ) ) | |||
{ | |||
throw new ManifestException( "Manifest sections should start with a \"" + ATTRIBUTE_NAME + | |||
"\" attribute and not \"" + sectionName.getName() + "\"" ); | |||
} | |||
nextSectionName = sectionName.getValue(); | |||
} | |||
else | |||
{ | |||
// we have already started reading this section | |||
// this line is the first attribute. set it and then let the normal | |||
// read handle the rest | |||
Attribute firstAttribute = ManifestUtil.buildAttribute( line ); | |||
section.addAttributeAndCheck( firstAttribute ); | |||
} | |||
m_mainSection = mainSection; | |||
} | |||
section.setName( nextSectionName ); | |||
nextSectionName = section.read( reader ); | |||
addSection( section ); | |||
} | |||
public void addAttribute( final Attribute attribute ) | |||
throws ManifestException | |||
{ | |||
m_mainSection.addAttribute( attribute ); | |||
} | |||
/** | |||
* Construct a manifest from Ant's default manifest file. | |||
* | |||
* @return The DefaultManifest value | |||
* @exception TaskException Description of Exception | |||
*/ | |||
public static Manifest getDefaultManifest() | |||
throws TaskException | |||
public void addSection( final Section section ) | |||
throws ManifestException | |||
{ | |||
try | |||
{ | |||
String s = "/org/apache/tools/ant/defaultManifest.mf"; | |||
InputStream in = Manifest.class.getResourceAsStream( s ); | |||
if( in == null ) | |||
{ | |||
throw new TaskException( "Could not find default manifest: " + s ); | |||
} | |||
try | |||
{ | |||
return new Manifest( new InputStreamReader( in, "ASCII" ) ); | |||
} | |||
catch( UnsupportedEncodingException e ) | |||
{ | |||
return new Manifest( new InputStreamReader( in ) ); | |||
} | |||
} | |||
catch( ManifestException e ) | |||
{ | |||
throw new TaskException( "Default manifest is invalid !!" ); | |||
} | |||
catch( IOException e ) | |||
if( section.getName() == null ) | |||
{ | |||
throw new TaskException( "Unable to read default manifest", e ); | |||
final String message = "Sections must have a name"; | |||
throw new ManifestException( message ); | |||
} | |||
m_sections.put( section.getName().toLowerCase(), section ); | |||
} | |||
/** | |||
* The name of the manifest file to write (if used as a task). | |||
* | |||
* @param f The new File value | |||
*/ | |||
public void setFile( File f ) | |||
public String[] getSectionNames( final Manifest other ) | |||
{ | |||
m_manifestFile = f; | |||
final Set keys = other.m_sections.keySet(); | |||
return (String[])keys.toArray( new String[ keys.size() ] ); | |||
} | |||
/** | |||
* Shall we update or replace an existing manifest? | |||
* | |||
* @param m The new ManifestMode value | |||
*/ | |||
public void setMode( ManifestMode m ) | |||
public String getManifestVersion() | |||
{ | |||
m_mode = m; | |||
return m_manifestVersion; | |||
} | |||
/** | |||
* Get the warnings for this manifest. | |||
* | |||
* @return an enumeration of warning strings | |||
*/ | |||
public Iterator getWarnings() | |||
public Section getMainSection() | |||
{ | |||
ArrayList warnings = new ArrayList(); | |||
for( Iterator e2 = m_mainSection.getWarnings(); e2.hasNext(); ) | |||
{ | |||
warnings.add( e2.next() ); | |||
} | |||
// create a vector and add in the warnings for all the sections | |||
for( Enumeration e = m_sections.elements(); e.hasMoreElements(); ) | |||
{ | |||
Section section = (Section)e.nextElement(); | |||
for( Iterator e2 = section.getWarnings(); e2.hasNext(); ) | |||
{ | |||
warnings.add( e2.next() ); | |||
} | |||
} | |||
return m_mainSection; | |||
} | |||
return warnings.iterator(); | |||
public Section getSection( final String name ) | |||
{ | |||
return (Section)m_sections.get( name ); | |||
} | |||
public void addAttribute( final Attribute attribute ) | |||
throws ManifestException, TaskException | |||
public Section[] getSections() | |||
{ | |||
m_mainSection.addAttribute( attribute ); | |||
final Collection sections = m_sections.values(); | |||
return (Section[])sections.toArray( new Section[ sections.size() ] ); | |||
} | |||
public void addSection( final Section section ) | |||
throws ManifestException, TaskException | |||
/** | |||
* Merge the contents of the given manifest into this manifest | |||
* | |||
* @param other the Manifest to be merged with this one. | |||
* @throws ManifestException if there is a problem merging the manfest | |||
* according to the Manifest spec. | |||
*/ | |||
public void merge( final Manifest other ) | |||
throws ManifestException | |||
{ | |||
if( section.getName() == null ) | |||
if( other.m_manifestVersion != null ) | |||
{ | |||
throw new TaskException( "Sections must have a name" ); | |||
m_manifestVersion = other.m_manifestVersion; | |||
} | |||
m_sections.put( section.getName().toLowerCase(), section ); | |||
m_mainSection.merge( other.m_mainSection ); | |||
mergeSections( other ); | |||
} | |||
public boolean equals( Object rhs ) | |||
public boolean equals( final Object object ) | |||
{ | |||
if( !( rhs instanceof Manifest ) ) | |||
if( !( object instanceof Manifest ) ) | |||
{ | |||
return false; | |||
} | |||
Manifest rhsManifest = (Manifest)rhs; | |||
if( m_manifestVersion == null ) | |||
final Manifest other = (Manifest)object; | |||
if( m_manifestVersion == null && other.m_manifestVersion != null ) | |||
{ | |||
if( rhsManifest.m_manifestVersion != null ) | |||
{ | |||
return false; | |||
} | |||
return false; | |||
} | |||
else if( !m_manifestVersion.equals( rhsManifest.m_manifestVersion ) ) | |||
else if( !m_manifestVersion.equals( other.m_manifestVersion ) ) | |||
{ | |||
return false; | |||
} | |||
if( m_sections.size() != rhsManifest.m_sections.size() ) | |||
if( m_sections.size() != other.m_sections.size() ) | |||
{ | |||
return false; | |||
} | |||
if( !m_mainSection.equals( rhsManifest.m_mainSection ) ) | |||
if( !m_mainSection.equals( other.m_mainSection ) ) | |||
{ | |||
return false; | |||
} | |||
for( Enumeration e = m_sections.elements(); e.hasMoreElements(); ) | |||
final Iterator e = m_sections.values().iterator(); | |||
while( e.hasNext() ) | |||
{ | |||
Section section = (Section)e.nextElement(); | |||
Section rhsSection = (Section)rhsManifest.m_sections.get( section.getName().toLowerCase() ); | |||
if( !section.equals( rhsSection ) ) | |||
final Section section = (Section)e.next(); | |||
final String key = section.getName().toLowerCase(); | |||
final Section otherSection = (Section)other.m_sections.get( key ); | |||
if( !section.equals( otherSection ) ) | |||
{ | |||
return false; | |||
} | |||
@@ -295,168 +153,23 @@ public class Manifest | |||
return true; | |||
} | |||
/** | |||
* Create or update the Manifest when used as a task. | |||
* | |||
* @exception TaskException Description of Exception | |||
*/ | |||
public void execute() | |||
throws TaskException | |||
{ | |||
if( m_manifestFile == null ) | |||
{ | |||
throw new TaskException( "the file attribute is required" ); | |||
} | |||
Manifest toWrite = getDefaultManifest(); | |||
if( m_mode.getValue().equals( "update" ) && m_manifestFile.exists() ) | |||
{ | |||
FileReader f = null; | |||
try | |||
{ | |||
f = new FileReader( m_manifestFile ); | |||
toWrite.merge( new Manifest( f ) ); | |||
} | |||
catch( ManifestException m ) | |||
{ | |||
throw new TaskException( "Existing manifest " + m_manifestFile | |||
+ " is invalid", m ); | |||
} | |||
catch( IOException e ) | |||
{ | |||
throw new | |||
TaskException( "Failed to read " + m_manifestFile, e ); | |||
} | |||
finally | |||
{ | |||
if( f != null ) | |||
{ | |||
try | |||
{ | |||
f.close(); | |||
} | |||
catch( IOException e ) | |||
{ | |||
} | |||
} | |||
} | |||
} | |||
try | |||
{ | |||
toWrite.merge( this ); | |||
} | |||
catch( ManifestException m ) | |||
{ | |||
throw new TaskException( "Manifest is invalid", m ); | |||
} | |||
PrintWriter w = null; | |||
try | |||
{ | |||
w = new PrintWriter( new FileWriter( m_manifestFile ) ); | |||
toWrite.write( w ); | |||
} | |||
catch( IOException e ) | |||
{ | |||
throw new TaskException( "Failed to write " + m_manifestFile, e ); | |||
} | |||
finally | |||
{ | |||
if( w != null ) | |||
{ | |||
w.close(); | |||
} | |||
} | |||
} | |||
/** | |||
* Merge the contents of the given manifest into this manifest | |||
* | |||
* @param other the Manifest to be merged with this one. | |||
* @throws ManifestException if there is a problem merging the manfest | |||
* according to the Manifest spec. | |||
*/ | |||
public void merge( Manifest other ) | |||
private void mergeSections( final Manifest other ) | |||
throws ManifestException | |||
{ | |||
if( other.m_manifestVersion != null ) | |||
{ | |||
m_manifestVersion = other.m_manifestVersion; | |||
} | |||
m_mainSection.merge( other.m_mainSection ); | |||
for( Enumeration e = other.m_sections.keys(); e.hasMoreElements(); ) | |||
final String[] sections = getSectionNames( other ); | |||
for( int i = 0; i < sections.length; i++ ) | |||
{ | |||
String sectionName = (String)e.nextElement(); | |||
Section ourSection = (Section)m_sections.get( sectionName ); | |||
Section otherSection = (Section)other.m_sections.get( sectionName ); | |||
if( ourSection == null ) | |||
final String sectionName = sections[ i ]; | |||
final Section section = getSection( sectionName ); | |||
final Section otherSection = other.getSection( sectionName ); | |||
if( section == null ) | |||
{ | |||
m_sections.put( sectionName.toLowerCase(), otherSection ); | |||
} | |||
else | |||
{ | |||
ourSection.merge( otherSection ); | |||
section.merge( otherSection ); | |||
} | |||
} | |||
} | |||
/** | |||
* Convert the manifest to its string representation | |||
* | |||
* @return a multiline string with the Manifest as it appears in a Manifest | |||
* file. | |||
*/ | |||
public String toString() | |||
{ | |||
StringWriter sw = new StringWriter(); | |||
try | |||
{ | |||
write( new PrintWriter( sw ) ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
return null; | |||
} | |||
return sw.toString(); | |||
} | |||
/** | |||
* Write the manifest out to a print writer. | |||
* | |||
* @param writer the Writer to which the manifest is written | |||
* @throws IOException if the manifest cannot be written | |||
*/ | |||
public void write( PrintWriter writer ) | |||
throws IOException, TaskException | |||
{ | |||
writer.println( Attributes.Name.MANIFEST_VERSION + ": " + m_manifestVersion ); | |||
String signatureVersion = m_mainSection.getAttributeValue( ATTRIBUTE_SIGNATURE_VERSION ); | |||
if( signatureVersion != null ) | |||
{ | |||
writer.println( ATTRIBUTE_SIGNATURE_VERSION + ": " + signatureVersion ); | |||
m_mainSection.removeAttribute( ATTRIBUTE_SIGNATURE_VERSION ); | |||
} | |||
m_mainSection.write( writer ); | |||
if( signatureVersion != null ) | |||
{ | |||
try | |||
{ | |||
m_mainSection.addAttribute( new Attribute( ATTRIBUTE_SIGNATURE_VERSION, signatureVersion ) ); | |||
} | |||
catch( ManifestException e ) | |||
{ | |||
// shouldn't happen - ignore | |||
} | |||
} | |||
for( Enumeration e = m_sections.elements(); e.hasMoreElements(); ) | |||
{ | |||
Section section = (Section)e.nextElement(); | |||
section.write( writer ); | |||
} | |||
} | |||
} |
@@ -0,0 +1,196 @@ | |||
/* | |||
* 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.File; | |||
import java.io.FileReader; | |||
import java.io.FileWriter; | |||
import java.io.IOException; | |||
import java.io.PrintWriter; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import org.apache.avalon.excalibur.io.IOUtil; | |||
import org.apache.myrmidon.api.AbstractTask; | |||
import org.apache.myrmidon.api.TaskException; | |||
/** | |||
* 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> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class ManifestTask | |||
extends AbstractTask | |||
{ | |||
private File m_destFile; | |||
private ManifestMode m_mode; | |||
private Manifest m_manifest = new Manifest(); | |||
/** | |||
* Construct an empty manifest | |||
*/ | |||
public ManifestTask() | |||
throws TaskException | |||
{ | |||
m_mode = new ManifestMode(); | |||
m_mode.setValue( "replace" ); | |||
} | |||
/** | |||
* The name of the manifest file to write. | |||
*/ | |||
public void setDestFile( final File destFile ) | |||
{ | |||
m_destFile = destFile; | |||
} | |||
/** | |||
* Shall we update or replace an existing manifest? | |||
*/ | |||
public void setMode( final ManifestMode mode ) | |||
{ | |||
m_mode = mode; | |||
} | |||
public void setManifestVersion( String manifestVersion ) | |||
{ | |||
m_manifest.setManifestVersion( manifestVersion ); | |||
} | |||
public void addMainSection( Section mainSection ) | |||
throws Exception | |||
{ | |||
m_manifest.setMainSection( mainSection ); | |||
} | |||
/** | |||
* Get the warnings for this manifest. | |||
* | |||
* @return an enumeration of warning strings | |||
*/ | |||
public Iterator getWarnings() | |||
{ | |||
ArrayList warnings = new ArrayList(); | |||
for( Iterator e2 = m_manifest.getMainSection().getWarnings(); e2.hasNext(); ) | |||
{ | |||
warnings.add( e2.next() ); | |||
} | |||
final Section[] sections = m_manifest.getSections(); | |||
for( int i = 0; i < sections.length; i++ ) | |||
{ | |||
final Section section = sections[ i ]; | |||
for( Iterator e2 = section.getWarnings(); e2.hasNext(); ) | |||
{ | |||
warnings.add( e2.next() ); | |||
} | |||
} | |||
return warnings.iterator(); | |||
} | |||
public void addAttribute( final Attribute attribute ) | |||
throws ManifestException, TaskException | |||
{ | |||
m_manifest.addAttribute( attribute ); | |||
} | |||
public void addSection( final Section section ) | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
m_manifest.addSection( section ); | |||
} | |||
catch( final ManifestException me ) | |||
{ | |||
throw new TaskException( me.getMessage(), me ); | |||
} | |||
} | |||
/** | |||
* Create or update the Manifest when used as a task. | |||
* | |||
* @exception TaskException Description of Exception | |||
*/ | |||
public void execute() | |||
throws TaskException | |||
{ | |||
if( null == m_destFile ) | |||
{ | |||
throw new TaskException( "the file attribute is required" ); | |||
} | |||
Manifest toWrite = getDefaultManifest(); | |||
if( m_mode.getValue().equals( "update" ) && m_destFile.exists() ) | |||
{ | |||
FileReader f = null; | |||
try | |||
{ | |||
f = new FileReader( m_destFile ); | |||
final Manifest other = ManifestUtil.buildManifest( f ); | |||
toWrite.merge( other ); | |||
} | |||
catch( ManifestException m ) | |||
{ | |||
throw new TaskException( "Existing manifest " + m_destFile | |||
+ " is invalid", m ); | |||
} | |||
catch( IOException e ) | |||
{ | |||
throw new | |||
TaskException( "Failed to read " + m_destFile, e ); | |||
} | |||
finally | |||
{ | |||
IOUtil.shutdownReader( f ); | |||
} | |||
} | |||
try | |||
{ | |||
toWrite.merge( m_manifest ); | |||
} | |||
catch( ManifestException m ) | |||
{ | |||
throw new TaskException( "Manifest is invalid", m ); | |||
} | |||
PrintWriter w = null; | |||
try | |||
{ | |||
w = new PrintWriter( new FileWriter( m_destFile ) ); | |||
ManifestUtil.write( toWrite, w ); | |||
} | |||
catch( IOException e ) | |||
{ | |||
throw new TaskException( "Failed to write " + m_destFile, e ); | |||
} | |||
finally | |||
{ | |||
IOUtil.shutdownWriter( w ); | |||
} | |||
} | |||
private Manifest getDefaultManifest() | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
return ManifestUtil.getDefaultManifest(); | |||
} | |||
catch( final ManifestException me ) | |||
{ | |||
throw new TaskException( me.getMessage(), me ); | |||
} | |||
} | |||
} |
@@ -8,7 +8,14 @@ | |||
package org.apache.tools.ant.taskdefs.manifest; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.InputStreamReader; | |||
import java.io.PrintWriter; | |||
import java.io.Reader; | |||
import java.io.UnsupportedEncodingException; | |||
import java.io.BufferedReader; | |||
import java.util.jar.Attributes; | |||
import org.apache.myrmidon.api.TaskException; | |||
/** | |||
* Utility methods for manifest stuff. | |||
@@ -20,6 +27,27 @@ import java.io.PrintWriter; | |||
*/ | |||
public final class ManifestUtil | |||
{ | |||
/** | |||
* The Name Attribute is the first in a named section | |||
*/ | |||
public final static String ATTRIBUTE_NAME = "Name"; | |||
/** | |||
* The From Header is disallowed in a Manifest | |||
*/ | |||
public final static String ATTRIBUTE_FROM = "From"; | |||
/** | |||
* The Class-Path Header is special - it can be duplicated | |||
*/ | |||
public final static String ATTRIBUTE_CLASSPATH = Attributes.Name.CLASS_PATH.toString(); | |||
/** | |||
* Default Manifest version if one is not specified | |||
*/ | |||
public final static String DEFAULT_MANIFEST_VERSION = "1.0"; | |||
/** | |||
* The max length of a line in a Manifest | |||
*/ | |||
public final static int MAX_LINE_LENGTH = 70; | |||
public static Attribute buildAttribute( final String line ) | |||
throws ManifestException | |||
{ | |||
@@ -28,6 +56,100 @@ public final class ManifestUtil | |||
return attribute; | |||
} | |||
public static Manifest buildManifest( final Reader reader ) | |||
throws ManifestException, IOException | |||
{ | |||
final Manifest manifest = new Manifest(); | |||
BufferedReader bufferedReader = new BufferedReader( reader ); | |||
// This should be the manifest version | |||
final Section mainSection = manifest.getMainSection(); | |||
String nextSectionName = mainSection.read( bufferedReader ); | |||
final String readManifestVersion = | |||
mainSection.getAttributeValue( Attributes.Name.MANIFEST_VERSION.toString() ); | |||
if( readManifestVersion != null ) | |||
{ | |||
manifest.setManifestVersion( readManifestVersion ); | |||
mainSection.removeAttribute( Attributes.Name.MANIFEST_VERSION.toString() ); | |||
} | |||
String line = null; | |||
while( ( line = bufferedReader.readLine() ) != null ) | |||
{ | |||
if( line.length() == 0 ) | |||
{ | |||
continue; | |||
} | |||
Section section = new Section(); | |||
if( nextSectionName == null ) | |||
{ | |||
Attribute sectionName = ManifestUtil.buildAttribute( line ); | |||
if( !sectionName.getName().equalsIgnoreCase( ManifestUtil.ATTRIBUTE_NAME ) ) | |||
{ | |||
throw new ManifestException( "Manifest sections should start with a \"" + ManifestUtil.ATTRIBUTE_NAME + | |||
"\" attribute and not \"" + sectionName.getName() + "\"" ); | |||
} | |||
nextSectionName = sectionName.getValue(); | |||
} | |||
else | |||
{ | |||
// we have already started reading this section | |||
// this line is the first attribute. set it and then let the normal | |||
// read handle the rest | |||
Attribute firstAttribute = ManifestUtil.buildAttribute( line ); | |||
section.addAttributeAndCheck( firstAttribute ); | |||
} | |||
section.setName( nextSectionName ); | |||
nextSectionName = section.read( bufferedReader ); | |||
manifest.addSection( section ); | |||
} | |||
return manifest; | |||
} | |||
/** | |||
* Construct a manifest from Ant's default manifest file. | |||
*/ | |||
public static Manifest getDefaultManifest() | |||
throws ManifestException | |||
{ | |||
try | |||
{ | |||
final InputStream input = getInputStream(); | |||
final InputStreamReader reader = getReader( input ); | |||
return buildManifest( reader ); | |||
} | |||
catch( final IOException ioe ) | |||
{ | |||
throw new ManifestException( "Unable to read default manifest", ioe ); | |||
} | |||
} | |||
private static InputStream getInputStream() | |||
throws ManifestException | |||
{ | |||
final String location = "default.mf"; | |||
final InputStream input = ManifestUtil.class.getResourceAsStream( location ); | |||
if( null == input ) | |||
{ | |||
throw new ManifestException( "Could not find default manifest: " + location ); | |||
} | |||
return input; | |||
} | |||
private static InputStreamReader getReader( final InputStream input ) | |||
{ | |||
try | |||
{ | |||
return new InputStreamReader( input, "ASCII" ); | |||
} | |||
catch( final UnsupportedEncodingException uee ) | |||
{ | |||
return new InputStreamReader( input ); | |||
} | |||
} | |||
/** | |||
* Parse a line into name and value pairs | |||
* | |||
@@ -56,12 +178,12 @@ public final class ManifestUtil | |||
final String name = attribute.getName(); | |||
final String value = attribute.getValue(); | |||
String line = name + ": " + value; | |||
while( line.getBytes().length > Manifest.MAX_LINE_LENGTH ) | |||
while( line.getBytes().length > MAX_LINE_LENGTH ) | |||
{ | |||
// try to find a MAX_LINE_LENGTH byte section | |||
int breakIndex = Manifest.MAX_LINE_LENGTH; | |||
int breakIndex = MAX_LINE_LENGTH; | |||
String section = line.substring( 0, breakIndex ); | |||
while( section.getBytes().length > Manifest.MAX_LINE_LENGTH && breakIndex > 0 ) | |||
while( section.getBytes().length > MAX_LINE_LENGTH && breakIndex > 0 ) | |||
{ | |||
breakIndex--; | |||
section = line.substring( 0, breakIndex ); | |||
@@ -75,4 +197,44 @@ public final class ManifestUtil | |||
} | |||
writer.println( line ); | |||
} | |||
/** | |||
* Write the manifest out to a print writer. | |||
* | |||
* @param writer the Writer to which the manifest is written | |||
* @throws IOException if the manifest cannot be written | |||
*/ | |||
public static void write( Manifest manifest, PrintWriter writer ) | |||
throws IOException | |||
{ | |||
final String sigVersionKey = Attributes.Name.SIGNATURE_VERSION.toString(); | |||
writer.println( Attributes.Name.MANIFEST_VERSION + ": " + manifest.getManifestVersion() ); | |||
final String signatureVersion = | |||
manifest.getMainSection().getAttributeValue( sigVersionKey ); | |||
if( signatureVersion != null ) | |||
{ | |||
writer.println( Attributes.Name.SIGNATURE_VERSION + ": " + signatureVersion ); | |||
manifest.getMainSection().removeAttribute( sigVersionKey ); | |||
} | |||
manifest.getMainSection().write( writer ); | |||
if( signatureVersion != null ) | |||
{ | |||
try | |||
{ | |||
manifest.getMainSection().addAttribute( new Attribute( sigVersionKey, signatureVersion ) ); | |||
} | |||
catch( ManifestException e ) | |||
{ | |||
// shouldn't happen - ignore | |||
} | |||
} | |||
final Section[] sections = manifest.getSections(); | |||
for( int i = 0; i < sections.length; i++ ) | |||
{ | |||
sections[ i ].write( writer ); | |||
} | |||
} | |||
} |
@@ -14,7 +14,6 @@ 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 | |||
@@ -28,26 +27,26 @@ import org.apache.myrmidon.api.TaskException; | |||
*/ | |||
public class Section | |||
{ | |||
private ArrayList warnings = new ArrayList(); | |||
private final ArrayList m_warnings = new ArrayList(); | |||
/** | |||
* The section's name if any. The main section in a manifest is unnamed. | |||
*/ | |||
private String name = null; | |||
private String m_name; | |||
/** | |||
* The section's attributes. | |||
*/ | |||
private Hashtable attributes = new Hashtable(); | |||
private final Hashtable m_attributes = new Hashtable(); | |||
/** | |||
* Set the Section's name | |||
* | |||
* @param name the section's name | |||
*/ | |||
public void setName( String name ) | |||
public void setName( final String name ) | |||
{ | |||
this.name = name; | |||
m_name = name; | |||
} | |||
/** | |||
@@ -57,23 +56,26 @@ public class Section | |||
* @return the attribute's value or null if the attribute does not exist | |||
* in the section | |||
*/ | |||
public String getAttributeValue( String attributeName ) | |||
public String getAttributeValue( final String attributeName ) | |||
{ | |||
Object attribute = attributes.get( attributeName.toLowerCase() ); | |||
if( attribute == null ) | |||
final Object attributeObject = m_attributes.get( attributeName.toLowerCase() ); | |||
if( null == attributeObject ) | |||
{ | |||
return null; | |||
} | |||
if( attribute instanceof Attribute ) | |||
else if( attributeObject instanceof Attribute ) | |||
{ | |||
return ( (Attribute)attribute ).getValue(); | |||
final Attribute attribute = (Attribute)attributeObject; | |||
return attribute.getValue(); | |||
} | |||
else | |||
{ | |||
String value = ""; | |||
for( Iterator e = ( (ArrayList)attribute ).iterator(); e.hasNext(); ) | |||
final ArrayList attributes = (ArrayList)attributeObject; | |||
Iterator e = attributes.iterator(); | |||
while( e.hasNext() ) | |||
{ | |||
Attribute classpathAttribute = (Attribute)e.next(); | |||
final Attribute classpathAttribute = (Attribute)e.next(); | |||
value += classpathAttribute.getValue() + " "; | |||
} | |||
return value.trim(); | |||
@@ -87,12 +89,12 @@ public class Section | |||
*/ | |||
public String getName() | |||
{ | |||
return name; | |||
return m_name; | |||
} | |||
public Iterator getWarnings() | |||
{ | |||
return warnings.iterator(); | |||
return m_warnings.iterator(); | |||
} | |||
/** | |||
@@ -105,59 +107,59 @@ public class Section | |||
* section. | |||
*/ | |||
public String addAttributeAndCheck( Attribute attribute ) | |||
throws ManifestException, TaskException | |||
throws ManifestException | |||
{ | |||
if( attribute.getName() == null || attribute.getValue() == null ) | |||
{ | |||
throw new TaskException( "Attributes must have name and value" ); | |||
throw new ManifestException( "Attributes must have name and value" ); | |||
} | |||
if( attribute.getName().equalsIgnoreCase( Manifest.ATTRIBUTE_NAME ) ) | |||
if( attribute.getName().equalsIgnoreCase( ManifestUtil.ATTRIBUTE_NAME ) ) | |||
{ | |||
warnings.add( "\"" + Manifest.ATTRIBUTE_NAME + "\" attributes should not occur in the " + | |||
m_warnings.add( "\"" + ManifestUtil.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() ) ) | |||
if( attribute.getName().toLowerCase().startsWith( ManifestUtil.ATTRIBUTE_FROM.toLowerCase() ) ) | |||
{ | |||
warnings.add( "Manifest attributes should not start with \"" + | |||
Manifest.ATTRIBUTE_FROM + "\" in \"" + attribute.getName() + ": " + attribute.getValue() + "\"" ); | |||
m_warnings.add( "Manifest attributes should not start with \"" + | |||
ManifestUtil.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 ) ) | |||
if( attributeName.equals( ManifestUtil.ATTRIBUTE_CLASSPATH ) ) | |||
{ | |||
ArrayList classpathAttrs = (ArrayList)attributes.get( attributeName ); | |||
ArrayList classpathAttrs = (ArrayList)m_attributes.get( attributeName ); | |||
if( classpathAttrs == null ) | |||
{ | |||
classpathAttrs = new ArrayList(); | |||
attributes.put( attributeName, classpathAttrs ); | |||
m_attributes.put( attributeName, classpathAttrs ); | |||
} | |||
classpathAttrs.add( attribute ); | |||
} | |||
else if( attributes.containsKey( attributeName ) ) | |||
else if( m_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 ); | |||
m_attributes.put( attributeName, attribute ); | |||
} | |||
} | |||
return null; | |||
} | |||
public void addAttribute( Attribute attribute ) | |||
throws ManifestException, TaskException | |||
public void addAttribute( final Attribute attribute ) | |||
throws ManifestException | |||
{ | |||
String check = addAttributeAndCheck( attribute ); | |||
if( check != null ) | |||
{ | |||
throw new TaskException( "Specify the section name using the \"name\" attribute of the <section> element rather " + | |||
throw new ManifestException( "Specify the section name using the \"name\" attribute of the <section> element rather " + | |||
"than using a \"Name\" manifest attribute" ); | |||
} | |||
} | |||
@@ -170,15 +172,15 @@ public class Section | |||
} | |||
Section rhsSection = (Section)rhs; | |||
if( attributes.size() != rhsSection.attributes.size() ) | |||
if( m_attributes.size() != rhsSection.m_attributes.size() ) | |||
{ | |||
return false; | |||
} | |||
for( Enumeration e = attributes.elements(); e.hasMoreElements(); ) | |||
for( Enumeration e = m_attributes.elements(); e.hasMoreElements(); ) | |||
{ | |||
Attribute attribute = (Attribute)e.nextElement(); | |||
Attribute rshAttribute = (Attribute)rhsSection.attributes.get( attribute.getName().toLowerCase() ); | |||
Attribute rshAttribute = (Attribute)rhsSection.m_attributes.get( attribute.getName().toLowerCase() ); | |||
if( !attribute.equals( rshAttribute ) ) | |||
{ | |||
return false; | |||
@@ -197,21 +199,21 @@ public class Section | |||
public void merge( Section section ) | |||
throws ManifestException | |||
{ | |||
if( name == null && section.getName() != null || | |||
name != null && !( name.equalsIgnoreCase( section.getName() ) ) ) | |||
if( m_name == null && section.getName() != null || | |||
m_name != null && !( m_name.equalsIgnoreCase( section.getName() ) ) ) | |||
{ | |||
throw new ManifestException( "Unable to merge sections with different names" ); | |||
} | |||
for( Enumeration e = section.attributes.keys(); e.hasMoreElements(); ) | |||
for( Enumeration e = section.m_attributes.keys(); e.hasMoreElements(); ) | |||
{ | |||
String attributeName = (String)e.nextElement(); | |||
if( attributeName.equals( Manifest.ATTRIBUTE_CLASSPATH ) && | |||
attributes.containsKey( attributeName ) ) | |||
if( attributeName.equals( ManifestUtil.ATTRIBUTE_CLASSPATH ) && | |||
m_attributes.containsKey( attributeName ) ) | |||
{ | |||
// classpath entries are vetors which are merged | |||
ArrayList classpathAttrs = (ArrayList)section.attributes.get( attributeName ); | |||
ArrayList ourClasspathAttrs = (ArrayList)attributes.get( attributeName ); | |||
ArrayList classpathAttrs = (ArrayList)section.m_attributes.get( attributeName ); | |||
ArrayList ourClasspathAttrs = (ArrayList)m_attributes.get( attributeName ); | |||
for( Iterator e2 = classpathAttrs.iterator(); e2.hasNext(); ) | |||
{ | |||
ourClasspathAttrs.add( e2.next() ); | |||
@@ -220,14 +222,14 @@ public class Section | |||
else | |||
{ | |||
// the merge file always wins | |||
attributes.put( attributeName, section.attributes.get( attributeName ) ); | |||
m_attributes.put( attributeName, section.m_attributes.get( attributeName ) ); | |||
} | |||
} | |||
// add in the warnings | |||
for( Iterator e = section.warnings.iterator(); e.hasNext(); ) | |||
for( Iterator e = section.m_warnings.iterator(); e.hasNext(); ) | |||
{ | |||
warnings.add( e.next() ); | |||
m_warnings.add( e.next() ); | |||
} | |||
} | |||
@@ -242,7 +244,7 @@ public class Section | |||
* @throws IOException if the section cannot be read from the reader. | |||
*/ | |||
public String read( BufferedReader reader ) | |||
throws ManifestException, IOException, TaskException | |||
throws ManifestException, IOException | |||
{ | |||
Attribute attribute = null; | |||
while( true ) | |||
@@ -257,11 +259,11 @@ public class Section | |||
// continuation line | |||
if( attribute == null ) | |||
{ | |||
if( name != null ) | |||
if( m_name != null ) | |||
{ | |||
// a continuation on the first line is a continuation of the name - concatenate | |||
// this line and the name | |||
name += line.substring( 1 ); | |||
m_name += line.substring( 1 ); | |||
} | |||
else | |||
{ | |||
@@ -292,7 +294,7 @@ public class Section | |||
*/ | |||
public void removeAttribute( String attributeName ) | |||
{ | |||
attributes.remove( attributeName.toLowerCase() ); | |||
m_attributes.remove( attributeName.toLowerCase() ); | |||
} | |||
/** | |||
@@ -304,12 +306,12 @@ public class Section | |||
public void write( PrintWriter writer ) | |||
throws IOException | |||
{ | |||
if( name != null ) | |||
if( m_name != null ) | |||
{ | |||
Attribute nameAttr = new Attribute( Manifest.ATTRIBUTE_NAME, name ); | |||
Attribute nameAttr = new Attribute( ManifestUtil.ATTRIBUTE_NAME, m_name ); | |||
ManifestUtil.write( nameAttr, writer ); | |||
} | |||
for( Enumeration e = attributes.elements(); e.hasMoreElements(); ) | |||
for( Enumeration e = m_attributes.elements(); e.hasMoreElements(); ) | |||
{ | |||
Object object = e.nextElement(); | |||
if( object instanceof Attribute ) | |||
@@ -18,12 +18,12 @@ import java.io.OutputStreamWriter; | |||
import java.io.PrintWriter; | |||
import java.io.Reader; | |||
import java.util.Enumeration; | |||
import java.util.Iterator; | |||
import java.util.zip.ZipFile; | |||
import org.apache.aut.zip.ZipOutputStream; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.tools.ant.taskdefs.manifest.Manifest; | |||
import org.apache.tools.ant.taskdefs.manifest.ManifestException; | |||
import org.apache.tools.ant.taskdefs.manifest.ManifestUtil; | |||
import org.apache.tools.ant.types.FileScanner; | |||
/** | |||
@@ -89,10 +89,10 @@ public class Jar | |||
try | |||
{ | |||
r = new FileReader( manifestFile ); | |||
Manifest newManifest = new Manifest( r ); | |||
Manifest newManifest = ManifestUtil.buildManifest( r ); | |||
if( m_manifest == null ) | |||
{ | |||
m_manifest = Manifest.getDefaultManifest(); | |||
m_manifest = ManifestUtil.getDefaultManifest(); | |||
} | |||
m_manifest.merge( newManifest ); | |||
} | |||
@@ -134,7 +134,7 @@ public class Jar | |||
{ | |||
if( m_manifest == null ) | |||
{ | |||
m_manifest = Manifest.getDefaultManifest(); | |||
m_manifest = ManifestUtil.getDefaultManifest(); | |||
} | |||
m_manifest.merge( newManifest ); | |||
buildFileManifest = true; | |||
@@ -172,10 +172,10 @@ public class Jar | |||
getLogger().debug( "Updating jar since the current jar has no manifest" ); | |||
return false; | |||
} | |||
Manifest currentManifest = new Manifest( new InputStreamReader( theZipFile.getInputStream( entry ) ) ); | |||
Manifest currentManifest = ManifestUtil.buildManifest( new InputStreamReader( theZipFile.getInputStream( entry ) ) ); | |||
if( m_manifest == null ) | |||
{ | |||
m_manifest = Manifest.getDefaultManifest(); | |||
m_manifest = ManifestUtil.getDefaultManifest(); | |||
} | |||
if( !currentManifest.equals( m_manifest ) ) | |||
{ | |||
@@ -231,22 +231,25 @@ public class Jar | |||
{ | |||
try | |||
{ | |||
m_execManifest = Manifest.getDefaultManifest(); | |||
m_execManifest = ManifestUtil.getDefaultManifest(); | |||
if( m_manifest != null ) | |||
{ | |||
m_execManifest.merge( m_manifest ); | |||
} | |||
/* | |||
for( Iterator e = m_execManifest.getWarnings(); e.hasNext(); ) | |||
{ | |||
getLogger().warn( "Manifest warning: " + (String)e.next() ); | |||
} | |||
*/ | |||
zipDir( null, zOut, "META-INF/" ); | |||
// time to write the manifest | |||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
PrintWriter writer = new PrintWriter( baos ); | |||
m_execManifest.write( writer ); | |||
Manifest manifest = m_execManifest; | |||
ManifestUtil.write( manifest, writer ); | |||
writer.flush(); | |||
ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() ); | |||
@@ -375,11 +378,12 @@ public class Jar | |||
{ | |||
if( m_execManifest == null ) | |||
{ | |||
m_execManifest = new Manifest( new InputStreamReader( is ) ); | |||
m_execManifest = ManifestUtil.buildManifest( new InputStreamReader( is ) ); | |||
} | |||
else if( isAddingNewFiles() ) | |||
{ | |||
m_execManifest.merge( new Manifest( new InputStreamReader( is ) ) ); | |||
final Manifest other = ManifestUtil.buildManifest( new InputStreamReader( is ) ); | |||
m_execManifest.merge( other ); | |||
} | |||
} | |||
catch( ManifestException e ) | |||
@@ -9,6 +9,7 @@ package org.apache.tools.ant.taskdefs.manifest; | |||
import java.io.PrintWriter; | |||
import java.io.IOException; | |||
import java.util.jar.Attributes; | |||
/** | |||
* Class to hold manifest attributes | |||
@@ -110,10 +111,11 @@ public class Attribute | |||
} | |||
final Attribute other = (Attribute)object; | |||
final String name = other.m_name; | |||
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 ) ); | |||
( null != m_name && null != name && | |||
m_name.toLowerCase().equals( name.toLowerCase() ) && | |||
null != m_value && m_value.equals( other.m_value ) ); | |||
} | |||
} |
@@ -7,23 +7,11 @@ | |||
*/ | |||
package org.apache.tools.ant.taskdefs.manifest; | |||
import java.io.BufferedReader; | |||
import java.io.File; | |||
import java.io.FileReader; | |||
import java.io.FileWriter; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.InputStreamReader; | |||
import java.io.PrintWriter; | |||
import java.io.Reader; | |||
import java.io.StringWriter; | |||
import java.io.UnsupportedEncodingException; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Enumeration; | |||
import java.util.Hashtable; | |||
import java.util.Iterator; | |||
import java.util.jar.Attributes; | |||
import org.apache.myrmidon.api.AbstractTask; | |||
import java.util.Set; | |||
import org.apache.myrmidon.api.TaskException; | |||
/** | |||
@@ -35,42 +23,11 @@ import org.apache.myrmidon.api.TaskException; | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class Manifest | |||
extends AbstractTask | |||
{ | |||
/** | |||
* The standard Signature Version header | |||
*/ | |||
public final static String ATTRIBUTE_SIGNATURE_VERSION = Attributes.Name.SIGNATURE_VERSION.toString(); | |||
/** | |||
* The Name Attribute is the first in a named section | |||
*/ | |||
public final static String ATTRIBUTE_NAME = "Name"; | |||
/** | |||
* The From Header is disallowed in a Manifest | |||
*/ | |||
public final static String ATTRIBUTE_FROM = "From"; | |||
/** | |||
* The Class-Path Header is special - it can be duplicated | |||
*/ | |||
public final static String ATTRIBUTE_CLASSPATH = Attributes.Name.CLASS_PATH.toString(); | |||
/** | |||
* Default Manifest version if one is not specified | |||
*/ | |||
public final static String DEFAULT_MANIFEST_VERSION = "1.0"; | |||
/** | |||
* The max length of a line in a Manifest | |||
*/ | |||
public final static int MAX_LINE_LENGTH = 70; | |||
/** | |||
* The version of this manifest | |||
*/ | |||
private String m_manifestVersion = DEFAULT_MANIFEST_VERSION; | |||
private String m_manifestVersion = ManifestUtil.DEFAULT_MANIFEST_VERSION; | |||
/** | |||
* The main section of this manifest | |||
@@ -82,211 +39,112 @@ public class Manifest | |||
*/ | |||
private Hashtable m_sections = new Hashtable(); | |||
private File m_manifestFile; | |||
private ManifestMode m_mode; | |||
/** | |||
* Construct an empty manifest | |||
*/ | |||
public Manifest() | |||
throws TaskException | |||
public void setManifestVersion( final String manifestVersion ) | |||
{ | |||
m_mode = new ManifestMode(); | |||
m_mode.setValue( "replace" ); | |||
m_manifestVersion = null; | |||
m_manifestVersion = manifestVersion; | |||
} | |||
/** | |||
* Read a manifest file from the given reader | |||
* | |||
* @param r Description of Parameter | |||
* @exception ManifestException Description of Exception | |||
* @exception IOException Description of Exception | |||
* @throws ManifestException if the manifest is not valid according to the | |||
* JAR spec | |||
* @throws IOException if the manifest cannot be read from the reader. | |||
*/ | |||
public Manifest( Reader r ) | |||
throws ManifestException, TaskException, IOException | |||
public void setMainSection( final Section mainSection ) | |||
{ | |||
BufferedReader reader = new BufferedReader( r ); | |||
// This should be the manifest version | |||
String nextSectionName = m_mainSection.read( reader ); | |||
String readManifestVersion = m_mainSection.getAttributeValue( Attributes.Name.MANIFEST_VERSION.toString() ); | |||
if( readManifestVersion != null ) | |||
{ | |||
m_manifestVersion = readManifestVersion; | |||
m_mainSection.removeAttribute( Attributes.Name.MANIFEST_VERSION.toString() ); | |||
} | |||
String line = null; | |||
while( ( line = reader.readLine() ) != null ) | |||
{ | |||
if( line.length() == 0 ) | |||
{ | |||
continue; | |||
} | |||
Section section = new Section(); | |||
if( nextSectionName == null ) | |||
{ | |||
Attribute sectionName = ManifestUtil.buildAttribute( line ); | |||
if( !sectionName.getName().equalsIgnoreCase( ATTRIBUTE_NAME ) ) | |||
{ | |||
throw new ManifestException( "Manifest sections should start with a \"" + ATTRIBUTE_NAME + | |||
"\" attribute and not \"" + sectionName.getName() + "\"" ); | |||
} | |||
nextSectionName = sectionName.getValue(); | |||
} | |||
else | |||
{ | |||
// we have already started reading this section | |||
// this line is the first attribute. set it and then let the normal | |||
// read handle the rest | |||
Attribute firstAttribute = ManifestUtil.buildAttribute( line ); | |||
section.addAttributeAndCheck( firstAttribute ); | |||
} | |||
m_mainSection = mainSection; | |||
} | |||
section.setName( nextSectionName ); | |||
nextSectionName = section.read( reader ); | |||
addSection( section ); | |||
} | |||
public void addAttribute( final Attribute attribute ) | |||
throws ManifestException | |||
{ | |||
m_mainSection.addAttribute( attribute ); | |||
} | |||
/** | |||
* Construct a manifest from Ant's default manifest file. | |||
* | |||
* @return The DefaultManifest value | |||
* @exception TaskException Description of Exception | |||
*/ | |||
public static Manifest getDefaultManifest() | |||
throws TaskException | |||
public void addSection( final Section section ) | |||
throws ManifestException | |||
{ | |||
try | |||
{ | |||
String s = "/org/apache/tools/ant/defaultManifest.mf"; | |||
InputStream in = Manifest.class.getResourceAsStream( s ); | |||
if( in == null ) | |||
{ | |||
throw new TaskException( "Could not find default manifest: " + s ); | |||
} | |||
try | |||
{ | |||
return new Manifest( new InputStreamReader( in, "ASCII" ) ); | |||
} | |||
catch( UnsupportedEncodingException e ) | |||
{ | |||
return new Manifest( new InputStreamReader( in ) ); | |||
} | |||
} | |||
catch( ManifestException e ) | |||
{ | |||
throw new TaskException( "Default manifest is invalid !!" ); | |||
} | |||
catch( IOException e ) | |||
if( section.getName() == null ) | |||
{ | |||
throw new TaskException( "Unable to read default manifest", e ); | |||
final String message = "Sections must have a name"; | |||
throw new ManifestException( message ); | |||
} | |||
m_sections.put( section.getName().toLowerCase(), section ); | |||
} | |||
/** | |||
* The name of the manifest file to write (if used as a task). | |||
* | |||
* @param f The new File value | |||
*/ | |||
public void setFile( File f ) | |||
public String[] getSectionNames( final Manifest other ) | |||
{ | |||
m_manifestFile = f; | |||
final Set keys = other.m_sections.keySet(); | |||
return (String[])keys.toArray( new String[ keys.size() ] ); | |||
} | |||
/** | |||
* Shall we update or replace an existing manifest? | |||
* | |||
* @param m The new ManifestMode value | |||
*/ | |||
public void setMode( ManifestMode m ) | |||
public String getManifestVersion() | |||
{ | |||
m_mode = m; | |||
return m_manifestVersion; | |||
} | |||
/** | |||
* Get the warnings for this manifest. | |||
* | |||
* @return an enumeration of warning strings | |||
*/ | |||
public Iterator getWarnings() | |||
public Section getMainSection() | |||
{ | |||
ArrayList warnings = new ArrayList(); | |||
for( Iterator e2 = m_mainSection.getWarnings(); e2.hasNext(); ) | |||
{ | |||
warnings.add( e2.next() ); | |||
} | |||
// create a vector and add in the warnings for all the sections | |||
for( Enumeration e = m_sections.elements(); e.hasMoreElements(); ) | |||
{ | |||
Section section = (Section)e.nextElement(); | |||
for( Iterator e2 = section.getWarnings(); e2.hasNext(); ) | |||
{ | |||
warnings.add( e2.next() ); | |||
} | |||
} | |||
return m_mainSection; | |||
} | |||
return warnings.iterator(); | |||
public Section getSection( final String name ) | |||
{ | |||
return (Section)m_sections.get( name ); | |||
} | |||
public void addAttribute( final Attribute attribute ) | |||
throws ManifestException, TaskException | |||
public Section[] getSections() | |||
{ | |||
m_mainSection.addAttribute( attribute ); | |||
final Collection sections = m_sections.values(); | |||
return (Section[])sections.toArray( new Section[ sections.size() ] ); | |||
} | |||
public void addSection( final Section section ) | |||
throws ManifestException, TaskException | |||
/** | |||
* Merge the contents of the given manifest into this manifest | |||
* | |||
* @param other the Manifest to be merged with this one. | |||
* @throws ManifestException if there is a problem merging the manfest | |||
* according to the Manifest spec. | |||
*/ | |||
public void merge( final Manifest other ) | |||
throws ManifestException | |||
{ | |||
if( section.getName() == null ) | |||
if( other.m_manifestVersion != null ) | |||
{ | |||
throw new TaskException( "Sections must have a name" ); | |||
m_manifestVersion = other.m_manifestVersion; | |||
} | |||
m_sections.put( section.getName().toLowerCase(), section ); | |||
m_mainSection.merge( other.m_mainSection ); | |||
mergeSections( other ); | |||
} | |||
public boolean equals( Object rhs ) | |||
public boolean equals( final Object object ) | |||
{ | |||
if( !( rhs instanceof Manifest ) ) | |||
if( !( object instanceof Manifest ) ) | |||
{ | |||
return false; | |||
} | |||
Manifest rhsManifest = (Manifest)rhs; | |||
if( m_manifestVersion == null ) | |||
final Manifest other = (Manifest)object; | |||
if( m_manifestVersion == null && other.m_manifestVersion != null ) | |||
{ | |||
if( rhsManifest.m_manifestVersion != null ) | |||
{ | |||
return false; | |||
} | |||
return false; | |||
} | |||
else if( !m_manifestVersion.equals( rhsManifest.m_manifestVersion ) ) | |||
else if( !m_manifestVersion.equals( other.m_manifestVersion ) ) | |||
{ | |||
return false; | |||
} | |||
if( m_sections.size() != rhsManifest.m_sections.size() ) | |||
if( m_sections.size() != other.m_sections.size() ) | |||
{ | |||
return false; | |||
} | |||
if( !m_mainSection.equals( rhsManifest.m_mainSection ) ) | |||
if( !m_mainSection.equals( other.m_mainSection ) ) | |||
{ | |||
return false; | |||
} | |||
for( Enumeration e = m_sections.elements(); e.hasMoreElements(); ) | |||
final Iterator e = m_sections.values().iterator(); | |||
while( e.hasNext() ) | |||
{ | |||
Section section = (Section)e.nextElement(); | |||
Section rhsSection = (Section)rhsManifest.m_sections.get( section.getName().toLowerCase() ); | |||
if( !section.equals( rhsSection ) ) | |||
final Section section = (Section)e.next(); | |||
final String key = section.getName().toLowerCase(); | |||
final Section otherSection = (Section)other.m_sections.get( key ); | |||
if( !section.equals( otherSection ) ) | |||
{ | |||
return false; | |||
} | |||
@@ -295,168 +153,23 @@ public class Manifest | |||
return true; | |||
} | |||
/** | |||
* Create or update the Manifest when used as a task. | |||
* | |||
* @exception TaskException Description of Exception | |||
*/ | |||
public void execute() | |||
throws TaskException | |||
{ | |||
if( m_manifestFile == null ) | |||
{ | |||
throw new TaskException( "the file attribute is required" ); | |||
} | |||
Manifest toWrite = getDefaultManifest(); | |||
if( m_mode.getValue().equals( "update" ) && m_manifestFile.exists() ) | |||
{ | |||
FileReader f = null; | |||
try | |||
{ | |||
f = new FileReader( m_manifestFile ); | |||
toWrite.merge( new Manifest( f ) ); | |||
} | |||
catch( ManifestException m ) | |||
{ | |||
throw new TaskException( "Existing manifest " + m_manifestFile | |||
+ " is invalid", m ); | |||
} | |||
catch( IOException e ) | |||
{ | |||
throw new | |||
TaskException( "Failed to read " + m_manifestFile, e ); | |||
} | |||
finally | |||
{ | |||
if( f != null ) | |||
{ | |||
try | |||
{ | |||
f.close(); | |||
} | |||
catch( IOException e ) | |||
{ | |||
} | |||
} | |||
} | |||
} | |||
try | |||
{ | |||
toWrite.merge( this ); | |||
} | |||
catch( ManifestException m ) | |||
{ | |||
throw new TaskException( "Manifest is invalid", m ); | |||
} | |||
PrintWriter w = null; | |||
try | |||
{ | |||
w = new PrintWriter( new FileWriter( m_manifestFile ) ); | |||
toWrite.write( w ); | |||
} | |||
catch( IOException e ) | |||
{ | |||
throw new TaskException( "Failed to write " + m_manifestFile, e ); | |||
} | |||
finally | |||
{ | |||
if( w != null ) | |||
{ | |||
w.close(); | |||
} | |||
} | |||
} | |||
/** | |||
* Merge the contents of the given manifest into this manifest | |||
* | |||
* @param other the Manifest to be merged with this one. | |||
* @throws ManifestException if there is a problem merging the manfest | |||
* according to the Manifest spec. | |||
*/ | |||
public void merge( Manifest other ) | |||
private void mergeSections( final Manifest other ) | |||
throws ManifestException | |||
{ | |||
if( other.m_manifestVersion != null ) | |||
{ | |||
m_manifestVersion = other.m_manifestVersion; | |||
} | |||
m_mainSection.merge( other.m_mainSection ); | |||
for( Enumeration e = other.m_sections.keys(); e.hasMoreElements(); ) | |||
final String[] sections = getSectionNames( other ); | |||
for( int i = 0; i < sections.length; i++ ) | |||
{ | |||
String sectionName = (String)e.nextElement(); | |||
Section ourSection = (Section)m_sections.get( sectionName ); | |||
Section otherSection = (Section)other.m_sections.get( sectionName ); | |||
if( ourSection == null ) | |||
final String sectionName = sections[ i ]; | |||
final Section section = getSection( sectionName ); | |||
final Section otherSection = other.getSection( sectionName ); | |||
if( section == null ) | |||
{ | |||
m_sections.put( sectionName.toLowerCase(), otherSection ); | |||
} | |||
else | |||
{ | |||
ourSection.merge( otherSection ); | |||
section.merge( otherSection ); | |||
} | |||
} | |||
} | |||
/** | |||
* Convert the manifest to its string representation | |||
* | |||
* @return a multiline string with the Manifest as it appears in a Manifest | |||
* file. | |||
*/ | |||
public String toString() | |||
{ | |||
StringWriter sw = new StringWriter(); | |||
try | |||
{ | |||
write( new PrintWriter( sw ) ); | |||
} | |||
catch( Exception e ) | |||
{ | |||
return null; | |||
} | |||
return sw.toString(); | |||
} | |||
/** | |||
* Write the manifest out to a print writer. | |||
* | |||
* @param writer the Writer to which the manifest is written | |||
* @throws IOException if the manifest cannot be written | |||
*/ | |||
public void write( PrintWriter writer ) | |||
throws IOException, TaskException | |||
{ | |||
writer.println( Attributes.Name.MANIFEST_VERSION + ": " + m_manifestVersion ); | |||
String signatureVersion = m_mainSection.getAttributeValue( ATTRIBUTE_SIGNATURE_VERSION ); | |||
if( signatureVersion != null ) | |||
{ | |||
writer.println( ATTRIBUTE_SIGNATURE_VERSION + ": " + signatureVersion ); | |||
m_mainSection.removeAttribute( ATTRIBUTE_SIGNATURE_VERSION ); | |||
} | |||
m_mainSection.write( writer ); | |||
if( signatureVersion != null ) | |||
{ | |||
try | |||
{ | |||
m_mainSection.addAttribute( new Attribute( ATTRIBUTE_SIGNATURE_VERSION, signatureVersion ) ); | |||
} | |||
catch( ManifestException e ) | |||
{ | |||
// shouldn't happen - ignore | |||
} | |||
} | |||
for( Enumeration e = m_sections.elements(); e.hasMoreElements(); ) | |||
{ | |||
Section section = (Section)e.nextElement(); | |||
section.write( writer ); | |||
} | |||
} | |||
} |
@@ -0,0 +1,196 @@ | |||
/* | |||
* 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.File; | |||
import java.io.FileReader; | |||
import java.io.FileWriter; | |||
import java.io.IOException; | |||
import java.io.PrintWriter; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import org.apache.avalon.excalibur.io.IOUtil; | |||
import org.apache.myrmidon.api.AbstractTask; | |||
import org.apache.myrmidon.api.TaskException; | |||
/** | |||
* 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> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class ManifestTask | |||
extends AbstractTask | |||
{ | |||
private File m_destFile; | |||
private ManifestMode m_mode; | |||
private Manifest m_manifest = new Manifest(); | |||
/** | |||
* Construct an empty manifest | |||
*/ | |||
public ManifestTask() | |||
throws TaskException | |||
{ | |||
m_mode = new ManifestMode(); | |||
m_mode.setValue( "replace" ); | |||
} | |||
/** | |||
* The name of the manifest file to write. | |||
*/ | |||
public void setDestFile( final File destFile ) | |||
{ | |||
m_destFile = destFile; | |||
} | |||
/** | |||
* Shall we update or replace an existing manifest? | |||
*/ | |||
public void setMode( final ManifestMode mode ) | |||
{ | |||
m_mode = mode; | |||
} | |||
public void setManifestVersion( String manifestVersion ) | |||
{ | |||
m_manifest.setManifestVersion( manifestVersion ); | |||
} | |||
public void addMainSection( Section mainSection ) | |||
throws Exception | |||
{ | |||
m_manifest.setMainSection( mainSection ); | |||
} | |||
/** | |||
* Get the warnings for this manifest. | |||
* | |||
* @return an enumeration of warning strings | |||
*/ | |||
public Iterator getWarnings() | |||
{ | |||
ArrayList warnings = new ArrayList(); | |||
for( Iterator e2 = m_manifest.getMainSection().getWarnings(); e2.hasNext(); ) | |||
{ | |||
warnings.add( e2.next() ); | |||
} | |||
final Section[] sections = m_manifest.getSections(); | |||
for( int i = 0; i < sections.length; i++ ) | |||
{ | |||
final Section section = sections[ i ]; | |||
for( Iterator e2 = section.getWarnings(); e2.hasNext(); ) | |||
{ | |||
warnings.add( e2.next() ); | |||
} | |||
} | |||
return warnings.iterator(); | |||
} | |||
public void addAttribute( final Attribute attribute ) | |||
throws ManifestException, TaskException | |||
{ | |||
m_manifest.addAttribute( attribute ); | |||
} | |||
public void addSection( final Section section ) | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
m_manifest.addSection( section ); | |||
} | |||
catch( final ManifestException me ) | |||
{ | |||
throw new TaskException( me.getMessage(), me ); | |||
} | |||
} | |||
/** | |||
* Create or update the Manifest when used as a task. | |||
* | |||
* @exception TaskException Description of Exception | |||
*/ | |||
public void execute() | |||
throws TaskException | |||
{ | |||
if( null == m_destFile ) | |||
{ | |||
throw new TaskException( "the file attribute is required" ); | |||
} | |||
Manifest toWrite = getDefaultManifest(); | |||
if( m_mode.getValue().equals( "update" ) && m_destFile.exists() ) | |||
{ | |||
FileReader f = null; | |||
try | |||
{ | |||
f = new FileReader( m_destFile ); | |||
final Manifest other = ManifestUtil.buildManifest( f ); | |||
toWrite.merge( other ); | |||
} | |||
catch( ManifestException m ) | |||
{ | |||
throw new TaskException( "Existing manifest " + m_destFile | |||
+ " is invalid", m ); | |||
} | |||
catch( IOException e ) | |||
{ | |||
throw new | |||
TaskException( "Failed to read " + m_destFile, e ); | |||
} | |||
finally | |||
{ | |||
IOUtil.shutdownReader( f ); | |||
} | |||
} | |||
try | |||
{ | |||
toWrite.merge( m_manifest ); | |||
} | |||
catch( ManifestException m ) | |||
{ | |||
throw new TaskException( "Manifest is invalid", m ); | |||
} | |||
PrintWriter w = null; | |||
try | |||
{ | |||
w = new PrintWriter( new FileWriter( m_destFile ) ); | |||
ManifestUtil.write( toWrite, w ); | |||
} | |||
catch( IOException e ) | |||
{ | |||
throw new TaskException( "Failed to write " + m_destFile, e ); | |||
} | |||
finally | |||
{ | |||
IOUtil.shutdownWriter( w ); | |||
} | |||
} | |||
private Manifest getDefaultManifest() | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
return ManifestUtil.getDefaultManifest(); | |||
} | |||
catch( final ManifestException me ) | |||
{ | |||
throw new TaskException( me.getMessage(), me ); | |||
} | |||
} | |||
} |
@@ -8,7 +8,14 @@ | |||
package org.apache.tools.ant.taskdefs.manifest; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.InputStreamReader; | |||
import java.io.PrintWriter; | |||
import java.io.Reader; | |||
import java.io.UnsupportedEncodingException; | |||
import java.io.BufferedReader; | |||
import java.util.jar.Attributes; | |||
import org.apache.myrmidon.api.TaskException; | |||
/** | |||
* Utility methods for manifest stuff. | |||
@@ -20,6 +27,27 @@ import java.io.PrintWriter; | |||
*/ | |||
public final class ManifestUtil | |||
{ | |||
/** | |||
* The Name Attribute is the first in a named section | |||
*/ | |||
public final static String ATTRIBUTE_NAME = "Name"; | |||
/** | |||
* The From Header is disallowed in a Manifest | |||
*/ | |||
public final static String ATTRIBUTE_FROM = "From"; | |||
/** | |||
* The Class-Path Header is special - it can be duplicated | |||
*/ | |||
public final static String ATTRIBUTE_CLASSPATH = Attributes.Name.CLASS_PATH.toString(); | |||
/** | |||
* Default Manifest version if one is not specified | |||
*/ | |||
public final static String DEFAULT_MANIFEST_VERSION = "1.0"; | |||
/** | |||
* The max length of a line in a Manifest | |||
*/ | |||
public final static int MAX_LINE_LENGTH = 70; | |||
public static Attribute buildAttribute( final String line ) | |||
throws ManifestException | |||
{ | |||
@@ -28,6 +56,100 @@ public final class ManifestUtil | |||
return attribute; | |||
} | |||
public static Manifest buildManifest( final Reader reader ) | |||
throws ManifestException, IOException | |||
{ | |||
final Manifest manifest = new Manifest(); | |||
BufferedReader bufferedReader = new BufferedReader( reader ); | |||
// This should be the manifest version | |||
final Section mainSection = manifest.getMainSection(); | |||
String nextSectionName = mainSection.read( bufferedReader ); | |||
final String readManifestVersion = | |||
mainSection.getAttributeValue( Attributes.Name.MANIFEST_VERSION.toString() ); | |||
if( readManifestVersion != null ) | |||
{ | |||
manifest.setManifestVersion( readManifestVersion ); | |||
mainSection.removeAttribute( Attributes.Name.MANIFEST_VERSION.toString() ); | |||
} | |||
String line = null; | |||
while( ( line = bufferedReader.readLine() ) != null ) | |||
{ | |||
if( line.length() == 0 ) | |||
{ | |||
continue; | |||
} | |||
Section section = new Section(); | |||
if( nextSectionName == null ) | |||
{ | |||
Attribute sectionName = ManifestUtil.buildAttribute( line ); | |||
if( !sectionName.getName().equalsIgnoreCase( ManifestUtil.ATTRIBUTE_NAME ) ) | |||
{ | |||
throw new ManifestException( "Manifest sections should start with a \"" + ManifestUtil.ATTRIBUTE_NAME + | |||
"\" attribute and not \"" + sectionName.getName() + "\"" ); | |||
} | |||
nextSectionName = sectionName.getValue(); | |||
} | |||
else | |||
{ | |||
// we have already started reading this section | |||
// this line is the first attribute. set it and then let the normal | |||
// read handle the rest | |||
Attribute firstAttribute = ManifestUtil.buildAttribute( line ); | |||
section.addAttributeAndCheck( firstAttribute ); | |||
} | |||
section.setName( nextSectionName ); | |||
nextSectionName = section.read( bufferedReader ); | |||
manifest.addSection( section ); | |||
} | |||
return manifest; | |||
} | |||
/** | |||
* Construct a manifest from Ant's default manifest file. | |||
*/ | |||
public static Manifest getDefaultManifest() | |||
throws ManifestException | |||
{ | |||
try | |||
{ | |||
final InputStream input = getInputStream(); | |||
final InputStreamReader reader = getReader( input ); | |||
return buildManifest( reader ); | |||
} | |||
catch( final IOException ioe ) | |||
{ | |||
throw new ManifestException( "Unable to read default manifest", ioe ); | |||
} | |||
} | |||
private static InputStream getInputStream() | |||
throws ManifestException | |||
{ | |||
final String location = "default.mf"; | |||
final InputStream input = ManifestUtil.class.getResourceAsStream( location ); | |||
if( null == input ) | |||
{ | |||
throw new ManifestException( "Could not find default manifest: " + location ); | |||
} | |||
return input; | |||
} | |||
private static InputStreamReader getReader( final InputStream input ) | |||
{ | |||
try | |||
{ | |||
return new InputStreamReader( input, "ASCII" ); | |||
} | |||
catch( final UnsupportedEncodingException uee ) | |||
{ | |||
return new InputStreamReader( input ); | |||
} | |||
} | |||
/** | |||
* Parse a line into name and value pairs | |||
* | |||
@@ -56,12 +178,12 @@ public final class ManifestUtil | |||
final String name = attribute.getName(); | |||
final String value = attribute.getValue(); | |||
String line = name + ": " + value; | |||
while( line.getBytes().length > Manifest.MAX_LINE_LENGTH ) | |||
while( line.getBytes().length > MAX_LINE_LENGTH ) | |||
{ | |||
// try to find a MAX_LINE_LENGTH byte section | |||
int breakIndex = Manifest.MAX_LINE_LENGTH; | |||
int breakIndex = MAX_LINE_LENGTH; | |||
String section = line.substring( 0, breakIndex ); | |||
while( section.getBytes().length > Manifest.MAX_LINE_LENGTH && breakIndex > 0 ) | |||
while( section.getBytes().length > MAX_LINE_LENGTH && breakIndex > 0 ) | |||
{ | |||
breakIndex--; | |||
section = line.substring( 0, breakIndex ); | |||
@@ -75,4 +197,44 @@ public final class ManifestUtil | |||
} | |||
writer.println( line ); | |||
} | |||
/** | |||
* Write the manifest out to a print writer. | |||
* | |||
* @param writer the Writer to which the manifest is written | |||
* @throws IOException if the manifest cannot be written | |||
*/ | |||
public static void write( Manifest manifest, PrintWriter writer ) | |||
throws IOException | |||
{ | |||
final String sigVersionKey = Attributes.Name.SIGNATURE_VERSION.toString(); | |||
writer.println( Attributes.Name.MANIFEST_VERSION + ": " + manifest.getManifestVersion() ); | |||
final String signatureVersion = | |||
manifest.getMainSection().getAttributeValue( sigVersionKey ); | |||
if( signatureVersion != null ) | |||
{ | |||
writer.println( Attributes.Name.SIGNATURE_VERSION + ": " + signatureVersion ); | |||
manifest.getMainSection().removeAttribute( sigVersionKey ); | |||
} | |||
manifest.getMainSection().write( writer ); | |||
if( signatureVersion != null ) | |||
{ | |||
try | |||
{ | |||
manifest.getMainSection().addAttribute( new Attribute( sigVersionKey, signatureVersion ) ); | |||
} | |||
catch( ManifestException e ) | |||
{ | |||
// shouldn't happen - ignore | |||
} | |||
} | |||
final Section[] sections = manifest.getSections(); | |||
for( int i = 0; i < sections.length; i++ ) | |||
{ | |||
sections[ i ].write( writer ); | |||
} | |||
} | |||
} |
@@ -14,7 +14,6 @@ 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 | |||
@@ -28,26 +27,26 @@ import org.apache.myrmidon.api.TaskException; | |||
*/ | |||
public class Section | |||
{ | |||
private ArrayList warnings = new ArrayList(); | |||
private final ArrayList m_warnings = new ArrayList(); | |||
/** | |||
* The section's name if any. The main section in a manifest is unnamed. | |||
*/ | |||
private String name = null; | |||
private String m_name; | |||
/** | |||
* The section's attributes. | |||
*/ | |||
private Hashtable attributes = new Hashtable(); | |||
private final Hashtable m_attributes = new Hashtable(); | |||
/** | |||
* Set the Section's name | |||
* | |||
* @param name the section's name | |||
*/ | |||
public void setName( String name ) | |||
public void setName( final String name ) | |||
{ | |||
this.name = name; | |||
m_name = name; | |||
} | |||
/** | |||
@@ -57,23 +56,26 @@ public class Section | |||
* @return the attribute's value or null if the attribute does not exist | |||
* in the section | |||
*/ | |||
public String getAttributeValue( String attributeName ) | |||
public String getAttributeValue( final String attributeName ) | |||
{ | |||
Object attribute = attributes.get( attributeName.toLowerCase() ); | |||
if( attribute == null ) | |||
final Object attributeObject = m_attributes.get( attributeName.toLowerCase() ); | |||
if( null == attributeObject ) | |||
{ | |||
return null; | |||
} | |||
if( attribute instanceof Attribute ) | |||
else if( attributeObject instanceof Attribute ) | |||
{ | |||
return ( (Attribute)attribute ).getValue(); | |||
final Attribute attribute = (Attribute)attributeObject; | |||
return attribute.getValue(); | |||
} | |||
else | |||
{ | |||
String value = ""; | |||
for( Iterator e = ( (ArrayList)attribute ).iterator(); e.hasNext(); ) | |||
final ArrayList attributes = (ArrayList)attributeObject; | |||
Iterator e = attributes.iterator(); | |||
while( e.hasNext() ) | |||
{ | |||
Attribute classpathAttribute = (Attribute)e.next(); | |||
final Attribute classpathAttribute = (Attribute)e.next(); | |||
value += classpathAttribute.getValue() + " "; | |||
} | |||
return value.trim(); | |||
@@ -87,12 +89,12 @@ public class Section | |||
*/ | |||
public String getName() | |||
{ | |||
return name; | |||
return m_name; | |||
} | |||
public Iterator getWarnings() | |||
{ | |||
return warnings.iterator(); | |||
return m_warnings.iterator(); | |||
} | |||
/** | |||
@@ -105,59 +107,59 @@ public class Section | |||
* section. | |||
*/ | |||
public String addAttributeAndCheck( Attribute attribute ) | |||
throws ManifestException, TaskException | |||
throws ManifestException | |||
{ | |||
if( attribute.getName() == null || attribute.getValue() == null ) | |||
{ | |||
throw new TaskException( "Attributes must have name and value" ); | |||
throw new ManifestException( "Attributes must have name and value" ); | |||
} | |||
if( attribute.getName().equalsIgnoreCase( Manifest.ATTRIBUTE_NAME ) ) | |||
if( attribute.getName().equalsIgnoreCase( ManifestUtil.ATTRIBUTE_NAME ) ) | |||
{ | |||
warnings.add( "\"" + Manifest.ATTRIBUTE_NAME + "\" attributes should not occur in the " + | |||
m_warnings.add( "\"" + ManifestUtil.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() ) ) | |||
if( attribute.getName().toLowerCase().startsWith( ManifestUtil.ATTRIBUTE_FROM.toLowerCase() ) ) | |||
{ | |||
warnings.add( "Manifest attributes should not start with \"" + | |||
Manifest.ATTRIBUTE_FROM + "\" in \"" + attribute.getName() + ": " + attribute.getValue() + "\"" ); | |||
m_warnings.add( "Manifest attributes should not start with \"" + | |||
ManifestUtil.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 ) ) | |||
if( attributeName.equals( ManifestUtil.ATTRIBUTE_CLASSPATH ) ) | |||
{ | |||
ArrayList classpathAttrs = (ArrayList)attributes.get( attributeName ); | |||
ArrayList classpathAttrs = (ArrayList)m_attributes.get( attributeName ); | |||
if( classpathAttrs == null ) | |||
{ | |||
classpathAttrs = new ArrayList(); | |||
attributes.put( attributeName, classpathAttrs ); | |||
m_attributes.put( attributeName, classpathAttrs ); | |||
} | |||
classpathAttrs.add( attribute ); | |||
} | |||
else if( attributes.containsKey( attributeName ) ) | |||
else if( m_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 ); | |||
m_attributes.put( attributeName, attribute ); | |||
} | |||
} | |||
return null; | |||
} | |||
public void addAttribute( Attribute attribute ) | |||
throws ManifestException, TaskException | |||
public void addAttribute( final Attribute attribute ) | |||
throws ManifestException | |||
{ | |||
String check = addAttributeAndCheck( attribute ); | |||
if( check != null ) | |||
{ | |||
throw new TaskException( "Specify the section name using the \"name\" attribute of the <section> element rather " + | |||
throw new ManifestException( "Specify the section name using the \"name\" attribute of the <section> element rather " + | |||
"than using a \"Name\" manifest attribute" ); | |||
} | |||
} | |||
@@ -170,15 +172,15 @@ public class Section | |||
} | |||
Section rhsSection = (Section)rhs; | |||
if( attributes.size() != rhsSection.attributes.size() ) | |||
if( m_attributes.size() != rhsSection.m_attributes.size() ) | |||
{ | |||
return false; | |||
} | |||
for( Enumeration e = attributes.elements(); e.hasMoreElements(); ) | |||
for( Enumeration e = m_attributes.elements(); e.hasMoreElements(); ) | |||
{ | |||
Attribute attribute = (Attribute)e.nextElement(); | |||
Attribute rshAttribute = (Attribute)rhsSection.attributes.get( attribute.getName().toLowerCase() ); | |||
Attribute rshAttribute = (Attribute)rhsSection.m_attributes.get( attribute.getName().toLowerCase() ); | |||
if( !attribute.equals( rshAttribute ) ) | |||
{ | |||
return false; | |||
@@ -197,21 +199,21 @@ public class Section | |||
public void merge( Section section ) | |||
throws ManifestException | |||
{ | |||
if( name == null && section.getName() != null || | |||
name != null && !( name.equalsIgnoreCase( section.getName() ) ) ) | |||
if( m_name == null && section.getName() != null || | |||
m_name != null && !( m_name.equalsIgnoreCase( section.getName() ) ) ) | |||
{ | |||
throw new ManifestException( "Unable to merge sections with different names" ); | |||
} | |||
for( Enumeration e = section.attributes.keys(); e.hasMoreElements(); ) | |||
for( Enumeration e = section.m_attributes.keys(); e.hasMoreElements(); ) | |||
{ | |||
String attributeName = (String)e.nextElement(); | |||
if( attributeName.equals( Manifest.ATTRIBUTE_CLASSPATH ) && | |||
attributes.containsKey( attributeName ) ) | |||
if( attributeName.equals( ManifestUtil.ATTRIBUTE_CLASSPATH ) && | |||
m_attributes.containsKey( attributeName ) ) | |||
{ | |||
// classpath entries are vetors which are merged | |||
ArrayList classpathAttrs = (ArrayList)section.attributes.get( attributeName ); | |||
ArrayList ourClasspathAttrs = (ArrayList)attributes.get( attributeName ); | |||
ArrayList classpathAttrs = (ArrayList)section.m_attributes.get( attributeName ); | |||
ArrayList ourClasspathAttrs = (ArrayList)m_attributes.get( attributeName ); | |||
for( Iterator e2 = classpathAttrs.iterator(); e2.hasNext(); ) | |||
{ | |||
ourClasspathAttrs.add( e2.next() ); | |||
@@ -220,14 +222,14 @@ public class Section | |||
else | |||
{ | |||
// the merge file always wins | |||
attributes.put( attributeName, section.attributes.get( attributeName ) ); | |||
m_attributes.put( attributeName, section.m_attributes.get( attributeName ) ); | |||
} | |||
} | |||
// add in the warnings | |||
for( Iterator e = section.warnings.iterator(); e.hasNext(); ) | |||
for( Iterator e = section.m_warnings.iterator(); e.hasNext(); ) | |||
{ | |||
warnings.add( e.next() ); | |||
m_warnings.add( e.next() ); | |||
} | |||
} | |||
@@ -242,7 +244,7 @@ public class Section | |||
* @throws IOException if the section cannot be read from the reader. | |||
*/ | |||
public String read( BufferedReader reader ) | |||
throws ManifestException, IOException, TaskException | |||
throws ManifestException, IOException | |||
{ | |||
Attribute attribute = null; | |||
while( true ) | |||
@@ -257,11 +259,11 @@ public class Section | |||
// continuation line | |||
if( attribute == null ) | |||
{ | |||
if( name != null ) | |||
if( m_name != null ) | |||
{ | |||
// a continuation on the first line is a continuation of the name - concatenate | |||
// this line and the name | |||
name += line.substring( 1 ); | |||
m_name += line.substring( 1 ); | |||
} | |||
else | |||
{ | |||
@@ -292,7 +294,7 @@ public class Section | |||
*/ | |||
public void removeAttribute( String attributeName ) | |||
{ | |||
attributes.remove( attributeName.toLowerCase() ); | |||
m_attributes.remove( attributeName.toLowerCase() ); | |||
} | |||
/** | |||
@@ -304,12 +306,12 @@ public class Section | |||
public void write( PrintWriter writer ) | |||
throws IOException | |||
{ | |||
if( name != null ) | |||
if( m_name != null ) | |||
{ | |||
Attribute nameAttr = new Attribute( Manifest.ATTRIBUTE_NAME, name ); | |||
Attribute nameAttr = new Attribute( ManifestUtil.ATTRIBUTE_NAME, m_name ); | |||
ManifestUtil.write( nameAttr, writer ); | |||
} | |||
for( Enumeration e = attributes.elements(); e.hasMoreElements(); ) | |||
for( Enumeration e = m_attributes.elements(); e.hasMoreElements(); ) | |||
{ | |||
Object object = e.nextElement(); | |||
if( object instanceof Attribute ) | |||