You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ba...@apache.org on 2008/09/18 07:53:07 UTC

svn commit: r696566 - in /maven/plugins/trunk/maven-eclipse-plugin/src: main/java/org/apache/maven/plugin/eclipse/writers/ test/resources/projects/project-rad-8/ test/resources/projects/project-rad-8/src/ test/resources/projects/project-rad-8/src/main/...

Author: baerrach
Date: Wed Sep 17 22:53:07 2008
New Revision: 696566

URL: http://svn.apache.org/viewvc?rev=696566&view=rev
Log:
[MECLIPSE-423] Fix NullPointerException when existing Manifest.MF file has no Class-Path element

EclipseManifestWriter and RadManifestWriter are a cut-and-paste. Created AbstractEclipseManifestWriter as shared parent class
and moved all the common stuff up.  Where the code varied EclipseManifestWriter's implementation was chosen.  This was because the variation was often a bug fix.  

The only variation that could not be easily sorted was in addDependencyToClassPath where they only differ at the end:
	EclipseManifestWriter:
		classpath.append( dependency.getEclipseProjectName() + ".jar" );
	RadManifestWriter
		classpath.append( dependency.getArtifactId() + ".jar" );
I have taken the eclipse one as being correct and changed RadPlugin to override getProjectNameForArifact() to return artifact.getArtifactId() to match RadManifestWriter dependency.getArtifactId() as above.  Integration tests still work but I need a RAD person to validate this for me.

Added testProject8 for IT test. Prior to patch this exercised the defect.  After the patch it looks like it is fixed.
However have asked for clarifiction about write() when a new MANIFEST.MF needs to be written but there is already an existing file.
See http://www.nabble.com/m-eclipse-p%3A-EclipseManifestWriter.write%28%29---doesn%27t-retain-any-keys-except-CLASS_PATH-and-MANIFEST_VERSION-td19546126.html
The problem is that the old values will be lost.  Need to check if that is the correct intention.

Added:
    maven/plugins/trunk/maven-eclipse-plugin/src/main/java/org/apache/maven/plugin/eclipse/writers/AbstractEclipseManifestWriter.java   (with props)
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/pom.xml   (with props)
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/project
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/java/
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/java/DummyClass.txt   (with props)
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/META-INF/
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/META-INF/MANIFEST.MF
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/META-INF/expected_MANIFEST.MF
    maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/WEB-INF/

