View Javadoc

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;
20  
21  import java.io.File;
22  import java.io.FileOutputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.OutputStream;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.Iterator;
29  import java.util.LinkedHashSet;
30  import java.util.LinkedList;
31  import java.util.List;
32  import java.util.ListIterator;
33  import java.util.Map;
34  import java.util.Set;
35  import java.util.TreeSet;
36  
37  import org.apache.maven.artifact.Artifact;
38  import org.apache.maven.artifact.handler.ArtifactHandler;
39  import org.apache.maven.model.Resource;
40  import org.apache.maven.plugin.MojoExecutionException;
41  import org.apache.maven.plugin.eclipse.reader.ReadWorkspaceLocations;
42  import org.apache.maven.plugin.eclipse.writers.EclipseClasspathWriter;
43  import org.apache.maven.plugin.eclipse.writers.EclipseManifestWriter;
44  import org.apache.maven.plugin.eclipse.writers.EclipseOSGiManifestWriter;
45  import org.apache.maven.plugin.eclipse.writers.EclipseProjectWriter;
46  import org.apache.maven.plugin.eclipse.writers.EclipseSettingsWriter;
47  import org.apache.maven.plugin.eclipse.writers.EclipseWriterConfig;
48  import org.apache.maven.plugin.eclipse.writers.wtp.EclipseWtpApplicationXMLWriter;
49  import org.apache.maven.plugin.eclipse.writers.wtp.EclipseWtpComponent15Writer;
50  import org.apache.maven.plugin.eclipse.writers.wtp.EclipseWtpComponentWriter;
51  import org.apache.maven.plugin.eclipse.writers.wtp.EclipseWtpFacetsWriter;
52  import org.apache.maven.plugin.eclipse.writers.wtp.EclipseWtpmodulesWriter;
53  import org.apache.maven.plugin.ide.AbstractIdeSupportMojo;
54  import org.apache.maven.plugin.ide.IdeDependency;
55  import org.apache.maven.plugin.ide.IdeUtils;
56  import org.apache.maven.plugin.ide.JeeUtils;
57  import org.apache.maven.project.MavenProject;
58  import org.codehaus.plexus.resource.ResourceManager;
59  import org.codehaus.plexus.resource.loader.FileResourceLoader;
60  import org.codehaus.plexus.resource.loader.ResourceNotFoundException;
61  import org.codehaus.plexus.util.FileUtils;
62  import org.codehaus.plexus.util.IOUtil;
63  import org.codehaus.plexus.util.StringUtils;
64  import org.codehaus.plexus.util.xml.Xpp3Dom;
65  
66  /**
67   * Generates the following eclipse configuration files:
68   * <ul>
69   * <li><code>.project</code> and <code>.classpath</code> files</li>
70   * <li><code>.setting/org.eclipse.jdt.core.prefs</code> with project specific compiler settings</li>
71   * <li>various configuration files for WTP (Web Tools Project), if the parameter <code>wtpversion</code> is set to a
72   * valid version (WTP configuration is not generated by default)</li>
73   * </ul>
74   * If this goal is run on a multiproject root, dependencies between modules will be configured as direct project
75   * dependencies in Eclipse (unless <code>useProjectReferences</code> is set to <code>false</code>).
76   * 
77   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
78   * @author <a href="mailto:fgiust@apache.org">Fabrizio Giustina</a>
79   * @version $Id: EclipsePlugin.java 641616 2008-03-26 22:42:42Z aheritier $
80   * @goal eclipse
81   * @execute phase="generate-resources"
82   */
83  public class EclipsePlugin
84      extends AbstractIdeSupportMojo
85  {
86  
87      private static final String NATURE_WST_FACET_CORE_NATURE = "org.eclipse.wst.common.project.facet.core.nature"; //$NON-NLS-1$
88  
89      private static final String BUILDER_WST_COMPONENT_STRUCTURAL_DEPENDENCY_RESOLVER =
90          "org.eclipse.wst.common.modulecore.ComponentStructuralBuilderDependencyResolver"; //$NON-NLS-1$
91  
92      protected static final String BUILDER_WST_VALIDATION = "org.eclipse.wst.validation.validationbuilder"; //$NON-NLS-1$
93  
94      private static final String BUILDER_JDT_CORE_JAVA = "org.eclipse.jdt.core.javabuilder"; //$NON-NLS-1$
95  
96      private static final String BUILDER_WST_COMPONENT_STRUCTURAL =
97          "org.eclipse.wst.common.modulecore.ComponentStructuralBuilder"; //$NON-NLS-1$
98  
99      private static final String BUILDER_WST_FACET = "org.eclipse.wst.common.project.facet.core.builder"; //$NON-NLS-1$
100 
101     private static final String BUILDER_PDE_MANIFEST = "org.eclipse.pde.ManifestBuilder"; //$NON-NLS-1$
102 
103     private static final String BUILDER_PDE_SCHEMA = "org.eclipse.pde.SchemaBuilder"; //$NON-NLS-1$
104 
105     private static final String NATURE_WST_MODULE_CORE_NATURE = "org.eclipse.wst.common.modulecore.ModuleCoreNature"; //$NON-NLS-1$
106 
107     private static final String NATURE_JDT_CORE_JAVA = "org.eclipse.jdt.core.javanature"; //$NON-NLS-1$
108 
109     private static final String NATURE_JEM_WORKBENCH_JAVA_EMF = "org.eclipse.jem.workbench.JavaEMFNature"; //$NON-NLS-1$
110 
111     private static final String NATURE_PDE_PLUGIN = "org.eclipse.pde.PluginNature"; //$NON-NLS-1$
112 
113     protected static final String COMMON_PATH_JDT_LAUNCHING_JRE_CONTAINER = "org.eclipse.jdt.launching.JRE_CONTAINER"; //$NON-NLS-1$
114 
115     protected static final String REQUIRED_PLUGINS_CONTAINER = "org.eclipse.pde.core.requiredPlugins"; //$NON-NLS-1$
116 
117     // warning, order is important for binary search
118     public static final String[] WTP_SUPPORTED_VERSIONS = new String[] { "1.0", "1.5", "2.0", "R7", "none" }; //$NON-NLS-1$ //$NON-NLS-2$  //$NON-NLS-3$
119 
120     /**
121      * Constant for 'artifactId' element in POM.xml.
122      */
123     private static final String POM_ELT_ARTIFACT_ID = "artifactId"; //$NON-NLS-1$
124 
125     /**
126      * Constant for 'groupId' element in POM.xml.
127      */
128     private static final String POM_ELT_GROUP_ID = "groupId"; //$NON-NLS-1$
129 
130     /**
131      * List of eclipse project natures. By default the <code>org.eclipse.jdt.core.javanature</code> nature plus the
132      * needed WTP natures are added. Natures added using this property <strong>replace</strong> the default list.
133      * 
134      * <pre>
135      * &lt;projectnatures&gt;
136      *    &lt;projectnature&gt;org.eclipse.jdt.core.javanature&lt;/projectnature&gt;
137      *    &lt;projectnature&gt;org.eclipse.wst.common.modulecore.ModuleCoreNature&lt;/projectnature&gt;
138      * &lt;/projectnatures&gt;
139      * </pre>
140      * 
141      * @parameter
142      */
143     private List projectnatures;
144 
145     /**
146      * List of artifact to exclude from eclipse classpath, beeing provided by some eclipse classPathContainer
147      * [MECLIPSE-79]
148      * 
149      * @since 2.5
150      * @parameter
151      */
152     private List excludes;
153 
154     /**
155      * List of eclipse project natures to be added to the default ones.
156      * 
157      * <pre>
158      * &lt;additionalProjectnatures&gt;
159      *    &lt;projectnature&gt;org.springframework.ide.eclipse.core.springnature&lt;/projectnature&gt;
160      * &lt;/additionalProjectnatures&gt;
161      * </pre>
162      * 
163      * @parameter
164      */
165     private List additionalProjectnatures;
166 
167     /**
168      * List of eclipse project facets to be added to the default ones.
169      * 
170      * <pre>
171      * &lt;additionalProjectFacets&gt;
172      *    &lt;jst.jsf&gt;1.1&lt;jst.jsf/&gt;
173      * &lt;/additionalProjectFacets&gt;
174      * </pre>
175      * 
176      * @parameter
177      */
178     private Map additionalProjectFacets;
179 
180     /**
181      * List of eclipse build commands. By default the <code>org.eclipse.jdt.core.javabuilder</code> builder plus the
182      * needed WTP builders are added. If you specify any configuration for this parameter, only those buildcommands
183      * specified will be used; the defaults won't be added. Use the <code>additionalBuildCommands</code> parameter for
184      * that. Configuration example: Old style:
185      * 
186      * <pre>
187      * &lt;buildcommands&gt;
188      *    &lt;buildcommand&gt;org.eclipse.wst.common.modulecore.ComponentStructuralBuilder&lt;/buildcommand&gt;
189      *    &lt;buildcommand&gt;org.eclipse.jdt.core.javabuilder&lt;/buildcommand&gt;
190      *    &lt;buildcommand&gt;org.eclipse.wst.common.modulecore.ComponentStructuralBuilderDependencyResolver&lt;/buildcommand&gt;
191      * &lt;/buildcommands&gt;
192      * </pre>
193      * 
194      * For new style, see <code>additionalBuildCommands</code>.
195      * 
196      * @parameter
197      */
198     private List buildcommands;
199 
200     /**
201      * List of eclipse build commands to be added to the default ones. Old style:
202      * 
203      * <pre>
204      * &lt;additionalBuildcommands&gt;
205      *    &lt;buildcommand&gt;org.springframework.ide.eclipse.core.springbuilder&lt;/buildcommand&gt;
206      * &lt;/additionalBuildcommands&gt;
207      * </pre>
208      * 
209      * New style:
210      * 
211      * <pre>
212      * &lt;additionalBuildcommands&gt;
213      *    &lt;buildCommand&gt;
214      *      &lt;name&gt;org.ui.externaltools.ExternalToolBuilder&lt;/name&gt;
215      *      &lt;triggers&gt;auto,full,incremental,&lt;/triggers&gt;
216      *      &lt;arguments&gt;
217      *        &lt;LaunchConfigHandle&gt;&amp;lt;project&amp;gt;./externalToolBuilders/MavenBuilder.launch&lt;/LaunchConfighandle&gt;
218      *      &lt;/arguments&gt;
219      *    &lt;/buildCommand&gt;
220      * &lt;/additionalBuildcommands&gt;
221      * </pre>
222      * 
223      * Note the difference between <code>build<strong>c</strong>ommand</code> and
224      * <code>build<strong>C</strong>ommand</code>. You can mix and match old and new-style configuration entries.
225      * 
226      * @parameter
227      */
228     private List additionalBuildcommands;
229 
230     /**
231      * List of container classpath entries. By default the <code>org.eclipse.jdt.launching.JRE_CONTAINER</code>
232      * classpath container is added. Configuration example:
233      * 
234      * <pre>
235      * &lt;classpathContainers&gt;
236      *    &lt;classpathContainer&gt;org.eclipse.jdt.launching.JRE_CONTAINER&lt;/classpathContainer&gt;
237      *    &lt;classpathContainer&gt;org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/Apache Tomcat v5.5&lt;/classpathContainer&gt;
238      *    &lt;classpathContainer&gt;org.eclipse.jst.j2ee.internal.web.container/artifact&lt;/classpathContainer&gt;
239      * &lt;/classpathContainers&gt;
240      * </pre>
241      * 
242      * @parameter
243      */
244     private List classpathContainers;
245 
246     /**
247      * Enables/disables the downloading of source attachments. Defaults to false. DEPRECATED - use downloadSources
248      * 
249      * @parameter expression="${eclipse.downloadSources}"
250      * @deprecated use downloadSources
251      */
252     private boolean eclipseDownloadSources;
253 
254     /**
255      * Eclipse workspace directory.
256      * 
257      * @parameter expression="${eclipse.projectDir}" alias="outputDir"
258      */
259     private File eclipseProjectDir;
260 
261     /**
262      * When set to false, the plugin will not create sub-projects and instead reference those sub-projects using the
263      * installed package in the local repository
264      * 
265      * @parameter expression="${eclipse.useProjectReferences}" default-value="true"
266      * @required
267      */
268     private boolean useProjectReferences;
269 
270     /**
271      * The default output directory
272      * 
273      * @parameter expression="${outputDirectory}" alias="outputDirectory"
274      *            default-value="${project.build.outputDirectory}"
275      * @required
276      */
277     private File buildOutputDirectory;
278 
279     /**
280      * The version of WTP for which configuration files will be generated. The default value is "none" (don't generate
281      * WTP configuration), supported versions are "R7", "1.0", and "1.5"
282      * 
283      * @parameter expression="${wtpversion}" default-value="none"
284      */
285     private String wtpversion;
286 
287     /**
288      * JEE context name of the WTP module. ( ex. WEB context name ).
289      * 
290      * @parameter expression="${wtpContextName}"
291      */
292     private String wtpContextName;
293 
294     /**
295      * Is it an PDE project? If yes, the plugin adds the necessary natures and build commands to the .project file.
296      * Additionally it copies all libraries to a project local directory and references them instead of referencing the
297      * files in the local Maven repository. It also ensured that the "Bundle-Classpath" in META-INF/MANIFEST.MF is
298      * synchronized.
299      * 
300      * @parameter expression="${eclipse.pde}" default-value="false"
301      */
302     private boolean pde;
303 
304     /**
305      * The relative path of the manifest file
306      * 
307      * @parameter expression="${eclipse.manifest}" default-value="${basedir}/META-INF/MANIFEST.MF"
308      */
309     private File manifest;
310 
311     /**
312      * Allow to configure additional generic configuration files for eclipse that will be written out to disk when
313      * running eclipse:eclipse. FOr each file you can specify the name and the text content.
314      * 
315      * <pre>
316      * &lt;plugin&gt;
317      *  &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
318      *  &lt;artifactId&gt;maven-eclipse-plugin&lt;/artifactId&gt;
319      *  &lt;configuration&gt;
320      *   &lt;additionalConfig&gt;
321      *    &lt;file&gt;
322      *      &lt;name&gt;.checkstyle&lt;/name&gt;
323      *      &lt;content&gt;
324      *        &lt;![CDATA[&lt;fileset-config file-format-version=&quot;1.2.0&quot; simple-config=&quot;true&quot;&gt;
325      *          &lt;fileset name=&quot;all&quot; enabled=&quot;true&quot; check-config-name=&quot;acme corporate style&quot; local=&quot;false&quot;&gt;
326      *              &lt;file-match-pattern match-pattern=&quot;.&quot; include-pattern=&quot;true&quot;/&gt;
327      *          &lt;/fileset&gt;
328      *          &lt;filter name=&quot;NonSrcDirs&quot; enabled=&quot;true&quot;/&gt;
329      *        &lt;/fileset-config&gt;]]&gt;
330      *      &lt;/content&gt;
331      *    &lt;/file&gt;
332      *   &lt;/additionalConfig&gt;
333      *  &lt;/configuration&gt;
334      * &lt;/plugin&gt;
335      * </pre>
336      * 
337      * Instead of the content you can also define (from version 2.5) an url to download the file :
338      * 
339      * <pre>
340      * &lt;plugin&gt;
341      *  &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
342      *  &lt;artifactId&gt;maven-eclipse-plugin&lt;/artifactId&gt;
343      *  &lt;configuration&gt;
344      *   &lt;additionalConfig&gt;
345      *    &lt;file&gt;
346      *      &lt;name&gt;.checkstyle&lt;/name&gt;
347      *      &lt;url&gt;http://some.place.org/path/to/file&lt;/url&gt;
348      *    &lt;/file&gt;
349      *   &lt;/additionalConfig&gt;
350      *  &lt;/configuration&gt;
351      * </pre>
352      * 
353      * or a location :
354      * 
355      * <pre>
356      * &lt;plugin&gt;
357      *  &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
358      *  &lt;artifactId&gt;maven-eclipse-plugin&lt;/artifactId&gt;
359      *  &lt;configuration&gt;
360      *   &lt;additionalConfig&gt;
361      *    &lt;file&gt;
362      *     &lt;name&gt;.checkstyle&lt;/name&gt;
363      *     &lt;location&gt;/checkstyle-config.xml&lt;/location&gt;
364      *    &lt;/file&gt;
365      *   &lt;/additionalConfig&gt;
366      *  &lt;/configuration&gt;
367      *  &lt;dependencies&gt;
368      *   &lt;!-- The file defined in the location is stored in this dependency --&gt;
369      *   &lt;dependency&gt;
370      *    &lt;groupId&gt;eclipsetest&lt;/groupId&gt;
371      *    &lt;artifactId&gt;checkstyle-config&lt;/artifactId&gt;
372      *    &lt;version&gt;1.0&lt;/version&gt;
373      *   &lt;/dependency&gt;
374      *  &lt;/dependencies&gt;
375      * &lt;/plugin&gt;
376      * </pre>
377      * 
378      * @parameter
379      */
380     private EclipseConfigFile[] additionalConfig;
381 
382     /**
383      * If set to <code>true</code>, the version number of the artifact is appended to the name of the generated
384      * Eclipse project. See projectNameTemplate for other options.
385      * 
386      * @parameter expression="${eclipse.addVersionToProjectName}" default-value="false"
387      */
388     private boolean addVersionToProjectName;
389 
390     /**
391      * If set to <code>true</code>, the groupId of the artifact is appended to the name of the generated Eclipse
392      * project. See projectNameTemplate for other options.
393      * 
394      * @parameter expression="${eclipse.addGroupIdToProjectName}" default-value="false"
395      */
396     private boolean addGroupIdToProjectName;
397 
398     /**
399      * Allows configuring the name of the eclipse projects. This property if set wins over addVersionToProjectName and
400      * addGroupIdToProjectName You can use <code>[groupId]</code>, <code>[artifactId]</code> and
401      * <code>[version]</code> variables. eg. <code>[groupId].[artifactId]-[version]</code>
402      * 
403      * @parameter expression="${eclipse.projectNameTemplate}"
404      */
405     private String projectNameTemplate;
406 
407     /**
408      * Parsed wtp version.
409      */
410     private float wtpVersionFloat;
411 
412     /**
413      * Not a plugin parameter. Is this a java project?
414      */
415     private boolean isJavaProject;
416 
417     /**
418      * Must the manifest files be written for java projects so that that the jee classpath for wtp is correct.
419      * 
420      * @parameter expression="${eclipse.wtpmanifest}" default-value="false"
421      */
422     private boolean wtpmanifest;
423 
424     /**
425      * Must the application files be written for ear projects in a separate directory.
426      * 
427      * @parameter expression="${eclipse.wtpapplicationxml}" default-value="false"
428      */
429     private boolean wtpapplicationxml;
430 
431     /**
432      * What WTP defined server to use for deployment informations.
433      * 
434      * @parameter expression="${eclipse.wtpdefaultserver}"
435      */
436     private String wtpdefaultserver;
437 
438     private WorkspaceConfiguration workspaceConfiguration;
439 
440     /**
441      * ResourceManager for getting additonalConfig files from resources
442      * 
443      * @component
444      * @required
445      * @readonly
446      */
447     private ResourceManager locator;
448 
449     /**
450      * This eclipse workspace is read and all artifacts detected there will be connected as eclipse projects and will
451      * not be linked to the jars in the local repository. Requirement is that it was created with the similar wtp
452      * settings as the reactor projects, but the project name template my differ. The pom's in the workspace projects
453      * may not contain variables in the artefactId, groupId and version tags.
454      * 
455      * @since 2.5
456      * @parameter expression="${eclipse.workspace}"
457      */
458     protected String workspace;
459 
460     /**
461      * Limit the use of project references to the current workspace. No project references will be created to projects
462      * in the reactor when they are not available in the workspace.
463      * 
464      * @parameter expression="${eclipse.limitProjectReferencesToWorkspace}" default-value="false"
465      */
466     protected boolean limitProjectReferencesToWorkspace;
467 
468     protected boolean isJavaProject()
469     {
470         return isJavaProject;
471     }
472 
473     protected boolean isPdeProject()
474     {
475         return pde;
476     }
477 
478     /**
479      * Getter for <code>buildcommands</code>.
480      * 
481      * @return Returns the buildcommands.
482      */
483     public List getBuildcommands()
484     {
485         return buildcommands;
486     }
487 
488     /**
489      * Setter for <code>buildcommands</code>.
490      * 
491      * @param buildcommands The buildcommands to set.
492      */
493     public void setBuildcommands( List buildcommands )
494     {
495         this.buildcommands = buildcommands;
496     }
497 
498     /**
499      * Getter for <code>buildOutputDirectory</code>.
500      * 
501      * @return Returns the buildOutputDirectory.
502      */
503     public File getBuildOutputDirectory()
504     {
505         return buildOutputDirectory;
506     }
507 
508     /**
509      * Setter for <code>buildOutputDirectory</code>.
510      * 
511      * @param buildOutputDirectory The buildOutputDirectory to set.
512      */
513     public void setBuildOutputDirectory( File buildOutputDirectory )
514     {
515         this.buildOutputDirectory = buildOutputDirectory;
516     }
517 
518     /**
519      * Getter for <code>classpathContainers</code>.
520      * 
521      * @return Returns the classpathContainers.
522      */
523     public List getClasspathContainers()
524     {
525         return classpathContainers;
526     }
527 
528     /**
529      * Setter for <code>classpathContainers</code>.
530      * 
531      * @param classpathContainers The classpathContainers to set.
532      */
533     public void setClasspathContainers( List classpathContainers )
534     {
535         this.classpathContainers = classpathContainers;
536     }
537 
538     /**
539      * Getter for <code>eclipseProjectDir</code>.
540      * 
541      * @return Returns the eclipseProjectDir.
542      */
543     public File getEclipseProjectDir()
544     {
545         return eclipseProjectDir;
546     }
547 
548     /**
549      * Setter for <code>eclipseProjectDir</code>.
550      * 
551      * @param eclipseProjectDir The eclipseProjectDir to set.
552      */
553     public void setEclipseProjectDir( File eclipseProjectDir )
554     {
555         this.eclipseProjectDir = eclipseProjectDir;
556     }
557 
558     /**
559      * Getter for <code>projectnatures</code>.
560      * 
561      * @return Returns the projectnatures.
562      */
563     public List getProjectnatures()
564     {
565         return projectnatures;
566     }
567 
568     /**
569      * Setter for <code>projectnatures</code>.
570      * 
571      * @param projectnatures The projectnatures to set.
572      */
573     public void setProjectnatures( List projectnatures )
574     {
575         this.projectnatures = projectnatures;
576     }
577 
578     /**
579      * Getter for <code>useProjectReferences</code>.
580      * 
581      * @return Returns the useProjectReferences.
582      */
583     public boolean getUseProjectReferences()
584     {
585         return useProjectReferences;
586     }
587 
588     /**
589      * Setter for <code>useProjectReferences</code>.
590      * 
591      * @param useProjectReferences The useProjectReferences to set.
592      */
593     public void setUseProjectReferences( boolean useProjectReferences )
594     {
595         this.useProjectReferences = useProjectReferences;
596     }
597 
598     /**
599      * Getter for <code>wtpversion</code>.
600      * 
601      * @return Returns the wtpversion.
602      */
603     public String getWtpversion()
604     {
605         return wtpversion;
606     }
607 
608     /**
609      * Setter for <code>wtpversion</code>.
610      * 
611      * @param wtpversion The wtpversion to set.
612      */
613     public void setWtpversion( String wtpversion )
614     {
615         this.wtpversion = wtpversion;
616     }
617 
618     /**
619      * Getter for <code>additionalBuildcommands</code>.
620      * 
621      * @return Returns the additionalBuildcommands.
622      */
623     public List getAdditionalBuildcommands()
624     {
625         return additionalBuildcommands;
626     }
627 
628     /**
629      * Setter for <code>additionalBuildcommands</code>.
630      * 
631      * @param additionalBuildcommands The additionalBuildcommands to set.
632      */
633     public void setAdditionalBuildcommands( List additionalBuildcommands )
634     {
635         this.additionalBuildcommands = additionalBuildcommands;
636     }
637 
638     /**
639      * Getter for <code>additionalProjectnatures</code>.
640      * 
641      * @return Returns the additionalProjectnatures.
642      */
643     public List getAdditionalProjectnatures()
644     {
645         return additionalProjectnatures;
646     }
647 
648     /**
649      * Setter for <code>additionalProjectnatures</code>.
650      * 
651      * @param additionalProjectnatures The additionalProjectnatures to set.
652      */
653     public void setAdditionalProjectnatures( List additionalProjectnatures )
654     {
655         this.additionalProjectnatures = additionalProjectnatures;
656     }
657 
658     /**
659      * Getter for <code>addVersionToProjectName</code>.
660      */
661     public boolean isAddVersionToProjectName()
662     {
663         return addVersionToProjectName;
664     }
665 
666     /**
667      * Setter for <code>addVersionToProjectName</code>.
668      */
669     public void setAddVersionToProjectName( boolean addVersionToProjectName )
670     {
671         this.addVersionToProjectName = addVersionToProjectName;
672     }
673 
674     /**
675      * Getter for <code>addGroupIdToProjectName</code>.
676      */
677     public boolean isAddGroupIdToProjectName()
678     {
679         return addGroupIdToProjectName;
680     }
681 
682     /**
683      * Setter for <code>addGroupIdToProjectName</code>.
684      */
685     public void setAddGroupIdToProjectName( boolean addGroupIdToProjectName )
686     {
687         this.addGroupIdToProjectName = addGroupIdToProjectName;
688     }
689 
690     public String getProjectNameTemplate()
691     {
692         return projectNameTemplate;
693     }
694 
695     public void setProjectNameTemplate( String projectNameTemplate )
696     {
697         this.projectNameTemplate = projectNameTemplate;
698     }
699 
700     /**
701      * @see org.apache.maven.plugin.Mojo#execute()
702      */
703     public boolean setup()
704         throws MojoExecutionException
705     {
706         boolean ready = true;
707 
708         checkDeprecations();
709 
710         ready = validate();
711 
712         // TODO: Why are we using project in some places, and executedProject in others??
713         ArtifactHandler artifactHandler = project.getArtifact().getArtifactHandler();
714 
715         // ear projects don't contain java sources
716         // pde projects are always java projects
717         isJavaProject =
718             pde ||
719                 ( Constants.LANGUAGE_JAVA.equals( artifactHandler.getLanguage() ) && !Constants.PROJECT_PACKAGING_EAR.equals( packaging ) );
720 
721         setupExtras();
722 
723         parseConfigurationOptions();
724 
725         // defaults
726         if ( projectnatures == null )
727         {
728             fillDefaultNatures( packaging );
729         }
730 
731         if ( additionalProjectnatures != null )
732         {
733             projectnatures.addAll( additionalProjectnatures );
734         }
735 
736         if ( buildcommands == null )
737         {
738             fillDefaultBuilders( packaging );
739         }
740         else
741         {
742             convertBuildCommandList( buildcommands );
743         }
744 
745         if ( additionalBuildcommands != null )
746         {
747             convertBuildCommandList( additionalBuildcommands );
748             buildcommands.addAll( additionalBuildcommands );
749         }
750 
751         if ( classpathContainers == null )
752         {
753             fillDefaultClasspathContainers( packaging );
754         }
755         else
756         {
757             verifyClasspathContainerListIsComplete();
758         }
759         locator.addSearchPath( FileResourceLoader.ID, project.getFile().getParentFile().getAbsolutePath() );
760         locator.setOutputDirectory( new File( project.getBuild().getDirectory() ) );
761 
762         // ready to start
763         return ready;
764     }
765 
766     protected void convertBuildCommandList( List commands )
767     {
768         if ( commands != null )
769         {
770             for ( ListIterator i = commands.listIterator(); i.hasNext(); )
771             {
772                 Object command = i.next();
773 
774                 if ( command instanceof String )
775                 {
776                     command = new BuildCommand( (String) command );
777                     i.set( command );
778                 }
779             }
780         }
781     }
782 
783     private void parseConfigurationOptions()
784     {
785         if ( "R7".equalsIgnoreCase( wtpversion ) ) //$NON-NLS-1$
786         {
787             wtpVersionFloat = 0.7f;
788         }
789         else if ( "1.0".equalsIgnoreCase( wtpversion ) ) //$NON-NLS-1$
790         {
791             wtpVersionFloat = 1.0f;
792         }
793         else if ( "1.5".equalsIgnoreCase( wtpversion ) ) //$NON-NLS-1$
794         {
795             wtpVersionFloat = 1.5f;
796         }
797         else if ( "2.0".equalsIgnoreCase( wtpversion ) ) //$NON-NLS-1$
798         {
799             wtpVersionFloat = 2.0f;
800         }
801         if ( !"none".equalsIgnoreCase( wtpversion ) )
802         {
803             getLog().info( Messages.getString( "EclipsePlugin.wtpversion", wtpversion ) );
804         }
805     }
806 
807     protected void setupExtras()
808         throws MojoExecutionException
809     {
810         // extension point.
811     }
812 
813     protected void verifyClasspathContainerListIsComplete()
814     {
815         boolean containsJREContainer = false;
816         // Check if classpathContainer contains a JRE (default, alternate or
817         // Execution Environment)
818         for ( Iterator iter = classpathContainers.iterator(); iter.hasNext(); )
819         {
820             Object classPathContainer = iter.next();
821             if ( classPathContainer != null &&
822                 classPathContainer.toString().startsWith( COMMON_PATH_JDT_LAUNCHING_JRE_CONTAINER ) )
823             {
824                 containsJREContainer = true;
825                 break;
826             }
827         }
828         if ( !containsJREContainer )
829         {
830             getLog().warn( Messages.getString( "EclipsePlugin.missingjrecontainer" ) ); //$NON-NLS-1$
831             classpathContainers.add( 0, COMMON_PATH_JDT_LAUNCHING_JRE_CONTAINER );
832         }
833     }
834 
835     private boolean validate()
836         throws MojoExecutionException
837     {
838         // validate sanity of the current m2 project
839         if ( Arrays.binarySearch( WTP_SUPPORTED_VERSIONS, wtpversion ) < 0 )
840         {
841             throw new MojoExecutionException(
842                                               Messages.getString( "EclipsePlugin.unsupportedwtp", new Object[] { //$NON-NLS-1$
843                                                                   wtpversion,
844                                                                       StringUtils.join( WTP_SUPPORTED_VERSIONS, " " ) } ) ); //$NON-NLS-1$
845         }
846 
847         assertNotEmpty( executedProject.getGroupId(), POM_ELT_GROUP_ID );
848         assertNotEmpty( executedProject.getArtifactId(), POM_ELT_ARTIFACT_ID );
849 
850         if ( executedProject.getFile() == null || !executedProject.getFile().exists() )
851         {
852             throw new MojoExecutionException( Messages.getString( "EclipsePlugin.missingpom" ) ); //$NON-NLS-1$
853         }
854 
855         if ( "pom".equals( packaging ) && eclipseProjectDir == null ) //$NON-NLS-1$
856         {
857             getLog().info( Messages.getString( "EclipsePlugin.pompackaging" ) ); //$NON-NLS-1$
858             return false;
859         }
860 
861         if ( "eclipse-plugin".equals( packaging ) )
862         {
863             pde = true;
864         }
865 
866         if ( eclipseProjectDir == null )
867         {
868             eclipseProjectDir = executedProject.getFile().getParentFile();
869         }
870 
871         if ( !eclipseProjectDir.exists() && !eclipseProjectDir.mkdirs() )
872         {
873             throw new MojoExecutionException( Messages.getString( "EclipsePlugin.cantcreatedir", eclipseProjectDir ) ); //$NON-NLS-1$
874         }
875 
876         if ( !eclipseProjectDir.equals( executedProject.getFile().getParentFile() ) )
877         {
878             if ( !eclipseProjectDir.isDirectory() )
879             {
880                 throw new MojoExecutionException( Messages.getString( "EclipsePlugin.notadir", eclipseProjectDir ) ); //$NON-NLS-1$
881             }
882             eclipseProjectDir = new File( eclipseProjectDir, executedProject.getArtifactId() );
883             if ( !eclipseProjectDir.isDirectory() && !eclipseProjectDir.mkdirs() )
884             {
885                 throw new MojoExecutionException( Messages.getString( "EclipsePlugin.cantcreatedir", eclipseProjectDir ) ); //$NON-NLS-1$
886             }
887         }
888 
889         validateExtras();
890 
891         return true;
892     }
893 
894     protected void validateExtras()
895     {
896         // provided for extension.
897     }
898 
899     private void checkDeprecations()
900     {
901         if ( eclipseDownloadSources )
902         {
903             // deprecated warning
904             getLog().warn( Messages.getString( "EclipsePlugin.deprecatedpar", new Object[] { //$NON-NLS-1$
905                                                "eclipse.downloadSources", //$NON-NLS-1$
906                                                    "downloadSources" } ) ); //$NON-NLS-1$
907             downloadSources = true;
908         }
909 
910         checkExtraDeprecations();
911     }
912 
913     protected void checkExtraDeprecations()
914     {
915         // provided for extension.
916     }
917 
918     public void writeConfiguration( IdeDependency[] deps )
919         throws MojoExecutionException
920     {
921         EclipseWriterConfig config = createEclipseWriterConfig( deps );
922 
923         if ( wtpmanifest && isJavaProject() )
924         {
925             EclipseManifestWriter.addManifestResource( getLog(), config );
926         }
927         // NOTE: This could change the config!
928         writeExtraConfiguration( config );
929 
930         if ( wtpVersionFloat == 0.7f )
931         {
932             new EclipseWtpmodulesWriter().init( getLog(), config ).write();
933         }
934 
935         if ( wtpVersionFloat >= 1.0f )
936         {
937             new EclipseWtpFacetsWriter().init( getLog(), config ).write();
938         }
939         if ( wtpVersionFloat == 1.0f )
940         {
941             new EclipseWtpComponentWriter().init( getLog(), config ).write();
942         }
943         if ( wtpVersionFloat >= 1.5 )
944         {
945             new EclipseWtpComponent15Writer().init( getLog(), config ).write();
946         }
947 
948         new EclipseSettingsWriter().init( getLog(), config ).write();
949 
950         if ( isJavaProject )
951         {
952             new EclipseClasspathWriter().init( getLog(), config ).write();
953         }
954 
955         if ( wtpapplicationxml )
956         {
957             new EclipseWtpApplicationXMLWriter().init( getLog(), config ).write();
958         }
959 
960         if ( pde )
961         {
962             this.getLog().info( "The Maven Eclipse plugin runs in 'pde'-mode." );
963             new EclipseOSGiManifestWriter().init( getLog(), config ).write();
964         }
965 
966         // NOTE: This one MUST be after EclipseClasspathwriter, and possibly others,
967         // since currently EclipseClasspathWriter does some magic to detect nested
968         // output folders and modifies the configuration by adding new (Ant) builders.
969         // So the .project file must be written AFTER those have run!
970         new EclipseProjectWriter().init( getLog(), config ).write();
971 
972         writeAdditionalConfig();
973 
974         getLog().info( Messages.getString( "EclipsePlugin.wrote", new Object[] { //$NON-NLS-1$
975                                            config.getEclipseProjectName(), eclipseProjectDir.getAbsolutePath() } ) );
976     }
977 
978     protected void writeAdditionalConfig()
979         throws MojoExecutionException
980     {
981         if ( additionalConfig != null )
982         {
983             for ( int j = 0; j < additionalConfig.length; j++ )
984             {
985                 EclipseConfigFile file = additionalConfig[j];
986                 File projectRelativeFile = new File( eclipseProjectDir, file.getName() );
987                 if ( projectRelativeFile.isDirectory() )
988                 {
989                     // just ignore?
990                     getLog().warn( Messages.getString( "EclipsePlugin.foundadir", //$NON-NLS-1$
991                                                        projectRelativeFile.getAbsolutePath() ) );
992                 }
993 
994                 try
995                 {
996                     projectRelativeFile.getParentFile().mkdirs();
997                     if ( file.getContent() == null )
998                     {
999                         InputStream inStream;
1000                         if ( file.getLocation() != null )
1001                         {
1002                             inStream = locator.getResourceAsInputStream( file.getLocation() );
1003                         }
1004                         else
1005                         {
1006                             inStream = file.getURL().openConnection().getInputStream();
1007                         }
1008                         OutputStream outStream = new FileOutputStream( projectRelativeFile );
1009                         try
1010                         {
1011                             IOUtil.copy( inStream, outStream );
1012                         }
1013                         finally
1014                         {
1015                             inStream.close();
1016                             outStream.close();
1017                         }
1018                     }
1019                     else
1020                     {
1021                         FileUtils.fileWrite( projectRelativeFile.getAbsolutePath(), file.getContent() );
1022                     }
1023                 }
1024                 catch ( IOException e )
1025                 {
1026                     throw new MojoExecutionException( Messages.getString( "EclipsePlugin.cantwritetofile", //$NON-NLS-1$
1027                                                                           projectRelativeFile.getAbsolutePath() ) );
1028                 }
1029                 catch ( ResourceNotFoundException e )
1030                 {
1031                     throw new MojoExecutionException( Messages.getString( "EclipsePlugin.cantfindresource", //$NON-NLS-1$
1032                                                                           file.getLocation() ) );
1033                 }
1034 
1035             }
1036         }
1037     }
1038 
1039     protected EclipseWriterConfig createEclipseWriterConfig( IdeDependency[] deps )
1040         throws MojoExecutionException
1041     {
1042         File projectBaseDir = executedProject.getFile().getParentFile();
1043 
1044         // build a list of UNIQUE source dirs (both src and resources) to be
1045         // used in classpath and wtpmodules
1046         EclipseSourceDir[] sourceDirs = buildDirectoryList( executedProject, eclipseProjectDir, buildOutputDirectory );
1047 
1048         EclipseWriterConfig config = new EclipseWriterConfig();
1049 
1050         config.setWorkspaceConfiguration( getWorkspaceConfiguration() );
1051 
1052         config.setProjectNameTemplate( calculateProjectNameTemplate() );
1053 
1054         String projectName = IdeUtils.getProjectName( config.getProjectNameTemplate(), project );
1055 
1056         config.setEclipseProjectName( projectName );
1057 
1058         config.setWtpapplicationxml( wtpapplicationxml );
1059 
1060         config.setWtpVersion( wtpVersionFloat );
1061 
1062         Set convertedBuildCommands = new LinkedHashSet();
1063 
1064         if ( buildcommands != null )
1065         {
1066             for ( Iterator it = buildcommands.iterator(); it.hasNext(); )
1067             {
1068                 Object cmd = it.next();
1069 
1070                 if ( cmd instanceof BuildCommand )
1071                 {
1072                     convertedBuildCommands.add( cmd );
1073                 }
1074                 else
1075                 {
1076                     convertedBuildCommands.add( new BuildCommand( (String) cmd ) );
1077                 }
1078             }
1079         }
1080 
1081         config.setBuildCommands( new LinkedList( convertedBuildCommands ) );
1082 
1083         config.setBuildOutputDirectory( buildOutputDirectory );
1084         config.setClasspathContainers( classpathContainers );
1085         config.setDeps( deps );
1086         config.setEclipseProjectDirectory( eclipseProjectDir );
1087         config.setLocalRepository( localRepository );
1088         config.setOSGIManifestFile( manifest );
1089         config.setPde( pde );
1090         config.setProject( project );
1091         config.setProjectBaseDir( projectBaseDir );
1092         config.setProjectnatures( projectnatures );
1093         config.setProjectFacets( additionalProjectFacets );
1094         config.setSourceDirs( sourceDirs );
1095         config.setAddVersionToProjectName( isAddVersionToProjectName() );
1096         config.setPackaging( packaging );
1097 
1098         collectWarContextRootsFromReactorEarConfiguration( config );
1099 
1100         return config;
1101     }
1102 
1103     /**
1104      * If this is a war module peek into the reactor an search for an ear module that defines the context root of this
1105      * module.
1106      * 
1107      * @param config config to save the context root.
1108      */
1109     private void collectWarContextRootsFromReactorEarConfiguration( EclipseWriterConfig config )
1110     {
1111         if ( reactorProjects != null && wtpContextName == null &&
1112             Constants.PROJECT_PACKAGING_WAR.equals( project.getPackaging() ) )
1113         {
1114             for ( Iterator iter = reactorProjects.iterator(); iter.hasNext(); )
1115             {
1116                 MavenProject reactorProject = (MavenProject) iter.next();
1117 
1118                 if ( Constants.PROJECT_PACKAGING_EAR.equals( reactorProject.getPackaging() ) )
1119                 {
1120                     Xpp3Dom[] warDefinitions =
1121                         IdeUtils.getPluginConfigurationDom( reactorProject, JeeUtils.ARTIFACT_MAVEN_EAR_PLUGIN,
1122                                                             new String[] { "modules", "webModule" } );
1123                     for ( int index = 0; index < warDefinitions.length; index++ )
1124                     {
1125                         Xpp3Dom groupId = warDefinitions[index].getChild( "groupId" );
1126                         Xpp3Dom artifactId = warDefinitions[index].getChild( "artifactId" );
1127                         Xpp3Dom contextRoot = warDefinitions[index].getChild( "contextRoot" );
1128                         if ( groupId != null && artifactId != null && contextRoot != null &&
1129                             groupId.getValue() != null && artifactId.getValue() != null &&
1130                             contextRoot.getValue() != null )
1131                         {
1132                             getLog().info(
1133                                            "Found context root definition for " + groupId.getValue() + ":" +
1134                                                artifactId.getValue() + " " + contextRoot.getValue() );
1135                             if ( project.getArtifactId().equals( artifactId.getValue() ) &&
1136                                 project.getGroupId().equals( groupId.getValue() ) )
1137                             {
1138                                 config.setContextName( contextRoot.getValue() );
1139                             }
1140                         }
1141                         else
1142                         {
1143                             getLog().info(
1144                                            "Found incomplete ear configuration in " + reactorProject.getGroupId() +
1145                                                ":" + reactorProject.getGroupId() + " found " +
1146                                                warDefinitions[index].toString() );
1147                         }
1148                     }
1149                 }
1150             }
1151         }
1152         if ( config.getContextName() == null && Constants.PROJECT_PACKAGING_WAR.equals( project.getPackaging() ) )
1153         {
1154             if ( wtpContextName == null )
1155             {
1156                 config.setContextName( project.getArtifactId() );
1157             }
1158             else
1159             {
1160                 config.setContextName( wtpContextName );
1161             }
1162         }
1163     }
1164 
1165     /**
1166      * Write any extra configuration information for the Eclipse project. This is an extension point, called before the
1167      * main configurations are written. <br/> <b> NOTE: This could change the config! </b>
1168      * 
1169      * @param config
1170      * @throws MojoExecutionException
1171      */
1172     protected void writeExtraConfiguration( EclipseWriterConfig config )
1173         throws MojoExecutionException
1174     {
1175         // extension point.
1176     }
1177 
1178     private void assertNotEmpty( String string, String elementName )
1179         throws MojoExecutionException
1180     {
1181         if ( string == null )
1182         {
1183             throw new MojoExecutionException( Messages.getString( "EclipsePlugin.missingelement", elementName ) ); //$NON-NLS-1$
1184         }
1185     }
1186 
1187     protected void fillDefaultNatures( String packaging )
1188     {
1189         projectnatures = new ArrayList();
1190 
1191         if ( wtpVersionFloat >= 1.0f )
1192         {
1193             projectnatures.add( NATURE_WST_FACET_CORE_NATURE ); // WTP 1.0 nature
1194         }
1195 
1196         if ( isJavaProject )
1197         {
1198             projectnatures.add( NATURE_JDT_CORE_JAVA );
1199         }
1200 
1201         if ( wtpVersionFloat >= 0.7f )
1202         {
1203             projectnatures.add( NATURE_WST_MODULE_CORE_NATURE ); // WTP 0.7/1.0 nature
1204 
1205             if ( isJavaProject )
1206             {
1207                 projectnatures.add( NATURE_JEM_WORKBENCH_JAVA_EMF ); // WTP 0.7/1.0 nature
1208             }
1209         }
1210 
1211         if ( pde )
1212         {
1213             projectnatures.add( NATURE_PDE_PLUGIN );
1214         }
1215 
1216     }
1217 
1218     protected void fillDefaultClasspathContainers( String packaging )
1219     {
1220         classpathContainers = new ArrayList();
1221 
1222         if ( getWorkspaceConfiguration().getDefaultClasspathContainer() != null )
1223         {
1224             getLog().info(
1225                            "Adding default classpath contaigner: " +
1226                                getWorkspaceConfiguration().getDefaultClasspathContainer() );
1227             classpathContainers.add( getWorkspaceConfiguration().getDefaultClasspathContainer() );
1228         }
1229         if ( pde )
1230         {
1231             classpathContainers.add( REQUIRED_PLUGINS_CONTAINER );
1232         }
1233     }
1234 
1235     protected void fillDefaultBuilders( String packaging )
1236     {
1237         buildcommands = new ArrayList();
1238 
1239         if ( wtpVersionFloat == 0.7f )
1240         {
1241             buildcommands.add( new BuildCommand( BUILDER_WST_COMPONENT_STRUCTURAL ) ); // WTP 0.7 builder
1242         }
1243 
1244         if ( isJavaProject )
1245         {
1246             buildcommands.add( new BuildCommand( BUILDER_JDT_CORE_JAVA ) );
1247         }
1248 
1249         if ( wtpVersionFloat >= 1.5f )
1250         {
1251             buildcommands.add( new BuildCommand( BUILDER_WST_FACET ) ); // WTP 1.5 builder
1252         }
1253 
1254         if ( wtpVersionFloat >= 0.7f )
1255         {
1256             buildcommands.add( new BuildCommand( BUILDER_WST_VALIDATION ) ); // WTP 0.7/1.0 builder
1257         }
1258 
1259         if ( wtpVersionFloat == 0.7f )
1260         {
1261             // WTP 0.7 builder
1262             buildcommands.add( new BuildCommand( BUILDER_WST_COMPONENT_STRUCTURAL_DEPENDENCY_RESOLVER ) );
1263         }
1264 
1265         if ( pde )
1266         {
1267             buildcommands.add( new BuildCommand( BUILDER_PDE_MANIFEST ) );
1268             buildcommands.add( new BuildCommand( BUILDER_PDE_SCHEMA ) );
1269         }
1270     }
1271 
1272     public EclipseSourceDir[] buildDirectoryList( MavenProject project, File basedir, File buildOutputDirectory )
1273         throws MojoExecutionException
1274     {
1275         File projectBaseDir = project.getFile().getParentFile();
1276 
1277         // avoid duplicated entries
1278         Set directories = new TreeSet();
1279 
1280         extractSourceDirs( directories, project.getCompileSourceRoots(), basedir, projectBaseDir, false, null );
1281 
1282         String relativeOutput = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, buildOutputDirectory, false );
1283 
1284         extractResourceDirs( directories, project.getBuild().getResources(), project, basedir, projectBaseDir, false,
1285                              relativeOutput );
1286 
1287         // If using the standard output location, don't mix the test output into it.
1288         String testOutput = null;
1289         boolean useStandardOutputDir =
1290             buildOutputDirectory.equals( new File( project.getBuild().getOutputDirectory() ) );
1291         if ( useStandardOutputDir )
1292         {
1293             getLog().debug(
1294                             "testOutput toRelativeAndFixSeparator " + projectBaseDir + " , " +
1295                                 project.getBuild().getTestOutputDirectory() );
1296             testOutput =
1297                 IdeUtils.toRelativeAndFixSeparator( projectBaseDir,
1298                                                     new File( project.getBuild().getTestOutputDirectory() ), false );
1299             getLog().debug( "testOutput after toRelative : " + testOutput );
1300         }
1301 
1302         extractSourceDirs( directories, project.getTestCompileSourceRoots(), basedir, projectBaseDir, true, testOutput );
1303 
1304         extractResourceDirs( directories, project.getBuild().getTestResources(), project, basedir, projectBaseDir,
1305                              true, testOutput );
1306 
1307         return (EclipseSourceDir[]) directories.toArray( new EclipseSourceDir[directories.size()] );
1308     }
1309 
1310     private void extractSourceDirs( Set directories, List sourceRoots, File basedir, File projectBaseDir, boolean test,
1311                                     String output )
1312         throws MojoExecutionException
1313     {
1314         for ( Iterator it = sourceRoots.iterator(); it.hasNext(); )
1315         {
1316 
1317             File sourceRootFile = new File( (String) it.next() );
1318 
1319             if ( sourceRootFile.isDirectory() )
1320             {
1321                 String sourceRoot =
1322                     IdeUtils.toRelativeAndFixSeparator( projectBaseDir, sourceRootFile,
1323                                                         !projectBaseDir.equals( basedir ) );
1324 
1325                 directories.add( new EclipseSourceDir( sourceRoot, output, false, test, null, null, false ) );
1326             }
1327         }
1328     }
1329 
1330     void extractResourceDirs( Set directories, List resources, MavenProject project, File basedir,
1331                               File workspaceProjectBaseDir, boolean test, final String output )
1332         throws MojoExecutionException
1333     {
1334         for ( Iterator it = resources.iterator(); it.hasNext(); )
1335         {
1336             Resource resource = (Resource) it.next();
1337 
1338             getLog().debug( "Processing resource dir: " + resource.getDirectory() );
1339 
1340             String includePattern = null;
1341             String excludePattern = null;
1342 
1343             if ( resource.getIncludes().size() != 0 )
1344             {
1345                 includePattern = StringUtils.join( resource.getIncludes().iterator(), "|" );
1346             }
1347 
1348             if ( resource.getExcludes().size() != 0 )
1349             {
1350                 excludePattern = StringUtils.join( resource.getExcludes().iterator(), "|" );
1351             }
1352 
1353             // TODO: figure out how to merge if the same dir is specified twice
1354             // with different in/exclude patterns.
1355 
1356             File resourceDirectory = new File( /* basedir, */resource.getDirectory() );
1357 
1358             if ( !resourceDirectory.exists() || !resourceDirectory.isDirectory() )
1359             {
1360                 getLog().debug( "Resource dir: " + resourceDirectory + " either missing or not a directory." );
1361                 continue;
1362             }
1363 
1364             String resourceDir =
1365                 IdeUtils.toRelativeAndFixSeparator( workspaceProjectBaseDir, resourceDirectory,
1366                                                     !workspaceProjectBaseDir.equals( basedir ) );
1367             String thisOutput = output;
1368             if ( thisOutput != null )
1369             {
1370                 // sometimes thisOutput is already an absolute path
1371                 File outputFile = new File( thisOutput );
1372                 if ( !outputFile.isAbsolute() )
1373                 {
1374                     outputFile = new File( workspaceProjectBaseDir, thisOutput );
1375                 }
1376                 // create output dir if it doesn't exist
1377                 outputFile.mkdirs();
1378 
1379                 if ( !StringUtils.isEmpty( resource.getTargetPath() ) )
1380                 {
1381                     outputFile = new File( outputFile, resource.getTargetPath() );
1382                     // create output dir if it doesn't exist
1383                     outputFile.mkdirs();
1384                 }
1385 
1386                 getLog().debug(
1387                                 "Making relative and fixing separator: { " + workspaceProjectBaseDir + ", " +
1388                                     outputFile + ", false }." );
1389                 thisOutput = IdeUtils.toRelativeAndFixSeparator( workspaceProjectBaseDir, outputFile, false );
1390             }
1391 
1392             getLog().debug(
1393                             "Adding eclipse source dir: { " + resourceDir + ", " + thisOutput + ", true, " + test +
1394                                 ", " + includePattern + ", " + excludePattern + " }." );
1395 
1396             directories.add( new EclipseSourceDir( resourceDir, thisOutput, true, test, includePattern, excludePattern,
1397                                                    resource.isFiltering() ) );
1398         }
1399     }
1400 
1401     /**
1402      * Calculate the project name template from the fields {@link #projectNameTemplate},
1403      * {@link #addVersionToProjectName} and {@link #addGroupIdToProjectName}
1404      * 
1405      * @return the project name template that should be used after considering the plugin configuration
1406      */
1407     private String calculateProjectNameTemplate()
1408     {
1409         if ( getProjectNameTemplate() != null )
1410         {
1411             if ( isAddVersionToProjectName() || isAddGroupIdToProjectName() )
1412             {
1413                 getLog().warn(
1414                                "projectNameTemplate definition overrides "
1415                                    + "addVersionToProjectName or addGroupIdToProjectName" );
1416             }
1417             return getProjectNameTemplate();
1418         }
1419         else if ( isAddVersionToProjectName() && isAddGroupIdToProjectName() )
1420         {
1421             return IdeUtils.PROJECT_NAME_WITH_GROUP_AND_VERSION_TEMPLATE;
1422         }
1423         else if ( isAddVersionToProjectName() )
1424         {
1425             return IdeUtils.PROJECT_NAME_WITH_VERSION_TEMPLATE;
1426         }
1427         else if ( isAddGroupIdToProjectName() )
1428         {
1429             return IdeUtils.PROJECT_NAME_WITH_GROUP_TEMPLATE;
1430         }
1431         return IdeUtils.PROJECT_NAME_DEFAULT_TEMPLATE;
1432     }
1433 
1434     /**
1435      * {@inheritDoc}
1436      */
1437     public String getProjectNameForArifact( Artifact artifact )
1438     {
1439         IdeDependency[] workspaceArtefacts = getWorkspaceArtefacts();
1440         for ( int index = 0; workspaceArtefacts != null && index < workspaceArtefacts.length; index++ )
1441         {
1442             IdeDependency workspaceArtefact = workspaceArtefacts[index];
1443             if ( workspaceArtefact.isAddedToClasspath() &&
1444                 workspaceArtefact.getGroupId().equals( artifact.getGroupId() ) &&
1445                 workspaceArtefact.getArtifactId().equals( artifact.getArtifactId() ) )
1446             {
1447                 if ( workspaceArtefact.getVersion().equals( artifact.getVersion() ) )
1448                 {
1449                     return workspaceArtefact.getEclipseProjectName();
1450                 }
1451             }
1452         }
1453         return IdeUtils.getProjectName( calculateProjectNameTemplate(), artifact );
1454     }
1455 
1456     /**
1457      * {@inheritDoc}
1458      */
1459     protected IdeDependency[] getWorkspaceArtefacts()
1460     {
1461         return getWorkspaceConfiguration().getWorkspaceArtefacts();
1462     }
1463 
1464     public WorkspaceConfiguration getWorkspaceConfiguration()
1465     {
1466         if ( workspaceConfiguration == null )
1467         {
1468             workspaceConfiguration = new WorkspaceConfiguration();
1469             if ( workspace != null )
1470             {
1471                 workspaceConfiguration.setWorkspaceDirectory( new File( workspace ) );
1472             }
1473             new ReadWorkspaceLocations().init( getLog(), workspaceConfiguration, project, wtpdefaultserver );
1474         }
1475         return workspaceConfiguration;
1476     }
1477 
1478     public List getExcludes()
1479     {
1480         return excludes;
1481     }
1482 
1483     /**
1484      * Utility method that locates a project in the workspace for the given artifact.
1485      * 
1486      * @param artifact the artifact a project should produce.
1487      * @return <code>true</code> if the artifact is produced by a reactor projectart.
1488      */
1489     private boolean isAvailableAsAWorkspaceProject( Artifact artifact )
1490     {
1491         IdeDependency[] workspaceArtefacts = getWorkspaceArtefacts();
1492         for ( int index = 0; workspaceArtefacts != null && index < workspaceArtefacts.length; index++ )
1493         {
1494             IdeDependency workspaceArtefact = workspaceArtefacts[index];
1495             if ( workspaceArtefact.getGroupId().equals( artifact.getGroupId() ) &&
1496                 workspaceArtefact.getArtifactId().equals( artifact.getArtifactId() ) )
1497             {
1498                 if ( workspaceArtefact.getVersion().equals( artifact.getVersion() ) )
1499                 {
1500                     workspaceArtefact.setAddedToClasspath( true );
1501                     getLog().debug( "Using workspace project: " + workspaceArtefact.getEclipseProjectName() );
1502                     return true;
1503                 }
1504                 else
1505                 {
1506                     getLog().info(
1507                                    "Artifact " +
1508                                        artifact.getId() +
1509                                        " already available as a workspace project, but with different version. Expected: " +
1510                                        artifact.getVersion() + ", found: " + workspaceArtefact.getVersion() );
1511                 }
1512             }
1513         }
1514         return false;
1515     }
1516 
1517     /*
1518      * (non-Javadoc)
1519      * 
1520      * @see org.apache.maven.plugin.ide.AbstractIdeSupportMojo#doDependencyResolution()
1521      */
1522     protected IdeDependency[] doDependencyResolution()
1523         throws MojoExecutionException
1524     {
1525 
1526         return super.doDependencyResolution();
1527     }
1528 
1529     /**
1530      * Checks if jar has to be resolved for the given artifact
1531      * 
1532      * @param art the artifact to check
1533      * @return true if resolution should happen
1534      */
1535     protected boolean hasToResolveJar( Artifact art )
1536     {
1537         return !( getUseProjectReferences() && isAvailableAsAReactorProject( art ) ) ||
1538             ( limitProjectReferencesToWorkspace && !( getUseProjectReferences() && isAvailableAsAWorkspaceProject( art ) ) );
1539     }
1540 
1541     /**
1542      * Checks if a projects reference has to be used for the given artifact
1543      * 
1544      * @param art the artifact to check
1545      * @return true if a project reference has to be used.
1546      */
1547     protected boolean useProjectReference( Artifact art )
1548     {
1549         boolean isReactorProject = getUseProjectReferences() && isAvailableAsAReactorProject( art );
1550         boolean isWorkspaceProject = getUseProjectReferences() && isAvailableAsAWorkspaceProject( art );
1551         return ( isReactorProject && !limitProjectReferencesToWorkspace ) || // default
1552             ( limitProjectReferencesToWorkspace && isWorkspaceProject ) || // limitProjectReferencesToWorkspace
1553             ( !isReactorProject && isWorkspaceProject ); // default + workspace projects
1554     }
1555 }