View Javadoc

1   /*
2    * Copyright (c) 2005-2007 Creative Sphere Limited.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *
10   *   Creative Sphere - initial API and implementation
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   * Module loader that loads files from maven style repository
52   *
53   * @author Daniel Sendula
54   */
55  public class MavenRepoModuleLoader extends AbstractServiceModuleLoader {
56  
57      /** Default buffer size - 10K */
58      public static final int DEFAULT_BUFFER_SIZE = 10240;
59  
60      /** Logger */
61      private final Logger logger = LoggerFactory.getLogger(MavenRepoModuleLoader.class);
62  
63      /** POM cache */
64      protected Map<String, POM> pomCache = new HashMap<String, POM>();
65  
66      /** Repositories */
67      protected Map<String, URL> repositories = new HashMap<String, URL>();
68  
69      /** Download buffer size */
70      protected int bufferSize = DEFAULT_BUFFER_SIZE;
71  
72      /** Local repository path */
73      protected File localRepository;
74  
75      /** Local path separator char */
76      private char separator = File.separatorChar;
77  
78      /**
79       * Constructor
80       */
81      public MavenRepoModuleLoader() {
82          localRepository = new File(System.getProperty("user.home"), ".m2/repository");
83          try {
84              // TODO setting up urls lasts too long. Why?
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       * Sets repositories
95       * @param repositories repositories
96       */
97      public void setRepositories(Map<String, URL> repositories) {
98      	this.repositories = repositories;
99      }
100 
101     /**
102      * Returns repositories
103      * @return repositories
104      */
105     public Map<String, URL> getRepositories() {
106     	return repositories;
107     }
108 
109     /**
110      * Stop method removes URLResolver from &quot;DefaultURLResolver&quot;.
111      */
112     public void stop() {
113         super.stop();
114 
115         pomCache.clear();
116     }
117 
118     /**
119      * This method checks if URI protocol is &quot;repo&quot; and file starts with &quot;maven&quot;. Also
120      * rest of the file must have at least two &quot;:&quot; for group id, artifact id and version. Type
121      * is assumed as jar and classifier can be empty.
122      * @param uri URI
123      * @return <code>true</code> if URI protocol is &quot;repo&quot; and file starts with &quot;maven&quot;.
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      * Loads a file from maven style repository
154      * @param uri URI
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      * Loads a file from maven style repository
168      * @param uri URI
169      * @param moduleId module id
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         // boolean updatedType = false;
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             // Try to load pom
202             pom = loadPom(artifact.toPOMArtifact());
203         } catch (IOException e) {
204             // If that fails try jar file directly
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                 // If that fails try to change the version to -SNAPSHOT
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            // updatedType = true;
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             // TODO check if early deploy is allowed
302             // We are deploying local file as repo file as well
303             deploymentManager.getDeployedModules().put(originalArtifact, module);
304 //                if (updatedType) {
305 ////                    URI updatedIdURI = new URI("repo:maven:" + artifact.getFullId());
306 //                    if (deploymentManager.getDeployedModules().containsKey(artifact)) {
307 //                        throw new RuntimeException("Overwriting existing module!");
308 //                    }
309 //                    deploymentManager.getDeployedModules().put(artifact, module);
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                 // TODO What do we do here?
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                 // TODO
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     //              if ((dependency.getVersion() == null) && (pom.getParentPOM() != null)) {
420     //                  updateDependency(pom, dependency);
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 //                    String groupId = dependency.getGroupId();
444 //                    String artifactId = dependency.getArtifactId();
445 //                    String version = dependency.getVersion();
446 //                    String type = dependency.getType();
447 //                    String classifier = dependency.getClassifier();
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                             // TODO
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                         // TODO - we do not want to download file each time!
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 //                                Artifact altArtifact = new Artifact(artifact);
619                                 String version = artifact.getVersion();
620                                 String tempVersion = version.substring(0, version.length() - 8) + snapshot.getTimestamp() + "-" + snapshot.getBuildNumber();
621 //                                altArtifact.setVersion(tempVersion);
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             // TODO
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 //            e.printStackTrace();
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      * Copies files and directories
716      * @param fromFile source file/dir
717      * @param toFile destination file/dir
718      * @return
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 }