Coverage Report - org.apache.maven.plugin.eclipse.writers.EclipseClasspathWriter
 
Classes in this File Line Coverage Branch Coverage Complexity
EclipseClasspathWriter
100%
76/76
N/A
21
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.maven.plugin.eclipse.writers;
 20  
 
 21  
 import java.io.File;
 22  
 import java.io.FileOutputStream;
 23  
 import java.io.IOException;
 24  
 import java.io.OutputStreamWriter;
 25  
 import java.io.Writer;
 26  
 import java.util.ArrayList;
 27  
 import java.util.HashMap;
 28  
 import java.util.HashSet;
 29  
 import java.util.Iterator;
 30  
 import java.util.List;
 31  
 import java.util.Map;
 32  
 import java.util.Set;
 33  
 
 34  
 import org.apache.maven.plugin.MojoExecutionException;
 35  
 import org.apache.maven.plugin.eclipse.BuildCommand;
 36  
 import org.apache.maven.plugin.eclipse.Constants;
 37  
 import org.apache.maven.plugin.eclipse.EclipseSourceDir;
 38  
 import org.apache.maven.plugin.eclipse.Messages;
 39  
 import org.apache.maven.plugin.ide.IdeDependency;
 40  
 import org.apache.maven.plugin.ide.IdeUtils;
 41  
 import org.codehaus.plexus.util.IOUtil;
 42  
 import org.codehaus.plexus.util.StringUtils;
 43  
 import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
 44  
 import org.codehaus.plexus.util.xml.XMLWriter;
 45  
 
 46  
 /**
 47  
  * Writes eclipse .classpath file.
 48  
  * 
 49  
  * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
 50  
  * @author <a href="mailto:kenney@neonics.com">Kenney Westerhof</a>
 51  
  * @author <a href="mailto:fgiust@apache.org">Fabrizio Giustina</a>
 52  
  * @version $Id: EclipseClasspathWriter.java 599684 2007-11-30 03:02:08Z aheritier $
 53  
  */
 54  1
 public class EclipseClasspathWriter
 55  
     extends AbstractEclipseWriter
 56  
 {
 57  
 
 58  
     /**
 59  
      * Eclipse build path variable M2_REPO
 60  
      */
 61  
     private static final String M2_REPO = "M2_REPO"; //$NON-NLS-1$
 62  
 
 63  
     /**
 64  
      * Attribute for sourcepath.
 65  
      */
 66  
     private static final String ATTR_SOURCEPATH = "sourcepath"; //$NON-NLS-1$
 67  
 
 68  
     /**
 69  
      * Attribute for output.
 70  
      */
 71  
     private static final String ATTR_OUTPUT = "output"; //$NON-NLS-1$
 72  
 
 73  
     /**
 74  
      * Attribute for path.
 75  
      */
 76  
     private static final String ATTR_PATH = "path"; //$NON-NLS-1$
 77  
 
 78  
     /**
 79  
      * Attribute for kind - Container (con), Variable (var)..etc.
 80  
      */
 81  
     private static final String ATTR_KIND = "kind"; //$NON-NLS-1$
 82  
 
 83  
     /**
 84  
      * Attribute value for kind: var
 85  
      */
 86  
     private static final String ATTR_VAR = "var"; //$NON-NLS-1$
 87  
 
 88  
     /**
 89  
      * Attribute value for kind: lib
 90  
      */
 91  
     private static final String ATTR_LIB = "lib"; //$NON-NLS-1$
 92  
 
 93  
     /**
 94  
      * Attribute value for kind: src
 95  
      */
 96  
     private static final String ATTR_SRC = "src"; //$NON-NLS-1$
 97  
 
 98  
     /**
 99  
      * Attribute name for source file includes in a path.
 100  
      */
 101  
     private static final String ATTR_INCLUDING = "including";
 102  
 
 103  
     /**
 104  
      * Attribute name for source file excludes in a path.
 105  
      */
 106  
     private static final String ATTR_EXCLUDING = "excluding";
 107  
 
 108  
     /**
 109  
      * Element for classpathentry.
 110  
      */
 111  
     private static final String ELT_CLASSPATHENTRY = "classpathentry"; //$NON-NLS-1$
 112  
 
 113  
     /**
 114  
      * Element for classpath.
 115  
      */
 116  
     private static final String ELT_CLASSPATH = "classpath"; //$NON-NLS-1$
 117  
 
 118  
     /**
 119  
      * File name that stores project classpath settings.
 120  
      */
 121  
     private static final String FILE_DOT_CLASSPATH = ".classpath"; //$NON-NLS-1$
 122  
 
 123  
     /**
 124  
      * @see org.apache.maven.plugin.eclipse.writers.EclipseWriter#write()
 125  
      */
 126  
     public void write()
 127  
         throws MojoExecutionException
 128  
     {
 129  
 
 130  
         Writer w;
 131  
 
 132  
         try
 133  
         {
 134  1
             w =
 135  
                 new OutputStreamWriter( new FileOutputStream( new File( config.getEclipseProjectDirectory(),
 136  
                                                                         FILE_DOT_CLASSPATH ) ), "UTF-8" );
 137  
         }
 138  
         catch ( IOException ex )
 139  
         {
 140  
             throw new MojoExecutionException( Messages.getString( "EclipsePlugin.erroropeningfile" ), ex ); //$NON-NLS-1$
 141  1
         }
 142  
 
 143  1
         XMLWriter writer = new PrettyPrintXMLWriter( w );
 144  
 
 145  1
         writer.startElement( ELT_CLASSPATH );
 146  
 
 147  1
         String defaultOutput =
 148  
             IdeUtils.toRelativeAndFixSeparator( config.getProjectBaseDir(), config.getBuildOutputDirectory(), false );
 149  
 
 150  
         // ----------------------------------------------------------------------
 151  
         // Source roots and resources
 152  
         // ----------------------------------------------------------------------
 153  
 
 154  
         // List<EclipseSourceDir>
 155  1
         List specialSources = new ArrayList();
 156  
 
 157  
         // Map<String,List<EclipseSourceDir>>
 158  1
         Map byOutputDir = new HashMap();
 159  
 
 160  3
         for ( int j = 0; j < config.getSourceDirs().length; j++ )
 161  
         {
 162  2
             EclipseSourceDir dir = config.getSourceDirs()[j];
 163  
 
 164  
             // List<EclipseSourceDir>
 165  2
             List byOutputDirs = (List) byOutputDir.get( dir.getOutput() );
 166  2
             if ( byOutputDirs == null )
 167  
             {
 168  
                 // ArrayList<EclipseSourceDir>
 169  2
                 byOutputDir.put( dir.getOutput() == null ? defaultOutput : dir.getOutput(), byOutputDirs =
 170  
                     new ArrayList() );
 171  
             }
 172  2
             byOutputDirs.add( dir );
 173  
         }
 174  
 
 175  3
         for ( int j = 0; j < config.getSourceDirs().length; j++ )
 176  
         {
 177  2
             EclipseSourceDir dir = config.getSourceDirs()[j];
 178  
 
 179  2
             log.debug( "Processing " + ( dir.isResource() ? "re" : "" ) + "source " + dir.getPath() + ": output=" +
 180  
                 dir.getOutput() + "; default output=" + defaultOutput );
 181  
 
 182  2
             boolean isSpecial = false;
 183  
 
 184  
             // handle resource with nested output folders
 185  2
             if ( dir.isResource() )
 186  
             {
 187  
                 // Check if the output is a subdirectory of the default output,
 188  
                 // and if the default output has any sources that copy there.
 189  
 
 190  2
                 if ( dir.getOutput() != null // resource output dir is set
 191  
                     &&
 192  
                     !dir.getOutput().equals( defaultOutput ) // output dir is not default target/classes
 193  
                     && dir.getOutput().startsWith( defaultOutput ) // ... but is nested
 194  
                     && byOutputDir.get( defaultOutput ) != null // ???
 195  
                     && !( (List) byOutputDir.get( defaultOutput ) ).isEmpty() // ???
 196  
                 )
 197  
                 {
 198  
                     // do not specify as source since the output will be nested. Instead, mark
 199  
                     // it as a todo, and handle it with a custom build.xml file later.
 200  
 
 201  1
                     log.debug( "Marking as special to prevent output folder nesting: " + dir.getPath() + " (output=" +
 202  
                         dir.getOutput() + ")" );
 203  
 
 204  1
                     isSpecial = true;
 205  1
                     specialSources.add( dir );
 206  
                 }
 207  
             }
 208  
 
 209  2
             writer.startElement( ELT_CLASSPATHENTRY );
 210  
 
 211  2
             writer.addAttribute( ATTR_KIND, "src" ); //$NON-NLS-1$
 212  2
             writer.addAttribute( ATTR_PATH, dir.getPath() );
 213  
 
 214  2
             if ( !isSpecial && dir.getOutput() != null && !defaultOutput.equals( dir.getOutput() ) )
 215  
             {
 216  
                 writer.addAttribute( ATTR_OUTPUT, dir.getOutput() );
 217  
             }
 218  
 
 219  2
             if ( StringUtils.isNotEmpty( dir.getInclude() ) )
 220  
             {
 221  
                 writer.addAttribute( ATTR_INCLUDING, dir.getInclude() );
 222  
             }
 223  
 
 224  2
             String excludes = dir.getExclude();
 225  
 
 226  2
             if ( dir.isResource() )
 227  
             {
 228  
                 // automatically exclude java files: eclipse doesn't have the concept of resource directory so it will
 229  
                 // try to compile any java file found in maven resource dirs
 230  2
                 excludes = StringUtils.isEmpty( excludes ) ? "**/*.java" : excludes + "|**/*.java";
 231  
             }
 232  
 
 233  2
             if ( StringUtils.isNotEmpty( excludes ) )
 234  
             {
 235  2
                 writer.addAttribute( ATTR_EXCLUDING, excludes );
 236  
             }
 237  
 
 238  2
             writer.endElement();
 239  
 
 240  
         }
 241  
 
 242  
         // handle the special sources.
 243  1
         if ( !specialSources.isEmpty() )
 244  
         {
 245  1
             log.info( "Creating maven-eclipse.xml Ant file to handle resources" );
 246  
 
 247  
             try
 248  
             {
 249  1
                 Writer buildXmlWriter =
 250  
                     new OutputStreamWriter( new FileOutputStream( new File( config.getEclipseProjectDirectory(),
 251  
                                                                             "maven-eclipse.xml" ) ), "UTF-8" );
 252  1
                 PrettyPrintXMLWriter buildXmlPrinter = new PrettyPrintXMLWriter( buildXmlWriter );
 253  
 
 254  1
                 buildXmlPrinter.startElement( "project" );
 255  1
                 buildXmlPrinter.addAttribute( "default", "copy-resources" );
 256  
 
 257  1
                 buildXmlPrinter.startElement( "target" );
 258  1
                 buildXmlPrinter.addAttribute( "name", "init" );
 259  
                 // initialize filtering tokens here
 260  1
                 buildXmlPrinter.endElement();
 261  
 
 262  1
                 buildXmlPrinter.startElement( "target" );
 263  1
                 buildXmlPrinter.addAttribute( "name", "copy-resources" );
 264  1
                 buildXmlPrinter.addAttribute( "depends", "init" );
 265  
 
 266  1
                 for ( Iterator it = specialSources.iterator(); it.hasNext(); )
 267  
                 {
 268  
                     // TODO: merge source dirs on output path+filtering to reduce
 269  
                     // <copy> tags for speed.
 270  1
                     EclipseSourceDir dir = (EclipseSourceDir) it.next();
 271  1
                     buildXmlPrinter.startElement( "copy" );
 272  1
                     buildXmlPrinter.addAttribute( "todir", dir.getOutput() );
 273  1
                     buildXmlPrinter.addAttribute( "filtering", "" + dir.isFiltering() );
 274  
 
 275  1
                     buildXmlPrinter.startElement( "fileset" );
 276  1
                     buildXmlPrinter.addAttribute( "dir", dir.getPath() );
 277  1
                     if ( dir.getInclude() != null )
 278  
                     {
 279  
                         buildXmlPrinter.addAttribute( "includes", dir.getInclude() );
 280  
                     }
 281  1
                     if ( dir.getExclude() != null )
 282  
                     {
 283  
                         buildXmlPrinter.addAttribute( "excludes", dir.getExclude() );
 284  
                     }
 285  1
                     buildXmlPrinter.endElement();
 286  
 
 287  1
                     buildXmlPrinter.endElement();
 288  1
                 }
 289  
 
 290  1
                 buildXmlPrinter.endElement();
 291  
 
 292  1
                 buildXmlPrinter.endElement();
 293  
 
 294  1
                 IOUtil.close( buildXmlWriter );
 295  
             }
 296  
             catch ( IOException e )
 297  
             {
 298  
                 throw new MojoExecutionException( "Cannot create " + config.getEclipseProjectDirectory() +
 299  
                     "/maven-eclipse.xml", e );
 300  1
             }
 301  
 
 302  1
             log.info( "Creating external launcher file" );
 303  
             // now create the launcher
 304  1
             new EclipseAntExternalLaunchConfigurationWriter().init( log, config, "Maven_Ant_Builder.launch",
 305  
                                                                     "maven-eclipse.xml" ).write();
 306  
 
 307  
             // finally add it to the project writer.
 308  
 
 309  1
             config.getBuildCommands().add(
 310  
                                            new BuildCommand(
 311  
                                                              "org.eclipse.ui.externaltools.ExternalToolBuilder",
 312  
                                                              "LaunchConfigHandle",
 313  
                                                              "<project>/" +
 314  
                                                                  EclipseLaunchConfigurationWriter.FILE_DOT_EXTERNAL_TOOL_BUILDERS +
 315  
                                                                  "Maven_Ant_Builder.launch" ) );
 316  
         }
 317  
 
 318  
         // ----------------------------------------------------------------------
 319  
         // The default output
 320  
         // ----------------------------------------------------------------------
 321  
 
 322  1
         writer.startElement( ELT_CLASSPATHENTRY );
 323  1
         writer.addAttribute( ATTR_KIND, ATTR_OUTPUT );
 324  1
         writer.addAttribute( ATTR_PATH, defaultOutput );
 325  1
         writer.endElement();
 326  
 
 327  
         // ----------------------------------------------------------------------
 328  
         // Container classpath entries
 329  
         // ----------------------------------------------------------------------
 330  
 
 331  1
         for ( Iterator it = config.getClasspathContainers().iterator(); it.hasNext(); )
 332  
         {
 333  
             writer.startElement( ELT_CLASSPATHENTRY );
 334  
             writer.addAttribute( ATTR_KIND, "con" ); //$NON-NLS-1$
 335  
             writer.addAttribute( ATTR_PATH, (String) it.next() );
 336  
             writer.endElement(); // name
 337  
         }
 338  
 
 339  
         // ----------------------------------------------------------------------
 340  
         // The dependencies
 341  
         // ----------------------------------------------------------------------
 342  1
         Set addedDependencies = new HashSet();
 343  
         // TODO if (..magic property equals orderDependencies..)
 344  1
         IdeDependency[] depsToWrite = config.getDepsOrdered();
 345  1
         for ( int j = 0; j < depsToWrite.length; j++ )
 346  
         {
 347  
             IdeDependency dep = depsToWrite[j];
 348  
 
 349  
             if ( dep.isAddedToClasspath() )
 350  
             {
 351  
                 String depId =
 352  
                     dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getClassifier() + ":" + dep.getVersion();
 353  
                 /* avoid duplicates in the classpath for artifacts with different types (like ejbs) */
 354  
                 if ( !addedDependencies.contains( depId ) )
 355  
                 {
 356  
                     addDependency( writer, dep );
 357  
                     addedDependencies.add( depId );
 358  
                 }
 359  
             }
 360  
         }
 361  
 
 362  1
         writer.endElement();
 363  
 
 364  1
         IOUtil.close( w );
 365  
 
 366  1
     }
 367  
 
 368  
     protected void addDependency( XMLWriter writer, IdeDependency dep )
 369  
         throws MojoExecutionException
 370  
     {
 371  
 
 372  
         String path;
 373  
         String kind;
 374  
         String sourcepath = null;
 375  
         String javadocpath = null;
 376  
 
 377  
         if ( dep.isReferencedProject() && !config.isPde() )
 378  
         {
 379  
             path = "/" + IdeUtils.getProjectName( config.getProjectNameTemplate(), dep ); //$NON-NLS-1$
 380  
             kind = ATTR_SRC;
 381  
         }
 382  
         else if ( dep.isReferencedProject() && config.isPde() )
 383  
         {
 384  
             // don't do anything, referenced projects are automatically handled by eclipse in PDE builds
 385  
             return;
 386  
         }
 387  
         else
 388  
         {
 389  
             File artifactPath = dep.getFile();
 390  
 
 391  
             if ( artifactPath == null )
 392  
             {
 393  
                 log.error( Messages.getString( "EclipsePlugin.artifactpathisnull", dep.getId() ) ); //$NON-NLS-1$
 394  
                 return;
 395  
             }
 396  
 
 397  
             if ( dep.isSystemScoped() )
 398  
             {
 399  
                 path = IdeUtils.toRelativeAndFixSeparator( config.getEclipseProjectDirectory(), artifactPath, false );
 400  
 
 401  
                 if ( log.isDebugEnabled() )
 402  
                 {
 403  
                     log.debug( Messages.getString( "EclipsePlugin.artifactissystemscoped", //$NON-NLS-1$
 404  
                                                    new Object[] { dep.getArtifactId(), path } ) );
 405  
                 }
 406  
 
 407  
                 kind = ATTR_LIB;
 408  
             }
 409  
             else
 410  
             {
 411  
                 File localRepositoryFile = new File( config.getLocalRepository().getBasedir() );
 412  
 
 413  
                 // if the dependency is not provided and the plugin runs in "pde mode", the dependency is
 414  
                 // added to the Bundle-Classpath:
 415  
                 if ( config.isPde() && ( dep.isProvided() || dep.isOsgiBundle() ) )
 416  
                 {
 417  
                     return;
 418  
                 }
 419  
                 else if ( config.isPde() && !dep.isProvided() && !dep.isTestDependency() )
 420  
                 {
 421  
                     // path for link created in .project, not to the actual file
 422  
                     path = dep.getFile().getName();
 423  
 
 424  
                     kind = ATTR_LIB;
 425  
                 }
 426  
                 // running in PDE mode and the dependency is provided means, that it is provided by
 427  
                 // the target platform. This case is covered by adding the plugin container
 428  
                 else
 429  
                 {
 430  
                     String fullPath = artifactPath.getPath();
 431  
 
 432  
                     path = M2_REPO + "/" //$NON-NLS-1$
 433  
                         + IdeUtils.toRelativeAndFixSeparator( localRepositoryFile, new File( fullPath ), false );
 434  
 
 435  
                     kind = ATTR_VAR; //$NON-NLS-1$
 436  
                 }
 437  
 
 438  
                 if ( dep.getSourceAttachment() != null )
 439  
                 {
 440  
                     if ( ATTR_VAR.equals( kind ) )
 441  
                     {
 442  
                         sourcepath =
 443  
                             M2_REPO +
 444  
                                 "/" //$NON-NLS-1$
 445  
                                 +
 446  
                                 IdeUtils.toRelativeAndFixSeparator( localRepositoryFile, dep.getSourceAttachment(),
 447  
                                                                     false );
 448  
                     }
 449  
                     else
 450  
                     {
 451  
                         // source archive must be referenced with the full path, we can't mix a lib with a variable
 452  
                         sourcepath = IdeUtils.getCanonicalPath( dep.getSourceAttachment() );
 453  
                     }
 454  
                 }
 455  
 
 456  
                 if ( dep.getJavadocAttachment() != null )
 457  
                 {
 458  
                     // NB eclipse (3.1) doesn't support variables in javadoc paths, so we need to add the
 459  
                     // full path for the maven repo
 460  
                     javadocpath =
 461  
                         StringUtils.replace( IdeUtils.getCanonicalPath( dep.getJavadocAttachment() ), "\\", "/" ); //$NON-NLS-1$ //$NON-NLS-2$
 462  
                 }
 463  
 
 464  
             }
 465  
 
 466  
         }
 467  
 
 468  
         writer.startElement( ELT_CLASSPATHENTRY );
 469  
         writer.addAttribute( ATTR_KIND, kind );
 470  
         writer.addAttribute( ATTR_PATH, path );
 471  
 
 472  
         if ( sourcepath != null )
 473  
         {
 474  
             writer.addAttribute( ATTR_SOURCEPATH, sourcepath );
 475  
         }
 476  
 
 477  
         boolean attributeElemOpen = false;
 478  
 
 479  
         if ( javadocpath != null )
 480  
         {
 481  
             if ( !attributeElemOpen )
 482  
             {
 483  
                 writer.startElement( "attributes" ); //$NON-NLS-1$
 484  
                 attributeElemOpen = true;
 485  
             }
 486  
 
 487  
             writer.startElement( "attribute" ); //$NON-NLS-1$
 488  
             writer.addAttribute( "value", "jar:file:/" + javadocpath + "!/" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 489  
             writer.addAttribute( "name", "javadoc_location" ); //$NON-NLS-1$ //$NON-NLS-2$
 490  
             writer.endElement();
 491  
 
 492  
         }
 493  
 
 494  
         if ( Constants.PROJECT_PACKAGING_WAR.equals( this.config.getPackaging() ) && config.getWtpapplicationxml() &&
 495  
             kind.equals( ATTR_VAR ) && !dep.isTestDependency() && !dep.isProvided() &&
 496  
             !dep.isSystemScopedOutsideProject( this.config.getProject() ) )
 497  
         {
 498  
             if ( !attributeElemOpen )
 499  
             {
 500  
                 writer.startElement( "attributes" ); //$NON-NLS-1$
 501  
                 attributeElemOpen = true;
 502  
             }
 503  
 
 504  
             writer.startElement( "attribute" ); //$NON-NLS-1$
 505  
             writer.addAttribute( "value", "/WEB-INF/lib" ); //$NON-NLS-1$ //$NON-NLS-2$
 506  
             writer.addAttribute( "name", "org.eclipse.jst.component.dependency" ); //$NON-NLS-1$ //$NON-NLS-2$
 507  
             writer.endElement();
 508  
 
 509  
         }
 510  
 
 511  
         if ( attributeElemOpen )
 512  
         {
 513  
             writer.endElement();
 514  
         }
 515  
         writer.endElement();
 516  
 
 517  
     }
 518  
 }