001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.ivy.plugins.resolver;
019:
020: import java.io.File;
021: import java.io.FileInputStream;
022: import java.io.IOException;
023: import java.net.URL;
024: import java.text.ParseException;
025: import java.text.SimpleDateFormat;
026: import java.util.ArrayList;
027: import java.util.Collection;
028: import java.util.Collections;
029: import java.util.Date;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.ListIterator;
034: import java.util.Map;
035:
036: import org.apache.ivy.core.IvyContext;
037: import org.apache.ivy.core.IvyPatternHelper;
038: import org.apache.ivy.core.LogOptions;
039: import org.apache.ivy.core.cache.ArtifactOrigin;
040: import org.apache.ivy.core.cache.CacheDownloadOptions;
041: import org.apache.ivy.core.cache.CacheMetadataOptions;
042: import org.apache.ivy.core.cache.DownloadListener;
043: import org.apache.ivy.core.cache.ModuleDescriptorWriter;
044: import org.apache.ivy.core.cache.RepositoryCacheManager;
045: import org.apache.ivy.core.event.EventManager;
046: import org.apache.ivy.core.event.download.EndArtifactDownloadEvent;
047: import org.apache.ivy.core.event.download.NeedArtifactEvent;
048: import org.apache.ivy.core.event.download.StartArtifactDownloadEvent;
049: import org.apache.ivy.core.module.descriptor.Artifact;
050: import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor;
051: import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
052: import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
053: import org.apache.ivy.core.module.id.ModuleId;
054: import org.apache.ivy.core.module.id.ModuleRevisionId;
055: import org.apache.ivy.core.report.ArtifactDownloadReport;
056: import org.apache.ivy.core.report.DownloadReport;
057: import org.apache.ivy.core.report.DownloadStatus;
058: import org.apache.ivy.core.report.MetadataArtifactDownloadReport;
059: import org.apache.ivy.core.resolve.DownloadOptions;
060: import org.apache.ivy.core.resolve.IvyNode;
061: import org.apache.ivy.core.resolve.ResolveData;
062: import org.apache.ivy.core.resolve.ResolvedModuleRevision;
063: import org.apache.ivy.core.search.ModuleEntry;
064: import org.apache.ivy.core.search.OrganisationEntry;
065: import org.apache.ivy.core.search.RevisionEntry;
066: import org.apache.ivy.plugins.parser.ModuleDescriptorParser;
067: import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry;
068: import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser;
069: import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter;
070: import org.apache.ivy.plugins.repository.ArtifactResourceResolver;
071: import org.apache.ivy.plugins.repository.Resource;
072: import org.apache.ivy.plugins.repository.ResourceDownloader;
073: import org.apache.ivy.plugins.repository.url.URLRepository;
074: import org.apache.ivy.plugins.repository.url.URLResource;
075: import org.apache.ivy.plugins.resolver.util.MDResolvedResource;
076: import org.apache.ivy.plugins.resolver.util.ResolvedResource;
077: import org.apache.ivy.plugins.resolver.util.ResourceMDParser;
078: import org.apache.ivy.util.ChecksumHelper;
079: import org.apache.ivy.util.HostUtil;
080: import org.apache.ivy.util.Message;
081:
082: /**
083: *
084: */
085: public abstract class BasicResolver extends AbstractResolver {
086: public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(
087: "yyyyMMddHHmmss");
088:
089: private String workspaceName;
090:
091: /**
092: * True if the files resolved are dependent of the environment from which they have been
093: * resolved, false otherwise. In general, relative paths are dependent of the environment, and
094: * absolute paths including machine reference are not.
095: */
096: private boolean envDependent = true;
097:
098: private List ivyattempts = new ArrayList();
099:
100: private Map artattempts = new HashMap();
101:
102: private boolean checkconsistency = true;
103:
104: private boolean allownomd = true;
105:
106: private String checksums = null;
107:
108: private URLRepository extartifactrep = new URLRepository(); // used only to download
109:
110: // external artifacts
111:
112: public BasicResolver() {
113: workspaceName = HostUtil.getLocalHostName();
114: }
115:
116: public String getWorkspaceName() {
117: return workspaceName;
118: }
119:
120: public void setWorkspaceName(String workspaceName) {
121: this .workspaceName = workspaceName;
122: }
123:
124: public boolean isEnvDependent() {
125: return envDependent;
126: }
127:
128: public void setEnvDependent(boolean envDependent) {
129: this .envDependent = envDependent;
130: }
131:
132: public ResolvedModuleRevision getDependency(
133: DependencyDescriptor dde, ResolveData data)
134: throws ParseException {
135: IvyContext context = IvyContext.pushNewCopyContext();
136: DependencyDescriptor systemDd = dde;
137: DependencyDescriptor nsDd = fromSystem(dde);
138: context.setDependencyDescriptor(systemDd);
139: context.setResolveData(data);
140: try {
141: clearIvyAttempts();
142: clearArtifactAttempts();
143: ModuleRevisionId systemMrid = systemDd
144: .getDependencyRevisionId();
145: ModuleRevisionId nsMrid = nsDd.getDependencyRevisionId();
146:
147: // check revision
148: int index = systemMrid.getRevision().indexOf("@");
149: if (index != -1
150: && !systemMrid.getRevision().substring(index + 1)
151: .equals(workspaceName)) {
152: Message.verbose("\t" + getName()
153: + ": unhandled revision => "
154: + systemMrid.getRevision());
155: return null;
156: }
157:
158: boolean isDynamic = getSettings().getVersionMatcher()
159: .isDynamic(systemMrid);
160: if (isDynamic && !acceptLatest()) {
161: Message.error("dynamic revisions not handled by "
162: + getClass().getName()
163: + ". impossible to resolve " + systemMrid);
164: return null;
165: }
166:
167: // we first search for the dependency in cache
168: ResolvedModuleRevision rmr = null;
169: rmr = findModuleInCache(systemDd, getCacheOptions(data));
170: if (rmr != null) {
171: if (rmr.getDescriptor().isDefault()
172: && rmr.getResolver() != this ) {
173: Message
174: .verbose("\t"
175: + getName()
176: + ": found revision in cache: "
177: + systemMrid
178: + " (resolved by "
179: + rmr.getResolver().getName()
180: + "): but it's a default one, maybe we can find a better one");
181: } else {
182: Message.verbose("\t" + getName()
183: + ": revision in cache: " + systemMrid);
184: return rmr;
185: }
186: }
187:
188: checkInterrupted();
189:
190: ResolvedResource ivyRef = findIvyFileRef(nsDd, data);
191: checkInterrupted();
192:
193: // get module descriptor
194: final ModuleDescriptorParser parser;
195: ModuleDescriptor nsMd;
196: ModuleDescriptor systemMd = null;
197: if (ivyRef == null) {
198: if (!isAllownomd()) {
199: Message.verbose("\t" + getName()
200: + ": no ivy file found for " + systemMrid);
201: return null;
202: }
203: parser = XmlModuleDescriptorParser.getInstance();
204: nsMd = DefaultModuleDescriptor.newDefaultInstance(
205: nsMrid, nsDd.getAllDependencyArtifacts());
206: ResolvedResource artifactRef = findFirstArtifactRef(
207: nsMd, nsDd, data);
208: checkInterrupted();
209: if (artifactRef == null) {
210: Message.verbose("\t" + getName()
211: + ": no ivy file nor artifact found for "
212: + systemMrid);
213: return null;
214: } else {
215: long lastModified = artifactRef.getLastModified();
216: if (lastModified != 0
217: && nsMd instanceof DefaultModuleDescriptor) {
218: ((DefaultModuleDescriptor) nsMd)
219: .setLastModified(lastModified);
220: }
221: Message.verbose("\t" + getName()
222: + ": no ivy file found for " + systemMrid
223: + ": using default data");
224: if (isDynamic) {
225: nsMd
226: .setResolvedModuleRevisionId(ModuleRevisionId
227: .newInstance(nsMrid,
228: artifactRef
229: .getRevision()));
230: }
231: systemMd = toSystem(nsMd);
232: MetadataArtifactDownloadReport madr = new MetadataArtifactDownloadReport(
233: systemMd.getMetadataArtifact());
234: madr.setDownloadStatus(DownloadStatus.NO);
235: madr.setSearched(true);
236: rmr = new ResolvedModuleRevision(this , this ,
237: systemMd, madr);
238: }
239: } else {
240: if (ivyRef instanceof MDResolvedResource) {
241: rmr = ((MDResolvedResource) ivyRef)
242: .getResolvedModuleRevision();
243: }
244: if (rmr == null) {
245: rmr = parse(ivyRef, systemDd, data);
246: if (rmr == null) {
247: return null;
248: }
249: }
250: if (!rmr.getReport().isDownloaded()) {
251: return toSystem(rmr);
252: } else {
253: nsMd = rmr.getDescriptor();
254: parser = ModuleDescriptorParserRegistry
255: .getInstance().getParser(
256: ivyRef.getResource());
257:
258: // check descriptor data is in sync with resource revision and names
259: systemMd = toSystem(nsMd);
260: if (checkconsistency) {
261: checkDescriptorConsistency(systemMrid,
262: systemMd, ivyRef);
263: checkDescriptorConsistency(nsMrid, nsMd, ivyRef);
264: } else {
265: if (systemMd instanceof DefaultModuleDescriptor) {
266: String revision = getRevision(ivyRef,
267: systemMrid, systemMd);
268: ((DefaultModuleDescriptor) systemMd)
269: .setModuleRevisionId(ModuleRevisionId
270: .newInstance(systemMrid,
271: revision));
272: } else {
273: Message
274: .warn("consistency disabled with instance of non DefaultModuleDescriptor..."
275: + " module info can't be updated, so consistency check will be done");
276: checkDescriptorConsistency(nsMrid, nsMd,
277: ivyRef);
278: checkDescriptorConsistency(systemMrid,
279: systemMd, ivyRef);
280: }
281: }
282: MetadataArtifactDownloadReport madr = new MetadataArtifactDownloadReport(
283: systemMd.getMetadataArtifact());
284: madr.setDownloadStatus(rmr.getReport()
285: .getDownloadStatus());
286: madr.setDownloadDetails(rmr.getReport()
287: .getDownloadDetails());
288: madr.setArtifactOrigin(rmr.getReport()
289: .getArtifactOrigin());
290: madr.setDownloadTimeMillis(rmr.getReport()
291: .getDownloadTimeMillis());
292: madr.setSize(rmr.getReport().getSize());
293: madr.setOriginalLocalFile(rmr.getReport()
294: .getOriginalLocalFile());
295: madr.setSearched(true);
296: rmr = new ResolvedModuleRevision(this , this ,
297: systemMd, madr);
298: }
299: }
300:
301: // resolve revision
302: ModuleRevisionId resolvedMrid = systemMrid;
303: if (isDynamic) {
304: resolvedMrid = systemMd.getResolvedModuleRevisionId();
305: if (resolvedMrid.getRevision() == null
306: || resolvedMrid.getRevision().length() == 0) {
307: if (ivyRef.getRevision() == null
308: || ivyRef.getRevision().length() == 0) {
309: resolvedMrid = ModuleRevisionId.newInstance(
310: resolvedMrid, "working@" + getName());
311: } else {
312: resolvedMrid = ModuleRevisionId.newInstance(
313: resolvedMrid, ivyRef.getRevision());
314: }
315: }
316: Message.verbose("\t\t["
317: + toSystem(resolvedMrid).getRevision() + "] "
318: + systemMrid.getModuleId());
319: }
320: systemMd.setResolvedModuleRevisionId(resolvedMrid);
321:
322: // check module descriptor revision
323: if (!getSettings().getVersionMatcher().accept(systemMrid,
324: systemMd)) {
325: Message.info("\t" + getName()
326: + ": unacceptable revision => was="
327: + systemMd.getModuleRevisionId().getRevision()
328: + " required=" + systemMrid.getRevision());
329: return null;
330: }
331:
332: // resolve and check publication date
333: if (data.getDate() != null) {
334: long pubDate = getPublicationDate(systemMd, systemDd,
335: data);
336: if (pubDate > data.getDate().getTime()) {
337: Message.info("\t" + getName()
338: + ": unacceptable publication date => was="
339: + new Date(pubDate) + " required="
340: + data.getDate());
341: return null;
342: } else if (pubDate == -1) {
343: Message
344: .info("\t"
345: + getName()
346: + ": impossible to guess publication date: artifact missing for "
347: + systemMrid);
348: return null;
349: }
350: systemMd.setResolvedPublicationDate(new Date(pubDate));
351: }
352:
353: if (!systemMd.isDefault()
354: && data.getSettings()
355: .logNotConvertedExclusionRule()
356: && systemMd instanceof DefaultModuleDescriptor) {
357: DefaultModuleDescriptor dmd = (DefaultModuleDescriptor) systemMd;
358: if (dmd.isNamespaceUseful()) {
359: Message
360: .warn("the module descriptor "
361: + ivyRef.getResource()
362: + " has information which can't be converted into "
363: + "the system namespace. "
364: + "It will require the availability of the namespace '"
365: + getNamespace().getName()
366: + "' to be fully usable.");
367: }
368: }
369:
370: RepositoryCacheManager cacheManager = getRepositoryCacheManager();
371:
372: // the metadata artifact which was used to cache the original metadata file
373: Artifact requestedMetadataArtifact = ivyRef == null ? systemMd
374: .getMetadataArtifact()
375: : parser.getMetadataArtifact(ModuleRevisionId
376: .newInstance(systemMrid, ivyRef
377: .getRevision()), ivyRef
378: .getResource());
379:
380: cacheManager.originalToCachedModuleDescriptor(this , ivyRef,
381: requestedMetadataArtifact, rmr,
382: new ModuleDescriptorWriter() {
383: public void write(
384: ResolvedResource originalMdResource,
385: ModuleDescriptor md, File src, File dest)
386: throws IOException, ParseException {
387: if (originalMdResource == null) {
388: // a basic ivy file is written containing default data
389: XmlModuleDescriptorWriter.write(md,
390: dest);
391: } else {
392: // copy and update ivy file from source to cache
393: parser.toIvyFile(new FileInputStream(
394: src), originalMdResource
395: .getResource(), dest, md);
396: long repLastModified = originalMdResource
397: .getLastModified();
398: if (repLastModified > 0) {
399: dest
400: .setLastModified(repLastModified);
401: }
402: }
403: }
404: });
405:
406: return rmr;
407: } finally {
408: IvyContext.popContext();
409: }
410: }
411:
412: private String getRevision(ResolvedResource ivyRef,
413: ModuleRevisionId askedMrid, ModuleDescriptor md)
414: throws ParseException {
415: String revision = ivyRef.getRevision();
416: if (revision == null) {
417: Message.debug("no revision found in reference for "
418: + askedMrid);
419: if (getSettings().getVersionMatcher().isDynamic(askedMrid)) {
420: if (md.getModuleRevisionId().getRevision() == null) {
421: return "working@" + getName();
422: } else {
423: Message.debug("using " + askedMrid);
424: revision = md.getModuleRevisionId().getRevision();
425: }
426: } else {
427: Message.debug("using " + askedMrid);
428: revision = askedMrid.getRevision();
429: }
430: }
431: return revision;
432: }
433:
434: public ResolvedModuleRevision parse(final ResolvedResource mdRef,
435: DependencyDescriptor dd, ResolveData data)
436: throws ParseException {
437:
438: DependencyDescriptor nsDd = dd;
439: dd = toSystem(nsDd);
440:
441: ModuleRevisionId mrid = dd.getDependencyRevisionId();
442: ModuleDescriptorParser parser = ModuleDescriptorParserRegistry
443: .getInstance().getParser(mdRef.getResource());
444: if (parser == null) {
445: Message.warn("no module descriptor parser available for "
446: + mdRef.getResource());
447: return null;
448: }
449: Message.verbose("\t" + getName() + ": found md file for "
450: + mrid);
451: Message.verbose("\t\t=> " + mdRef);
452: Message.debug("\tparser = " + parser);
453:
454: ModuleRevisionId resolvedMrid = mrid;
455:
456: // first check if this dependency has not yet been resolved
457: if (getSettings().getVersionMatcher().isDynamic(mrid)) {
458: resolvedMrid = ModuleRevisionId.newInstance(mrid, mdRef
459: .getRevision());
460: IvyNode node = data.getNode(resolvedMrid);
461: if (node != null && node.getModuleRevision() != null) {
462: // this revision has already be resolved : return it
463: if (node.getDescriptor() != null
464: && node.getDescriptor().isDefault()) {
465: Message
466: .verbose("\t"
467: + getName()
468: + ": found already resolved revision: "
469: + resolvedMrid
470: + ": but it's a default one, maybe we can find a better one");
471: } else {
472: Message.verbose("\t" + getName()
473: + ": revision already resolved: "
474: + resolvedMrid);
475: node.getModuleRevision().getReport().setSearched(
476: true);
477: return node.getModuleRevision();
478: }
479: }
480: }
481:
482: Artifact moduleArtifact = parser.getMetadataArtifact(
483: resolvedMrid, mdRef.getResource());
484: return getRepositoryCacheManager().cacheModuleDescriptor(this ,
485: mdRef, dd, moduleArtifact, downloader,
486: getCacheOptions(data));
487: }
488:
489: protected ResourceMDParser getRMDParser(
490: final DependencyDescriptor dd, final ResolveData data) {
491: return new ResourceMDParser() {
492: public MDResolvedResource parse(Resource resource,
493: String rev) {
494: try {
495: ResolvedModuleRevision rmr = BasicResolver.this
496: .parse(new ResolvedResource(resource, rev),
497: dd, data);
498: if (rmr == null) {
499: return null;
500: } else {
501: return new MDResolvedResource(resource, rev,
502: rmr);
503: }
504: } catch (ParseException e) {
505: Message.warn("Failed to parse the file '"
506: + resource + "': " + e.getMessage());
507: return null;
508: }
509: }
510:
511: };
512: }
513:
514: protected ResourceMDParser getDefaultRMDParser(final ModuleId mid) {
515: return new ResourceMDParser() {
516: public MDResolvedResource parse(Resource resource,
517: String rev) {
518: DefaultModuleDescriptor md = DefaultModuleDescriptor
519: .newDefaultInstance(new ModuleRevisionId(mid,
520: rev));
521: MetadataArtifactDownloadReport madr = new MetadataArtifactDownloadReport(
522: md.getMetadataArtifact());
523: madr.setDownloadStatus(DownloadStatus.NO);
524: madr.setSearched(true);
525: return new MDResolvedResource(resource, rev,
526: new ResolvedModuleRevision(BasicResolver.this ,
527: BasicResolver.this , md, madr));
528: }
529: };
530: }
531:
532: // private boolean isResolved(ResolveData data, ModuleRevisionId mrid) {
533: // IvyNode node = getSystemNode(data, mrid);
534: // return node != null && node.getModuleRevision() != null;
535: // }
536: //
537: private void checkDescriptorConsistency(ModuleRevisionId mrid,
538: ModuleDescriptor md, ResolvedResource ivyRef)
539: throws ParseException {
540: boolean ok = true;
541: StringBuffer errors = new StringBuffer();
542: if (!mrid.getOrganisation().equals(
543: md.getModuleRevisionId().getOrganisation())) {
544: Message.error("\t" + getName()
545: + ": bad organisation found in "
546: + ivyRef.getResource() + ": expected='"
547: + mrid.getOrganisation() + "' found='"
548: + md.getModuleRevisionId().getOrganisation() + "'");
549: errors.append("bad organisation: expected='"
550: + mrid.getOrganisation() + "' found='"
551: + md.getModuleRevisionId().getOrganisation()
552: + "'; ");
553: ok = false;
554: }
555: if (!mrid.getName().equals(md.getModuleRevisionId().getName())) {
556: Message.error("\t" + getName()
557: + ": bad module name found in "
558: + ivyRef.getResource() + ": expected='"
559: + mrid.getName() + " found='"
560: + md.getModuleRevisionId().getName() + "'");
561: errors.append("bad module name: expected='"
562: + mrid.getName() + "' found='"
563: + md.getModuleRevisionId().getName() + "'; ");
564: ok = false;
565: }
566: if (ivyRef.getRevision() != null
567: && !ivyRef.getRevision().startsWith("working@")) {
568: ModuleRevisionId expectedMrid = ModuleRevisionId
569: .newInstance(mrid, ivyRef.getRevision());
570: if (!getSettings().getVersionMatcher().accept(expectedMrid,
571: md)) {
572: Message.error("\t" + getName()
573: + ": bad revision found in "
574: + ivyRef.getResource() + ": expected='"
575: + ivyRef.getRevision() + " found='"
576: + md.getModuleRevisionId().getRevision() + "'");
577: errors.append("bad revision: expected='"
578: + ivyRef.getRevision() + "' found='"
579: + md.getModuleRevisionId().getRevision()
580: + "'; ");
581: ok = false;
582: }
583: }
584: if (!getSettings().getStatusManager().isStatus(md.getStatus())) {
585: Message.error("\t" + getName() + ": bad status found in "
586: + ivyRef.getResource() + ": '" + md.getStatus()
587: + "'");
588: errors.append("bad status: '" + md.getStatus() + "'; ");
589: ok = false;
590: }
591: if (!ok) {
592: throw new ParseException(
593: "inconsistent module descriptor file found in '"
594: + ivyRef.getResource() + "': " + errors, 0);
595: }
596: }
597:
598: protected void clearIvyAttempts() {
599: ivyattempts.clear();
600: clearArtifactAttempts();
601: }
602:
603: protected void logIvyAttempt(String attempt) {
604: ivyattempts.add(attempt);
605: Message.verbose("\t\ttried " + attempt);
606: }
607:
608: protected void logArtifactAttempt(Artifact art, String attempt) {
609: List attempts = (List) artattempts.get(art);
610: if (attempts == null) {
611: attempts = new ArrayList();
612: artattempts.put(art, attempts);
613: }
614: attempts.add(attempt);
615: Message.verbose("\t\ttried " + attempt);
616: }
617:
618: protected void logAttempt(String attempt) {
619: Artifact currentArtifact = (Artifact) IvyContext.getContext()
620: .get(getName() + ".artifact");
621: if (currentArtifact != null) {
622: logArtifactAttempt(currentArtifact, attempt);
623: } else {
624: logIvyAttempt(attempt);
625: }
626: }
627:
628: public void reportFailure() {
629: Message.warn("==== " + getName() + ": tried");
630: for (ListIterator iter = ivyattempts.listIterator(); iter
631: .hasNext();) {
632: String m = (String) iter.next();
633: Message.warn(" " + m);
634: }
635: for (Iterator iter = artattempts.keySet().iterator(); iter
636: .hasNext();) {
637: Artifact art = (Artifact) iter.next();
638: List attempts = (List) artattempts.get(art);
639: if (attempts != null) {
640: Message.warn(" -- artifact " + art + ":");
641: for (ListIterator iterator = attempts.listIterator(); iterator
642: .hasNext();) {
643: String m = (String) iterator.next();
644: Message.warn(" " + m);
645: }
646: }
647: }
648: }
649:
650: public void reportFailure(Artifact art) {
651: Message.warn("==== " + getName() + ": tried");
652: List attempts = (List) artattempts.get(art);
653: if (attempts != null) {
654: for (ListIterator iter = attempts.listIterator(); iter
655: .hasNext();) {
656: String m = (String) iter.next();
657: Message.warn(" " + m);
658: }
659: }
660: }
661:
662: protected boolean acceptLatest() {
663: return true;
664: }
665:
666: public DownloadReport download(Artifact[] artifacts,
667: DownloadOptions options) {
668: RepositoryCacheManager cacheManager = getRepositoryCacheManager();
669:
670: clearArtifactAttempts();
671: DownloadReport dr = new DownloadReport();
672: for (int i = 0; i < artifacts.length; i++) {
673: ArtifactDownloadReport adr = cacheManager.download(
674: artifacts[i], artifactResourceResolver, downloader,
675: getCacheDownloadOptions(options));
676: if (DownloadStatus.FAILED == adr.getDownloadStatus()) {
677: if (!ArtifactDownloadReport.MISSING_ARTIFACT.equals(adr
678: .getDownloadDetails())) {
679: Message.warn("\t" + adr);
680: }
681: } else if (DownloadStatus.NO == adr.getDownloadStatus()) {
682: Message.verbose("\t" + adr);
683: } else if (LogOptions.LOG_QUIET.equals(options.getLog())) {
684: Message.verbose("\t" + adr);
685: } else {
686: Message.info("\t" + adr);
687: }
688: dr.addArtifactReport(adr);
689: checkInterrupted();
690: }
691: return dr;
692: }
693:
694: protected void clearArtifactAttempts() {
695: artattempts.clear();
696: }
697:
698: public boolean exists(Artifact artifact) {
699: ResolvedResource artifactRef = getArtifactRef(artifact, null);
700: if (artifactRef != null) {
701: return artifactRef.getResource().exists();
702: }
703: return false;
704: }
705:
706: protected long getPublicationDate(ModuleDescriptor md,
707: DependencyDescriptor dd, ResolveData data) {
708: if (md.getPublicationDate() != null) {
709: return md.getPublicationDate().getTime();
710: }
711: ResolvedResource artifactRef = findFirstArtifactRef(md, dd,
712: data);
713: if (artifactRef != null) {
714: return artifactRef.getLastModified();
715: }
716: return -1;
717: }
718:
719: public String toString() {
720: return getName();
721: }
722:
723: public String[] listTokenValues(String token, Map otherTokenValues) {
724: Collection ret = findNames(otherTokenValues, token);
725: return (String[]) ret.toArray(new String[ret.size()]);
726: }
727:
728: public OrganisationEntry[] listOrganisations() {
729: Collection names = findNames(Collections.EMPTY_MAP,
730: IvyPatternHelper.ORGANISATION_KEY);
731: OrganisationEntry[] ret = new OrganisationEntry[names.size()];
732: int i = 0;
733: for (Iterator iter = names.iterator(); iter.hasNext(); i++) {
734: String org = (String) iter.next();
735: ret[i] = new OrganisationEntry(this , org);
736: }
737: return ret;
738: }
739:
740: public ModuleEntry[] listModules(OrganisationEntry org) {
741: Map tokenValues = new HashMap();
742: tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, org
743: .getOrganisation());
744: Collection names = findNames(tokenValues,
745: IvyPatternHelper.MODULE_KEY);
746: ModuleEntry[] ret = new ModuleEntry[names.size()];
747: int i = 0;
748: for (Iterator iter = names.iterator(); iter.hasNext(); i++) {
749: String name = (String) iter.next();
750: ret[i] = new ModuleEntry(org, name);
751: }
752: return ret;
753: }
754:
755: public RevisionEntry[] listRevisions(ModuleEntry mod) {
756: Map tokenValues = new HashMap();
757: tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, mod
758: .getOrganisation());
759: tokenValues.put(IvyPatternHelper.MODULE_KEY, mod.getModule());
760: Collection names = findNames(tokenValues,
761: IvyPatternHelper.REVISION_KEY);
762: RevisionEntry[] ret = new RevisionEntry[names.size()];
763: int i = 0;
764: for (Iterator iter = names.iterator(); iter.hasNext(); i++) {
765: String name = (String) iter.next();
766: ret[i] = new RevisionEntry(mod, name);
767: }
768: return ret;
769: }
770:
771: protected abstract Collection findNames(Map tokenValues,
772: String token);
773:
774: protected ResolvedResource findFirstArtifactRef(
775: ModuleDescriptor md, DependencyDescriptor dd,
776: ResolveData data) {
777: ResolvedResource ret = null;
778: String[] conf = md.getConfigurationsNames();
779: for (int i = 0; i < conf.length; i++) {
780: Artifact[] artifacts = md.getArtifacts(conf[i]);
781: for (int j = 0; j < artifacts.length; j++) {
782: ret = getArtifactRef(artifacts[j], data.getDate());
783: if (ret != null) {
784: return ret;
785: }
786: }
787: }
788: return null;
789: }
790:
791: protected long getAndCheck(Resource resource, File dest)
792: throws IOException {
793: long size = get(resource, dest);
794: String[] checksums = getChecksumAlgorithms();
795: boolean checked = false;
796: for (int i = 0; i < checksums.length && !checked; i++) {
797: checked = check(resource, dest, checksums[i]);
798: }
799: return size;
800: }
801:
802: /**
803: * Checks the given resource checksum if a checksum resource exists.
804: *
805: * @param resource
806: * the resource to check
807: * @param dest
808: * the file where the resource has been downloaded
809: * @param algorithm
810: * the checksum algorithm to use
811: * @return true if the checksum has been successfully checked, false if the checksum wasn't
812: * available
813: * @throws IOException
814: * if a checksum exist but do not match the downloaded file checksum
815: */
816: private boolean check(Resource resource, File dest, String algorithm)
817: throws IOException {
818: Resource csRes = resource.clone(resource.getName() + "."
819: + algorithm);
820: if (csRes.exists()) {
821: Message.debug(algorithm + " file found for " + resource
822: + ": checking...");
823: File csFile = File.createTempFile("ivytmp", algorithm);
824: try {
825: get(csRes, csFile);
826: try {
827: ChecksumHelper.check(dest, csFile, algorithm);
828: Message.verbose(algorithm + " OK for " + resource);
829: return true;
830: } catch (IOException ex) {
831: dest.delete();
832: throw ex;
833: }
834: } finally {
835: csFile.delete();
836: }
837: } else {
838: return false;
839: }
840: }
841:
842: protected ResolvedResource getArtifactRef(Artifact artifact,
843: Date date) {
844: IvyContext.getContext().set(getName() + ".artifact", artifact);
845: try {
846: ResolvedResource ret = findArtifactRef(artifact, date);
847: if (ret == null && artifact.getUrl() != null) {
848: URL url = artifact.getUrl();
849: Message.verbose("\tusing url for " + artifact + ": "
850: + url);
851: logArtifactAttempt(artifact, url.toExternalForm());
852: ret = new ResolvedResource(new URLResource(url),
853: artifact.getModuleRevisionId().getRevision());
854: }
855: return ret;
856: } finally {
857: IvyContext.getContext().set(getName() + ".artifact", null);
858: }
859: }
860:
861: protected abstract ResolvedResource findArtifactRef(
862: Artifact artifact, Date date);
863:
864: protected abstract long get(Resource resource, File dest)
865: throws IOException;
866:
867: public boolean isCheckconsistency() {
868: return checkconsistency;
869: }
870:
871: public void setCheckconsistency(boolean checkConsitency) {
872: checkconsistency = checkConsitency;
873: }
874:
875: public boolean isAllownomd() {
876: return allownomd;
877: }
878:
879: public void setAllownomd(boolean b) {
880: allownomd = b;
881: }
882:
883: public String[] getChecksumAlgorithms() {
884: String csDef = checksums == null ? getSettings().getVariable(
885: "ivy.checksums") : checksums;
886: if (csDef == null) {
887: return new String[0];
888: }
889: // csDef is a comma separated list of checksum algorithms to use with this resolver
890: // we parse and return it as a String[]
891: String[] checksums = csDef.split(",");
892: List algos = new ArrayList();
893: for (int i = 0; i < checksums.length; i++) {
894: String cs = checksums[i].trim();
895: if (!"".equals(cs) && !"none".equals(cs)) {
896: algos.add(cs);
897: }
898: }
899: return (String[]) algos.toArray(new String[algos.size()]);
900: }
901:
902: public void setChecksums(String checksums) {
903: this .checksums = checksums;
904: }
905:
906: private final ArtifactResourceResolver artifactResourceResolver = new ArtifactResourceResolver() {
907: public ResolvedResource resolve(Artifact artifact) {
908: artifact = fromSystem(artifact);
909: return getArtifactRef(artifact, null);
910: }
911: };
912:
913: private final ResourceDownloader downloader = new ResourceDownloader() {
914: public void download(Artifact artifact, Resource resource,
915: File dest) throws IOException {
916: if (dest.exists()) {
917: dest.delete();
918: }
919: File part = new File(dest.getAbsolutePath() + ".part");
920: if (resource.getName().equals(
921: String.valueOf(artifact.getUrl()))) {
922: if (part.getParentFile() != null) {
923: part.getParentFile().mkdirs();
924: }
925: extartifactrep.get(resource.getName(), part);
926: } else {
927: getAndCheck(resource, part);
928: }
929: if (!part.renameTo(dest)) {
930: throw new IOException(
931: "impossible to move part file to definitive one: "
932: + part + " -> " + dest);
933: }
934:
935: }
936: };
937:
938: }
|