1 package org.apache.maven.archetype.ui.generation;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.commons.lang3.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 @Override
61 public void selectArchetype( ArchetypeGenerationRequest request, Boolean interactiveMode, String catalogs )
62 throws ArchetypeNotDefined, UnknownArchetype, UnknownGroup, IOException, PrompterException,
63 ArchetypeSelectionFailure
64 {
65 ArchetypeDefinition definition = new ArchetypeDefinition( request );
66
67 if ( definition.isDefined() && StringUtils.isNotEmpty( request.getArchetypeRepository() ) )
68 {
69 getLogger().info( "Archetype defined by properties" );
70 return;
71 }
72
73 Map<String, List<Archetype>> archetypes = getArchetypesByCatalog( request.getProjectBuildingRequest(), catalogs );
74
75 if ( StringUtils.isNotBlank( request.getFilter() ) )
76 {
77
78 archetypes = ArchetypeSelectorUtils.getFilteredArchetypesByCatalog( archetypes, request.getFilter() );
79 if ( archetypes.isEmpty() )
80 {
81 getLogger().info( "Your filter doesn't match any archetype, so try again with another value." );
82 return;
83 }
84 }
85
86 if ( definition.isDefined() )
87 {
88 Map.Entry<String, Archetype> found =
89 findArchetype( archetypes, request.getArchetypeGroupId(), request.getArchetypeArtifactId() );
90
91 if ( found != null )
92 {
93 String catalogKey = found.getKey();
94 Archetype archetype = found.getValue();
95
96 updateRepository( definition, archetype );
97
98 getLogger().info( "Archetype repository not defined. Using the one from " + archetype + " found in catalog "
99 + catalogKey );
100 }
101 else
102 {
103 getLogger().warn(
104 "Archetype not found in any catalog. Falling back to central repository." );
105 getLogger().warn(
106 "Add a repository with id 'archetype' in your settings.xml if archetype's repository is elsewhere." );
107 }
108 }
109 else if ( definition.isPartiallyDefined() )
110 {
111 Map.Entry<String, Archetype> found =
112 findArchetype( archetypes, request.getArchetypeGroupId(), request.getArchetypeArtifactId() );
113
114 if ( found != null )
115 {
116 String catalogKey = found.getKey();
117 Archetype archetype = found.getValue();
118
119 updateDefinition( definition, archetype );
120
121 getLogger().info( "Archetype " + archetype + " found in catalog " + catalogKey );
122 }
123 else
124 {
125 getLogger().warn( "Specified archetype not found." );
126 if ( interactiveMode.booleanValue() )
127 {
128 definition.setVersion( null );
129 definition.setGroupId( null );
130 definition.setArtifactId( null );
131 }
132 }
133 }
134
135
136 if ( definition.getGroupId() == null )
137 {
138 definition.setGroupId( DEFAULT_ARCHETYPE_GROUPID );
139 }
140 if ( definition.getVersion() == null )
141 {
142 definition.setVersion( DEFAULT_ARCHETYPE_VERSION );
143 }
144
145 if ( !definition.isPartiallyDefined() )
146 {
147
148 if ( definition.getArtifactId() == null )
149 {
150 getLogger().info(
151 "No archetype defined. Using " + DEFAULT_ARCHETYPE_ARTIFACTID + " (" + definition.getGroupId() + ":"
152 + DEFAULT_ARCHETYPE_ARTIFACTID + ":" + definition.getVersion() + ")" );
153 definition.setArtifactId( DEFAULT_ARCHETYPE_ARTIFACTID );
154 }
155
156 if ( interactiveMode.booleanValue() && ( archetypes.size() > 0 ) )
157 {
158 Archetype selectedArchetype = archetypeSelectionQueryer.selectArchetype( archetypes, definition );
159
160 updateDefinition( definition, selectedArchetype );
161 }
162
163
164
165 if ( !definition.isPartiallyDefined() )
166 {
167 throw new ArchetypeSelectionFailure( "No valid archetypes could be found to choose." );
168 }
169 }
170
171
172 definition.updateRequest( request );
173 }
174
175
176 private Map<String, List<Archetype>> getArchetypesByCatalog( ProjectBuildingRequest buildingRequest, String catalogs )
177 {
178 if ( catalogs == null )
179 {
180 throw new NullPointerException( "Catalogs cannot be null" );
181 }
182
183 Map<String, List<Archetype>> archetypes = new LinkedHashMap<>();
184
185 for ( String catalog : StringUtils.split( catalogs, "," ) )
186 {
187 if ( "internal".equalsIgnoreCase( catalog ) )
188 {
189 archetypes.put( "internal", archetypeManager.getInternalCatalog().getArchetypes() );
190 }
191 else if ( "local".equalsIgnoreCase( catalog ) )
192 {
193 archetypes.put( "local", archetypeManager.getLocalCatalog( buildingRequest ).getArchetypes() );
194 }
195 else if ( "remote".equalsIgnoreCase( catalog ) )
196 {
197 List<Archetype> archetypesFromRemote =
198 archetypeManager.getRemoteCatalog( buildingRequest ).getArchetypes();
199
200 if ( archetypesFromRemote.size() > 0 )
201 {
202 archetypes.put( "remote", archetypesFromRemote );
203 }
204 else
205 {
206 getLogger().warn( "No archetype found in remote catalog. Defaulting to internal catalog" );
207 archetypes.put( "internal", archetypeManager.getInternalCatalog().getArchetypes() );
208 }
209 }
210 else
211 {
212 throw new IllegalArgumentException( "archetypeCatalog '" + catalog + "' is not supported anymore. "
213 + "Please read the plugin documentation for details." );
214 }
215 }
216
217 if ( archetypes.size() == 0 )
218 {
219 getLogger().info( "No catalog defined. Using internal catalog" );
220
221 archetypes.put( "internal", archetypeManager.getInternalCatalog().getArchetypes() );
222 }
223 return archetypes;
224 }
225
226 private void updateRepository( ArchetypeDefinition definition, Archetype archetype )
227 {
228 String repository = archetype.getRepository();
229 if ( StringUtils.isNotEmpty( repository ) )
230 {
231 definition.setRepository( repository );
232 }
233 }
234
235 private void updateDefinition( ArchetypeDefinition definition, Archetype archetype )
236 {
237 definition.setGroupId( archetype.getGroupId() );
238 definition.setArtifactId( archetype.getArtifactId() );
239 definition.setVersion( archetype.getVersion() );
240 definition.setName( archetype.getArtifactId() );
241 updateRepository( definition, archetype );
242 definition.setGoals( StringUtils.join( archetype.getGoals().iterator(), "," ) );
243 }
244
245 public void setArchetypeSelectionQueryer( ArchetypeSelectionQueryer archetypeSelectionQueryer )
246 {
247 this.archetypeSelectionQueryer = archetypeSelectionQueryer;
248 }
249
250 private Map.Entry<String, Archetype> findArchetype( Map<String, List<Archetype>> archetypes, String groupId,
251 String artifactId )
252 {
253 Archetype example = new Archetype();
254 example.setGroupId( groupId );
255 example.setArtifactId( artifactId );
256
257 for ( Map.Entry<String, List<Archetype>> entry : archetypes.entrySet() )
258 {
259 List<Archetype> catalog = entry.getValue();
260
261 if ( catalog.contains( example ) )
262 {
263 Archetype archetype = catalog.get( catalog.indexOf( example ) );
264
265 return newMapEntry( entry.getKey(), archetype );
266 }
267 }
268
269 return null;
270 }
271
272 private static <K, V> Map.Entry<K, V> newMapEntry( K key, V value )
273 {
274 Map<K, V> map = new HashMap<>( 1 );
275 map.put( key, value );
276
277 return map.entrySet().iterator().next();
278 }
279 }