View Javadoc
1   package org.apache.maven.archetype.ui.generation;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.apache.maven.archetype.ArchetypeGenerationRequest;
24  import org.apache.maven.archetype.ArchetypeManager;
25  import org.apache.maven.archetype.catalog.Archetype;
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.apache.maven.archetype.ui.ArchetypeDefinition;
31  import org.apache.maven.project.ProjectBuildingRequest;
32  import org.codehaus.plexus.component.annotations.Component;
33  import org.codehaus.plexus.component.annotations.Requirement;
34  import org.codehaus.plexus.components.interactivity.PrompterException;
35  import org.codehaus.plexus.logging.AbstractLogEnabled;
36  
37  import java.io.IOException;
38  import java.util.HashMap;
39  import java.util.LinkedHashMap;
40  import java.util.List;
41  import java.util.Map;
42  
43  @Component( role = ArchetypeSelector.class, hint = "default" )
44  public class DefaultArchetypeSelector
45      extends AbstractLogEnabled
46      implements ArchetypeSelector
47  {
48      static final String DEFAULT_ARCHETYPE_GROUPID = "org.apache.maven.archetypes";
49  
50      static final String DEFAULT_ARCHETYPE_VERSION = "1.0";
51  
52      static final String DEFAULT_ARCHETYPE_ARTIFACTID = "maven-archetype-quickstart";
53  
54      @Requirement
55      private ArchetypeSelectionQueryer archetypeSelectionQueryer;
56  
57      @Requirement
58      private ArchetypeManager archetypeManager;
59  
60      public void selectArchetype( ArchetypeGenerationRequest request, Boolean interactiveMode, String catalogs )
61          throws ArchetypeNotDefined, UnknownArchetype, UnknownGroup, IOException, PrompterException,
62          ArchetypeSelectionFailure
63      {
64          ArchetypeDefinition definition = new ArchetypeDefinition( request );
65  
66          if ( definition.isDefined() && StringUtils.isNotEmpty( request.getArchetypeRepository() ) )
67          {
68              getLogger().info( "Archetype defined by properties" );
69              return;
70          }
71  
72          Map<String, List<Archetype>> archetypes = getArchetypesByCatalog( request.getProjectBuildingRequest(), catalogs );
73  
74          if ( StringUtils.isNotBlank( request.getFilter() ) )
75          {
76              // applying some filtering depending on filter parameter
77              archetypes = ArchetypeSelectorUtils.getFilteredArchetypesByCatalog( archetypes, request.getFilter() );
78              if ( archetypes.isEmpty() )
79              {
80                  getLogger().info( "Your filter doesn't match any archetype, so try again with another value." );
81                  return;
82              }
83          }
84  
85          if ( definition.isDefined() )
86          {
87              Map.Entry<String, Archetype> found =
88                  findArchetype( archetypes, request.getArchetypeGroupId(), request.getArchetypeArtifactId() );
89  
90              if ( found != null )
91              {
92                  String catalogKey = found.getKey();
93                  Archetype archetype = found.getValue();
94  
95                  updateRepository( definition, archetype );
96  
97                  getLogger().info( "Archetype repository not defined. Using the one from " + archetype + " found in catalog "
98                                        + catalogKey );
99              }
100             else
101             {
102                 getLogger().warn(
103                     "Archetype not found in any catalog. Falling back to central repository (http://repo.maven.apache.org/maven2)." );
104                 getLogger().warn(
105                     "Use -DarchetypeRepository=<your repository> if archetype's repository is elsewhere." );
106 
107                 definition.setRepository( "http://repo.maven.apache.org/maven2" );
108             }
109         }
110         else if ( definition.isPartiallyDefined() )
111         {
112             Map.Entry<String, Archetype> found =
113                 findArchetype( archetypes, request.getArchetypeGroupId(), request.getArchetypeArtifactId() );
114 
115             if ( found != null )
116             {
117                 String catalogKey = found.getKey();
118                 Archetype archetype = found.getValue();
119 
120                 updateDefinition( definition, archetype );
121 
122                 getLogger().info( "Archetype " + archetype + " found in catalog " + catalogKey );
123             }
124             else
125             {
126                 getLogger().warn( "Specified archetype not found." );
127                 if ( interactiveMode.booleanValue() )
128                 {
129                     definition.setVersion( null );
130                     definition.setGroupId( null );
131                     definition.setArtifactId( null );
132                 }
133             }
134         }
135 
136         // set the defaults - only group and version can be auto-defaulted
137         if ( definition.getGroupId() == null )
138         {
139             definition.setGroupId( DEFAULT_ARCHETYPE_GROUPID );
140         }
141         if ( definition.getVersion() == null )
142         {
143             definition.setVersion( DEFAULT_ARCHETYPE_VERSION );
144         }
145 
146         if ( !definition.isPartiallyDefined() )
147         {
148             // if artifact ID is set to its default, we still prompt to confirm
149             if ( definition.getArtifactId() == null )
150             {
151                 getLogger().info(
152                     "No archetype defined. Using " + DEFAULT_ARCHETYPE_ARTIFACTID + " (" + definition.getGroupId() + ":"
153                         + DEFAULT_ARCHETYPE_ARTIFACTID + ":" + definition.getVersion() + ")" );
154                 definition.setArtifactId( DEFAULT_ARCHETYPE_ARTIFACTID );
155             }
156 
157             if ( interactiveMode.booleanValue() && ( archetypes.size() > 0 ) )
158             {
159                 Archetype selectedArchetype = archetypeSelectionQueryer.selectArchetype( archetypes, definition );
160 
161                 updateDefinition( definition, selectedArchetype );
162             }
163 
164             // Make sure the groupId and artifactId are valid, the version may just default to
165             // the latest release.
166             if ( !definition.isPartiallyDefined() )
167             {
168                 throw new ArchetypeSelectionFailure( "No valid archetypes could be found to choose." );
169             }
170         }
171 
172         // finally update the request with gathered information
173         definition.updateRequest( request );
174     }
175 
176 
177     private Map<String, List<Archetype>> getArchetypesByCatalog( ProjectBuildingRequest buildingRequest, String catalogs )
178     {
179         if ( catalogs == null )
180         {
181             throw new NullPointerException( "Catalogs cannot be null" );
182         }
183 
184         Map<String, List<Archetype>> archetypes = new LinkedHashMap<String, List<Archetype>>();
185 
186         for ( String catalog : StringUtils.split( catalogs, "," ) )
187         {
188             if ( "internal".equalsIgnoreCase( catalog ) )
189             {
190                 archetypes.put( "internal", archetypeManager.getInternalCatalog().getArchetypes() );
191             }
192             else if ( "local".equalsIgnoreCase( catalog ) )
193             {
194                 archetypes.put( "local", archetypeManager.getLocalCatalog( buildingRequest ).getArchetypes() );
195             }
196             else if ( "remote".equalsIgnoreCase( catalog ) )
197             {
198                 List<Archetype> archetypesFromRemote =
199                     archetypeManager.getRemoteCatalog( buildingRequest ).getArchetypes();
200                 
201                 if ( archetypesFromRemote.size() > 0 )
202                 {
203                     archetypes.put( "remote", archetypesFromRemote );
204                 }
205                 else
206                 {
207                     getLogger().warn( "No archetype found in remote catalog. Defaulting to internal catalog" );
208                     archetypes.put( "internal", archetypeManager.getInternalCatalog().getArchetypes() );
209                 }
210             }
211         }
212 
213         if ( archetypes.size() == 0 )
214         {
215             getLogger().info( "No catalog defined. Using internal catalog" );
216 
217             archetypes.put( "internal", archetypeManager.getInternalCatalog().getArchetypes() );
218         }
219         return archetypes;
220     }
221 
222     private void updateRepository( ArchetypeDefinition definition, Archetype archetype )
223     {
224         String repository = archetype.getRepository();
225         if ( StringUtils.isNotEmpty( repository ) )
226         {
227             definition.setRepository( repository );
228         }
229     }
230 
231     private void updateDefinition( ArchetypeDefinition definition, Archetype archetype )
232     {
233         definition.setGroupId( archetype.getGroupId() );
234         definition.setArtifactId( archetype.getArtifactId() );
235         definition.setVersion( archetype.getVersion() );
236         definition.setName( archetype.getArtifactId() );
237         updateRepository( definition, archetype );
238         definition.setGoals( StringUtils.join( archetype.getGoals().iterator(), "," ) );
239     }
240 
241     public void setArchetypeSelectionQueryer( ArchetypeSelectionQueryer archetypeSelectionQueryer )
242     {
243         this.archetypeSelectionQueryer = archetypeSelectionQueryer;
244     }
245 
246     private Map.Entry<String, Archetype> findArchetype( Map<String, List<Archetype>> archetypes, String groupId,
247                                                         String artifactId )
248     {
249         Archetype example = new Archetype();
250         example.setGroupId( groupId );
251         example.setArtifactId( artifactId );
252 
253         for ( Map.Entry<String, List<Archetype>> entry : archetypes.entrySet() )
254         {
255             List<Archetype> catalog = entry.getValue();
256 
257             if ( catalog.contains( example ) )
258             {
259                 Archetype archetype = catalog.get( catalog.indexOf( example ) );
260 
261                 return newMapEntry( entry.getKey(), archetype );
262             }
263         }
264 
265         return null;
266     }
267 
268     private static <K, V> Map.Entry<K, V> newMapEntry( K key, V value )
269     {
270         Map<K, V> map = new HashMap<K, V>( 1 );
271         map.put( key, value );
272 
273         return map.entrySet().iterator().next();
274     }
275 }