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.util.ArrayList;
021: import java.util.Collection;
022: import java.util.Collections;
023: import java.util.Date;
024: import java.util.HashMap;
025: import java.util.HashSet;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.ListIterator;
029: import java.util.Map;
030: import java.util.Set;
031:
032: import org.apache.ivy.core.IvyContext;
033: import org.apache.ivy.core.IvyPatternHelper;
034: import org.apache.ivy.core.module.descriptor.Artifact;
035: import org.apache.ivy.core.module.descriptor.DefaultArtifact;
036: import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
037: import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
038: import org.apache.ivy.core.module.id.ModuleRevisionId;
039: import org.apache.ivy.core.resolve.IvyNode;
040: import org.apache.ivy.core.resolve.ResolveData;
041: import org.apache.ivy.core.settings.IvyPattern;
042: import org.apache.ivy.plugins.conflict.ConflictManager;
043: import org.apache.ivy.plugins.latest.LatestStrategy;
044: import org.apache.ivy.plugins.resolver.util.MDResolvedResource;
045: import org.apache.ivy.plugins.resolver.util.ResolvedResource;
046: import org.apache.ivy.plugins.resolver.util.ResourceMDParser;
047: import org.apache.ivy.plugins.version.VersionMatcher;
048: import org.apache.ivy.util.Message;
049:
050: /**
051: *
052: */
053: public abstract class AbstractResourceResolver extends BasicResolver {
054:
055: private static final Map IVY_ARTIFACT_ATTRIBUTES = new HashMap();
056: static {
057: IVY_ARTIFACT_ATTRIBUTES.put(IvyPatternHelper.ARTIFACT_KEY,
058: "ivy");
059: IVY_ARTIFACT_ATTRIBUTES.put(IvyPatternHelper.TYPE_KEY, "ivy");
060: IVY_ARTIFACT_ATTRIBUTES.put(IvyPatternHelper.EXT_KEY, "xml");
061: }
062:
063: private List ivyPatterns = new ArrayList(); // List (String pattern)
064:
065: private List artifactPatterns = new ArrayList(); // List (String pattern)
066:
067: private boolean m2compatible = false;
068:
069: public AbstractResourceResolver() {
070: }
071:
072: public ResolvedResource findIvyFileRef(DependencyDescriptor dd,
073: ResolveData data) {
074: ModuleRevisionId mrid = dd.getDependencyRevisionId();
075: if (isM2compatible()) {
076: mrid = convertM2IdForResourceSearch(mrid);
077: }
078: return findResourceUsingPatterns(mrid, ivyPatterns,
079: DefaultArtifact.newIvyArtifact(mrid, data.getDate()),
080: getRMDParser(dd, data), data.getDate());
081: }
082:
083: protected ResolvedResource findArtifactRef(Artifact artifact,
084: Date date) {
085: ModuleRevisionId mrid = artifact.getModuleRevisionId();
086: if (isM2compatible()) {
087: mrid = convertM2IdForResourceSearch(mrid);
088: }
089: return findResourceUsingPatterns(mrid, artifactPatterns,
090: artifact, getDefaultRMDParser(artifact
091: .getModuleRevisionId().getModuleId()), date);
092: }
093:
094: protected ResolvedResource findResourceUsingPatterns(
095: ModuleRevisionId moduleRevision, List patternList,
096: Artifact artifact, ResourceMDParser rmdparser, Date date) {
097: List resolvedResources = new ArrayList();
098: Set foundRevisions = new HashSet();
099: boolean dynamic = getSettings().getVersionMatcher().isDynamic(
100: moduleRevision);
101: boolean stop = false;
102: for (Iterator iter = patternList.iterator(); iter.hasNext()
103: && !stop;) {
104: String pattern = (String) iter.next();
105: ResolvedResource rres = findResourceUsingPattern(
106: moduleRevision, pattern, artifact, rmdparser, date);
107: if ((rres != null)
108: && !foundRevisions.contains(rres.getRevision())) {
109: // only add the first found ResolvedResource for each revision
110: foundRevisions.add(rres.getRevision());
111: resolvedResources.add(rres);
112: stop = !dynamic; // stop iterating if we are not searching a dynamic revision
113: }
114: }
115:
116: if (resolvedResources.size() > 1) {
117: ResolvedResource[] rress = (ResolvedResource[]) resolvedResources
118: .toArray(new ResolvedResource[resolvedResources
119: .size()]);
120: return findResource(rress, getName(), getLatestStrategy(),
121: getSettings().getVersionMatcher(), rmdparser,
122: moduleRevision, date);
123: } else if (resolvedResources.size() == 1) {
124: return (ResolvedResource) resolvedResources.get(0);
125: } else {
126: return null;
127: }
128: }
129:
130: protected abstract ResolvedResource findResourceUsingPattern(
131: ModuleRevisionId mrid, String pattern, Artifact artifact,
132: ResourceMDParser rmdparser, Date date);
133:
134: public ResolvedResource findResource(ResolvedResource[] rress,
135: String name, LatestStrategy strategy,
136: VersionMatcher versionMatcher, ResourceMDParser rmdparser,
137: ModuleRevisionId mrid, Date date) {
138: ResolvedResource found = null;
139: List sorted = strategy.sort(rress);
140: List rejected = new ArrayList();
141: List foundBlacklisted = new ArrayList();
142: IvyContext context = IvyContext.getContext();
143:
144: for (ListIterator iter = sorted.listIterator(sorted.size()); iter
145: .hasPrevious();) {
146: ResolvedResource rres = (ResolvedResource) iter.previous();
147: if (filterNames(
148: new ArrayList(Collections.singleton(rres
149: .getRevision()))).isEmpty()) {
150: Message.debug("\t" + name + ": filtered by name: "
151: + rres);
152: continue;
153: }
154: if ((date != null && rres.getLastModified() > date
155: .getTime())) {
156: Message.verbose("\t" + name + ": too young: " + rres);
157: rejected.add(rres.getRevision() + " ("
158: + rres.getLastModified() + ")");
159: continue;
160: }
161: ModuleRevisionId foundMrid = ModuleRevisionId.newInstance(
162: mrid, rres.getRevision());
163:
164: ResolveData data = context.getResolveData();
165: if (data != null
166: && data.getReport() != null
167: && data.isBlacklisted(data.getReport()
168: .getConfiguration(), foundMrid)) {
169: Message.debug("\t" + name + ": blacklisted: " + rres);
170: rejected.add(rres.getRevision() + " (blacklisted)");
171: foundBlacklisted.add(foundMrid);
172: continue;
173: }
174:
175: if (!versionMatcher.accept(mrid, foundMrid)) {
176: Message.debug("\t" + name
177: + ": rejected by version matcher: " + rres);
178: rejected.add(rres.getRevision());
179: continue;
180: }
181: if (versionMatcher.needModuleDescriptor(mrid, foundMrid)) {
182: ResolvedResource r = rmdparser.parse(
183: rres.getResource(), rres.getRevision());
184: if (r == null) {
185: Message
186: .debug("\t"
187: + name
188: + ": impossible to get module descriptor resource: "
189: + rres);
190: rejected
191: .add(rres.getRevision() + " (no or bad MD)");
192: continue;
193: }
194: ModuleDescriptor md = ((MDResolvedResource) r)
195: .getResolvedModuleRevision().getDescriptor();
196: if (md.isDefault()) {
197: Message
198: .debug("\t"
199: + name
200: + ": default md rejected by version matcher"
201: + "requiring module descriptor: "
202: + rres);
203: rejected.add(rres.getRevision() + " (MD)");
204: continue;
205: } else if (!versionMatcher.accept(mrid, md)) {
206: Message.debug("\t" + name
207: + ": md rejected by version matcher: "
208: + rres);
209: rejected.add(rres.getRevision() + " (MD)");
210: continue;
211: } else {
212: found = r;
213: }
214: } else {
215: found = rres;
216: }
217:
218: if (found != null) {
219: if (!found.getResource().exists()) {
220: Message.debug("\t" + name
221: + ": resource not reachable for " + mrid
222: + ": res=" + found.getResource());
223: logAttempt(found.getResource().toString());
224: continue;
225: }
226: break;
227: }
228: }
229: if (found == null && !rejected.isEmpty()) {
230: logAttempt(rejected.toString());
231: }
232: if (found == null && !foundBlacklisted.isEmpty()) {
233: // all acceptable versions have been blacklisted, this means that an unsolvable conflict
234: // has been found
235: DependencyDescriptor dd = context.getDependencyDescriptor();
236: IvyNode parentNode = context.getResolveData().getNode(
237: dd.getParentRevisionId());
238: ConflictManager cm = parentNode.getConflictManager(mrid
239: .getModuleId());
240: cm.handleAllBlacklistedRevisions(dd, foundBlacklisted);
241: }
242:
243: return found;
244: }
245:
246: protected Collection findNames(Map tokenValues, String token) {
247: Collection names = new HashSet();
248: names.addAll(findIvyNames(tokenValues, token));
249: if (isAllownomd()) {
250: names.addAll(findArtifactNames(tokenValues, token));
251: }
252: return names;
253: }
254:
255: protected Collection findIvyNames(Map tokenValues, String token) {
256: Collection names = new HashSet();
257: tokenValues = new HashMap(tokenValues);
258: tokenValues.put(IvyPatternHelper.ARTIFACT_KEY, "ivy");
259: tokenValues.put(IvyPatternHelper.TYPE_KEY, "ivy");
260: tokenValues.put(IvyPatternHelper.EXT_KEY, "xml");
261: findTokenValues(names, getIvyPatterns(), tokenValues, token);
262: filterNames(names);
263: return names;
264: }
265:
266: protected Collection findArtifactNames(Map tokenValues, String token) {
267: Collection names = new HashSet();
268: tokenValues = new HashMap(tokenValues);
269: tokenValues.put(IvyPatternHelper.ARTIFACT_KEY, tokenValues
270: .get(IvyPatternHelper.MODULE_KEY));
271: tokenValues.put(IvyPatternHelper.TYPE_KEY, "jar");
272: tokenValues.put(IvyPatternHelper.EXT_KEY, "jar");
273: findTokenValues(names, getArtifactPatterns(), tokenValues,
274: token);
275: filterNames(names);
276: return names;
277: }
278:
279: /**
280: * Filters names before returning them in the findXXXNames or findTokenValues method.
281: * <p>
282: * Remember to call the super implementation when overriding this method.
283: * </p>
284: *
285: * @param names
286: * the list to filter.
287: * @return the filtered list
288: */
289: protected Collection filterNames(Collection names) {
290: getSettings().filterIgnore(names);
291: return names;
292: }
293:
294: protected void findTokenValues(Collection names, List patterns,
295: Map tokenValues, String token) {
296: //to be overridden by subclasses wanting to have listing features
297: }
298:
299: /**
300: * example of pattern : ~/Workspace/[module]/[module].ivy.xml
301: *
302: * @param pattern
303: */
304: public void addIvyPattern(String pattern) {
305: ivyPatterns.add(pattern);
306: }
307:
308: public void addArtifactPattern(String pattern) {
309: artifactPatterns.add(pattern);
310: }
311:
312: public List getIvyPatterns() {
313: return Collections.unmodifiableList(ivyPatterns);
314: }
315:
316: public List getArtifactPatterns() {
317: return Collections.unmodifiableList(artifactPatterns);
318: }
319:
320: protected void setIvyPatterns(List patterns) {
321: ivyPatterns = patterns;
322: }
323:
324: protected void setArtifactPatterns(List patterns) {
325: artifactPatterns = patterns;
326: }
327:
328: /*
329: * Methods respecting ivy conf method specifications
330: */
331: public void addConfiguredIvy(IvyPattern p) {
332: ivyPatterns.add(p.getPattern());
333: }
334:
335: public void addConfiguredArtifact(IvyPattern p) {
336: artifactPatterns.add(p.getPattern());
337: }
338:
339: public void dumpSettings() {
340: super .dumpSettings();
341: Message.debug("\t\tm2compatible: " + isM2compatible());
342: Message.debug("\t\tivy patterns:");
343: for (ListIterator iter = getIvyPatterns().listIterator(); iter
344: .hasNext();) {
345: String p = (String) iter.next();
346: Message.debug("\t\t\t" + p);
347: }
348: Message.debug("\t\tartifact patterns:");
349: for (ListIterator iter = getArtifactPatterns().listIterator(); iter
350: .hasNext();) {
351: String p = (String) iter.next();
352: Message.debug("\t\t\t" + p);
353: }
354: }
355:
356: public boolean isM2compatible() {
357: return m2compatible;
358: }
359:
360: public void setM2compatible(boolean compatible) {
361: m2compatible = compatible;
362: }
363:
364: protected ModuleRevisionId convertM2IdForResourceSearch(
365: ModuleRevisionId mrid) {
366: if (mrid.getOrganisation().indexOf('.') == -1) {
367: return mrid;
368: }
369: return ModuleRevisionId.newInstance(mrid.getOrganisation()
370: .replace('.', '/'), mrid.getName(), mrid.getBranch(),
371: mrid.getRevision(), mrid.getExtraAttributes());
372: }
373:
374: }
|