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 */
042@Deprecated
043public final class ScopeDependencySelector implements DependencySelector {
044
045    private final boolean transitive;
046
047    private final Collection<String> included;
048
049    private final Collection<String> excluded;
050
051    /**
052     * Creates a new selector using the specified includes and excludes.
053     *
054     * @param included The set of scopes to include, may be {@code null} or empty to include any scope.
055     * @param excluded The set of scopes to exclude, may be {@code null} or empty to exclude no scope.
056     */
057    public ScopeDependencySelector(Collection<String> included, Collection<String> excluded) {
058        transitive = false;
059        this.included = clone(included);
060        this.excluded = clone(excluded);
061    }
062
063    private static Collection<String> clone(Collection<String> scopes) {
064        Collection<String> copy;
065        if (scopes == null || scopes.isEmpty()) {
066            // checking for null is faster than isEmpty()
067            copy = null;
068        } else {
069            copy = new HashSet<>(scopes);
070            if (copy.size() <= 2) {
071                // contains() is faster for smallish array (sorted for equals()!)
072                copy = new ArrayList<>(new TreeSet<>(copy));
073            }
074        }
075        return copy;
076    }
077
078    /**
079     * Creates a new selector using the specified excludes.
080     *
081     * @param excluded The set of scopes to exclude, may be {@code null} or empty to exclude no scope.
082     */
083    public ScopeDependencySelector(String... excluded) {
084        this(null, (excluded != null) ? Arrays.asList(excluded) : null);
085    }
086
087    private ScopeDependencySelector(boolean transitive, Collection<String> included, Collection<String> excluded) {
088        this.transitive = transitive;
089        this.included = included;
090        this.excluded = excluded;
091    }
092
093    public boolean selectDependency(Dependency dependency) {
094        requireNonNull(dependency, "dependency cannot be null");
095        if (!transitive) {
096            return true;
097        }
098
099        String scope = dependency.getScope();
100        return (included == null || included.contains(scope)) && (excluded == null || !excluded.contains(scope));
101    }
102
103    public DependencySelector deriveChildSelector(DependencyCollectionContext context) {
104        requireNonNull(context, "context cannot be null");
105        if (this.transitive || context.getDependency() == null) {
106            return this;
107        }
108
109        return new ScopeDependencySelector(true, included, excluded);
110    }
111
112    @Override
113    public boolean equals(Object obj) {
114        if (this == obj) {
115            return true;
116        } else if (null == obj || !getClass().equals(obj.getClass())) {
117            return false;
118        }
119
120        ScopeDependencySelector that = (ScopeDependencySelector) obj;
121        return transitive == that.transitive
122                && Objects.equals(included, that.included)
123                && Objects.equals(excluded, that.excluded);
124    }
125
126    @Override
127    public int hashCode() {
128        int hash = 17;
129        hash = hash * 31 + (transitive ? 1 : 0);
130        hash = hash * 31 + (included != null ? included.hashCode() : 0);
131        hash = hash * 31 + (excluded != null ? excluded.hashCode() : 0);
132        return hash;
133    }
134
135    @Override
136    public String toString() {
137        return String.format(
138                "%s(included: %s, excluded: %s, transitive: %s)",
139                getClass().getSimpleName(), included, excluded, transitive);
140    }
141}