001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.eclipse.aether.util.graph.selector;
020
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.Collection;
024import java.util.HashSet;
025import java.util.Objects;
026import java.util.TreeSet;
027
028import org.eclipse.aether.collection.DependencyCollectionContext;
029import org.eclipse.aether.collection.DependencySelector;
030import org.eclipse.aether.graph.Dependency;
031
032import static java.util.Objects.requireNonNull;
033
034/**
035 * A dependency selector that filters transitive dependencies based on their scope. Direct dependencies are always
036 * included regardless of their scope. <em>Note:</em> This filter does not assume any relationships between the scopes.
037 * In particular, the filter is not aware of scopes that logically include other scopes.
038 *
039 * @see Dependency#getScope()
040 * @deprecated this class is deprecated. Use same named class from impl module instead.
041 * @see org.eclipse.aether.scope.ScopeManager#getDependencySelector(org.eclipse.aether.RepositorySystemSession, org.eclipse.aether.scope.ResolutionScope)
042 */
043@Deprecated
044public final class ScopeDependencySelector implements DependencySelector {
045
046    private final boolean transitive;
047
048    private final Collection<String> included;
049
050    private final Collection<String> excluded;
051
052    /**
053     * Creates a new selector using the specified includes and excludes.
054     *
055     * @param included the set of scopes to include, may be {@code null} or empty to include any scope
056     * @param excluded the set of scopes to exclude, may be {@code null} or empty to exclude no scope
057     */
058    public ScopeDependencySelector(Collection<String> included, Collection<String> excluded) {
059        transitive = false;
060        this.included = clone(included);
061        this.excluded = clone(excluded);
062    }
063
064    private static Collection<String> clone(Collection<String> scopes) {
065        Collection<String> copy;
066        if (scopes == null || scopes.isEmpty()) {
067            // checking for null is faster than isEmpty()
068            copy = null;
069        } else {
070            copy = new HashSet<>(scopes);
071            if (copy.size() <= 2) {
072                // contains() is faster for smallish array (sorted for equals()!)
073                copy = new ArrayList<>(new TreeSet<>(copy));
074            }
075        }
076        return copy;
077    }
078
079    /**
080     * Creates a new selector using the specified excludes.
081     *
082     * @param excluded the set of scopes to exclude, may be {@code null} or empty to exclude no scope
083     */
084    public ScopeDependencySelector(String... excluded) {
085        this(null, (excluded != null) ? Arrays.asList(excluded) : null);
086    }
087
088    private ScopeDependencySelector(boolean transitive, Collection<String> included, Collection<String> excluded) {
089        this.transitive = transitive;
090        this.included = included;
091        this.excluded = excluded;
092    }
093
094    public boolean selectDependency(Dependency dependency) {
095        requireNonNull(dependency, "dependency cannot be null");
096        if (!transitive) {
097            return true;
098        }
099
100        String scope = dependency.getScope();
101        return (included == null || included.contains(scope)) && (excluded == null || !excluded.contains(scope));
102    }
103
104    public DependencySelector deriveChildSelector(DependencyCollectionContext context) {
105        requireNonNull(context, "context cannot be null");
106        if (this.transitive || context.getDependency() == null) {
107            return this;
108        }
109
110        return new ScopeDependencySelector(true, included, excluded);
111    }
112
113    @Override
114    public boolean equals(Object obj) {
115        if (this == obj) {
116            return true;
117        } else if (null == obj || !getClass().equals(obj.getClass())) {
118            return false;
119        }
120
121        ScopeDependencySelector that = (ScopeDependencySelector) obj;
122        return transitive == that.transitive
123                && Objects.equals(included, that.included)
124                && Objects.equals(excluded, that.excluded);
125    }
126
127    @Override
128    public int hashCode() {
129        int hash = 17;
130        hash = hash * 31 + (transitive ? 1 : 0);
131        hash = hash * 31 + (included != null ? included.hashCode() : 0);
132        hash = hash * 31 + (excluded != null ? excluded.hashCode() : 0);
133        return hash;
134    }
135
136    @Override
137    public String toString() {
138        return String.format(
139                "%s(included: %s, excluded: %s, transitive: %s)",
140                getClass().getSimpleName(), included, excluded, transitive);
141    }
142}