1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.archetype.common;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.File;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.io.Reader;
30 import java.net.MalformedURLException;
31 import java.net.URL;
32 import java.net.URLClassLoader;
33 import java.nio.charset.StandardCharsets;
34 import java.util.ArrayList;
35 import java.util.Enumeration;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.TreeMap;
39 import java.util.zip.ZipEntry;
40 import java.util.zip.ZipFile;
41
42 import org.apache.commons.io.IOUtils;
43 import org.apache.maven.archetype.downloader.DownloadException;
44 import org.apache.maven.archetype.downloader.Downloader;
45 import org.apache.maven.archetype.exception.UnknownArchetype;
46 import org.apache.maven.archetype.metadata.ArchetypeDescriptor;
47 import org.apache.maven.archetype.metadata.io.xpp3.ArchetypeDescriptorXpp3Reader;
48 import org.apache.maven.archetype.old.descriptor.ArchetypeDescriptorBuilder;
49 import org.apache.maven.model.Model;
50 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
51 import org.eclipse.aether.RepositorySystemSession;
52 import org.eclipse.aether.repository.RemoteRepository;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 @Named
57 @Singleton
58 public class DefaultArchetypeArtifactManager implements ArchetypeArtifactManager {
59 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultArchetypeArtifactManager.class);
60
61 @Inject
62 private Downloader downloader;
63
64 @Inject
65 private PomManager pomManager;
66
67 private Map<String, File> archetypeCache = new TreeMap<>();
68
69 @Override
70 public File getArchetypeFile(
71 final String groupId,
72 final String artifactId,
73 final String version,
74 final List<RemoteRepository> repositories,
75 RepositorySystemSession repositorySystemSession)
76 throws UnknownArchetype {
77 try {
78 File archetype = getArchetype(groupId, artifactId, version);
79
80 if (archetype == null) {
81 archetype = downloader.download(groupId, artifactId, version, repositories, repositorySystemSession);
82
83 setArchetype(groupId, artifactId, version, archetype);
84 }
85 return archetype;
86 } catch (DownloadException ex) {
87 throw new UnknownArchetype(ex);
88 }
89 }
90
91 @Override
92 public ClassLoader getArchetypeJarLoader(File archetypeFile) throws UnknownArchetype {
93 try {
94 URL[] urls = new URL[1];
95
96 urls[0] = archetypeFile.toURI().toURL();
97
98 return new URLClassLoader(urls);
99 } catch (MalformedURLException e) {
100 throw new UnknownArchetype(e);
101 }
102 }
103
104 @Override
105 public Model getArchetypePom(File jar) throws XmlPullParserException, UnknownArchetype, IOException {
106
107 try (ZipFile zipFile = getArchetypeZipFile(jar)) {
108 String pomFileName = null;
109
110 Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
111 while (enumeration.hasMoreElements()) {
112 ZipEntry el = enumeration.nextElement();
113
114 String entry = el.getName();
115 if (entry.startsWith("META-INF") && entry.endsWith("pom.xml")) {
116 pomFileName = entry;
117 }
118 }
119
120 if (pomFileName == null) {
121 return null;
122 }
123
124 ZipEntry pom = zipFile.getEntry(pomFileName);
125
126 if (pom == null) {
127 return null;
128 }
129 return pomManager.readPom(zipFile.getInputStream(pom));
130 }
131 }
132
133 @Override
134 public ZipFile getArchetypeZipFile(File archetypeFile) throws UnknownArchetype {
135 try {
136 return new ZipFile(archetypeFile);
137 } catch (IOException e) {
138 throw new UnknownArchetype(e);
139 }
140 }
141
142 @Override
143 public boolean isFileSetArchetype(File archetypeFile) {
144 LOGGER.debug("checking fileset archetype status on " + archetypeFile);
145
146 try (ZipFile zipFile = getArchetypeZipFile(archetypeFile)) {
147 return isFileSetArchetype(zipFile);
148 } catch (IOException | UnknownArchetype e) {
149 LOGGER.debug(e.toString());
150 return false;
151 }
152 }
153
154 @Override
155 public boolean isOldArchetype(File archetypeFile) {
156 LOGGER.debug("checking old archetype status on " + archetypeFile);
157
158 try (ZipFile zipFile = getArchetypeZipFile(archetypeFile)) {
159 return isOldArchetype(zipFile);
160 } catch (IOException | UnknownArchetype e) {
161 LOGGER.debug(e.toString());
162 return false;
163 }
164 }
165
166 @Override
167 public boolean exists(
168 String archetypeGroupId,
169 String archetypeArtifactId,
170 String archetypeVersion,
171 List<RemoteRepository> remoteRepositories,
172 RepositorySystemSession repositorySystemSession) {
173 try {
174 File archetype = getArchetype(archetypeGroupId, archetypeArtifactId, archetypeVersion);
175 if (archetype == null) {
176 archetype = downloader.download(
177 archetypeGroupId,
178 archetypeArtifactId,
179 archetypeVersion,
180 remoteRepositories,
181 repositorySystemSession);
182 setArchetype(archetypeGroupId, archetypeArtifactId, archetypeVersion, archetype);
183 }
184
185 return archetype.exists();
186 } catch (DownloadException e) {
187 LOGGER.debug(
188 "Archetype " + archetypeGroupId + ":" + archetypeArtifactId + ":" + archetypeVersion
189 + " doesn't exist",
190 e);
191 return false;
192 }
193 }
194
195 @Override
196 public String getPostGenerationScript(File archetypeFile) throws UnknownArchetype {
197 try (ZipFile zipFile = getArchetypeZipFile(archetypeFile)) {
198 Reader reader = getDescriptorReader(zipFile, Constants.ARCHETYPE_POST_GENERATION_SCRIPT);
199 return reader == null ? null : IOUtils.toString(reader);
200 } catch (IOException e) {
201 throw new UnknownArchetype(e);
202 }
203 }
204
205 @Override
206 public ArchetypeDescriptor getFileSetArchetypeDescriptor(File archetypeFile) throws UnknownArchetype {
207 try (ZipFile zipFile = getArchetypeZipFile(archetypeFile)) {
208 return loadFileSetArchetypeDescriptor(zipFile);
209 } catch (XmlPullParserException | IOException e) {
210 throw new UnknownArchetype(e);
211 }
212 }
213
214 @Override
215 public List<String> getFilesetArchetypeResources(File archetypeFile) throws UnknownArchetype {
216 LOGGER.debug("getFilesetArchetypeResources( \"" + archetypeFile.getAbsolutePath() + "\" )");
217 List<String> archetypeResources = new ArrayList<>();
218
219 try (ZipFile zipFile = getArchetypeZipFile(archetypeFile)) {
220 Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
221 while (enumeration.hasMoreElements()) {
222 ZipEntry entry = enumeration.nextElement();
223
224 if (entry.getName().startsWith(Constants.ARCHETYPE_RESOURCES)) {
225
226 String resource = entry.getName().substring(Constants.ARCHETYPE_RESOURCES.length() + 1);
227 LOGGER.debug(" - found resource (" + Constants.ARCHETYPE_RESOURCES + "/)" + resource);
228
229 archetypeResources.add(resource);
230 } else {
231 LOGGER.debug(" - ignored resource " + entry.getName());
232 }
233 }
234 return archetypeResources;
235 } catch (IOException e) {
236 throw new UnknownArchetype(e);
237 }
238 }
239
240 @Override
241 public org.apache.maven.archetype.old.descriptor.ArchetypeDescriptor getOldArchetypeDescriptor(File archetypeFile)
242 throws UnknownArchetype {
243 try (ZipFile zipFile = getArchetypeZipFile(archetypeFile)) {
244 return loadOldArchetypeDescriptor(zipFile);
245 } catch (XmlPullParserException | IOException e) {
246 throw new UnknownArchetype(e);
247 }
248 }
249
250 private File getArchetype(String archetypeGroupId, String archetypeArtifactId, String archetypeVersion) {
251 String key = archetypeGroupId + ":" + archetypeArtifactId + ":" + archetypeVersion;
252
253 if (archetypeCache.containsKey(key)) {
254 LOGGER.debug("Found archetype " + key + " in cache: " + archetypeCache.get(key));
255
256 return archetypeCache.get(key);
257 }
258
259 LOGGER.debug("Not found archetype " + key + " in cache");
260 return null;
261 }
262
263 private void setArchetype(
264 String archetypeGroupId, String archetypeArtifactId, String archetypeVersion, File archetype) {
265 String key = archetypeGroupId + ":" + archetypeArtifactId + ":" + archetypeVersion;
266
267 archetypeCache.put(key, archetype);
268 }
269
270 private boolean isFileSetArchetype(ZipFile zipFile) throws IOException {
271 try (Reader reader = getArchetypeDescriptorReader(zipFile)) {
272 return (reader != null);
273 }
274 }
275
276 private boolean isOldArchetype(ZipFile zipFile) throws IOException {
277 try (Reader reader = getOldArchetypeDescriptorReader(zipFile)) {
278 return (reader != null);
279 }
280 }
281
282 private org.apache.maven.archetype.metadata.ArchetypeDescriptor loadFileSetArchetypeDescriptor(ZipFile zipFile)
283 throws IOException, XmlPullParserException {
284
285 try (Reader reader = getArchetypeDescriptorReader(zipFile)) {
286 if (reader == null) {
287 return null;
288 }
289
290 ArchetypeDescriptorXpp3Reader archetypeReader = new ArchetypeDescriptorXpp3Reader();
291 return archetypeReader.read(reader, false);
292 } catch (IOException | XmlPullParserException e) {
293 throw e;
294 }
295 }
296
297 private org.apache.maven.archetype.old.descriptor.ArchetypeDescriptor loadOldArchetypeDescriptor(ZipFile zipFile)
298 throws IOException, XmlPullParserException {
299 try (Reader reader = getOldArchetypeDescriptorReader(zipFile)) {
300 if (reader == null) {
301 return null;
302 }
303
304 ArchetypeDescriptorBuilder builder = new ArchetypeDescriptorBuilder();
305 return builder.build(reader);
306 }
307 }
308
309 private Reader getArchetypeDescriptorReader(ZipFile zipFile) throws IOException {
310 return getDescriptorReader(zipFile, Constants.ARCHETYPE_DESCRIPTOR);
311 }
312
313 private Reader getOldArchetypeDescriptorReader(ZipFile zipFile) throws IOException {
314 Reader reader = getDescriptorReader(zipFile, Constants.OLD_ARCHETYPE_DESCRIPTOR);
315
316 if (reader == null) {
317 reader = getDescriptorReader(zipFile, Constants.OLDER_ARCHETYPE_DESCRIPTOR);
318 }
319
320 return reader;
321 }
322
323 private Reader getDescriptorReader(ZipFile zipFile, String descriptor) throws IOException {
324 ZipEntry entry = searchEntry(zipFile, descriptor);
325
326 if (entry == null) {
327 return null;
328 }
329
330 InputStream is = zipFile.getInputStream(entry);
331
332 if (is == null) {
333 throw new IOException("The " + descriptor + " descriptor cannot be read in " + zipFile.getName() + ".");
334 }
335
336 return new InputStreamReader(is, StandardCharsets.UTF_8);
337 }
338
339 private ZipEntry searchEntry(ZipFile zipFile, String searchString) {
340 LOGGER.debug("Searching for " + searchString + " inside " + zipFile.getName());
341
342 Enumeration<? extends ZipEntry> enu = zipFile.entries();
343 while (enu.hasMoreElements()) {
344 ZipEntry entryfound = enu.nextElement();
345 LOGGER.debug(" - " + entryfound.getName());
346
347 if (searchString.equals(entryfound.getName())) {
348 LOGGER.debug("Entry found");
349 return entryfound;
350 }
351 }
352 return null;
353 }
354 }