1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.archetype.ui.generation;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.util.HashMap;
26 import java.util.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.maven.archetype.ArchetypeGenerationRequest;
32 import org.apache.maven.archetype.ArchetypeManager;
33 import org.apache.maven.archetype.catalog.Archetype;
34 import org.apache.maven.archetype.exception.ArchetypeSelectionFailure;
35 import org.apache.maven.archetype.ui.ArchetypeDefinition;
36 import org.codehaus.plexus.components.interactivity.PrompterException;
37 import org.eclipse.aether.RepositorySystemSession;
38 import org.eclipse.aether.repository.RemoteRepository;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 @Named("default")
43 @Singleton
44 public class DefaultArchetypeSelector implements ArchetypeSelector {
45 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultArchetypeSelector.class);
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 private ArchetypeSelectionQueryer archetypeSelectionQueryer;
53
54 private ArchetypeManager archetypeManager;
55
56 @Inject
57 public DefaultArchetypeSelector(
58 ArchetypeSelectionQueryer archetypeSelectionQueryer, ArchetypeManager archetypeManager) {
59 this.archetypeManager = archetypeManager;
60 this.archetypeSelectionQueryer = archetypeSelectionQueryer;
61 }
62
63 @Override
64 public void selectArchetype(ArchetypeGenerationRequest request, Boolean interactiveMode, String catalogs)
65 throws PrompterException, ArchetypeSelectionFailure {
66 ArchetypeDefinition definition = new ArchetypeDefinition(request);
67
68 if (definition.isDefined() && StringUtils.isNotEmpty(request.getArchetypeRepository())) {
69 LOGGER.info("Archetype defined by properties");
70 return;
71 }
72
73 Map<String, List<Archetype>> archetypes =
74 getArchetypesByCatalog(request.getRepositorySession(), request.getRemoteRepositories(), catalogs);
75
76 if (StringUtils.isNotBlank(request.getFilter())) {
77
78 archetypes = ArchetypeSelectorUtils.getFilteredArchetypesByCatalog(archetypes, request.getFilter());
79 if (archetypes.isEmpty()) {
80 LOGGER.info("Your filter doesn't match any archetype, so try again with another value.");
81 return;
82 }
83 }
84
85 if (definition.isDefined()) {
86 Map.Entry<String, Archetype> found =
87 findArchetype(archetypes, request.getArchetypeGroupId(), request.getArchetypeArtifactId());
88
89 if (found != null) {
90 String catalogKey = found.getKey();
91 Archetype archetype = found.getValue();
92
93 updateRepository(definition, archetype);
94
95 LOGGER.info("Archetype repository not defined. Using the one from " + archetype + " found in catalog "
96 + catalogKey);
97 } else {
98 LOGGER.warn("Archetype not found in any catalog. Falling back to central repository.");
99 LOGGER.warn(
100 "Add a repository with id 'archetype' in your settings.xml if archetype's repository is elsewhere.");
101 }
102 } else if (definition.isPartiallyDefined()) {
103 Map.Entry<String, Archetype> found =
104 findArchetype(archetypes, request.getArchetypeGroupId(), request.getArchetypeArtifactId());
105
106 if (found != null) {
107 String catalogKey = found.getKey();
108 Archetype archetype = found.getValue();
109
110 updateDefinition(definition, archetype);
111
112 LOGGER.info("Archetype " + archetype + " found in catalog " + catalogKey);
113 } else {
114 LOGGER.warn("Specified archetype not found.");
115 if (interactiveMode.booleanValue()) {
116 definition.setVersion(null);
117 definition.setGroupId(null);
118 definition.setArtifactId(null);
119 }
120 }
121 }
122
123
124 if (definition.getGroupId() == null) {
125 definition.setGroupId(DEFAULT_ARCHETYPE_GROUPID);
126 }
127 if (definition.getVersion() == null) {
128 definition.setVersion(DEFAULT_ARCHETYPE_VERSION);
129 }
130
131 if (!definition.isPartiallyDefined()) {
132
133 if (definition.getArtifactId() == null) {
134 LOGGER.info("No archetype defined. Using " + DEFAULT_ARCHETYPE_ARTIFACTID + " ("
135 + definition.getGroupId() + ":" + DEFAULT_ARCHETYPE_ARTIFACTID + ":"
136 + definition.getVersion() + ")");
137 definition.setArtifactId(DEFAULT_ARCHETYPE_ARTIFACTID);
138 }
139
140 if (interactiveMode.booleanValue() && (!archetypes.isEmpty())) {
141 Archetype selectedArchetype = archetypeSelectionQueryer.selectArchetype(archetypes, definition);
142
143 updateDefinition(definition, selectedArchetype);
144 }
145
146
147
148 if (!definition.isPartiallyDefined()) {
149 throw new ArchetypeSelectionFailure("No valid archetypes could be found to choose.");
150 }
151 }
152
153
154 definition.updateRequest(request);
155 }
156
157 private Map<String, List<Archetype>> getArchetypesByCatalog(
158 RepositorySystemSession repositorySession, List<RemoteRepository> remoteRepositories, String catalogs) {
159 if (catalogs == null) {
160 throw new NullPointerException("Catalogs cannot be null");
161 }
162
163 Map<String, List<Archetype>> archetypes = new LinkedHashMap<>();
164
165 for (String catalog : StringUtils.split(catalogs, ",")) {
166 if ("internal".equalsIgnoreCase(catalog)) {
167 archetypes.put("internal", archetypeManager.getInternalCatalog().getArchetypes());
168 } else if ("local".equalsIgnoreCase(catalog)) {
169 archetypes.put(
170 "local",
171 archetypeManager.getLocalCatalog(repositorySession).getArchetypes());
172 } else if ("remote".equalsIgnoreCase(catalog)) {
173 List<Archetype> archetypesFromRemote = archetypeManager
174 .getRemoteCatalog(repositorySession, remoteRepositories)
175 .getArchetypes();
176
177 if (!archetypesFromRemote.isEmpty()) {
178 archetypes.put("remote", archetypesFromRemote);
179 } else {
180 LOGGER.warn("No archetype found in remote catalog. Defaulting to internal catalog");
181 archetypes.put(
182 "internal", archetypeManager.getInternalCatalog().getArchetypes());
183 }
184 } else {
185 throw new IllegalArgumentException("archetypeCatalog '" + catalog + "' is not supported anymore. "
186 + "Please read the plugin documentation for details.");
187 }
188 }
189
190 if (archetypes.isEmpty()) {
191 LOGGER.info("No catalog defined. Using internal catalog");
192
193 archetypes.put("internal", archetypeManager.getInternalCatalog().getArchetypes());
194 }
195 return archetypes;
196 }
197
198 private void updateRepository(ArchetypeDefinition definition, Archetype archetype) {
199 String repository = archetype.getRepository();
200 if (repository != null && !repository.isEmpty()) {
201 definition.setRepository(repository);
202 }
203 }
204
205 private void updateDefinition(ArchetypeDefinition definition, Archetype archetype) {
206 definition.setGroupId(archetype.getGroupId());
207 definition.setArtifactId(archetype.getArtifactId());
208 definition.setVersion(archetype.getVersion());
209 definition.setName(archetype.getArtifactId());
210 updateRepository(definition, archetype);
211 definition.setGoals(StringUtils.join(archetype.getGoals().iterator(), ","));
212 }
213
214 public void setArchetypeSelectionQueryer(ArchetypeSelectionQueryer archetypeSelectionQueryer) {
215 this.archetypeSelectionQueryer = archetypeSelectionQueryer;
216 }
217
218 private Map.Entry<String, Archetype> findArchetype(
219 Map<String, List<Archetype>> archetypes, String groupId, String artifactId) {
220 Archetype example = new Archetype();
221 example.setGroupId(groupId);
222 example.setArtifactId(artifactId);
223
224 for (Map.Entry<String, List<Archetype>> entry : archetypes.entrySet()) {
225 List<Archetype> catalog = entry.getValue();
226
227 if (catalog.contains(example)) {
228 Archetype archetype = catalog.get(catalog.indexOf(example));
229
230 return newMapEntry(entry.getKey(), archetype);
231 }
232 }
233
234 return null;
235 }
236
237 private static <K, V> Map.Entry<K, V> newMapEntry(K key, V value) {
238 Map<K, V> map = new HashMap<>(1);
239 map.put(key, value);
240
241 return map.entrySet().iterator().next();
242 }
243 }