2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
18
package org.apache.ivy.plugins.resolver;
20
import java.util.ArrayList;
21
import java.util.Arrays;
22
import java.util.Collection;
23
import java.util.Collections;
24
import java.util.Date;
25
import java.util.HashMap;
26
import java.util.HashSet;
27
import java.util.Iterator;
28
import java.util.LinkedHashSet;
29
import java.util.List;
30
import java.util.ListIterator;
33
import java.util.Map.Entry;
35
import org.apache.ivy.core.IvyContext;
36
import org.apache.ivy.core.IvyPatternHelper;
37
import org.apache.ivy.core.module.descriptor.Artifact;
38
import org.apache.ivy.core.module.descriptor.DefaultArtifact;
39
import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
40
import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
41
import org.apache.ivy.core.module.id.ModuleRevisionId;
42
import org.apache.ivy.core.resolve.IvyNode;
43
import org.apache.ivy.core.resolve.ResolveData;
44
import org.apache.ivy.core.settings.IvyPattern;
45
import org.apache.ivy.plugins.conflict.ConflictManager;
46
import org.apache.ivy.plugins.matcher.Matcher;
47
import org.apache.ivy.plugins.resolver.util.MDResolvedResource;
48
import org.apache.ivy.plugins.resolver.util.ResolvedResource;
49
import org.apache.ivy.plugins.resolver.util.ResourceMDParser;
50
import org.apache.ivy.plugins.version.VersionMatcher;
51
import org.apache.ivy.util.Message;
56
public abstract class AbstractPatternsBasedResolver extends BasicResolver {
58
private static final Map IVY_ARTIFACT_ATTRIBUTES = new HashMap();
60
IVY_ARTIFACT_ATTRIBUTES.put(IvyPatternHelper.ARTIFACT_KEY, "ivy");
61
IVY_ARTIFACT_ATTRIBUTES.put(IvyPatternHelper.TYPE_KEY, "ivy");
62
IVY_ARTIFACT_ATTRIBUTES.put(IvyPatternHelper.EXT_KEY, "xml");
65
private List ivyPatterns = new ArrayList(); // List (String pattern)
67
private List artifactPatterns = new ArrayList(); // List (String pattern)
69
private boolean m2compatible = false;
71
public AbstractPatternsBasedResolver() {
74
public ResolvedResource findIvyFileRef(DependencyDescriptor dd, ResolveData data) {
75
ModuleRevisionId mrid = dd.getDependencyRevisionId();
76
if (isM2compatible()) {
77
mrid = convertM2IdForResourceSearch(mrid);
79
return findResourceUsingPatterns(mrid, ivyPatterns, DefaultArtifact.newIvyArtifact(mrid,
80
data.getDate()), getRMDParser(dd, data), data.getDate());
83
protected ResolvedResource findArtifactRef(Artifact artifact, Date date) {
84
ModuleRevisionId mrid = artifact.getModuleRevisionId();
85
if (isM2compatible()) {
86
mrid = convertM2IdForResourceSearch(mrid);
88
return findResourceUsingPatterns(mrid, artifactPatterns, artifact,
89
getDefaultRMDParser(artifact.getModuleRevisionId().getModuleId()), date);
92
protected ResolvedResource findResourceUsingPatterns(ModuleRevisionId moduleRevision,
93
List patternList, Artifact artifact, ResourceMDParser rmdparser, Date date) {
94
List resolvedResources = new ArrayList();
95
Set foundRevisions = new HashSet();
96
boolean dynamic = getSettings().getVersionMatcher().isDynamic(moduleRevision);
98
for (Iterator iter = patternList.iterator(); iter.hasNext() && !stop;) {
99
String pattern = (String) iter.next();
100
ResolvedResource rres = findResourceUsingPattern(
101
moduleRevision, pattern, artifact, rmdparser, date);
102
if ((rres != null) && !foundRevisions.contains(rres.getRevision())) {
103
// only add the first found ResolvedResource for each revision
104
foundRevisions.add(rres.getRevision());
105
resolvedResources.add(rres);
106
stop = !dynamic; // stop iterating if we are not searching a dynamic revision
110
if (resolvedResources.size() > 1) {
111
ResolvedResource[] rress = (ResolvedResource[]) resolvedResources
112
.toArray(new ResolvedResource[resolvedResources.size()]);
113
return findResource(rress, rmdparser, moduleRevision, date);
114
} else if (resolvedResources.size() == 1) {
115
return (ResolvedResource) resolvedResources.get(0);
121
protected abstract ResolvedResource findResourceUsingPattern(ModuleRevisionId mrid,
122
String pattern, Artifact artifact, ResourceMDParser rmdparser, Date date);
124
public ResolvedResource findResource(ResolvedResource[] rress, ResourceMDParser rmdparser,
125
ModuleRevisionId mrid, Date date) {
126
String name = getName();
127
VersionMatcher versionMatcher = getSettings().getVersionMatcher();
129
ResolvedResource found = null;
130
List sorted = getLatestStrategy().sort(rress);
131
List rejected = new ArrayList();
132
List foundBlacklisted = new ArrayList();
133
IvyContext context = IvyContext.getContext();
135
for (ListIterator iter = sorted.listIterator(sorted.size()); iter.hasPrevious();) {
136
ResolvedResource rres = (ResolvedResource) iter.previous();
137
if (filterNames(new ArrayList(Collections.singleton(rres.getRevision()))).isEmpty()) {
138
Message.debug("\t" + name + ": filtered by name: " + rres);
141
if ((date != null && rres.getLastModified() > date.getTime())) {
142
Message.verbose("\t" + name + ": too young: " + rres);
143
rejected.add(rres.getRevision() + " (" + rres.getLastModified() + ")");
146
ModuleRevisionId foundMrid = ModuleRevisionId.newInstance(mrid, rres.getRevision());
148
ResolveData data = context.getResolveData();
150
&& data.getReport() != null
151
&& data.isBlacklisted(data.getReport().getConfiguration(), foundMrid)) {
152
Message.debug("\t" + name + ": blacklisted: " + rres);
153
rejected.add(rres.getRevision() + " (blacklisted)");
154
foundBlacklisted.add(foundMrid);
158
if (!versionMatcher.accept(mrid, foundMrid)) {
159
Message.debug("\t" + name + ": rejected by version matcher: " + rres);
160
rejected.add(rres.getRevision());
163
if (versionMatcher.needModuleDescriptor(mrid, foundMrid)) {
164
ResolvedResource r = rmdparser.parse(rres.getResource(), rres.getRevision());
166
Message.debug("\t" + name
167
+ ": impossible to get module descriptor resource: " + rres);
168
rejected.add(rres.getRevision() + " (no or bad MD)");
171
ModuleDescriptor md = ((MDResolvedResource) r).getResolvedModuleRevision()
173
if (md.isDefault()) {
174
Message.debug("\t" + name + ": default md rejected by version matcher"
175
+ "requiring module descriptor: " + rres);
176
rejected.add(rres.getRevision() + " (MD)");
178
} else if (!versionMatcher.accept(mrid, md)) {
179
Message.debug("\t" + name + ": md rejected by version matcher: " + rres);
180
rejected.add(rres.getRevision() + " (MD)");
190
if (!found.getResource().exists()) {
191
Message.debug("\t" + name + ": resource not reachable for " + mrid + ": res="
192
+ found.getResource());
193
logAttempt(found.getResource().toString());
199
if (found == null && !rejected.isEmpty()) {
200
logAttempt(rejected.toString());
202
if (found == null && !foundBlacklisted.isEmpty()) {
203
// all acceptable versions have been blacklisted, this means that an unsolvable conflict
205
DependencyDescriptor dd = context.getDependencyDescriptor();
206
IvyNode parentNode = context.getResolveData().getNode(dd.getParentRevisionId());
207
ConflictManager cm = parentNode.getConflictManager(mrid.getModuleId());
208
cm.handleAllBlacklistedRevisions(dd, foundBlacklisted);
214
protected Collection findNames(Map tokenValues, String token) {
215
Collection names = new HashSet();
216
names.addAll(findIvyNames(tokenValues, token));
218
names.addAll(findArtifactNames(tokenValues, token));
223
protected Collection findIvyNames(Map tokenValues, String token) {
224
Collection names = new HashSet();
225
tokenValues = new HashMap(tokenValues);
226
tokenValues.put(IvyPatternHelper.ARTIFACT_KEY, "ivy");
227
tokenValues.put(IvyPatternHelper.TYPE_KEY, "ivy");
228
tokenValues.put(IvyPatternHelper.EXT_KEY, "xml");
229
if (isM2compatible()) {
230
convertM2TokenValuesForResourceSearch(tokenValues);
232
findTokenValues(names, getIvyPatterns(), tokenValues, token);
237
protected Collection findArtifactNames(Map tokenValues, String token) {
238
Collection names = new HashSet();
239
tokenValues = new HashMap(tokenValues);
241
.put(IvyPatternHelper.ARTIFACT_KEY, tokenValues.get(IvyPatternHelper.MODULE_KEY));
242
tokenValues.put(IvyPatternHelper.TYPE_KEY, "jar");
243
tokenValues.put(IvyPatternHelper.EXT_KEY, "jar");
244
if (isM2compatible()) {
245
convertM2TokenValuesForResourceSearch(tokenValues);
247
findTokenValues(names, getArtifactPatterns(), tokenValues, token);
252
public Map[] listTokenValues(String[] tokens, Map criteria) {
253
Set result = new LinkedHashSet();
256
List ivyPatterns = getIvyPatterns();
257
Map tokenValues = new HashMap(criteria);
258
tokenValues.put(IvyPatternHelper.TYPE_KEY, "ivy");
259
tokenValues.put(IvyPatternHelper.EXT_KEY, "xml");
260
if (isM2compatible()) {
261
convertM2TokenValuesForResourceSearch(tokenValues);
263
for (Iterator it = ivyPatterns.iterator(); it.hasNext();) {
264
String ivyPattern = (String) it.next();
265
result.addAll(resolveTokenValues(tokens, ivyPattern, tokenValues, false));
269
List artifactPatterns = getArtifactPatterns();
270
tokenValues = new HashMap(criteria);
271
tokenValues.put(IvyPatternHelper.TYPE_KEY, "jar");
272
tokenValues.put(IvyPatternHelper.EXT_KEY, "jar");
273
if (isM2compatible()) {
274
convertM2TokenValuesForResourceSearch(tokenValues);
276
for (Iterator it = artifactPatterns.iterator(); it.hasNext();) {
277
String artifactPattern = (String) it.next();
278
result.addAll(resolveTokenValues(tokens, artifactPattern, tokenValues, true));
282
return (Map[]) result.toArray(new Map[result.size()]);
285
private Set resolveTokenValues(String[] tokens, String pattern, Map criteria, boolean noMd) {
286
Set result = new LinkedHashSet();
287
Set tokenSet = new HashSet(Arrays.asList(tokens));
289
Map tokenValues = new HashMap();
290
for (Iterator it = criteria.entrySet().iterator(); it.hasNext();) {
291
Map.Entry entry = (Entry) it.next();
292
Object key = entry.getKey();
293
Object value = entry.getValue();
294
if (value instanceof String) {
295
tokenValues.put(key, value);
299
if (tokenSet.isEmpty()) {
300
// no more tokens to resolve
301
result.add(tokenValues);
305
String partiallyResolvedPattern = IvyPatternHelper.substituteTokens(pattern, tokenValues);
306
String token = IvyPatternHelper.getFirstToken(partiallyResolvedPattern);
307
if ((token == null) && exist(partiallyResolvedPattern)) {
308
// no more tokens to resolve
309
result.add(tokenValues);
313
tokenSet.remove(token);
315
Matcher matcher = null;
316
Object criteriaForToken = criteria.get(token);
317
if (criteriaForToken instanceof Matcher) {
318
matcher = (Matcher) criteriaForToken;
321
String[] values = listTokenValues(partiallyResolvedPattern, token);
322
if (values == null) {
326
List vals = new ArrayList(Arrays.asList(values));
329
for (Iterator it = vals.iterator(); it.hasNext();) {
330
String value = (String) it.next();
331
if ((matcher != null) && !matcher.matches(value)) {
335
tokenValues.put(token, value);
336
String moreResolvedPattern = IvyPatternHelper.substituteTokens(
337
partiallyResolvedPattern, tokenValues);
339
Map newCriteria = new HashMap(criteria);
340
newCriteria.put(token, value);
341
if (noMd && "artifact".equals(token)) {
342
newCriteria.put("module", value);
343
} else if (noMd && "module".equals(token)) {
344
newCriteria.put("artifact", value);
346
result.addAll(resolveTokenValues(
347
(String[]) tokenSet.toArray(new String[tokenSet.size()]),
348
moreResolvedPattern, newCriteria, noMd));
354
protected abstract String[] listTokenValues(String pattern, String token);
356
protected abstract boolean exist(String path);
359
* Filters names before returning them in the findXXXNames or findTokenValues method.
361
* Remember to call the super implementation when overriding this method.
365
* the list to filter.
366
* @return the filtered list
368
protected Collection filterNames(Collection names) {
369
getSettings().filterIgnore(names);
373
protected void findTokenValues(Collection names, List patterns, Map tokenValues, String token) {
374
//to be overridden by subclasses wanting to have listing features
378
* example of pattern : ~/Workspace/[module]/[module].ivy.xml
382
public void addIvyPattern(String pattern) {
383
ivyPatterns.add(pattern);
386
public void addArtifactPattern(String pattern) {
387
artifactPatterns.add(pattern);
390
public List getIvyPatterns() {
391
return Collections.unmodifiableList(ivyPatterns);
394
public List getArtifactPatterns() {
395
return Collections.unmodifiableList(artifactPatterns);
398
protected void setIvyPatterns(List patterns) {
399
ivyPatterns = patterns;
402
protected void setArtifactPatterns(List patterns) {
403
artifactPatterns = patterns;
407
* Methods respecting ivy conf method specifications
409
public void addConfiguredIvy(IvyPattern p) {
410
ivyPatterns.add(p.getPattern());
413
public void addConfiguredArtifact(IvyPattern p) {
414
artifactPatterns.add(p.getPattern());
417
public void dumpSettings() {
418
super.dumpSettings();
419
Message.debug("\t\tm2compatible: " + isM2compatible());
420
Message.debug("\t\tivy patterns:");
421
for (ListIterator iter = getIvyPatterns().listIterator(); iter.hasNext();) {
422
String p = (String) iter.next();
423
Message.debug("\t\t\t" + p);
425
Message.debug("\t\tartifact patterns:");
426
for (ListIterator iter = getArtifactPatterns().listIterator(); iter.hasNext();) {
427
String p = (String) iter.next();
428
Message.debug("\t\t\t" + p);
432
public boolean isM2compatible() {
436
public void setM2compatible(boolean compatible) {
437
m2compatible = compatible;
440
protected ModuleRevisionId convertM2IdForResourceSearch(ModuleRevisionId mrid) {
441
if (mrid.getOrganisation() == null || mrid.getOrganisation().indexOf('.') == -1) {
444
return ModuleRevisionId.newInstance(mrid.getOrganisation().replace('.', '/'),
445
mrid.getName(), mrid.getBranch(), mrid.getRevision(),
446
mrid.getQualifiedExtraAttributes());
449
protected String convertM2OrganizationForResourceSearch(String org) {
450
return org.replace('.', '/');
453
protected void convertM2TokenValuesForResourceSearch(Map tokenValues) {
454
if (tokenValues.get(IvyPatternHelper.ORGANISATION_KEY) instanceof String) {
455
tokenValues.put(IvyPatternHelper.ORGANISATION_KEY,
456
convertM2OrganizationForResourceSearch(
457
(String) tokenValues.get(IvyPatternHelper.ORGANISATION_KEY)));