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.OutputStreamWriter;
25  import java.io.Writer;
26  import java.util.ArrayList;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.regex.Matcher;
32  import java.util.regex.Pattern;
33  
34  import org.apache.maven.artifact.Artifact;
35  import org.apache.maven.artifact.deployer.ArtifactDeployer;
36  import org.apache.maven.artifact.deployer.ArtifactDeploymentException;
37  import org.apache.maven.artifact.factory.ArtifactFactory;
38  import org.apache.maven.artifact.installer.ArtifactInstallationException;
39  import org.apache.maven.artifact.installer.ArtifactInstaller;
40  import org.apache.maven.artifact.metadata.ArtifactMetadata;
41  import org.apache.maven.artifact.repository.ArtifactRepository;
42  import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
43  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
44  import org.apache.maven.model.Dependency;
45  import org.apache.maven.model.License;
46  import org.apache.maven.model.Model;
47  import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
48  import org.apache.maven.plugin.AbstractMojo;
49  import org.apache.maven.plugin.MojoExecutionException;
50  import org.apache.maven.plugin.MojoFailureException;
51  import org.apache.maven.plugin.eclipse.osgiplugin.EclipseOsgiPlugin;
52  import org.apache.maven.plugin.eclipse.osgiplugin.ExplodedPlugin;
53  import org.apache.maven.plugin.eclipse.osgiplugin.PackagedPlugin;
54  import org.apache.maven.project.artifact.ProjectArtifactMetadata;
55  import org.codehaus.plexus.PlexusConstants;
56  import org.codehaus.plexus.PlexusContainer;
57  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
58  import org.codehaus.plexus.components.interactivity.InputHandler;
59  import org.codehaus.plexus.context.Context;
60  import org.codehaus.plexus.context.ContextException;
61  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
62  import org.codehaus.plexus.util.IOUtil;
63  import org.codehaus.plexus.util.StringUtils;
64  
65  import aQute.lib.osgi.Analyzer;
66  
67  /**
68   * Add eclipse artifacts from an eclipse installation to the local repo. This mojo automatically analize the eclipse
69   * directory, copy plugins jars to the local maven repo, and generates appropriate poms. This is the official central
70   * repository builder for Eclipse plugins, so it has the necessary default values. For customized repositories see
71   * {@link MakeArtifactsMojo} Typical usage:
72   * <code>mvn eclipse:to-maven -DdeployTo=maven.org::default::scpexe://repo1.maven.org/home/maven/repository-staging/to-ibiblio/eclipse-staging -DeclipseDir=.</code>
73   * 
74   * @author Fabrizio Giustina
75   * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
76   * @version $Id: EclipseToMavenMojo.java 1154368 2011-08-05 20:13:42Z rfscholte $
77   * @goal to-maven
78   * @requiresProject false
79   */
80  public class EclipseToMavenMojo
81      extends AbstractMojo
82      implements Contextualizable
83  {
84  
85      /**
86       * A pattern the <code>deployTo</code> param should match.
87       */
88      private static final Pattern DEPLOYTO_PATTERN = Pattern.compile( "(.+)::(.+)::(.+)" ); //$NON-NLS-1$
89  
90      /**
91       * A pattern for a 4 digit osgi version number.
92       */
93      private static final Pattern VERSION_PATTERN = Pattern.compile( "(([0-9]+\\.)+[0-9]+)" ); //$NON-NLS-1$
94  
95      /**
96       * Plexus container, needed to manually lookup components for deploy of artifacts.
97       */
98      private PlexusContainer container;
99  
100     /**
101      * Local maven repository.
102      * 
103      * @parameter expression="${localRepository}"
104      * @required
105      * @readonly
106      */
107     private ArtifactRepository localRepository;
108 
109     /**
110      * ArtifactRepositoryFactory component.
111      * 
112      * @component
113      */
114     private ArtifactRepositoryFactory artifactRepositoryFactory;
115 
116     /**
117      * ArtifactFactory component.
118      * 
119      * @component
120      */
121     private ArtifactFactory artifactFactory;
122 
123     /**
124      * ArtifactInstaller component.
125      * 
126      * @component
127      */
128     protected ArtifactInstaller installer;
129 
130     /**
131      * ArtifactDeployer component.
132      * 
133      * @component
134      */
135     private ArtifactDeployer deployer;
136 
137     /**
138      * Eclipse installation dir. If not set, a value for this parameter will be asked on the command line.
139      * 
140      * @parameter expression="${eclipseDir}"
141      */
142     private File eclipseDir;
143 
144     /**
145      * Input handler, needed for comand line handling.
146      * 
147      * @component
148      */
149     protected InputHandler inputHandler;
150 
151     /**
152      * Strip qualifier (fourth token) from the plugin version. Qualifiers are for eclipse plugin the equivalent of
153      * timestamped snapshot versions for Maven, but the date is maintained also for released version (e.g. a jar for the
154      * release <code>3.2</code> can be named <code>org.eclipse.core.filesystem_1.0.0.v20060603.jar</code>. It's usually
155      * handy to not to include this qualifier when generating maven artifacts for major releases, while it's needed when
156      * working with eclipse integration/nightly builds.
157      * 
158      * @parameter expression="${stripQualifier}" default-value="false"
159      */
160     private boolean stripQualifier;
161 
162     /**
163      * Specifies a remote repository to which generated artifacts should be deployed to. If this property is specified,
164      * artifacts are also deployed to the remote repo. The format for this parameter is <code>id::layout::url</code>
165      * 
166      * @parameter expression="${deployTo}"
167      */
168     private String deployTo;
169 
170     /**
171      * @see org.apache.maven.plugin.Mojo#execute()
172      */
173     public void execute()
174         throws MojoExecutionException, MojoFailureException
175     {
176         if ( eclipseDir == null )
177         {
178             getLog().info( Messages.getString( "EclipseToMavenMojo.eclipseDirectoryPrompt" ) ); //$NON-NLS-1$
179 
180             String eclipseDirString;
181             try
182             {
183                 eclipseDirString = inputHandler.readLine();
184             }
185             catch ( IOException e )
186             {
187                 throw new MojoFailureException( Messages.getString( "EclipseToMavenMojo.errorreadingfromstandardinput" ) ); //$NON-NLS-1$
188             }
189             eclipseDir = new File( eclipseDirString );
190         }
191 
192         if ( !eclipseDir.isDirectory() )
193         {
194             throw new MojoFailureException(
195                                             Messages.getString(
196                                                                 "EclipseToMavenMojo.directoydoesnotexist", eclipseDir.getAbsolutePath() ) ); //$NON-NLS-1$
197         }
198 
199         File pluginDir = new File( eclipseDir, "plugins" ); //$NON-NLS-1$
200 
201         if ( !pluginDir.isDirectory() )
202         {
203             throw new MojoFailureException(
204                                             Messages.getString(
205                                                                 "EclipseToMavenMojo.plugindirectorydoesnotexist", pluginDir.getAbsolutePath() ) ); //$NON-NLS-1$
206         }
207 
208         File[] files = pluginDir.listFiles();
209 
210         ArtifactRepository remoteRepo = resolveRemoteRepo();
211 
212         if ( remoteRepo != null )
213         {
214             getLog().info( Messages.getString( "EclipseToMavenMojo.remoterepositorydeployto", deployTo ) ); //$NON-NLS-1$
215         }
216 
217         Map plugins = new HashMap();
218         Map models = new HashMap();
219 
220         for ( int j = 0; j < files.length; j++ )
221         {
222             File file = files[j];
223 
224             getLog().info( Messages.getString( "EclipseToMavenMojo.processingfile", file.getAbsolutePath() ) ); //$NON-NLS-1$
225 
226             processFile( file, plugins, models );
227         }
228 
229         int i = 1;
230         for ( Iterator it = plugins.keySet().iterator(); it.hasNext(); )
231         {
232             getLog().info(
233                            Messages.getString(
234                                                "EclipseToMavenMojo.processingplugin", new Object[] { new Integer( i++ ), new Integer( plugins.keySet().size() ) } ) ); //$NON-NLS-1$
235             String key = (String) it.next();
236             EclipseOsgiPlugin plugin = (EclipseOsgiPlugin) plugins.get( key );
237             Model model = (Model) models.get( key );
238             writeArtifact( plugin, model, remoteRepo );
239         }
240     }
241 
242     protected void processFile( File file, Map plugins, Map models )
243         throws MojoExecutionException, MojoFailureException
244     {
245         EclipseOsgiPlugin plugin = getEclipsePlugin( file );
246 
247         if ( plugin == null )
248         {
249             getLog().warn( Messages.getString( "EclipseToMavenMojo.skippingfile", file.getAbsolutePath() ) ); //$NON-NLS-1$
250             return;
251         }
252 
253         Model model = createModel( plugin );
254 
255         if ( model == null )
256         {
257             return;
258         }
259 
260         processPlugin( plugin, model, plugins, models );
261     }
262 
263     protected void processPlugin( EclipseOsgiPlugin plugin, Model model, Map plugins, Map models )
264         throws MojoExecutionException, MojoFailureException
265     {
266         plugins.put( getKey( model ), plugin );
267         models.put( getKey( model ), model );
268     }
269 
270     protected String getKey( Model model )
271     {
272         return model.getGroupId() + "." + model.getArtifactId(); //$NON-NLS-1$
273     }
274 
275     private String getKey( Dependency dependency )
276     {
277         return dependency.getGroupId() + "." + dependency.getArtifactId(); //$NON-NLS-1$
278     }
279 
280     /**
281      * Resolve version ranges in the model provided, overriding version ranges with versions from the dependency in the
282      * provided map of models. TODO doesn't check if the version is in range, it just overwrites it
283      * 
284      * @param model
285      * @param models
286      * @throws MojoFailureException
287      */
288     protected void resolveVersionRanges( Model model, Map models )
289         throws MojoFailureException
290     {
291         for ( Iterator it = model.getDependencies().iterator(); it.hasNext(); )
292         {
293             Dependency dep = (Dependency) it.next();
294             if ( dep.getVersion().indexOf( "[" ) > -1 || dep.getVersion().indexOf( "(" ) > -1 ) //$NON-NLS-1$ //$NON-NLS-2$
295             {
296                 String key = getKey( model );
297                 Model dependencyModel = (Model) models.get( getKey( dep ) );
298                 if ( dependencyModel != null )
299                 {
300                     dep.setVersion( dependencyModel.getVersion() );
301                 }
302                 else
303                 {
304                     throw new MojoFailureException(
305                                                     Messages.getString(
306                                                                         "EclipseToMavenMojo.unabletoresolveversionrange", new Object[] { dep //$NON-NLS-1$
307                                                                             , key } ) ); //$NON-NLS-1$
308                 }
309             }
310         }
311     }
312 
313     /**
314      * Get a {@link EclipseOsgiPlugin} object from a plugin jar/dir found in the target dir.
315      * 
316      * @param file plugin jar or dir
317      * @throws MojoExecutionException if anything bad happens while parsing files
318      */
319     private EclipseOsgiPlugin getEclipsePlugin( File file )
320         throws MojoExecutionException
321     {
322         if ( file.isDirectory() )
323         {
324             return new ExplodedPlugin( file );
325         }
326         else if ( file.getName().endsWith( ".jar" ) ) //$NON-NLS-1$
327         {
328             try
329             {
330                 return new PackagedPlugin( file );
331             }
332             catch ( IOException e )
333             {
334                 throw new MojoExecutionException(
335                                                   Messages.getString(
336                                                                       "EclipseToMavenMojo.unabletoaccessjar", file.getAbsolutePath() ), e ); //$NON-NLS-1$
337             }
338         }
339 
340         return null;
341     }
342 
343     /**
344      * Create the {@link Model} from a plugin manifest
345      * 
346      * @param plugin Eclipse plugin jar or dir
347      * @throws MojoExecutionException if anything bad happens while parsing files
348      */
349     private Model createModel( EclipseOsgiPlugin plugin )
350         throws MojoExecutionException
351     {
352 
353         String name, bundleName, version, groupId, artifactId, requireBundle;
354 
355         try
356         {
357             if ( !plugin.hasManifest() )
358             {
359                 getLog().warn( Messages.getString( "EclipseToMavenMojo.plugindoesnothavemanifest", plugin ) ); //$NON-NLS-1$
360                 return null;
361             }
362 
363             Analyzer analyzer = new Analyzer();
364 
365             Map bundleSymbolicNameHeader =
366                 analyzer.parseHeader( plugin.getManifestAttribute( Analyzer.BUNDLE_SYMBOLICNAME ) );
367             bundleName = (String) bundleSymbolicNameHeader.keySet().iterator().next();
368             version = plugin.getManifestAttribute( Analyzer.BUNDLE_VERSION );
369 
370             if ( bundleName == null || version == null )
371             {
372                 getLog().error( Messages.getString( "EclipseToMavenMojo.unabletoreadbundlefrommanifest" ) ); //$NON-NLS-1$
373                 return null;
374             }
375 
376             version = osgiVersionToMavenVersion( version );
377 
378             name = plugin.getManifestAttribute( Analyzer.BUNDLE_NAME );
379 
380             requireBundle = plugin.getManifestAttribute( Analyzer.REQUIRE_BUNDLE );
381 
382         }
383         catch ( IOException e )
384         {
385             throw new MojoExecutionException(
386                                               Messages.getString( "EclipseToMavenMojo.errorprocessingplugin", plugin ), e ); //$NON-NLS-1$
387         }
388 
389         Dependency[] deps = parseDependencies( requireBundle );
390 
391         groupId = createGroupId( bundleName );
392         artifactId = createArtifactId( bundleName );
393 
394         Model model = new Model();
395         model.setModelVersion( "4.0.0" ); //$NON-NLS-1$
396         model.setGroupId( groupId );
397         model.setArtifactId( artifactId );
398         model.setName( name );
399         model.setVersion( version );
400 
401         model.setProperties( plugin.getPomProperties() );
402 
403         if ( groupId.startsWith( "org.eclipse" ) ) //$NON-NLS-1$
404         {
405             // why do we need a parent?
406 
407             // Parent parent = new Parent();
408             // parent.setGroupId( "org.eclipse" );
409             // parent.setArtifactId( "eclipse" );
410             // parent.setVersion( "1" );
411             // model.setParent( parent );
412 
413             // infer license for know projects, everything at eclipse is licensed under EPL
414             // maybe too simplicistic, but better than nothing
415             License license = new License();
416             license.setName( "Eclipse Public License - v 1.0" ); //$NON-NLS-1$
417             license.setUrl( "http://www.eclipse.org/org/documents/epl-v10.html" ); //$NON-NLS-1$
418             model.addLicense( license );
419         }
420 
421         if ( deps.length > 0 )
422         {
423             for ( int k = 0; k < deps.length; k++ )
424             {
425                 model.getDependencies().add( deps[k] );
426             }
427 
428         }
429 
430         return model;
431     }
432 
433     /**
434      * Writes the artifact to the repo
435      * 
436      * @param model
437      * @param remoteRepo remote repository (if set)
438      * @throws MojoExecutionException
439      */
440     private void writeArtifact( EclipseOsgiPlugin plugin, Model model, ArtifactRepository remoteRepo )
441         throws MojoExecutionException
442     {
443         Writer fw = null;
444         ArtifactMetadata metadata = null;
445         File pomFile = null;
446         Artifact pomArtifact =
447             artifactFactory.createArtifact( model.getGroupId(), model.getArtifactId(), model.getVersion(), null, "pom" ); //$NON-NLS-1$
448         Artifact artifact =
449             artifactFactory.createArtifact( model.getGroupId(), model.getArtifactId(), model.getVersion(), null,
450                                             Constants.PROJECT_PACKAGING_JAR );
451         try
452         {
453             pomFile = File.createTempFile( "pom-", ".xml" ); //$NON-NLS-1$ //$NON-NLS-2$
454 
455             // TODO use WriterFactory.newXmlWriter() when plexus-utils is upgraded to 1.4.5+
456             fw = new OutputStreamWriter( new FileOutputStream( pomFile ), "UTF-8" ); //$NON-NLS-1$
457             model.setModelEncoding( "UTF-8" ); // to be removed when encoding is detected instead of forced to UTF-8 //$NON-NLS-1$
458             pomFile.deleteOnExit();
459             new MavenXpp3Writer().write( fw, model );
460             metadata = new ProjectArtifactMetadata( pomArtifact, pomFile );
461             pomArtifact.addMetadata( metadata );
462         }
463         catch ( IOException e )
464         {
465             throw new MojoExecutionException(
466                                               Messages.getString(
467                                                                   "EclipseToMavenMojo.errorwritingtemporarypom", e.getMessage() ), e ); //$NON-NLS-1$
468         }
469         finally
470         {
471             IOUtil.close( fw );
472         }
473 
474         try
475         {
476             File jarFile = plugin.getJarFile();
477 
478             if ( remoteRepo != null )
479             {
480                 deployer.deploy( pomFile, pomArtifact, remoteRepo, localRepository );
481                 deployer.deploy( jarFile, artifact, remoteRepo, localRepository );
482             }
483             else
484             {
485                 installer.install( pomFile, pomArtifact, localRepository );
486                 installer.install( jarFile, artifact, localRepository );
487             }
488         }
489         catch ( ArtifactDeploymentException e )
490         {
491             throw new MojoExecutionException(
492                                               Messages.getString( "EclipseToMavenMojo.errordeployartifacttorepository" ), e ); //$NON-NLS-1$
493         }
494         catch ( ArtifactInstallationException e )
495         {
496             throw new MojoExecutionException(
497                                               Messages.getString( "EclipseToMavenMojo.errorinstallartifacttorepository" ), e ); //$NON-NLS-1$
498         }
499         catch ( IOException e )
500         {
501             throw new MojoExecutionException(
502                                               Messages.getString(
503                                                                   "EclipseToMavenMojo.errorgettingjarfileforplugin", plugin ), e ); //$NON-NLS-1$
504         }
505         finally
506         {
507             pomFile.delete();
508         }
509 
510     }
511 
512     protected String osgiVersionToMavenVersion( String version )
513     {
514         return osgiVersionToMavenVersion( version, null, stripQualifier );
515     }
516 
517     /**
518      * The 4th (build) token MUST be separed with "-" and not with "." in maven. A version with 4 dots is not parsed,
519      * and the whole string is considered a qualifier. See tests in DefaultArtifactVersion for reference.
520      * 
521      * @param version initial version
522      * @param forcedQualifier build number
523      * @param stripQualifier always remove 4th token in version
524      * @return converted version
525      */
526     protected String osgiVersionToMavenVersion( String version, String forcedQualifier, boolean stripQualifier )
527     {
528         if ( stripQualifier && StringUtils.countMatches( version, "." ) > 2 ) //$NON-NLS-1$
529         {
530             version = StringUtils.substring( version, 0, version.lastIndexOf( '.' ) ); //$NON-NLS-1$
531         }
532         else if ( StringUtils.countMatches( version, "." ) > 2 ) //$NON-NLS-1$
533         {
534             int lastDot = version.lastIndexOf( '.' ); //$NON-NLS-1$
535             if ( StringUtils.isNotEmpty( forcedQualifier ) )
536             {
537                 version = StringUtils.substring( version, 0, lastDot ) + "-" + forcedQualifier; //$NON-NLS-1$
538             }
539             else
540             {
541                 version = StringUtils.substring( version, 0, lastDot ) + "-" //$NON-NLS-1$
542                     + StringUtils.substring( version, lastDot + 1, version.length() );
543             }
544         }
545         return version;
546     }
547 
548     /**
549      * Resolves the deploy<code>deployTo</code> parameter to an <code>ArtifactRepository</code> instance (if set).
550      * 
551      * @throws MojoFailureException
552      * @throws MojoExecutionException
553      * @return ArtifactRepository instance of null if <code>deployTo</code> is not set.
554      */
555     private ArtifactRepository resolveRemoteRepo()
556         throws MojoFailureException, MojoExecutionException
557     {
558         if ( deployTo != null )
559         {
560             Matcher matcher = DEPLOYTO_PATTERN.matcher( deployTo );
561 
562             if ( !matcher.matches() )
563             {
564                 throw new MojoFailureException( deployTo,
565                                                 Messages.getString( "EclipseToMavenMojo.invalidsyntaxforrepository" ), //$NON-NLS-1$
566                                                 Messages.getString( "EclipseToMavenMojo.invalidremoterepositorysyntax" ) ); //$NON-NLS-1$
567             }
568             else
569             {
570                 String id = matcher.group( 1 ).trim();
571                 String layout = matcher.group( 2 ).trim();
572                 String url = matcher.group( 3 ).trim();
573 
574                 ArtifactRepositoryLayout repoLayout;
575                 try
576                 {
577                     repoLayout = (ArtifactRepositoryLayout) container.lookup( ArtifactRepositoryLayout.ROLE, layout );
578                 }
579                 catch ( ComponentLookupException e )
580                 {
581                     throw new MojoExecutionException(
582                                                       Messages.getString(
583                                                                           "EclipseToMavenMojo.cannotfindrepositorylayout", layout ), e ); //$NON-NLS-1$
584                 }
585 
586                 return artifactRepositoryFactory.createDeploymentArtifactRepository( id, url, repoLayout, true );
587             }
588         }
589         return null;
590     }
591 
592     /**
593      * {@inheritDoc}
594      */
595     public void contextualize( Context context )
596         throws ContextException
597     {
598         this.container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
599     }
600 
601     /**
602      * Get the group id as the tokens until last dot e.g. <code>org.eclipse.jdt</code> -> <code>org.eclipse</code>
603      * 
604      * @param bundleName bundle name
605      * @return group id
606      */
607     protected String createGroupId( String bundleName )
608     {
609         int i = bundleName.lastIndexOf( '.' ); //$NON-NLS-1$
610         if ( i > 0 )
611         {
612             return bundleName.substring( 0, i );
613         }
614         else
615             return bundleName;
616     }
617 
618     /**
619      * Get the artifact id as the tokens after last dot e.g. <code>org.eclipse.jdt</code> -> <code>jdt</code>
620      * 
621      * @param bundleName bundle name
622      * @return artifact id
623      */
624     protected String createArtifactId( String bundleName )
625     {
626         int i = bundleName.lastIndexOf( '.' ); //$NON-NLS-1$
627         if ( i > 0 )
628         {
629             return bundleName.substring( i + 1 );
630         }
631         else
632             return bundleName;
633     }
634 
635     /**
636      * Parses the "Require-Bundle" and convert it to a list of dependencies.
637      * 
638      * @param requireBundle "Require-Bundle" entry
639      * @return an array of <code>Dependency</code>
640      */
641     protected Dependency[] parseDependencies( String requireBundle )
642     {
643         if ( requireBundle == null )
644         {
645             return new Dependency[0];
646         }
647 
648         List dependencies = new ArrayList();
649 
650         Analyzer analyzer = new Analyzer();
651 
652         Map requireBundleHeader = analyzer.parseHeader( requireBundle );
653 
654         // now iterates on bundles and extract dependencies
655         for ( Iterator iter = requireBundleHeader.entrySet().iterator(); iter.hasNext(); )
656         {
657             Map.Entry entry = (Map.Entry) iter.next();
658             String bundleName = (String) entry.getKey();
659             Map attributes = (Map) entry.getValue();
660 
661             String version = (String) attributes.get( Analyzer.BUNDLE_VERSION.toLowerCase() );
662             boolean optional = "optional".equals( attributes.get( "resolution:" ) ); //$NON-NLS-1$ //$NON-NLS-2$
663 
664             if ( version == null )
665             {
666                 getLog().info( Messages.getString( "EclipseToMavenMojo.missingversionforbundle", bundleName ) ); //$NON-NLS-1$
667                 version = "[0,)"; //$NON-NLS-1$
668             }
669 
670             version = fixBuildNumberSeparator( version );
671 
672             Dependency dep = new Dependency();
673             dep.setGroupId( createGroupId( bundleName ) );
674             dep.setArtifactId( createArtifactId( bundleName ) );
675             dep.setVersion( version );
676             dep.setOptional( optional );
677 
678             dependencies.add( dep );
679 
680         }
681 
682         return (Dependency[]) dependencies.toArray( new Dependency[dependencies.size()] );
683 
684     }
685 
686     /**
687      * Fix the separator for the 4th token in a versions. In maven this must be "-", in OSGI it's "."
688      * 
689      * @param versionRange input range
690      * @return modified version range
691      */
692     protected String fixBuildNumberSeparator( String versionRange )
693     {
694         // should not be called with a null versionRange, but a check doesn't hurt...
695         if ( versionRange == null )
696         {
697             return null;
698         }
699 
700         StringBuffer newVersionRange = new StringBuffer();
701 
702         Matcher matcher = VERSION_PATTERN.matcher( versionRange );
703 
704         while ( matcher.find() )
705         {
706             String group = matcher.group();
707 
708             if ( StringUtils.countMatches( group, "." ) > 2 ) //$NON-NLS-1$
709             {
710                 // build number found, fix it
711                 int lastDot = group.lastIndexOf( '.' ); //$NON-NLS-1$
712                 group = StringUtils.substring( group, 0, lastDot ) + "-" //$NON-NLS-1$
713                     + StringUtils.substring( group, lastDot + 1, group.length() );
714             }
715             matcher.appendReplacement( newVersionRange, group );
716         }
717 
718         matcher.appendTail( newVersionRange );
719 
720         return newVersionRange.toString();
721     }
722 
723 }