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.ide;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.maven.artifact.Artifact;
27  import org.apache.maven.artifact.factory.ArtifactFactory;
28  import org.apache.maven.artifact.repository.ArtifactRepository;
29  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
30  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
31  import org.apache.maven.artifact.resolver.ArtifactResolver;
32  import org.apache.maven.artifact.versioning.ArtifactVersion;
33  import org.apache.maven.artifact.versioning.VersionRange;
34  import org.apache.maven.model.Dependency;
35  import org.apache.maven.model.Plugin;
36  import org.apache.maven.model.PluginExecution;
37  import org.apache.maven.plugin.MojoExecutionException;
38  import org.apache.maven.plugin.eclipse.Messages;
39  import org.apache.maven.plugin.logging.Log;
40  import org.apache.maven.project.MavenProject;
41  import org.codehaus.plexus.util.FileUtils;
42  import org.codehaus.plexus.util.StringUtils;
43  import org.codehaus.plexus.util.xml.Xpp3Dom;
44  
45  /**
46   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
47   * @author <a href="mailto:fgiust@users.sourceforge.net">Fabrizio Giustina</a>
48   * @version $Id: IdeUtils.java 1517906 2013-08-27 18:25:03Z krosenvold $
49   */
50  public class IdeUtils
51  {
52      public static final String JAVA_1_1 = "1.1";
53  
54      public static final String JAVA_1_2 = "1.2";
55  
56      public static final String JAVA_1_3 = "1.3";
57  
58      public static final String JAVA_1_4 = "1.4";
59  
60      public static final String JAVA_5_0 = "5.0";
61  
62      public static final String JAVA_6_0 = "6.0";
63  
64      public static final String PROJECT_NAME_DEFAULT_TEMPLATE = "[artifactId]";
65  
66      public static final String PROJECT_NAME_WITH_VERSION_TEMPLATE = "[artifactId]-[version]";
67  
68      public static final String PROJECT_NAME_WITH_GROUP_TEMPLATE = "[groupId].[artifactId]";
69  
70      public static final String PROJECT_NAME_WITH_GROUP_AND_VERSION_TEMPLATE = "[groupId].[artifactId]-[version]";
71  
72      /**
73       * compiler plugin id.
74       */
75      private static final String ARTIFACT_MAVEN_COMPILER_PLUGIN = "maven-compiler-plugin"; //$NON-NLS-1$
76  
77      /**
78       * 'source' property for maven-compiler-plugin.
79       */
80      private static final String PROPERTY_SOURCE = "source"; //$NON-NLS-1$
81  
82      /**
83       * 'encoding' property for maven-compiler-plugin.
84       */
85      private static final String PROPERTY_ENCODING = "encoding"; //$NON-NLS-1$
86  
87      /**
88       * 'target' property for maven-compiler-plugin.
89       */
90      private static final String PROPERTY_TARGET = "target"; //$NON-NLS-1$
91  
92      /**
93       * The suffix used to mark a file as not available.
94       */
95      public static final String NOT_AVAILABLE_MARKER_FILE_SUFFIX = "-not-available";
96  
97      /**
98       * Delete a file, handling log messages and exceptions
99       *
100      * @param f File to be deleted
101      * @throws MojoExecutionException only if a file exists and can't be deleted
102      */
103     public static void delete( File f, Log log )
104         throws MojoExecutionException
105     {
106         if ( f.isDirectory() )
107         {
108             log.info( Messages.getString( "EclipseCleanMojo.deletingDirectory", f.getName() ) ); //$NON-NLS-1$
109         }
110         else
111         {
112             log.info( Messages.getString( "EclipseCleanMojo.deletingFile", f.getName() ) ); //$NON-NLS-1$
113         }
114 
115         if ( f.exists() )
116         {
117             if ( !f.delete() )
118             {
119                 try
120                 {
121                     FileUtils.forceDelete( f );
122                 }
123                 catch ( IOException e )
124                 {
125                     throw new MojoExecutionException( Messages.getString( "EclipseCleanMojo.failedtodelete", //$NON-NLS-1$
126                                                                           new Object[] { f.getName(),
127                                                                               f.getAbsolutePath() } ) );
128                 }
129             }
130         }
131         else
132         {
133             log.debug( Messages.getString( "EclipseCleanMojo.nofilefound", f.getName() ) ); //$NON-NLS-1$
134         }
135     }
136 
137     public static String getCanonicalPath( File file )
138         throws MojoExecutionException
139     {
140         try
141         {
142             return file.getCanonicalPath();
143         }
144         catch ( IOException e )
145         {
146             throw new MojoExecutionException( Messages.getString( "EclipsePlugin.cantcanonicalize", file //$NON-NLS-1$
147             .getAbsolutePath() ), e );
148         }
149     }
150 
151     /**
152      * Returns a compiler plugin settings, considering also settings altered in plugin executions .
153      *
154      * @param project maven project
155      * @return option value (may be null)
156      */
157     public static String getCompilerPluginSetting( MavenProject project, String optionName )
158     {
159         String value = findCompilerPluginSettingInPlugins( project.getModel().getBuild().getPlugins(), optionName );
160         if ( value == null && project.getModel().getBuild().getPluginManagement() != null )
161         {
162             value =
163                 findCompilerPluginSettingInPlugins( project.getModel().getBuild().getPluginManagement().getPlugins(),
164                                                     optionName );
165         }
166         return value;
167     }
168 
169     /**
170      * Returns the source version configured for the compiler plugin. Returns the minimum version required to compile
171      * both standard and test sources, if settings are different.
172      *
173      * @param project maven project
174      * @return java source version
175      */
176     public static String getCompilerSourceVersion( MavenProject project )
177     {
178         return IdeUtils.getCompilerPluginSetting( project, PROPERTY_SOURCE );
179     }
180 
181     /**
182      * Returns the source encoding configured for the compiler plugin. Returns the minimum version required to compile
183      * both standard and test sources, if settings are different.
184      *
185      * @param project maven project
186      * @return java source version
187      */
188     public static String getCompilerSourceEncoding( MavenProject project )
189     {
190         String value = IdeUtils.getCompilerPluginSetting( project, PROPERTY_ENCODING );
191 		if ( value == null )
192         {
193             project.getProperties().getProperty( "project.build.sourceEncoding" );
194         }
195 		return value;
196     }
197 
198     /**
199      * Returns the target version configured for the compiler plugin. Returns the minimum version required to compile
200      * both standard and test sources, if settings are different.
201      *
202      * @param project maven project
203      * @return java target version
204      */
205     public static String getCompilerTargetVersion( MavenProject project )
206     {
207         return IdeUtils.getCompilerPluginSetting( project, PROPERTY_TARGET );
208     }
209 
210     // /**
211     // * Extracts the version of the first matching dependency in the given list.
212     // *
213     // * @param artifactIds artifact names to compare against for extracting version
214     // * @param dependencies Collection of dependencies for our project
215     // * @param len expected length of the version sub-string
216     // * @return
217     // */
218     // public static String getDependencyVersion( String[] artifactIds, List dependencies, int len )
219     // {
220     // for ( int j = 0; j < artifactIds.length; j++ )
221     // {
222     // String id = artifactIds[j];
223     // for ( Iterator itr = dependencies.iterator(); itr.hasNext(); )
224     // {
225     // Dependency dependency = (Dependency) itr.next();
226     // if ( id.equals( dependency.getArtifactId() ) )
227     // {
228     // return StringUtils.substring( dependency.getVersion(), 0, len );
229     // }
230     // }
231     // }
232     // return null;
233     // }
234 
235     /**
236      * Extracts the version of the first matching artifact in the given list.
237      * <p>
238      * The {@code len} parameter indicated what to to return:
239      * <ul>
240      *   <li><strong>1</strong> indicated <code>major</code> version</li>
241      *   <li><strong>3</strong> indicated <code>major dot minor</code> version</li>
242      *   <li><strong>5 and above</strong> indicates <code>major dot minor dot incremental</code> version
243      * </ul>
244      * 
245      * @param artifactIds artifact names to compare against for extracting version
246      * @param artifacts Set of artifacts for our project
247      * @param len expected length of the version sub-string
248      * @return
249      */
250     public static String getArtifactVersion( String[] artifactIds, List dependencies, int len )
251     {
252         String version = null;
253         ArtifactVersion artifactVersion = getArtifactVersion( artifactIds, dependencies );
254         if ( artifactVersion != null )
255         {
256             StringBuilder versionBuffer = new StringBuilder();
257             if( len >= 1 )
258             {
259                 versionBuffer.append( artifactVersion.getMajorVersion() );
260             }
261             if( len >= 2 )
262             {
263                 versionBuffer.append( '.' );
264             }            
265             if( len >= 3 )
266             {
267                 versionBuffer.append( artifactVersion.getMinorVersion() );
268             }
269             if( len >= 4 )
270             {
271                 versionBuffer.append( '.' );
272             }            
273             if( len >= 5 )
274             {
275                 versionBuffer.append( artifactVersion.getIncrementalVersion() );
276             }
277             version = versionBuffer.toString();
278         }
279         return version;
280     }
281     
282     /**
283      * 
284      * @param artifactIds an array of artifactIds, should not be <code>null</code>
285      * @param dependencies a list of {@link Dependency}-objects, should not be <code>null</code>
286      * @return the resolved ArtifactVersion, otherwise <code>null</code>
287      */
288     public static ArtifactVersion getArtifactVersion( String[] artifactIds, List /*<Dependency>*/ dependencies )
289     {
290         for (String id : artifactIds) {
291             for (Object dependency : dependencies) {
292                 Dependency dep = (Dependency) dependency;
293                 if (id.equals(dep.getArtifactId())) {
294                     return VersionRange.createFromVersion(dep.getVersion()).getRecommendedVersion();
295                 }
296 
297             }
298         }
299         return null;
300     }
301 
302     /**
303      * Search for a configuration setting of an other plugin for a configuration setting.
304      *
305      * @todo there should be a better way to do this
306      * @param project the current maven project to get the configuration from.
307      * @param pluginId the group id and artifact id of the plugin to search for
308      * @param optionName the option to get from the configuration
309      * @param defaultValue the default value if the configuration was not found
310      * @return the value of the option configured in the plugin configuration
311      */
312     public static String getPluginSetting( MavenProject project, String pluginId, String optionName, String defaultValue )
313     {
314         Xpp3Dom dom = getPluginConfigurationDom( project, pluginId );
315         if ( dom != null && dom.getChild( optionName ) != null )
316         {
317             return dom.getChild( optionName ).getValue();
318         }
319         return defaultValue;
320     }
321 
322     /**
323      * Search for the configuration Xpp3 dom of an other plugin.
324      *
325      * @todo there should be a better way to do this
326      * @param project the current maven project to get the configuration from.
327      * @param pluginId the group id and artifact id of the plugin to search for
328      * @return the value of the option configured in the plugin configuration
329      */
330     public static Xpp3Dom getPluginConfigurationDom( MavenProject project, String pluginId )
331     {
332 
333         Plugin plugin = (org.apache.maven.model.Plugin) project.getBuild().getPluginsAsMap().get( pluginId );
334         if ( plugin != null )
335         {
336             // TODO: This may cause ClassCastExceptions eventually, if the dom impls differ.
337             return (Xpp3Dom) plugin.getConfiguration();
338         }
339         return null;
340     }
341 
342     /**
343      * Search for the configuration Xpp3 dom of an other plugin.
344      *
345      * @todo there should be a better way to do this
346      * @param project the current maven project to get the configuration from.
347      * @param artifactId the artifact id of the plugin to search for
348      * @return the value of the option configured in the plugin configuration
349      */
350     public static Xpp3Dom[] getPluginConfigurationDom( MavenProject project, String artifactId,
351                                                        String[] subConfiguration )
352     {
353         ArrayList configurationDomList = new ArrayList();
354         Xpp3Dom configuration = getPluginConfigurationDom( project, artifactId );
355         if ( configuration != null )
356         {
357             configurationDomList.add( configuration );
358             for ( int index = 0; !configurationDomList.isEmpty() && subConfiguration != null
359                 && index < subConfiguration.length; index++ )
360             {
361                 ArrayList newConfigurationDomList = new ArrayList();
362                 for (Object aConfigurationDomList : configurationDomList) {
363                     Xpp3Dom child = (Xpp3Dom) aConfigurationDomList;
364                     Xpp3Dom[] deeperChild = child.getChildren(subConfiguration[index]);
365                     for (Xpp3Dom aDeeperChild : deeperChild) {
366                         if (aDeeperChild != null) {
367                             newConfigurationDomList.add(aDeeperChild);
368                         }
369                     }
370                 }
371                 configurationDomList = newConfigurationDomList;
372             }
373         }
374         return (Xpp3Dom[]) configurationDomList.toArray( new Xpp3Dom[configurationDomList.size()] );
375     }
376 
377     /**
378      * Calculate the project name template from the specified value <code>projectNameTemplate</code>,
379      * <code>addVersionToProjectName</code> and <code>addGroupIdToProjectName</code>
380      * <p>
381      * Note: if projectNameTemplate is not null then that value will be used regardless of the values for
382      * addVersionToProjectName or addGroupIdToProjectName and a warning will be issued.
383      *
384      * @param projectNameTemplate the current projectNameTemplate, if available
385      * @param addVersionToProjectName whether to include Version in the project name
386      * @param addGroupIdToProjectName whether to include GroupId in the project name.
387      * @return the project name template.
388      */
389     public static String calculateProjectNameTemplate( String projectNameTemplate, boolean addVersionToProjectName,
390                                                        boolean addGroupIdToProjectName, Log log )
391     {
392         if ( projectNameTemplate != null )
393         {
394             if ( addVersionToProjectName || addGroupIdToProjectName )
395             {
396                 log.warn( "projectNameTemplate definition overrides "
397                     + "addVersionToProjectName or addGroupIdToProjectName" );
398             }
399             return projectNameTemplate;
400         }
401         else if ( addVersionToProjectName && addGroupIdToProjectName )
402         {
403             return IdeUtils.PROJECT_NAME_WITH_GROUP_AND_VERSION_TEMPLATE;
404         }
405         else if ( addVersionToProjectName )
406         {
407             return IdeUtils.PROJECT_NAME_WITH_VERSION_TEMPLATE;
408         }
409         else if ( addGroupIdToProjectName )
410         {
411             return IdeUtils.PROJECT_NAME_WITH_GROUP_TEMPLATE;
412         }
413         return IdeUtils.PROJECT_NAME_DEFAULT_TEMPLATE;
414     }
415 
416     /**
417      * Use {@link IdeDependency#getEclipseProjectName()} instead.
418      */
419     protected static String getProjectName( String template, IdeDependency dep )
420     {
421         return getProjectName( template, dep.getGroupId(), dep.getArtifactId(), dep.getVersion() );
422     }
423 
424     /**
425      * Use the project name template to create an eclipse project.
426      *
427      * @param template Template for the project name
428      * @param artifact the artifact to create the project name for
429      * @return the created ide project name
430      */
431     public static String getProjectName( String template, Artifact artifact )
432     {
433         return getProjectName( template, artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );
434     }
435 
436     public static String getProjectName( String template, MavenProject project )
437     {
438         return getProjectName( template, project.getGroupId(), project.getArtifactId(), project.getVersion() );
439     }
440 
441     public static String getProjectName( MavenProject project, boolean addVersionToProjectName )
442     {
443         return getProjectName( addVersionToProjectName ? PROJECT_NAME_WITH_VERSION_TEMPLATE
444                         : PROJECT_NAME_DEFAULT_TEMPLATE, project );
445     }
446 
447     /**
448      * @param artifact the artifact
449      * @return the not-available marker file for the specified artifact
450      */
451     public static File getNotAvailableMarkerFile( ArtifactRepository localRepository, Artifact artifact )
452     {
453         return new File( localRepository.getBasedir(), localRepository.pathOf( artifact )
454             + NOT_AVAILABLE_MARKER_FILE_SUFFIX );
455     }
456 
457     /**
458      * Wrapper around {@link ArtifactResolver#resolve(Artifact, List, ArtifactRepository)}
459      *
460      * @param artifactResolver see {@link ArtifactResolver#resolve(Artifact, List, ArtifactRepository)}
461      * @param artifact see {@link ArtifactResolver#resolve(Artifact, List, ArtifactRepository)}
462      * @param remoteRepos see {@link ArtifactResolver#resolve(Artifact, List, ArtifactRepository)}
463      * @param localRepository see {@link ArtifactResolver#resolve(Artifact, List, ArtifactRepository)}
464      * @param log Logger
465      * @return the artifact, resolved if possible.
466      */
467     public static Artifact resolveArtifact( ArtifactResolver artifactResolver, Artifact artifact, List remoteRepos,
468                                             ArtifactRepository localRepository, Log log )
469 
470     {
471         try
472         {
473             artifactResolver.resolve( artifact, remoteRepos, localRepository );
474         }
475         catch ( ArtifactNotFoundException e )
476         {
477             // ignore, the jar has not been found
478 
479             /*
480              * This method gets called with no remote repositories to avoid remote trips (which would ideally be
481              * realized by means of a per-request offline flag), the set of available remote repos can however affect
482              * the resolution from the local repo as well, in particular in Maven 3. So double check whether the local
483              * file is really not present.
484              */
485             if ( artifact.getFile() != null && artifact.getFile().isFile() )
486             {
487                 artifact.setResolved( true );
488             }
489         }
490         catch ( ArtifactResolutionException e )
491         {
492             String message =
493                 Messages.getString( "IdeUtils.errorresolving", new Object[] { artifact.getClassifier(),
494                     artifact.getId(), e.getMessage() } );
495 
496             log.warn( message );
497         }
498 
499         return artifact;
500     }
501 
502     /**
503      * Wrap {@link ArtifactFactory#createArtifactWithClassifier} so that the type and classifier are set correctly for
504      * "sources" and "javadoc".
505      *
506      * @param groupId see {@link ArtifactFactory#createArtifactWithClassifier}
507      * @param artifactId see {@link ArtifactFactory#createArtifactWithClassifier}
508      * @param version see {@link ArtifactFactory#createArtifactWithClassifier}
509      * @param depClassifier see {@link ArtifactFactory#createArtifactWithClassifier}
510      * @param inClassifier either "sources" of "javadoc"
511      * @param artifactFactory see {@link ArtifactFactory#createArtifactWithClassifier}
512      * @return see {@link ArtifactFactory#createArtifactWithClassifier}
513      * @see ArtifactFactory#createArtifactWithClassifier
514      */
515     public static Artifact createArtifactWithClassifier( String groupId, String artifactId, String version,
516                                                          String depClassifier, String inClassifier,
517                                                          ArtifactFactory artifactFactory )
518     {
519         String type;
520 
521         // the "sources" classifier maps to the "java-source" type
522         if ( "sources".equals( inClassifier ) )
523         {
524             type = "java-source";
525         }
526         else
527         {
528             type = inClassifier;
529         }
530 
531         String finalClassifier;
532         if ( depClassifier == null )
533         {
534             finalClassifier = inClassifier;
535         }
536         else if ( "sources".equals( inClassifier ) && "tests".equals( depClassifier ) )
537         {
538             // MECLIPSE-151 - if the dependency is a test, get the correct classifier for it. (ignore for javadocs)
539             finalClassifier = "test-sources";
540         }
541         else
542         {
543             finalClassifier = depClassifier + "-" + inClassifier;
544         }
545 
546         return artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, type, finalClassifier );
547     }
548 
549     public static String resolveJavaVersion( MavenProject project )
550     {
551         String version = IdeUtils.getCompilerTargetVersion( project );
552         if ( version == null )
553         {
554             version = IdeUtils.getCompilerSourceVersion( project );
555         }
556 
557         if ( "1.5".equals( version ) ) //$NON-NLS-1$
558         {
559             version = IdeUtils.JAVA_5_0;// see MECLIPSE-47 eclipse only accept 5.0 as a valid version
560         }
561         else if ( "1.6".equals( version ) ) //$NON-NLS-1$
562         {
563             version = IdeUtils.JAVA_6_0;
564         }
565         else if ( version != null && version.length() == 1 )
566         {
567             version = version + ".0";// 5->5.0 6->6.0 7->7.0 //$NON-NLS-1$
568         }
569 
570         return version == null ? IdeUtils.JAVA_1_4 : version;
571     }
572 
573     public static String toRelativeAndFixSeparator( File basedir, File fileToAdd, boolean replaceSlashesWithDashes )
574         throws MojoExecutionException
575     {
576         if ( !fileToAdd.isAbsolute() )
577         {
578             fileToAdd = new File( basedir, fileToAdd.getPath() );
579         }
580 
581         String basedirPath = getCanonicalPath( basedir );
582         String absolutePath = getCanonicalPath( fileToAdd );
583 
584         String relative;
585 
586         if ( absolutePath.equals( basedirPath ) )
587         {
588             relative = "."; //$NON-NLS-1$
589         }
590         else if ( absolutePath.startsWith( basedirPath ) )
591         {
592             // MECLIPSE-261
593             // The canonical form of a windows root dir ends in a slash, whereas the canonical form of any other file
594             // does not.
595             // The absolutePath is assumed to be: basedirPath + Separator + fileToAdd
596             // In the case of a windows root directory the Separator is missing since it is contained within
597             // basedirPath.
598             int length = basedirPath.length() + 1;
599             if ( basedirPath.endsWith( "\\" ) )
600             {
601                 length--;
602             }
603             relative = absolutePath.substring( length );
604         }
605         else
606         {
607             relative = absolutePath;
608         }
609 
610         relative = fixSeparator( relative );
611 
612         if ( replaceSlashesWithDashes )
613         {
614             relative = StringUtils.replace( relative, '/', '-' );
615             relative = StringUtils.replace( relative, ':', '-' ); // remove ":" for absolute paths in windows
616         }
617 
618         return relative;
619     }
620 
621     /**
622      * Convert the provided filename from a Windows separator \\ to a unix/java separator /
623      *
624      * @param filename file name to fix separator
625      * @return filename with all \\ replaced with /
626      */
627     public static String fixSeparator( String filename )
628     {
629         return StringUtils.replace( filename, '\\', '/' );
630     }
631 
632     /**
633      * NOTE: This is to account for the unfortunate fact that "file:" URIs differ between Windows and Unix. On a Windows
634      * box, the path "C:\dir" is mapped to "file:/C:/dir". On a Unix box, the path "/home/dir" is mapped to
635      * "file:/home/dir". So, in the first case the slash after "file:" is not part of the corresponding filesystem path
636      * while in the later case it is. This discrepancy makes verifying the javadoc attachments in ".classpath" a little
637      * tricky.
638      *
639      * @param input string input that may contain a windows URI
640      * @return all windows URI convert "file:C:/dir" to "file:/C:/dir"
641      */
642     public static String fixWindowsDriveURI( String input )
643     {
644         return input.replaceAll( "file:([a-zA-Z]):", "file:/$1:" );
645     }
646 
647     /**
648      * Returns a compiler plugin settings from a list of plugins .
649      *
650      * @param project maven project
651      * @return option value (may be null)
652      */
653     private static String findCompilerPluginSettingInPlugins( List plugins, String optionName )
654     {
655         String value = null;
656 
657         for (Object plugin1 : plugins) {
658             Plugin plugin = (Plugin) plugin1;
659 
660             if (plugin.getArtifactId().equals(ARTIFACT_MAVEN_COMPILER_PLUGIN)) {
661                 // TODO: This may cause ClassCastExceptions eventually, if the dom impls differ.
662                 Xpp3Dom o = (Xpp3Dom) plugin.getConfiguration();
663 
664                 // this is the default setting
665                 if (o != null && o.getChild(optionName) != null) {
666                     value = o.getChild(optionName).getValue();
667                 }
668 
669                 List executions = plugin.getExecutions();
670 
671                 // a different source/target version can be configured for test sources compilation
672                 for (Object execution1 : executions) {
673                     PluginExecution execution = (PluginExecution) execution1;
674 
675                     // TODO: This may cause ClassCastExceptions eventually, if the dom impls differ.
676                     o = (Xpp3Dom) execution.getConfiguration();
677 
678                     if (o != null && o.getChild(optionName) != null) {
679                         value = o.getChild(optionName).getValue();
680                     }
681                 }
682             }
683         }
684         return value;
685     }
686 
687     private static String getProjectName( String template, String groupId, String artifactId, String version )
688     {
689         String s = template;
690         s = s.replaceAll( "\\[groupId\\]", groupId );
691         s = s.replaceAll( "\\[artifactId\\]", artifactId );
692         s = s.replaceAll( "\\[version\\]", version );
693         return s;
694     }
695 
696     private IdeUtils()
697     {
698         // don't instantiate
699     }
700 }