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  
20  package org.apache.maven.archetype.ui;
21  
22  import org.apache.commons.collections.iterators.ArrayIterator;
23  import org.apache.maven.archetype.ArchetypeGenerationRequest;
24  import org.apache.maven.archetype.catalog.Archetype;
25  import org.apache.maven.archetype.common.ArchetypeDefinition;
26  import org.apache.maven.archetype.exception.ArchetypeNotDefined;
27  import org.apache.maven.archetype.exception.ArchetypeSelectionFailure;
28  import org.apache.maven.archetype.exception.UnknownArchetype;
29  import org.apache.maven.archetype.exception.UnknownGroup;
30  import org.codehaus.plexus.components.interactivity.PrompterException;
31  import org.codehaus.plexus.logging.AbstractLogEnabled;
32  import org.codehaus.plexus.util.StringUtils;
33  
34  import java.io.IOException;
35  import java.util.HashMap;
36  import java.util.Iterator;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.Properties;
40  
41  /** @plexus.component */
42  public class DefaultArchetypeSelector
43      extends AbstractLogEnabled
44      implements ArchetypeSelector
45  {
46      static final String DEFAULT_ARCHETYPE_GROUPID = "org.apache.maven.archetypes";
47  
48      static final String DEFAULT_ARCHETYPE_VERSION = "1.0";
49  
50      static final String DEFAULT_ARCHETYPE_ARTIFACTID = "maven-archetype-quickstart";
51  
52      /** @plexus.requirement */
53      private ArchetypeSelectionQueryer archetypeSelectionQueryer;
54      /** @plexus.requirement */
55      private org.apache.maven.archetype.Archetype archetype;
56  
57      public void selectArchetype( ArchetypeGenerationRequest request, Boolean interactiveMode, String catalogs )
58          throws ArchetypeNotDefined, UnknownArchetype, UnknownGroup, IOException, PrompterException,
59          ArchetypeSelectionFailure
60      {
61          //This should be an internal class
62          ArchetypeDefinition definition = new ArchetypeDefinition();
63  
64          definition.setGroupId( request.getArchetypeGroupId() );
65          definition.setArtifactId( request.getArchetypeArtifactId() );
66          definition.setVersion( request.getArchetypeVersion() );
67  
68          Map archetypes = getArchetypesByCatalog( catalogs );
69  
70          if ( definition.isDefined() && StringUtils.isNotEmpty( request.getArchetypeRepository() ) )
71          {
72              getLogger().info( "Archetype defined by properties" );
73          }
74          else
75          {
76              if ( definition.isDefined() && StringUtils.isEmpty( request.getArchetypeRepository() ) )
77              {
78                  Iterator ca = new ArrayIterator( StringUtils.split ( catalogs, "," ) );
79                  boolean found = false;
80                  while ( !found && ca.hasNext() )
81                  {
82                      String catalogKey = (String) ca.next();
83  
84                      String[] keySplitted = catalogKey.split( "-", 2 );
85  
86                      List catalog = (List) archetypes.get( catalogKey );
87  
88                      Archetype example = new Archetype();
89                      example.setGroupId( request.getArchetypeGroupId() );
90                      example.setArtifactId( request.getArchetypeArtifactId() );
91  
92                      if ( catalog.contains( example ) )
93                      {
94                          found = true;
95  
96                          Archetype foundArchetype = (Archetype) catalog.get( catalog.indexOf( example ) );
97                          definition.setName( foundArchetype.getArtifactId() );
98                          if ( StringUtils.isNotEmpty( foundArchetype.getRepository() ) )
99                          {
100                             definition.setRepository( foundArchetype.getRepository() );
101                         }
102                         else if ( keySplitted.length > 1 )
103                         {
104                             int lastIndex = catalogKey.lastIndexOf( "/" );
105                             String catalogBase =
106                                 catalogKey.substring( 0, ( lastIndex > 7 ? lastIndex : catalogKey.length() ) );
107                             definition.setRepository( catalogBase );
108                         }
109 
110                         getLogger().info(
111                                           "Archetype repository missing. Using the one from " + foundArchetype
112                                               + " found in catalog " + catalogKey );
113                     }
114                 }
115                 if ( !found )
116                 {
117                     getLogger().warn( "No archetype repository found. Falling back to central repository (http://repo1.maven.org/maven2). " );
118                     getLogger().warn( "Use -DarchetypeRepository=<your repository> if archetype's repository is elsewhere." );
119 
120                     definition.setRepository( "http://repo1.maven.org/maven2" );
121                 }
122             }
123             if ( !definition.isDefined() && definition.isPartiallyDefined() )
124             {
125                 Iterator ca = new ArrayIterator( StringUtils.split( catalogs, "," ) );
126                 boolean found = false;
127                 while ( !found && ca.hasNext() )
128                 {
129                     String catalogKey = (String) ca.next();
130 
131                     List catalog = (List) archetypes.get( catalogKey );
132 
133                     String[] keySplitted = catalogKey.split( ":", 2 );
134 
135                     Archetype example = new Archetype();
136                     example.setGroupId( request.getArchetypeGroupId() );
137                     example.setArtifactId( request.getArchetypeArtifactId() );
138 
139                     if ( catalog.contains ( example ) )
140                     {
141                         found = true;
142 
143                         Archetype foundArchetype = (Archetype) catalog.get( catalog.indexOf( example ) );
144                         definition.setGroupId( foundArchetype.getGroupId() );
145                         definition.setArtifactId( foundArchetype.getArtifactId() );
146                         definition.setVersion( foundArchetype.getVersion() );
147                         definition.setName( foundArchetype.getArtifactId() );
148 
149                         if ( StringUtils.isNotEmpty( foundArchetype.getRepository() ) )
150                         {
151                             definition.setRepository( foundArchetype.getRepository() );
152                         }
153                         else if ( keySplitted.length > 1 )
154                         {
155                             int lastIndex = catalogKey.lastIndexOf( "/" );
156                             String catalogBase =
157                                 catalogKey.substring( 0, ( lastIndex > 7 ? lastIndex : catalogKey.length() ) );
158                             definition.setRepository( catalogBase );
159                         }
160 
161                         String goals = StringUtils.join( foundArchetype.getGoals().iterator(), "," );
162                         definition.setGoals( goals );
163 
164                         getLogger().info( "Archetype " + foundArchetype + " found in catalog " + catalogKey );
165                     }
166                 }
167                 if ( !found )
168                 {
169                     getLogger().warn( "Specified archetype not found." );
170                     if ( interactiveMode.booleanValue() )
171                     {
172                         definition.setVersion( null );
173                         definition.setGroupId( null );
174                         definition.setArtifactId( null );
175                     }
176                 }
177             }
178         }
179 
180         // set the defaults - only group and version can be auto-defaulted
181         if ( definition.getGroupId() == null )
182         {
183             definition.setGroupId( DEFAULT_ARCHETYPE_GROUPID );
184         }
185         if ( definition.getVersion() == null )
186         {
187             definition.setVersion( DEFAULT_ARCHETYPE_VERSION );
188         }
189 
190         if ( !definition.isDefined() && !definition.isPartiallyDefined() )
191         {
192             // if artifact ID is set to it's default, we still prompt to confirm
193             if ( definition.getArtifactId() == null )
194             {
195                 getLogger().info( "No archetype defined. Using " + DEFAULT_ARCHETYPE_ARTIFACTID + " ("
196                     + definition.getGroupId() + ":" + DEFAULT_ARCHETYPE_ARTIFACTID + ":" + definition.getVersion()
197                     + ")" );
198                 definition.setArtifactId( DEFAULT_ARCHETYPE_ARTIFACTID );
199             }
200 
201             if ( interactiveMode.booleanValue() )
202             {
203                 if ( archetypes.size() > 0 )
204                 {
205                     Archetype selectedArchetype = archetypeSelectionQueryer.selectArchetype( archetypes, definition );
206 
207                     definition.setGroupId( selectedArchetype.getGroupId() );
208                     definition.setArtifactId( selectedArchetype.getArtifactId() );
209                     definition.setVersion( selectedArchetype.getVersion() );
210                     definition.setName( selectedArchetype.getArtifactId() );
211                     String catalogKey = getCatalogKey( archetypes, selectedArchetype );
212                     String[] keySplitted = catalogKey.split( ":", 2 );
213                     if ( StringUtils.isNotEmpty( selectedArchetype.getRepository() ) )
214                     {
215                         definition.setRepository( selectedArchetype.getRepository() );
216                     }
217                     else if ( keySplitted.length > 1 )
218                     {
219                         int lastIndex = catalogKey.lastIndexOf( "/" );
220                         String catalogBase =
221                             catalogKey.substring( 0, ( lastIndex > 7 ? lastIndex : catalogKey.length() ) );
222                         definition.setRepository( catalogBase );
223                     }
224                     String goals = StringUtils.join( selectedArchetype.getGoals().iterator(), "," );
225                     definition.setGoals( goals );
226                 }
227             }
228         }
229 
230         // Make sure the groupId and artifactId are valid, the version may just default to
231         // the latest release.
232 
233         if ( !definition.isPartiallyDefined() )
234         {
235             throw new ArchetypeSelectionFailure( "No valid archetypes could be found to choose." );
236         }
237 
238         request.setArchetypeGroupId( definition.getGroupId() );
239 
240         request.setArchetypeArtifactId( definition.getArtifactId() );
241 
242         request.setArchetypeVersion( definition.getVersion() );
243 
244         request.setArchetypeGoals( definition.getGoals() );
245 
246         request.setArchetypeName( definition.getName() );
247 
248         if ( StringUtils.isNotEmpty( definition.getRepository() ) )
249         {
250             request.setArchetypeRepository( definition.getRepository() );
251         }
252     }
253 
254     private Map getArchetypesByCatalog( String catalogs )
255     {
256         if ( catalogs == null )
257         {
258             throw new NullPointerException( "catalogs can not be null" );
259         }
260 
261         Map archetypes = new HashMap();
262 
263         for ( Iterator ca = new ArrayIterator( StringUtils.split( catalogs, "," ) ); ca.hasNext(); )
264         {
265             String catalog = (String) ca.next();
266 
267             if ( "internal".equalsIgnoreCase( catalog ) )
268             {
269                 archetypes.put( "internal", archetype.getInternalCatalog().getArchetypes() );
270             }
271             else if ( "local".equalsIgnoreCase( catalog ) )
272             {
273                 archetypes.put( "local", archetype.getDefaultLocalCatalog().getArchetypes() );
274             }
275             else if ( "remote".equalsIgnoreCase( catalog ) )
276             {
277                 List archetypesFromRemote = archetype.getRemoteCatalog().getArchetypes();
278                 if ( archetypesFromRemote.size() > 0 )
279                 {
280                     archetypes.put( "remote", archetypesFromRemote );
281                 }
282                 else
283                 {
284                     getLogger().warn( "No archetype found in Remote catalog. Defaulting to internal Catalog" );
285                     archetypes.put( "internal", archetype.getInternalCatalog().getArchetypes() );
286                 }
287             }
288             else if ( catalog.startsWith( "file://" ) )
289             {
290                 String path = catalog.substring( 7 );
291                 archetypes.put( catalog, archetype.getLocalCatalog( path ).getArchetypes() );
292             }
293             else if ( catalog.startsWith( "http://" ) )
294             {
295                 archetypes.put( catalog, archetype.getRemoteCatalog( catalog ).getArchetypes() );
296             }
297         }
298 
299         if ( archetypes.size() == 0 )
300         {
301             getLogger().info( "No catalog defined. Using internal catalog" );
302 
303             archetypes.put( "internal", archetype.getInternalCatalog().getArchetypes() );
304         }
305         return archetypes;
306     }
307 
308     private Properties getArchetypeDataSourceProperties( String sourceRoleHint, Properties archetypeCatalogProperties )
309     {
310         Properties p = new Properties();
311 
312         for ( Iterator i = archetypeCatalogProperties.keySet().iterator(); i.hasNext(); )
313         {
314             String key = (String) i.next();
315 
316             if ( key.startsWith( sourceRoleHint ) )
317             {
318                 String k = key.substring( sourceRoleHint.length() + 1 );
319 
320                 p.setProperty( k, archetypeCatalogProperties.getProperty( key ) );
321             }
322         }
323 
324         return p;
325     }
326 
327     public void setArchetypeSelectionQueryer( ArchetypeSelectionQueryer archetypeSelectionQueryer )
328     {
329         this.archetypeSelectionQueryer = archetypeSelectionQueryer;
330     }
331 
332     private String getCatalogKey( Map archetypes, Archetype selectedArchetype )
333     {
334         String key = "";
335         Iterator keys = archetypes.keySet().iterator();
336         boolean found = false;
337         while ( keys.hasNext() && !found )
338         {
339             key = (String) keys.next();
340             List catalog = (List) archetypes.get( key );
341             if ( catalog.contains( selectedArchetype ) )
342             {
343                 found = true;
344             }
345         }
346         return key;
347     }
348 }