// Licensed 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 // // http://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 net.sourceforge.eclipsejetty.util; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import net.sourceforge.eclipsejetty.JettyPlugin; import net.sourceforge.eclipsejetty.JettyPluginUtils; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.launching.IRuntimeClasspathEntry; /** * Matchers for classpath entries. * * @author Manfred Hantschel */ public abstract class DependencyMatcher { /** * Matches all entries. * * @return the matcher */ public static DependencyMatcher all() { return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { return entries; } @Override public String toString() { return "all"; //$NON-NLS-1$ } }; } /** * Each entry must match each matcher. The result is the intersection of the result of all specified matchers. * * @param matchers the matchers * @return the matcher */ public static DependencyMatcher and(final DependencyMatcher... matchers) { if ((matchers == null) || (matchers.length == 0)) { return all(); } if (matchers.length == 1) { return matchers[0]; } return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { Collection<Dependency> results = new LinkedHashSet<Dependency>(entries); for (DependencyMatcher matcher : matchers) { results = matcher.match(results); } return results; } @Override public String toString() { return "and" + Arrays.toString(matchers); //$NON-NLS-1$ } }; } /** * Each entry matches at least one of the specified matchers. The result is the union of the results of all * specified matchers. * * @param matchers the matchers * @return the matcher */ public static DependencyMatcher or(final DependencyMatcher... matchers) { if ((matchers == null) || (matchers.length == 0)) { return all(); } if (matchers.length == 1) { return matchers[0]; } return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { Collection<Dependency> results = new LinkedHashSet<Dependency>(); for (DependencyMatcher matcher : matchers) { results.addAll(matcher.match(new ArrayList<Dependency>(entries))); } return results; } @Override public String toString() { return "or" + Arrays.toString(matchers); //$NON-NLS-1$ } }; } /** * Keeps those entries, that do not match the specified matcher. The result is the inversion of the result of the * specified matcher. * * @param matcher the matcher * @return the matcher */ public static DependencyMatcher not(final DependencyMatcher matcher) { return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { entries.removeAll(matcher.match(new ArrayList<Dependency>(entries))); return entries; } @Override public String toString() { return "not[" + matcher + "]"; //$NON-NLS-1$ //$NON-NLS-2$ } }; } public static DependencyMatcher bootstrapClasses() { return withClasspathProperty(IRuntimeClasspathEntry.BOOTSTRAP_CLASSES); } public static DependencyMatcher standardClasses() { return withClasspathProperty(IRuntimeClasspathEntry.STANDARD_CLASSES); } public static DependencyMatcher userClasses() { return withClasspathProperty(IRuntimeClasspathEntry.USER_CLASSES); } /** * Matches only those entries with the specified classpath property: BOOTSTRAP_CLASSES, STANDARD_CLASSES, * USER_CLASSES. * * @param classpathProperty the property as defined in the {@link IRuntimeClasspathEntry} class * @return all matching entries */ public static DependencyMatcher withClasspathProperty(final int classpathProperty) { return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { Iterator<Dependency> iterator = entries.iterator(); while (iterator.hasNext()) { Dependency entry = iterator.next(); if (classpathProperty != entry.getRuntimeClasspathEntry().getClasspathProperty()) { iterator.remove(); } } return entries; } @Override public String toString() { switch (classpathProperty) { case IRuntimeClasspathEntry.BOOTSTRAP_CLASSES: return "bootstrapClasses"; //$NON-NLS-1$ case IRuntimeClasspathEntry.STANDARD_CLASSES: return "standardClasses"; //$NON-NLS-1$ case IRuntimeClasspathEntry.USER_CLASSES: return "userClasses"; //$NON-NLS-1$ default: return "withClasspathProperty " + classpathProperty; //$NON-NLS-1$ } } }; } public static DependencyMatcher ofTypeArchive(final int type) { return ofType(IRuntimeClasspathEntry.ARCHIVE); } public static DependencyMatcher ofTypeContainer(final int type) { return ofType(IRuntimeClasspathEntry.CONTAINER); } public static DependencyMatcher ofTypeOther(final int type) { return ofType(IRuntimeClasspathEntry.OTHER); } public static DependencyMatcher ofTypeProject(final int type) { return ofType(IRuntimeClasspathEntry.PROJECT); } public static DependencyMatcher ofTypeVariable(final int type) { return ofType(IRuntimeClasspathEntry.VARIABLE); } /** * Matches only those entries with the specified type: ARCHIVE, CONTAINER, OTHER, PROJECT, VARIABLE. * * @param type the type as defined in the {@link IRuntimeClasspathEntry} class * @return all matching entries */ public static DependencyMatcher ofType(final int type) { return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { Iterator<Dependency> iterator = entries.iterator(); while (iterator.hasNext()) { Dependency entry = iterator.next(); if (type != entry.getRuntimeClasspathEntry().getType()) { iterator.remove(); } } return entries; } @Override public String toString() { switch (type) { case IRuntimeClasspathEntry.ARCHIVE: return "of type archive"; //$NON-NLS-1$ case IRuntimeClasspathEntry.CONTAINER: return "of type container"; //$NON-NLS-1$ case IRuntimeClasspathEntry.OTHER: return "of type other"; //$NON-NLS-1$ case IRuntimeClasspathEntry.PROJECT: return "of type project"; //$NON-NLS-1$ case IRuntimeClasspathEntry.VARIABLE: return "of type variable"; //$NON-NLS-1$ default: return "of type " + type; //$NON-NLS-1$ } } }; } /** * Matches all entries, that match the specified scope. * * @param scope the scope * @return all matching entries */ public static DependencyMatcher withScope(final MavenScope scope) { return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { Iterator<Dependency> iterator = entries.iterator(); while (iterator.hasNext()) { Dependency entry = iterator.next(); if (scope == entry.getScope()) { continue; } iterator.remove(); } return entries; } @Override public String toString() { return "with scope " + scope; //$NON-NLS-1$ } }; } /** * Matches all entries, that are in the specified collection * * @param excludedEntries a collection of {@link IRuntimeClasspathEntry}s * @return all matching entries */ public static DependencyMatcher notIn(Collection<IRuntimeClasspathEntry> excludedEntries) throws CoreException { final Set<IRuntimeClasspathEntry> excludedEntriesSet = new LinkedHashSet<IRuntimeClasspathEntry>(excludedEntries); return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { Iterator<Dependency> iterator = entries.iterator(); while (iterator.hasNext()) { if (excludedEntriesSet.contains(iterator.next().getRuntimeClasspathEntry())) { iterator.remove(); } } return entries; } @Override public String toString() { return "notIn" + excludedEntriesSet; //$NON-NLS-1$ } }; } /** * Matches all entries, that are included * * @param included a list of regular expression of file or path names * @return all matching entries * @throws CoreException if the included list cannot be parsed * @deprecated replaced by a mechanism using generic ids */ @Deprecated public static DependencyMatcher isIncludedRegEx(Collection<String> included) throws CoreException { final List<RegularMatcher> includedLibs = new ArrayList<RegularMatcher>(); try { JettyPluginUtils.extractPatterns(includedLibs, included); } catch (final IllegalArgumentException e) { throw new CoreException(new Status(IStatus.ERROR, JettyPlugin.PLUGIN_ID, e.getMessage(), e)); } return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { Iterator<Dependency> iterator = entries.iterator(); entry: while (iterator.hasNext()) { IRuntimeClasspathEntry entry = iterator.next().getRuntimeClasspathEntry(); String path = entry.getLocation(); String forwardSlashes = path.replace('\\', '/'); String backSlashes = path.replace('/', '\\'); for (final RegularMatcher includedLib : includedLibs) { if ((includedLib.matches(forwardSlashes)) || (includedLib.matches(backSlashes))) { continue entry; } } iterator.remove(); } return entries; } @Override public String toString() { return "included" + includedLibs; //$NON-NLS-1$ } }; } /** * Matches all entries, that are not excluded * * @param excluded a list of regular expression of file or path names * @return all matching entries * @throws CoreException if the excluded list cannot be parsed * @deprecated replaced by a mechanism using generic ids */ @Deprecated public static DependencyMatcher notExcludedRegEx(Collection<String> excluded) throws CoreException { final List<RegularMatcher> excludedLibs = new ArrayList<RegularMatcher>(); try { JettyPluginUtils.extractPatterns(excludedLibs, excluded); } catch (final IllegalArgumentException e) { throw new CoreException(new Status(IStatus.ERROR, JettyPlugin.PLUGIN_ID, e.getMessage(), e)); } return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { Iterator<Dependency> iterator = entries.iterator(); entry: while (iterator.hasNext()) { IRuntimeClasspathEntry entry = iterator.next().getRuntimeClasspathEntry(); String path = entry.getLocation(); String forwardSlashes = path.replace('\\', '/'); String backSlashes = path.replace('/', '\\'); for (final RegularMatcher excludedLib : excludedLibs) { if ((excludedLib.matches(forwardSlashes)) || (excludedLib.matches(backSlashes))) { iterator.remove(); continue entry; } } } return entries; } @Override public String toString() { return "notExcluded" + excludedLibs; //$NON-NLS-1$ } }; } /** * Matches all entries, that are included * * @param includedGenericIds a list of generic ids * @return all matching entries * @throws CoreException if the included list cannot be parsed */ public static DependencyMatcher isIncludedGenericId(final Collection<String> includedGenericIds) throws CoreException { return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { Iterator<Dependency> iterator = entries.iterator(); while (iterator.hasNext()) { Dependency entry = iterator.next(); if (includedGenericIds.contains(entry.getGenericId())) { continue; } iterator.remove(); } return entries; } @Override public String toString() { return "included" + includedGenericIds; //$NON-NLS-1$ } }; } /** * Matches all entries, that are not excluded * * @param excludedGenericIds a list of generic ids * @return all matching entries * @throws CoreException if the excluded list cannot be parsed */ public static DependencyMatcher notExcludedGenericIds(final Collection<String> excludedGenericIds) throws CoreException { return new DependencyMatcher() { @Override public Collection<Dependency> match(Collection<Dependency> entries) { Iterator<Dependency> iterator = entries.iterator(); while (iterator.hasNext()) { Dependency entry = iterator.next(); if (!excludedGenericIds.contains(entry.getGenericId())) { continue; } iterator.remove(); } return entries; } @Override public String toString() { return "notExcluded" + excludedGenericIds; //$NON-NLS-1$ } }; } public abstract Collection<Dependency> match(Collection<Dependency> entries); /** * {@inheritDoc} */ @Override public abstract String toString(); }