1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.extend.repository.maven;
14
15 import java.io.File;
16 import java.io.FileInputStream;
17 import java.io.FileNotFoundException;
18 import java.io.FileOutputStream;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.MalformedURLException;
22 import java.net.URI;
23 import java.net.URISyntaxException;
24 import java.net.URL;
25 import java.nio.MappedByteBuffer;
26 import java.nio.channels.FileChannel;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.StringTokenizer;
32
33 import org.abstracthorizon.extend.repository.maven.pom.Artifact;
34 import org.abstracthorizon.extend.repository.maven.pom.Dependencies;
35 import org.abstracthorizon.extend.repository.maven.pom.Dependency;
36 import org.abstracthorizon.extend.repository.maven.pom.Exclusions;
37 import org.abstracthorizon.extend.repository.maven.pom.MavenMetadata;
38 import org.abstracthorizon.extend.repository.maven.pom.POM;
39 import org.abstracthorizon.extend.repository.maven.pom.Snapshot;
40 import org.abstracthorizon.extend.server.deployment.DeploymentManager;
41 import org.abstracthorizon.extend.server.deployment.Module;
42 import org.abstracthorizon.extend.server.deployment.ModuleId;
43 import org.abstracthorizon.extend.server.deployment.service.AbstractServiceModuleLoader;
44 import org.abstracthorizon.extend.server.deployment.support.AbstractModule;
45 import org.abstracthorizon.extend.server.deployment.support.ProvisionalModule;
46 import org.abstracthorizon.extend.server.support.URLUtils;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50
51
52
53
54
55 public class MavenRepoModuleLoader extends AbstractServiceModuleLoader {
56
57
58 public static final int DEFAULT_BUFFER_SIZE = 10240;
59
60
61 private final Logger logger = LoggerFactory.getLogger(MavenRepoModuleLoader.class);
62
63
64 protected Map<String, POM> pomCache = new HashMap<String, POM>();
65
66
67 protected Map<String, URL> repositories = new HashMap<String, URL>();
68
69
70 protected int bufferSize = DEFAULT_BUFFER_SIZE;
71
72
73 protected File localRepository;
74
75
76 private char separator = File.separatorChar;
77
78
79
80
81 public MavenRepoModuleLoader() {
82 localRepository = new File(System.getProperty("user.home"), ".m2/repository");
83 try {
84
85 repositories.put("central", new URL("http://repo1.maven.org/maven2"));
86 repositories.put("abstracthorizon", new URL("http://repository.abstracthorizon.org/maven2/abstracthorizon"));
87 repositories.put("abstracthorizon.snapshot", new URL("http://repository.abstracthorizon.org/maven2/abstracthorizon.snapshot"));
88 } catch (MalformedURLException e) {
89 throw new RuntimeException(e);
90 }
91 }
92
93
94
95
96
97 public void setRepositories(Map<String, URL> repositories) {
98 this.repositories = repositories;
99 }
100
101
102
103
104
105 public Map<String, URL> getRepositories() {
106 return repositories;
107 }
108
109
110
111
112 public void stop() {
113 super.stop();
114
115 pomCache.clear();
116 }
117
118
119
120
121
122
123
124
125 public boolean canLoad(URI uri) {
126 String f = uri.getSchemeSpecificPart();
127 String scheme = uri.getScheme();
128 if ((scheme != null) && scheme.equals("repo") && (f != null) && f.startsWith("maven:")) {
129 f = f.substring(6);
130 int i = f.indexOf(':');
131 if (i > 0) {
132 i = f.indexOf(':', i + 1);
133 if (i > 0) {
134 return true;
135 }
136 }
137 }
138 return false;
139 }
140
141 public ModuleId toModuleId(URI uri) {
142 if (canLoad(uri)) {
143 String file = uri.getSchemeSpecificPart();
144 if (file != null) {
145 Artifact artifact = parseArtifact(file.substring(6));
146 return artifact;
147 }
148 }
149 return null;
150 }
151
152
153
154
155
156 public Module load(URI uri) {
157 String file = uri.getSchemeSpecificPart();
158 if (file != null) {
159 Artifact artifact = parseArtifact(file.substring(6));
160 return loadAs(uri, artifact);
161 } else {
162 return null;
163 }
164 }
165
166
167
168
169
170
171 public Module loadAs(URI uri, ModuleId moduleId) {
172 if (!(moduleId instanceof Artifact)) {
173 moduleId = new Artifact(moduleId);
174 }
175 return loadAndDeploy((Artifact)moduleId, new HashSet<Artifact>());
176 }
177
178 public Module loadAndDeploy(Artifact artifact, Set<Artifact> excludes) {
179
180 if (artifact instanceof Dependency) {
181 artifact = new Artifact(artifact);
182 }
183
184 String originalId = artifact.getFullId();
185 Artifact originalArtifact = new Artifact(artifact);
186
187 if (logger.isDebugEnabled()) {
188 logger.debug("Loading module " + originalId);
189 }
190
191
192
193 DeploymentManager deploymentManager = getDeploymentManager();
194 Module existing = deploymentManager.getDeployedModules().get(artifact);
195 if ((existing != null) && !(existing instanceof ProvisionalModule)) {
196 return existing;
197 }
198
199 POM pom = null;
200 try {
201
202 pom = loadPom(artifact.toPOMArtifact());
203 } catch (IOException e) {
204
205 try {
206 Artifact a = artifact;
207 if (a.getType() == null) {
208 a = new Artifact(artifact);
209 a.setType("jar");
210 }
211 File localFile = createLocalFile(a);
212 downloadFile(a, localFile);
213 } catch (IOException e2) {
214
215 if (!artifact.isSnapshot()) {
216 Artifact snapshotArtifact = artifact.toSnapshotArtifact();
217 Module m = loadAndDeploy(snapshotArtifact, excludes);
218 if (m != null) {
219
220 if (!getDeploymentManager().getDeployedModules().containsKey(artifact)) {
221 getDeploymentManager().getDeployedModules().put(artifact, m);
222 }
223 if (artifact.getType() == null) {
224 try {
225 POM snapshotPOM = loadPom(snapshotArtifact.toPOMArtifact());
226 artifact.setType(snapshotPOM.getType());
227 if (artifact.getType() == null) {
228 artifact.setType("jar");
229 }
230
231 if (!getDeploymentManager().getDeployedModules().containsKey(artifact)) {
232 getDeploymentManager().getDeployedModules().put(artifact, m);
233 }
234 } catch (IOException ignore) {
235 }
236 }
237 return m;
238 } else {
239 throw new RuntimeException(e);
240 }
241 } else {
242 throw new RuntimeException(e);
243 }
244 }
245 }
246 if (artifact.getType() == null) {
247 artifact.setType(pom.getPackaging());
248 if (artifact.getType() == null) {
249 artifact.setType("jar");
250 }
251
252
253 Module m = deploymentManager.getDeployedModules().get(artifact);
254 if (m != null) {
255 deploymentManager.getDeployedModules().put(originalArtifact, m);
256 logger.info(" Found full spec artifact " + originalArtifact + ".");
257 return m;
258 }
259 if (artifact.isSnapshot()) {
260 Artifact artifact2 = artifact.toNonSnapshotArtifact();
261
262 m = deploymentManager.getDeployedModules().get(artifact2);
263 if (m != null) {
264 deploymentManager.getDeployedModules().put(originalArtifact, m);
265 logger.info(" Found final version of artifact " + artifact2.toString() + ".");
266 return m;
267 }
268 }
269
270 }
271 if (artifact.isSnapshot()) {
272 Artifact artifact2 = artifact.toNonSnapshotArtifact();
273
274 Module m = deploymentManager.getDeployedModules().get(artifact2);
275 if (m != null) {
276 deploymentManager.getDeployedModules().put(originalArtifact, m);
277 logger.info(" Found final version of artifact " + artifact2.toString() + ".");
278 return m;
279 }
280 }
281
282 File localFile = createLocalFile(artifact);
283 if (!localFile.exists()) {
284 try {
285 downloadFile(artifact, localFile);
286 } catch (IOException e) {
287 throw new RuntimeException(e);
288 }
289 }
290
291 URI localURI = localFile.toURI();
292
293 if (deploymentManager.canLoad(localURI)) {
294 Module module = deploymentManager.loadAs(localURI, artifact);
295 if (module instanceof AbstractModule) {
296 AbstractModule abstractModule = (AbstractModule)module;
297 abstractModule.setModuleId(artifact);
298 }
299 deploymentManager.deploy(artifact, module);
300
301
302
303 deploymentManager.getDeployedModules().put(originalArtifact, module);
304
305
306
307
308
309
310
311 if (pom != null) {
312 String type = pom.getPackaging();
313 if ((type == null) || !type.equals("war")) {
314 try {
315 processDependencies(pom, module, excludes);
316 } catch (IOException e) {
317 throw new RuntimeException(e);
318 }
319 }
320 }
321 return module;
322 }
323
324 return null;
325 }
326
327 public POM loadPom(Artifact pomArtifact) throws FileNotFoundException {
328
329 if (!"pom".equals(pomArtifact.getType())) {
330 if (pomArtifact.getType() == null) {
331 pomArtifact = pomArtifact.toPOMArtifact();
332 } else {
333
334 throw new RuntimeException("Tried to load " + pomArtifact + " as POM");
335 }
336 }
337 String pomId = pomArtifact.getShortId();
338
339 POM pom = pomCache.get(pomId);
340 if (pom == null) {
341 if (logger.isDebugEnabled()) {
342 logger.debug("Loading pom " + pomId);
343 }
344
345 File pomFile = createLocalFile(pomArtifact);
346 if (!pomFile.exists()) {
347 downloadFile(pomArtifact, pomFile);
348 }
349
350 pom = new POM();
351
352 try {
353 XMLProcessor processor = new XMLProcessor(pomFile);
354 processor.setStartObject(pom);
355 processor.process();
356 } catch (Exception e) {
357
358 throw new RuntimeException(e);
359 }
360
361 if (pom.getParent() != null) {
362 POM parentPom = loadPom(pom.getParent());
363 pom.setParentPOM(parentPom);
364 }
365
366
367 HashMap<String, String> properties = new HashMap<String, String>();
368 collectProperties(properties, pom);
369 if (pom.getVersion() != null) {
370 properties.put("pom.version", pom.getVersion());
371 properties.put("project.version", pom.getVersion());
372 } else {
373 properties.put("pom.version", pomArtifact.getVersion());
374 properties.put("project.version", pomArtifact.getVersion());
375 }
376 if (pom.getGroupId() != null) {
377 properties.put("pom.groupId", pom.getGroupId());
378 properties.put("project.groupId", pom.getGroupId());
379 } else {
380 properties.put("pom.groupId", pomArtifact.getGroupId());
381 properties.put("project.groupId", pomArtifact.getGroupId());
382 }
383 if (pom.getArtifactId() != null) {
384 properties.put("pom.artifactId", pom.getArtifactId());
385 properties.put("project.artifactId", pom.getArtifactId());
386 } else {
387 properties.put("pom.artifactId", pomArtifact.getArtifactId());
388 properties.put("project.artifactId", pomArtifact.getArtifactId());
389 }
390 SubstitutionTraverser.substitute(pom, properties);
391
392 pomCache.put(pomId, pom);
393 }
394 return pom;
395 }
396
397 protected void collectProperties(Map<String, String> properties, POM pom) {
398 Map<String, String> p = pom.getProperties();
399 if (p != null) {
400 for (Map.Entry<String, String> entry : p.entrySet()) {
401 properties.put(entry.getKey(), entry.getValue());
402 }
403 }
404 POM parent = pom.getParentPOM();
405 if (parent != null) {
406 collectProperties(properties, parent);
407 }
408 }
409
410 public void processDependencies(POM pom, Module module, Set<Artifact> excludes) throws FileNotFoundException {
411 long started = 0;
412 if (logger.isDebugEnabled()) {
413 logger.debug(" Processing dependencies for " + module.getModuleId());
414 started = System.currentTimeMillis();
415 }
416 Dependencies dependencies = pom.getDependencies();
417 if (dependencies != null) {
418 for (Dependency dependency : dependencies.getDependencies()) {
419
420
421
422 if (pom.getParentPOM() != null) {
423 updateDependency(pom, dependency);
424 }
425
426 String scope = dependency.getScope();
427 if (((scope == null)
428 || scope.equals("runtime")
429 || scope.equals("compile"))
430 && !excludesContain(excludes, dependency)) {
431
432 if (logger.isDebugEnabled()) {
433 logger.debug(" Dependency " + dependency.getFullId() + " as " + scope);
434 }
435
436 Set<Artifact> innerExcludes = excludes;
437 if (dependency.getExclusions() != null) {
438 innerExcludes = new HashSet<Artifact>();
439 innerExcludes.addAll(excludes);
440 innerExcludes.addAll(dependency.getExclusions().getExclusions());
441 }
442
443
444
445
446
447
448 try {
449 POM dependendPom = loadPom(dependency.toPOMArtifact());
450 if (dependency.getType() == null) {
451 dependency.setType(dependendPom.getPackaging());
452 }
453
454 URI moduleURI = null;
455 try {
456 moduleURI = new URI("repo:maven:" + dependency.getFullId());
457 } catch (URISyntaxException e) {
458 throw new RuntimeException(e);
459 }
460
461 Module m;
462 if (!deploymentManager.getDeployedModules().containsKey(dependency)) {
463
464 m = loadAndDeploy(dependency, innerExcludes);
465 if (m != null) {
466 if (!deploymentManager.getDeployedModules().containsValue(m)) {
467 deploymentManager.deploy(dependency, m);
468 } else if (!deploymentManager.getDeployedModules().containsKey(dependency)) {
469 Artifact a = new Artifact(dependency);
470 deploymentManager.getDeployedModules().put(a, m);
471 } else {
472 if (logger.isDebugEnabled()) {
473 logger.debug("Module " + m.getModuleId() + " at " + dependency + " already exists");
474 }
475 }
476 } else {
477 if (logger.isDebugEnabled()) {
478 logger.debug(" " + dependency);
479 }
480
481 m = getDeploymentManager().loadAndDeploy(moduleURI);
482 }
483 } else {
484 m = deploymentManager.getDeployedModules().get(dependency);
485 }
486 if (m == null) {
487
488 throw new RuntimeException("Couldn't load " + moduleURI);
489 }
490 module.getDependsOn().add(m);
491 m.getDependOnThis().add(module);
492 } catch (FileNotFoundException e) {
493 if (!"true".equalsIgnoreCase(dependency.getOptional())) {
494 throw e;
495 }
496 }
497 }
498 }
499 }
500 if (logger.isDebugEnabled()) {
501 logger.debug(" Processed dependencies for " + module.getModuleId() + "(" + Long.toString(System.currentTimeMillis() - started) + "ms)");
502 }
503 }
504
505 public void updateDependency(POM pom, Dependency dependency) {
506 Dependency managedDependency = pom.findManagedDependency(dependency.getGroupId(), dependency.getArtifactId());
507 if (managedDependency != null) {
508 if (dependency.getVersion() == null) {
509 dependency.setVersion(managedDependency.getVersion());
510 }
511 if (dependency.getScope() == null) {
512 dependency.setScope(managedDependency.getScope());
513 }
514 if (dependency.getType() == null) {
515 dependency.setType(managedDependency.getType());
516 }
517 if (dependency.getClassifier() == null) {
518 dependency.setClassifier(managedDependency.getClassifier());
519 }
520 if (managedDependency.getExclusions() != null) {
521 if (dependency.getExclusions() != null) {
522 Exclusions exclusions = dependency.getExclusions();
523 exclusions.getExclusions().addAll(managedDependency.getExclusions().getExclusions());
524 } else {
525 Exclusions exclusions = dependency.addExclusions();
526 exclusions.getExclusions().addAll(managedDependency.getExclusions().getExclusions());
527 }
528 }
529 } else {
530 if (dependency.getVersion() == null) {
531 throw new RuntimeException("No defined managed dependency for " + dependency.getGroupId() + ":" + dependency.getArtifactId());
532 }
533 }
534 }
535
536 public static boolean excludesContain(Set<Artifact> excludes, Dependency dependency) {
537 for (Artifact artifact : excludes) {
538 if (artifact.getGroupId().equals(dependency.getGroupId())) {
539 if (artifact.getArtifactId().equals(dependency.getArtifactId())) {
540 if ((artifact.getVersion() == null)
541 || (dependency.getVersion() == null)
542 || artifact.getVersion().equals(dependency.getVersion())) {
543
544 if ((artifact.getType() == null)
545 || (dependency.getType() == null)
546 || artifact.getType().equals(dependency.getType())) {
547
548 if ((artifact.getClassifier() == null)
549 || (dependency.getClassifier() == null)
550 || artifact.getClassifier().equals(dependency.getClassifier())) {
551 return true;
552 }
553 }
554 }
555 }
556 }
557 }
558 return false;
559 }
560
561 public File createLocalFile(Artifact artifact) {
562 StringBuffer fileName = new StringBuffer();
563 fileName.append(artifact.getGroupId().replace('.', separator)).append(separator);
564 fileName.append(artifact.getArtifactId()).append(separator);
565 fileName.append(artifact.getVersion()).append(separator);
566 fileName.append(artifact.getArtifactId()).append('-').append(artifact.getVersion());
567 if (artifact.getClassifier() != null) {
568 fileName.append('-').append(artifact.getClassifier());
569 }
570 fileName.append('.').append(artifact.getType());
571
572 File repository = new File(System.getProperty("user.home"), ".m2/repository");
573 File localFile = new File(repository, fileName.toString());
574 return localFile;
575 }
576
577 public File createLocalFile(Artifact artifact, String file) {
578 StringBuffer fileName = new StringBuffer();
579 fileName.append(artifact.getGroupId().replace('.', separator)).append(separator);
580 fileName.append(artifact.getArtifactId()).append(separator);
581 fileName.append(artifact.getVersion()).append(separator);
582 fileName.append(file);
583
584 File repository = new File(System.getProperty("user.home"), ".m2/repository");
585 File localFile = new File(repository, fileName.toString());
586 return localFile;
587 }
588
589 public void downloadFile(Artifact artifact, File toFile) throws FileNotFoundException {
590 for (Map.Entry<String, URL> entry : repositories.entrySet()) {
591 try {
592 downloadFile(entry.getValue(), artifact, toFile);
593 return;
594 } catch (FileNotFoundException e1) {
595 if (artifact.isSnapshot()) {
596 try {
597 File file = createLocalFile(artifact, "maven-metadata-" + entry.getKey() + ".xml");
598
599
600 URL url = URLUtils.add(entry.getValue(), artifact.getGroupId().replace('.', '/') + '/' + artifact.getArtifactId() + '/' + artifact.getVersion() + "/maven-metadata.xml");
601 downloadFile(url, file);
602
603 MavenMetadata mavenMetadata = new MavenMetadata();
604 try {
605 XMLProcessor processor = new XMLProcessor(file);
606 processor.setStartObject(mavenMetadata);
607 processor.process();
608 } catch (Exception e3) {
609 throw new RuntimeException(e3);
610 }
611 if ((mavenMetadata.getVersioning() != null)
612 && (mavenMetadata.getVersioning().getSnapshot() != null)) {
613
614 Snapshot snapshot = mavenMetadata.getVersioning().getSnapshot();
615 if ((snapshot.getBuildNumber() != null)
616 && (snapshot.getTimestamp() != null)) {
617
618
619 String version = artifact.getVersion();
620 String tempVersion = version.substring(0, version.length() - 8) + snapshot.getTimestamp() + "-" + snapshot.getBuildNumber();
621
622 File tempFile = createLocalFile(artifact);
623 if (!tempFile.exists()) {
624 downloadFile(entry.getValue(), artifact, tempVersion, tempFile);
625 }
626
627 if (!toFile.equals(tempFile)) {
628 copyFile(tempFile, toFile);
629 }
630 return;
631 }
632 }
633 } catch (FileNotFoundException i2) {
634 } catch (MalformedURLException e2) {
635 throw new RuntimeException(e2);
636 }
637 }
638 }
639 }
640 throw new FileNotFoundException("Cannot download artifact " + artifact.getFullId());
641 }
642
643 public void downloadFile(URL url, Artifact artifact, File toFile) throws FileNotFoundException {
644 downloadFile(url, artifact, artifact.getVersion(), toFile);
645 }
646
647 public void downloadFile(URL url, Artifact artifact, String altVersion, File toFile) throws FileNotFoundException {
648 try {
649 StringBuffer path = new StringBuffer();
650 path.append(artifact.getGroupId().replace('.', '/')).append('/').append(artifact.getArtifactId()).append('/').append(artifact.getVersion()).append('/');
651 path.append(artifact.getArtifactId()).append('-').append(altVersion);
652 if (artifact.getClassifier() != null) {
653 path.append('-').append(artifact.getClassifier());
654 }
655 path.append('.').append(artifact.getType());
656 URL finalURL = URLUtils.add(url, path.toString());
657
658
659 if (logger.isDebugEnabled()) {
660 logger.info("Downloading from " + finalURL.toString());
661 }
662 downloadFile(finalURL, toFile);
663 } catch (MalformedURLException e) {
664 throw new RuntimeException(e);
665 }
666 }
667
668 protected void downloadFile(URL url, File file) throws FileNotFoundException {
669 try {
670 InputStream input = url.openStream();
671 try {
672 File parent = file.getParentFile();
673 if (!parent.exists()) {
674 if (!parent.mkdirs()) {
675 throw new RuntimeException("Cannot create directory " + parent.getAbsolutePath());
676 }
677 }
678 FileOutputStream output = new FileOutputStream(file);
679 try {
680 byte[] buffer = new byte[bufferSize];
681 int r = input.read(buffer);
682 while (r > 0) {
683 output.write(buffer, 0, r);
684 r = input.read(buffer);
685 }
686 } finally {
687 output.close();
688 }
689 } finally {
690 input.close();
691 }
692 } catch (IOException e) {
693
694 throw new FileNotFoundException(url.toString());
695 }
696 }
697
698 public static Artifact parseArtifact(String fileId) {
699 Artifact artifact = new Artifact();
700 StringTokenizer tokenizer = new StringTokenizer(fileId, ":");
701 artifact.setGroupId(tokenizer.nextToken());
702 artifact.setArtifactId(tokenizer.nextToken());
703 artifact.setVersion(tokenizer.nextToken());
704 if (tokenizer.hasMoreTokens()) {
705 artifact.setType(tokenizer.nextToken());
706 }
707 if (tokenizer.hasMoreTokens()) {
708 artifact.setClassifier(tokenizer.nextToken());
709 }
710
711 return artifact;
712 }
713
714
715
716
717
718
719
720 public static boolean copyFile(File fromFile, File toFile) {
721 if (!toFile.equals(fromFile)) {
722 try {
723 FileInputStream fromInputStream = new FileInputStream(fromFile);
724 try {
725 FileOutputStream toOutputStream = new FileOutputStream(toFile);
726 try {
727 FileChannel inChannel = fromInputStream.getChannel();
728 try {
729 FileChannel outChannel = toOutputStream.getChannel();
730 try {
731 MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
732
733 outChannel.write(buffer);
734 } finally {
735 outChannel.close();
736 }
737 } finally {
738 inChannel.close();
739 }
740 } finally {
741 toOutputStream.close();
742 }
743 } finally {
744 fromInputStream.close();
745 }
746 return true;
747 } catch (IOException exc) {
748 return false;
749 }
750 } else {
751 return true;
752 }
753 }
754 }