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.IOException;
022: import java.text.ParseException;
023: import java.util.ArrayList;
024: import java.util.Arrays;
025: import java.util.Date;
026: import java.util.Iterator;
027: import java.util.List;
028:
029: import org.apache.ivy.core.module.descriptor.Artifact;
030: import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
031: import org.apache.ivy.core.module.id.ModuleRevisionId;
032: import org.apache.ivy.core.report.ArtifactDownloadReport;
033: import org.apache.ivy.core.report.DownloadReport;
034: import org.apache.ivy.core.report.DownloadStatus;
035: import org.apache.ivy.core.resolve.DownloadOptions;
036: import org.apache.ivy.core.resolve.ResolveData;
037: import org.apache.ivy.core.resolve.ResolvedModuleRevision;
038: import org.apache.ivy.plugins.latest.ArtifactInfo;
039: import org.apache.ivy.plugins.latest.LatestStrategy;
040: import org.apache.ivy.plugins.resolver.util.HasLatestStrategy;
041: import org.apache.ivy.plugins.resolver.util.ResolvedResource;
042: import org.apache.ivy.util.Message;
043: import org.apache.ivy.util.StringUtils;
044:
045: /**
046: *
047: */
048: public class ChainResolver extends AbstractResolver {
049: public static class ResolvedModuleRevisionArtifactInfo implements
050: ArtifactInfo {
051: private ResolvedModuleRevision rmr;
052:
053: public ResolvedModuleRevisionArtifactInfo(
054: ResolvedModuleRevision rmr) {
055: this .rmr = rmr;
056: }
057:
058: public String getRevision() {
059: return rmr.getId().getRevision();
060: }
061:
062: public long getLastModified() {
063: return rmr.getPublicationDate().getTime();
064: }
065:
066: }
067:
068: private boolean returnFirst = false;
069:
070: private List chain = new ArrayList();
071:
072: private boolean dual;
073:
074: private Boolean checkmodified = null;
075:
076: public void add(DependencyResolver resolver) {
077: chain.add(resolver);
078: }
079:
080: /**
081: * True if this resolver should check lastmodified date to know if ivy files are up to date.
082: *
083: * @return
084: */
085: public boolean isCheckmodified() {
086: if (checkmodified == null) {
087: if (getSettings() != null) {
088: String check = getSettings().getVariable(
089: "ivy.resolver.default.check.modified");
090: return check != null ? Boolean.valueOf(check)
091: .booleanValue() : false;
092: } else {
093: return false;
094: }
095: } else {
096: return checkmodified.booleanValue();
097: }
098: }
099:
100: public void setCheckmodified(boolean check) {
101: checkmodified = Boolean.valueOf(check);
102: }
103:
104: public ResolvedModuleRevision getDependency(
105: DependencyDescriptor dd, ResolveData data)
106: throws ParseException {
107: data = new ResolveData(data, doValidate(data));
108: ResolvedModuleRevision ret = null;
109:
110: List errors = new ArrayList();
111:
112: ResolvedModuleRevision mr = null;
113:
114: ModuleRevisionId mrid = dd.getDependencyRevisionId();
115:
116: Message.verbose(getName() + ": Checking cache for: " + dd);
117: mr = findModuleInCache(dd, getCacheOptions(data), true);
118: if (mr != null) {
119: Message
120: .verbose(getName()
121: + ": module revision found in cache: "
122: + mr.getId());
123: return resolvedRevision(mr);
124: }
125:
126: boolean isDynamic = getSettings().getVersionMatcher()
127: .isDynamic(mrid);
128: for (Iterator iter = chain.iterator(); iter.hasNext();) {
129: DependencyResolver resolver = (DependencyResolver) iter
130: .next();
131: LatestStrategy oldLatest = setLatestIfRequired(resolver,
132: getLatestStrategy());
133: try {
134: mr = resolver.getDependency(dd, data);
135: } catch (Exception ex) {
136: Message.verbose("problem occured while resolving " + dd
137: + " with " + resolver + ": "
138: + StringUtils.getStackTrace(ex));
139: errors.add(ex);
140: } finally {
141: if (oldLatest != null) {
142: setLatest(resolver, oldLatest);
143: }
144: }
145: checkInterrupted();
146: if (mr != null) {
147: boolean shouldReturn = returnFirst;
148: shouldReturn |= !isDynamic && ret != null
149: && !ret.getDescriptor().isDefault();
150: if (!shouldReturn) {
151: // check if latest is asked and compare to return the most recent
152: String mrDesc = mr.getId()
153: + (mr.getDescriptor().isDefault() ? "[default]"
154: : "") + " from "
155: + mr.getResolver().getName();
156: Message.debug("\tchecking " + mrDesc + " against "
157: + ret);
158: if (ret == null) {
159: Message
160: .debug("\tmodule revision kept as first found: "
161: + mrDesc);
162: ret = mr;
163: } else if (isAfter(mr, ret, data.getDate())) {
164: Message
165: .debug("\tmodule revision kept as younger: "
166: + mrDesc);
167: ret = mr;
168: } else if (!mr.getDescriptor().isDefault()
169: && ret.getDescriptor().isDefault()) {
170: Message
171: .debug("\tmodule revision kept as better (not default): "
172: + mrDesc);
173: ret = mr;
174: } else {
175: Message
176: .debug("\tmodule revision discarded as older: "
177: + mrDesc);
178: }
179: if (!isDynamic && !ret.getDescriptor().isDefault()) {
180: Message
181: .debug("\tmodule revision found and is not default: returning "
182: + mrDesc);
183: return resolvedRevision(mr);
184: }
185: } else {
186: return resolvedRevision(mr);
187: }
188: }
189: }
190: if (ret == null && !errors.isEmpty()) {
191: if (errors.size() == 1) {
192: Exception ex = (Exception) errors.get(0);
193: if (ex instanceof RuntimeException) {
194: throw (RuntimeException) ex;
195: } else if (ex instanceof ParseException) {
196: throw (ParseException) ex;
197: } else {
198: throw new RuntimeException(ex.toString(), ex);
199: }
200: } else {
201: StringBuffer err = new StringBuffer();
202: for (Iterator iter = errors.iterator(); iter.hasNext();) {
203: Exception ex = (Exception) iter.next();
204: err.append("\t").append(
205: StringUtils.getErrorMessage(ex)).append(
206: "\n");
207: }
208: err.setLength(err.length() - 1);
209: throw new RuntimeException(
210: "several problems occured while resolving "
211: + dd + ":\n" + err);
212: }
213: }
214: return resolvedRevision(ret);
215: }
216:
217: private ResolvedModuleRevision resolvedRevision(
218: ResolvedModuleRevision mr) {
219: if (isDual() && mr != null) {
220: return new ResolvedModuleRevision(mr.getResolver(), this ,
221: mr.getDescriptor(), mr.getReport());
222: } else {
223: return mr;
224: }
225: }
226:
227: private LatestStrategy setLatestIfRequired(
228: DependencyResolver resolver, LatestStrategy latestStrategy) {
229: String latestName = getLatestStrategyName(resolver);
230: if (latestName != null && !"default".equals(latestName)) {
231: LatestStrategy oldLatest = getLatest(resolver);
232: setLatest(resolver, latestStrategy);
233: return oldLatest;
234: } else {
235: return null;
236: }
237: }
238:
239: /**
240: * Returns true if rmr1 is after rmr2, using the latest strategy to determine which is the
241: * latest
242: *
243: * @param rmr1
244: * @param rmr2
245: * @return
246: */
247: private boolean isAfter(ResolvedModuleRevision rmr1,
248: ResolvedModuleRevision rmr2, Date date) {
249: ArtifactInfo[] ais = new ArtifactInfo[] {
250: new ResolvedModuleRevisionArtifactInfo(rmr2),
251: new ResolvedModuleRevisionArtifactInfo(rmr1) };
252: return getLatestStrategy().findLatest(ais, date) != ais[0];
253: }
254:
255: public ResolvedResource findIvyFileRef(DependencyDescriptor dd,
256: ResolveData data) {
257: for (Iterator iter = chain.iterator(); iter.hasNext();) {
258: DependencyResolver resolver = (DependencyResolver) iter
259: .next();
260: ResolvedResource result = resolver.findIvyFileRef(dd, data);
261: if (result != null) {
262: return result;
263: }
264: }
265:
266: return null;
267: }
268:
269: public void reportFailure() {
270: for (Iterator iter = chain.iterator(); iter.hasNext();) {
271: DependencyResolver resolver = (DependencyResolver) iter
272: .next();
273: resolver.reportFailure();
274: }
275: }
276:
277: public void reportFailure(Artifact art) {
278: for (Iterator iter = chain.iterator(); iter.hasNext();) {
279: DependencyResolver resolver = (DependencyResolver) iter
280: .next();
281: resolver.reportFailure(art);
282: }
283: }
284:
285: public DownloadReport download(Artifact[] artifacts,
286: DownloadOptions options) {
287: List artifactsToDownload = new ArrayList(Arrays
288: .asList(artifacts));
289: DownloadReport report = new DownloadReport();
290: for (Iterator iter = chain.iterator(); iter.hasNext()
291: && !artifactsToDownload.isEmpty();) {
292: DependencyResolver resolver = (DependencyResolver) iter
293: .next();
294: DownloadReport r = resolver.download(
295: (Artifact[]) artifactsToDownload
296: .toArray(new Artifact[artifactsToDownload
297: .size()]), options);
298: ArtifactDownloadReport[] adr = r.getArtifactsReports();
299: for (int i = 0; i < adr.length; i++) {
300: if (adr[i].getDownloadStatus() != DownloadStatus.FAILED) {
301: artifactsToDownload.remove(adr[i].getArtifact());
302: report.addArtifactReport(adr[i]);
303: }
304: }
305: }
306: for (Iterator iter = artifactsToDownload.iterator(); iter
307: .hasNext();) {
308: Artifact art = (Artifact) iter.next();
309: ArtifactDownloadReport adr = new ArtifactDownloadReport(art);
310: adr.setDownloadStatus(DownloadStatus.FAILED);
311: report.addArtifactReport(adr);
312: }
313: return report;
314: }
315:
316: public List getResolvers() {
317: return chain;
318: }
319:
320: public void publish(Artifact artifact, File src, boolean overwrite)
321: throws IOException {
322:
323: getFirstResolver().publish(artifact, src, overwrite);
324: }
325:
326: public void abortPublishTransaction() throws IOException {
327: getFirstResolver().abortPublishTransaction();
328: }
329:
330: public void beginPublishTransaction(ModuleRevisionId module,
331: boolean overwrite) throws IOException {
332: getFirstResolver().beginPublishTransaction(module, overwrite);
333: }
334:
335: public void commitPublishTransaction() throws IOException {
336: getFirstResolver().commitPublishTransaction();
337: }
338:
339: private DependencyResolver getFirstResolver() {
340: if (chain.isEmpty()) {
341: throw new IllegalStateException(
342: "invalid chain resolver with no sub resolver");
343: }
344: return ((DependencyResolver) chain.get(0));
345: }
346:
347: public boolean isReturnFirst() {
348: return returnFirst;
349: }
350:
351: public void setReturnFirst(boolean returnFirst) {
352: this .returnFirst = returnFirst;
353: }
354:
355: public void dumpSettings() {
356: Message.verbose("\t" + getName() + " [chain] " + chain);
357: Message.debug("\t\treturn first: " + isReturnFirst());
358: Message.debug("\t\tdual: " + isDual());
359: for (Iterator iter = chain.iterator(); iter.hasNext();) {
360: DependencyResolver r = (DependencyResolver) iter.next();
361: Message.debug("\t\t-> " + r.getName());
362: }
363: }
364:
365: public boolean exists(Artifact artifact) {
366: for (Iterator iter = chain.iterator(); iter.hasNext();) {
367: DependencyResolver resolver = (DependencyResolver) iter
368: .next();
369: if (resolver.exists(artifact)) {
370: return true;
371: }
372: }
373: return false;
374: }
375:
376: private static void setLatest(DependencyResolver resolver,
377: LatestStrategy latest) {
378: if (resolver instanceof HasLatestStrategy) {
379: HasLatestStrategy r = (HasLatestStrategy) resolver;
380: r.setLatestStrategy(latest);
381: }
382: }
383:
384: private static LatestStrategy getLatest(DependencyResolver resolver) {
385: if (resolver instanceof HasLatestStrategy) {
386: HasLatestStrategy r = (HasLatestStrategy) resolver;
387: return r.getLatestStrategy();
388: }
389: return null;
390: }
391:
392: private static String getLatestStrategyName(
393: DependencyResolver resolver) {
394: if (resolver instanceof HasLatestStrategy) {
395: HasLatestStrategy r = (HasLatestStrategy) resolver;
396: return r.getLatest();
397: }
398: return null;
399: }
400:
401: public void setDual(boolean b) {
402: dual = b;
403: }
404:
405: public boolean isDual() {
406: return dual;
407: }
408:
409: }
|