| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * https://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| package org.apache.ivy.plugins.resolver; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.ivy.core.IvyPatternHelper; |
| import org.apache.ivy.core.module.descriptor.Artifact; |
| import org.apache.ivy.core.module.descriptor.DefaultArtifact; |
| import org.apache.ivy.core.module.descriptor.DependencyDescriptor; |
| import org.apache.ivy.core.module.id.ModuleRevisionId; |
| import org.apache.ivy.core.resolve.ResolveData; |
| import org.apache.ivy.core.settings.IvyPattern; |
| import org.apache.ivy.plugins.matcher.Matcher; |
| import org.apache.ivy.plugins.resolver.util.ResolvedResource; |
| import org.apache.ivy.plugins.resolver.util.ResourceMDParser; |
| import org.apache.ivy.util.Message; |
| |
| /** |
| * |
| */ |
| public abstract class AbstractPatternsBasedResolver extends BasicResolver { |
| |
| private List<String> ivyPatterns = new ArrayList<>(); |
| |
| private List<String> artifactPatterns = new ArrayList<>(); |
| |
| private boolean m2compatible = false; |
| |
| public AbstractPatternsBasedResolver() { |
| } |
| |
| public ResolvedResource findIvyFileRef(DependencyDescriptor dd, ResolveData data) { |
| ModuleRevisionId mrid = dd.getDependencyRevisionId(); |
| if (isM2compatible()) { |
| mrid = convertM2IdForResourceSearch(mrid); |
| } |
| return findResourceUsingPatterns(mrid, ivyPatterns, |
| DefaultArtifact.newIvyArtifact(mrid, data.getDate()), getRMDParser(dd, data), |
| data.getDate()); |
| } |
| |
| @Override |
| public ResolvedResource findArtifactRef(Artifact artifact, Date date) { |
| ModuleRevisionId mrid = artifact.getModuleRevisionId(); |
| if (isM2compatible()) { |
| mrid = convertM2IdForResourceSearch(mrid); |
| } |
| return findResourceUsingPatterns(mrid, artifactPatterns, artifact, |
| getDefaultRMDParser(artifact.getModuleRevisionId().getModuleId()), date); |
| } |
| |
| @Override |
| public ResolvedResource findResource(ResolvedResource[] rress, ResourceMDParser rmdparser, |
| ModuleRevisionId mrid, Date date) { |
| if (isM2compatible()) { |
| // convert 'M2'-organisation back to 'Ivy'-organisation |
| mrid = convertM2ResourceSearchIdToNormal(mrid); |
| } |
| return super.findResource(rress, rmdparser, mrid, date); |
| } |
| |
| protected ResolvedResource findResourceUsingPatterns(ModuleRevisionId moduleRevision, |
| List<String> patternList, Artifact artifact, ResourceMDParser rmdparser, Date date) { |
| List<ResolvedResource> resolvedResources = new ArrayList<>(); |
| Set<String> foundRevisions = new HashSet<>(); |
| boolean dynamic = getSettings().getVersionMatcher().isDynamic(moduleRevision); |
| for (String pattern : patternList) { |
| ResolvedResource rres = findResourceUsingPattern(moduleRevision, pattern, artifact, |
| rmdparser, date); |
| if (rres != null && !foundRevisions.contains(rres.getRevision())) { |
| // only add the first found ResolvedResource for each revision |
| foundRevisions.add(rres.getRevision()); |
| resolvedResources.add(rres); |
| if (!dynamic) { |
| // stop iterating if we are not searching a dynamic revision |
| break; |
| } |
| } |
| } |
| |
| if (resolvedResources.size() > 1) { |
| ResolvedResource[] rress = resolvedResources |
| .toArray(new ResolvedResource[resolvedResources.size()]); |
| return findResource(rress, rmdparser, moduleRevision, date); |
| } else if (resolvedResources.size() == 1) { |
| return resolvedResources.get(0); |
| } else { |
| return null; |
| } |
| } |
| |
| protected abstract ResolvedResource findResourceUsingPattern(ModuleRevisionId mrid, |
| String pattern, Artifact artifact, ResourceMDParser rmdparser, Date date); |
| |
| @Override |
| protected Collection<String> findNames(Map<String, String> tokenValues, String token) { |
| Collection<String> names = new HashSet<>(findIvyNames(tokenValues, token)); |
| if (isAllownomd()) { |
| names.addAll(findArtifactNames(tokenValues, token)); |
| } |
| return names; |
| } |
| |
| protected Collection<String> findIvyNames(Map<String, String> tokenValues, String token) { |
| Collection<String> names = new HashSet<>(); |
| tokenValues = new HashMap<>(tokenValues); |
| tokenValues.put(IvyPatternHelper.ARTIFACT_KEY, "ivy"); |
| tokenValues.put(IvyPatternHelper.TYPE_KEY, "ivy"); |
| tokenValues.put(IvyPatternHelper.EXT_KEY, "xml"); |
| if (isM2compatible()) { |
| convertM2TokenValuesForResourceSearch(tokenValues); |
| } |
| findTokenValues(names, getIvyPatterns(), tokenValues, token); |
| filterNames(names); |
| return names; |
| } |
| |
| protected Collection<String> findArtifactNames(Map<String, String> tokenValues, String token) { |
| Collection<String> names = new HashSet<>(); |
| tokenValues = new HashMap<>(tokenValues); |
| tokenValues |
| .put(IvyPatternHelper.ARTIFACT_KEY, tokenValues.get(IvyPatternHelper.MODULE_KEY)); |
| tokenValues.put(IvyPatternHelper.TYPE_KEY, "jar"); |
| tokenValues.put(IvyPatternHelper.EXT_KEY, "jar"); |
| if (isM2compatible()) { |
| convertM2TokenValuesForResourceSearch(tokenValues); |
| } |
| findTokenValues(names, getArtifactPatterns(), tokenValues, token); |
| filterNames(names); |
| return names; |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public Map<String, String>[] listTokenValues(String[] tokens, Map<String, Object> criteria) { |
| Set<Map<String, String>> result = new LinkedHashSet<>(); |
| |
| // use ivy patterns |
| Map<String, Object> subcriteria = new HashMap<>(criteria); |
| subcriteria.put(IvyPatternHelper.TYPE_KEY, "ivy"); |
| subcriteria.put(IvyPatternHelper.EXT_KEY, getModuleDescriptorExtension()); |
| if (isM2compatible()) { |
| convertM2CriteriaForResourceSearch(subcriteria); |
| } |
| for (String ivyPattern : getIvyPatterns()) { |
| result.addAll(resolveTokenValues(tokens, ivyPattern, subcriteria, false)); |
| } |
| |
| if (isAllownomd()) { |
| subcriteria = new HashMap<>(criteria); |
| subcriteria.put(IvyPatternHelper.TYPE_KEY, "jar"); |
| subcriteria.put(IvyPatternHelper.EXT_KEY, "jar"); |
| if (isM2compatible()) { |
| convertM2CriteriaForResourceSearch(subcriteria); |
| } |
| for (String artifactPattern : getArtifactPatterns()) { |
| result.addAll(resolveTokenValues(tokens, artifactPattern, subcriteria, true)); |
| } |
| } |
| |
| return result.toArray(new Map[result.size()]); |
| } |
| |
| protected String getModuleDescriptorExtension() { |
| return "xml"; |
| } |
| |
| private Set<Map<String, String>> resolveTokenValues(String[] tokens, String pattern, |
| Map<String, Object> criteria, boolean noMd) { |
| Set<Map<String, String>> result = new LinkedHashSet<>(); |
| Set<String> tokenSet = new HashSet<>(Arrays.asList(tokens)); |
| |
| Map<String, String> tokenValues = new HashMap<>(); |
| for (Map.Entry<String, Object> entry : criteria.entrySet()) { |
| Object value = entry.getValue(); |
| if (value instanceof String) { |
| tokenValues.put(entry.getKey(), (String) value); |
| } |
| } |
| |
| if (tokenSet.isEmpty()) { |
| // no more tokens to resolve |
| result.add(tokenValues); |
| return result; |
| } |
| |
| String partiallyResolvedPattern = IvyPatternHelper.substituteTokens(pattern, tokenValues); |
| String token = IvyPatternHelper.getFirstToken(partiallyResolvedPattern); |
| if (token == null && exist(partiallyResolvedPattern)) { |
| // no more tokens to resolve |
| result.add(tokenValues); |
| return result; |
| } |
| |
| tokenSet.remove(token); |
| |
| Matcher matcher = null; |
| Object criteriaForToken = criteria.get(token); |
| if (criteriaForToken instanceof Matcher) { |
| matcher = (Matcher) criteriaForToken; |
| } |
| |
| String[] values = listTokenValues(partiallyResolvedPattern, token); |
| if (values == null) { |
| return result; |
| } |
| |
| List<String> valueList = new ArrayList<>(Arrays.asList(values)); |
| filterNames(valueList); |
| |
| for (String value : valueList) { |
| if (matcher != null && !matcher.matches(value)) { |
| continue; |
| } |
| |
| tokenValues.put(token, value); |
| String moreResolvedPattern = IvyPatternHelper.substituteTokens( |
| partiallyResolvedPattern, tokenValues); |
| |
| Map<String, Object> newCriteria = new HashMap<>(criteria); |
| newCriteria.put(token, value); |
| if (noMd && "artifact".equals(token)) { |
| newCriteria.put("module", value); |
| } else if (noMd && "module".equals(token)) { |
| newCriteria.put("artifact", value); |
| } |
| result.addAll(resolveTokenValues(tokenSet.toArray(new String[tokenSet.size()]), |
| moreResolvedPattern, newCriteria, noMd)); |
| } |
| |
| return result; |
| } |
| |
| protected abstract String[] listTokenValues(String pattern, String token); |
| |
| protected abstract boolean exist(String path); |
| |
| protected void findTokenValues(Collection<String> names, List<String> patterns, |
| Map<String, String> tokenValues, String token) { |
| // to be overridden by subclasses wanting to have listing features |
| } |
| |
| /** |
| * example of pattern : ~/Workspace/[module]/[module].ivy.xml |
| * |
| * @param pattern String |
| */ |
| public void addIvyPattern(String pattern) { |
| ivyPatterns.add(pattern); |
| } |
| |
| public void addArtifactPattern(String pattern) { |
| artifactPatterns.add(pattern); |
| } |
| |
| public List<String> getIvyPatterns() { |
| return Collections.unmodifiableList(ivyPatterns); |
| } |
| |
| public List<String> getArtifactPatterns() { |
| return Collections.unmodifiableList(artifactPatterns); |
| } |
| |
| protected void setIvyPatterns(List<String> patterns) { |
| ivyPatterns = patterns; |
| } |
| |
| protected void setArtifactPatterns(List<String> patterns) { |
| artifactPatterns = patterns; |
| } |
| |
| /* |
| * Methods respecting ivy conf method specifications |
| */ |
| public void addConfiguredIvy(IvyPattern p) { |
| ivyPatterns.add(p.getPattern()); |
| } |
| |
| public void addConfiguredArtifact(IvyPattern p) { |
| artifactPatterns.add(p.getPattern()); |
| } |
| |
| @Override |
| public void dumpSettings() { |
| super.dumpSettings(); |
| Message.debug("\t\tm2compatible: " + isM2compatible()); |
| Message.debug("\t\tivy patterns:"); |
| for (String p : getIvyPatterns()) { |
| Message.debug("\t\t\t" + p); |
| } |
| Message.debug("\t\tartifact patterns:"); |
| for (String p : getArtifactPatterns()) { |
| Message.debug("\t\t\t" + p); |
| } |
| } |
| |
| public boolean isM2compatible() { |
| return m2compatible; |
| } |
| |
| public void setM2compatible(boolean compatible) { |
| m2compatible = compatible; |
| } |
| |
| protected ModuleRevisionId convertM2ResourceSearchIdToNormal(ModuleRevisionId mrid) { |
| if (mrid.getOrganisation() == null || mrid.getOrganisation().indexOf('/') == -1) { |
| return mrid; |
| } |
| return ModuleRevisionId.newInstance(mrid.getOrganisation().replace('/', '.'), |
| mrid.getName(), mrid.getBranch(), mrid.getRevision(), |
| mrid.getQualifiedExtraAttributes()); |
| } |
| |
| protected ModuleRevisionId convertM2IdForResourceSearch(ModuleRevisionId mrid) { |
| if (mrid.getOrganisation() == null || mrid.getOrganisation().indexOf('.') == -1) { |
| return mrid; |
| } |
| return ModuleRevisionId.newInstance(mrid.getOrganisation().replace('.', '/'), |
| mrid.getName(), mrid.getBranch(), mrid.getRevision(), |
| mrid.getQualifiedExtraAttributes()); |
| } |
| |
| protected String convertM2OrganizationForResourceSearch(String org) { |
| return org.replace('.', '/'); |
| } |
| |
| protected void convertM2TokenValuesForResourceSearch(Map<String, String> tokenValues) { |
| tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, |
| convertM2OrganizationForResourceSearch(tokenValues |
| .get(IvyPatternHelper.ORGANISATION_KEY))); |
| } |
| |
| protected void convertM2CriteriaForResourceSearch(Map<String, Object> criteria) { |
| Object org = criteria.get(IvyPatternHelper.ORGANISATION_KEY); |
| if (org instanceof String) { |
| criteria.put(IvyPatternHelper.ORGANISATION_KEY, |
| convertM2OrganizationForResourceSearch((String) org)); |
| } |
| } |
| |
| } |