Added: maven/plugins/trunk/maven-eclipse-plugin/src/main/java/org/apache/maven/plugin/eclipse/writers/AbstractEclipseManifestWriter.java
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-eclipse-plugin/src/main/java/org/apache/maven/plugin/eclipse/writers/AbstractEclipseManifestWriter.java?rev=696566&view=auto
==============================================================================
--- maven/plugins/trunk/maven-eclipse-plugin/src/main/java/org/apache/maven/plugin/eclipse/writers/AbstractEclipseManifestWriter.java (added)
+++ maven/plugins/trunk/maven-eclipse-plugin/src/main/java/org/apache/maven/plugin/eclipse/writers/AbstractEclipseManifestWriter.java Wed Sep 17 22:53:07 2008
@@ -0,0 +1,313 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.eclipse.writers;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.eclipse.EclipseSourceDir;
+import org.apache.maven.plugin.eclipse.Messages;
+import org.apache.maven.plugin.eclipse.writers.wtp.AbstractWtpResourceWriter;
+import org.apache.maven.plugin.ide.IdeDependency;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+
+/**
+ * Common behaviours for creating or adapting the manifest files for eclipse environments.
+ * 
+ * @author <a href="mailto:nir@cfc.at">Richard van Nieuwenhoven </a>
+ */
+public abstract class AbstractEclipseManifestWriter
+    extends AbstractEclipseWriter
+{
+
+    protected static final String MANIFEST_MF_FILENAME = "MANIFEST.MF";
+
+    protected static final String META_INF_DIRECTORY = "META-INF";
+
+    public AbstractEclipseManifestWriter()
+    {
+        super();
+    }
+
+    /**
+     * Aphabeticaly sort the classpath. Do this by splitting it up, sort the entries and gleue them together again.
+     * 
+     * @param newValue classpath to sort
+     * @return the sorted classpath
+     */
+    protected String orderClasspath( String newValue )
+    {
+        if ( newValue == null )
+        {
+            return null;
+        }
+        String[] entries = newValue.split( " " );
+        Arrays.sort( entries );
+        StringBuffer buffer = new StringBuffer( newValue.length() );
+        for ( int index = 0; index < entries.length; index++ )
+        {
+            buffer.append( entries[index] );
+            buffer.append( ' ' );
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Read and parse the existing manifest file.
+     * 
+     * @param manifestFile file
+     * @return the read manifest
+     * @throws IOException if the file could not be read
+     */
+    protected Manifest readExistingManifest( File manifestFile )
+        throws IOException
+    {
+        if ( !manifestFile.exists() )
+        {
+            return null;
+        }
+
+        Manifest existingManifest = new Manifest();
+        FileInputStream inputStream = new FileInputStream( manifestFile );
+        try
+        {
+            existingManifest.read( inputStream );
+        }
+        finally
+        {
+            IOUtil.close( inputStream );
+        }
+        return existingManifest;
+    }
+
+    /**
+     * Add one dependency to the blank separated classpath stringbuffer. When the project is available in the reactor
+     * (current build) then the project is used else the jar representing the artifact. System dependencies will only be
+     * included if they are in this project.
+     * 
+     * @param classpath existing classpath to append
+     * @param dependency dependency to append as jar or as project
+     */
+    protected void addDependencyToClassPath( StringBuffer classpath, IdeDependency dependency )
+    {
+        if ( !dependency.isTestDependency() && !dependency.isProvided()
+            && !dependency.isSystemScopedOutsideProject( this.config.getProject() ) )
+        {
+
+            // blank is the separator in manifest classpath's
+            if ( classpath.length() != 0 )
+            {
+                classpath.append( ' ' );
+            }
+            // if the dependency is a workspace project add the project and not
+            // the jar
+            if ( !dependency.isReferencedProject() )
+            {
+                classpath.append( dependency.getFile().getName() );
+            }
+            else
+            {
+                classpath.append( dependency.getEclipseProjectName() + ".jar" );
+            }
+        }
+    }
+
+    /**
+     * Check if the two manifests are equal. Manifest.equal can not be used because of the special case the Classpath
+     * entr, witch must be comaired sorted so that a different oder in the classpath does not result in "not equal".
+     * This not not realy correct but in this case it is more important to reduce the number of version-controll files.
+     * 
+     * @param manifest the new manifest
+     * @param existingManifest to compaire the new one with
+     * @return are the manifests equal
+     */
+    protected boolean areManifestsEqual( Manifest manifest, Manifest existingManifest )
+    {
+        if ( existingManifest == null )
+        {
+            log.info( "@@@ FALSE - Manifest are not equal because existingManifest is null" );
+            return false;
+        }
+
+        Set keys = new HashSet();
+        Attributes existingMap = existingManifest.getMainAttributes();
+        Attributes newMap = manifest.getMainAttributes();
+        keys.addAll( existingMap.keySet() );
+        keys.addAll( newMap.keySet() );
+        Iterator iterator = keys.iterator();
+        while ( iterator.hasNext() )
+        {
+            Attributes.Name key = (Attributes.Name) iterator.next();
+            String newValue = (String) newMap.get( key );
+            String existingValue = (String) existingMap.get( key );
+            // special case classpath... they are equal when there entries
+            // are equal
+            if ( Attributes.Name.CLASS_PATH.equals( key ) )
+            {
+                newValue = orderClasspath( newValue );
+                existingValue = orderClasspath( existingValue );
+            }
+            if ( ( newValue == null || !newValue.equals( existingValue ) )
+                && ( existingValue == null || !existingValue.equals( newValue ) ) )
+            {
+                log.info( "@@@ FALSE - Manifest are not equal because key = " + key + " has existing value = " + existingValue + " and new value = "
+                    + newValue + " are different" );
+                return false;
+            }
+        }
+        log.info( "@@@ TRUE - Manifests are equal" );
+        return true;
+    }
+
+    /**
+     * Convert all dependencies in a blank seperated list of jars and projects representing the classpath.
+     * 
+     * @return the blank separeted classpath string
+     */
+    protected String constructManifestClasspath()
+    {
+        StringBuffer stringBuffer = new StringBuffer();
+        IdeDependency[] deps = this.config.getDepsOrdered();
+
+        for ( int index = 0; index < deps.length; index++ )
+        {
+            addDependencyToClassPath( stringBuffer, deps[index] );
+        }
+
+        return stringBuffer.toString();
+    }
+
+    /**
+     * Create a manifest contaigning the required classpath.
+     * 
+     * @return the newly created manifest
+     */
+    protected Manifest createNewManifest()
+    {
+        Manifest manifest = new Manifest();
+        manifest.getMainAttributes().put( Attributes.Name.MANIFEST_VERSION, "1.0" );
+        manifest.getMainAttributes().put( Attributes.Name.CLASS_PATH, constructManifestClasspath() );
+        return manifest;
+    }
+
+    /**
+     * Verify is the manifest sould be overwritten this sould take in account that the manifest should only be written
+     * if the contents of the classpath was changed not the order. The classpath sorting oder should be ignored.
+     * 
+     * @param manifest the newly created classpath
+     * @param manifestFile the file where the manifest
+     * @return if the new manifest file must be written
+     * @throws MojoExecutionException
+     */
+    protected boolean shouldNewManifestFileBeWritten( Manifest manifest, File manifestFile )
+        throws MojoExecutionException
+    {
+        try
+        {
+            Manifest existingManifest = readExistingManifest( manifestFile );
+            if ( areManifestsEqual( manifest, existingManifest ) )
+            {
+                this.log.info( Messages.getString( "EclipseCleanMojo.unchanged", manifestFile.getAbsolutePath() ) );
+                return false;
+            }
+        }
+        catch ( Exception e )
+        {
+            throw new MojoExecutionException( Messages.getString( "EclipseCleanMojo.nofilefound",
+                                                                  manifestFile.getAbsolutePath() ), e );
+        }
+        return true;
+    }
+
+    /**
+     * Search the project for the existing META-INF directory where the manifest should be located.
+     * 
+     * @return the absolute path to the META-INF directory
+     * @throws MojoExecutionException
+     */
+    protected abstract String getMetaInfBaseDirectory( MavenProject project )
+        throws MojoExecutionException;
+
+    /**
+     * If the existing manifest file located in <code>getMetaInfBaseDirectory()</code> 
+     * already has a correct MANIFEST_VERSION and CLASS_PATH value then do nothing.
+     * <p>
+     * Otherwise generate a <b>NEW</b> (i.e the old one is overwritten) which only contains
+     * values for MANIFEST_VERSION and CLASS_PATH, all other previous entries are not kept.
+     * 
+     * @see AbstractWtpResourceWriter#write(EclipseSourceDir[], ArtifactRepository, File)
+     * @param sourceDirs all eclipse source directorys
+     * @param localRepository the local reposetory
+     * @param buildOutputDirectory build output directory (target)
+     * @throws MojoExecutionException when writing the config files was not possible
+     */
+    public void write()
+        throws MojoExecutionException
+    {
+        String metaInfBaseDirectory = getMetaInfBaseDirectory( this.config.getProject() );
+
+        if ( metaInfBaseDirectory == null )
+        {
+            // TODO: if this really is an error, shouldn't we stop the build??
+            throw new MojoExecutionException(
+                                              Messages.getString(
+                                                                  "EclipseCleanMojo.nofilefound",
+                                                                  new Object[] { EclipseManifestWriter.META_INF_DIRECTORY } ) );
+        }
+        File manifestFile =
+            new File( metaInfBaseDirectory + File.separatorChar + EclipseManifestWriter.META_INF_DIRECTORY
+                + File.separatorChar + EclipseManifestWriter.MANIFEST_MF_FILENAME );
+        Manifest manifest = createNewManifest();
+
+        if ( shouldNewManifestFileBeWritten( manifest, manifestFile ) )
+        {
+            log.info( "Writing manifest..." );
+
+            manifestFile.getParentFile().mkdirs();
+
+            try
+            {
+                FileOutputStream stream = new FileOutputStream( manifestFile );
+
+                manifest.write( stream );
+
+                stream.close();
+
+            }
+            catch ( Exception e )
+            {
+                this.log.error( Messages.getString( "EclipsePlugin.cantwritetofile",
+                                                    new Object[] { manifestFile.getAbsolutePath() } ) );
+            }
+        }
+    }
+
+}
\ No newline at end of file

Propchange: maven/plugins/trunk/maven-eclipse-plugin/src/main/java/org/apache/maven/plugin/eclipse/writers/AbstractEclipseManifestWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/pom.xml
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/pom.xml?rev=696566&view=auto
==============================================================================
--- maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/pom.xml (added)
+++ maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/pom.xml Wed Sep 17 22:53:07 2008
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <packaging>war</packaging>
+  <groupId>eclipse.test</groupId>
+  <artifactId>project-rad-8</artifactId>
+  <version>1</version>
+  <dependencies>
+    <!-- No dependencies as per MECLIPSE-423 -->
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.0</version>
+        <configuration>
+          <source>1.4</source>
+          <target>1.4</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

Propchange: maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/project
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/project?rev=696566&view=auto
==============================================================================
--- maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/project (added)
+++ maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/project Wed Sep 17 22:53:07 2008
@@ -0,0 +1,57 @@
+<projectDescription>
+  <name>maven-eclipse-plugin-test-project-rad-2</name>
+  <comment/>
+  <projects/>
+  <buildSpec>
+    <buildCommand>
+      <name>com.ibm.wtp.migration.MigrationBuilder</name>
+      <arguments/>
+    </buildCommand>
+    <buildCommand>
+      <name>org.eclipse.jdt.core.javabuilder</name>
+      <arguments/>
+    </buildCommand>
+    <buildCommand>
+      <name>com.ibm.etools.j2ee.ui.LibDirBuilder</name>
+      <arguments/>
+    </buildCommand>
+    <buildCommand>
+      <name>com.ibm.etools.webtools.additions.linksbuilder</name>
+      <arguments/>
+    </buildCommand>
+    <buildCommand>
+      <name>com.ibm.etools.webpage.template.templatebuilder</name>
+      <arguments/>
+    </buildCommand>
+    <buildCommand>
+      <name>com.ibm.etools.siteedit.SiteNavBuilder</name>
+      <arguments/>
+    </buildCommand>
+    <buildCommand>
+      <name>com.ibm.etools.siteedit.SiteUpdateBuilder</name>
+      <arguments/>
+    </buildCommand>
+    <buildCommand>
+      <name>com.ibm.etools.validation.validationbuilder</name>
+      <arguments/>
+    </buildCommand>
+    <buildCommand>
+      <name>com.ibm.wtp.j2ee.LibCopyBuilder</name>
+      <arguments/>
+    </buildCommand>
+    <buildCommand>
+      <name>com.ibm.etools.webtools.additions.jspcompilationbuilder</name>
+      <arguments/>
+    </buildCommand>
+    <buildCommand>
+      <name>com.ibm.sse.model.structuredbuilder</name>
+      <arguments/>
+    </buildCommand>
+  </buildSpec>
+  <natures>
+    <nature>com.ibm.wtp.web.WebNature</nature>
+    <nature>org.eclipse.jdt.core.javanature</nature>
+    <nature>com.ibm.etools.siteedit.WebSiteNature</nature>
+    <nature>com.ibm.etools.webpage.template.templatenature</nature>
+  </natures>
+</projectDescription>
\ No newline at end of file

Added: maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/java/DummyClass.txt
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/java/DummyClass.txt?rev=696566&view=auto
==============================================================================
--- maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/java/DummyClass.txt (added)
+++ maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/java/DummyClass.txt Wed Sep 17 22:53:07 2008
@@ -0,0 +1,7 @@
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id: DummyClass.txt 474384 2006-11-13 16:10:39Z jdcasey $
+ */
+public class DummyClass
+{
+}

Propchange: maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/java/DummyClass.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Added: maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/META-INF/MANIFEST.MF
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/META-INF/MANIFEST.MF?rev=696566&view=auto
==============================================================================
--- maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/META-INF/MANIFEST.MF (added)
+++ maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/META-INF/MANIFEST.MF Wed Sep 17 22:53:07 2008
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+

Added: maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/META-INF/expected_MANIFEST.MF
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/META-INF/expected_MANIFEST.MF?rev=696566&view=auto
==============================================================================
--- maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/META-INF/expected_MANIFEST.MF (added)
+++ maven/plugins/trunk/maven-eclipse-plugin/src/test/resources/projects/project-rad-8/src/main/webapp/META-INF/expected_MANIFEST.MF Wed Sep 17 22:53:07 2008
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: 
+