001package org.eclipse.aether.util.filter;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 * 
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 * 
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.Arrays;
023import java.util.Collection;
024import java.util.Collections;
025import java.util.HashSet;
026
027import org.eclipse.aether.graph.DependencyFilter;
028import org.eclipse.aether.util.artifact.JavaScopes;
029
030/**
031 * A utility class assisting in the creation of dependency node filters.
032 */
033public final class DependencyFilterUtils
034{
035
036    private DependencyFilterUtils()
037    {
038        // hide constructor
039    }
040
041    /**
042     * Creates a new filter that negates the specified filter.
043     * 
044     * @param filter The filter to negate, must not be {@code null}.
045     * @return The new filter, never {@code null}.
046     */
047    public static DependencyFilter notFilter( DependencyFilter filter )
048    {
049        return new NotDependencyFilter( filter );
050    }
051
052    /**
053     * Creates a new filter that combines the specified filters using a logical {@code AND}. If no filters are
054     * specified, the resulting filter accepts everything.
055     * 
056     * @param filters The filters to combine, may be {@code null}.
057     * @return The new filter, never {@code null}.
058     */
059    public static DependencyFilter andFilter( DependencyFilter... filters )
060    {
061        if ( filters != null && filters.length == 1 )
062        {
063            return filters[0];
064        }
065        else
066        {
067            return new AndDependencyFilter( filters );
068        }
069    }
070
071    /**
072     * Creates a new filter that combines the specified filters using a logical {@code AND}. If no filters are
073     * specified, the resulting filter accepts everything.
074     * 
075     * @param filters The filters to combine, may be {@code null}.
076     * @return The new filter, never {@code null}.
077     */
078    public static DependencyFilter andFilter( Collection<DependencyFilter> filters )
079    {
080        if ( filters != null && filters.size() == 1 )
081        {
082            return filters.iterator().next();
083        }
084        else
085        {
086            return new AndDependencyFilter( filters );
087        }
088    }
089
090    /**
091     * Creates a new filter that combines the specified filters using a logical {@code OR}. If no filters are specified,
092     * the resulting filter accepts nothing.
093     * 
094     * @param filters The filters to combine, may be {@code null}.
095     * @return The new filter, never {@code null}.
096     */
097    public static DependencyFilter orFilter( DependencyFilter... filters )
098    {
099        if ( filters != null && filters.length == 1 )
100        {
101            return filters[0];
102        }
103        else
104        {
105            return new OrDependencyFilter( filters );
106        }
107    }
108
109    /**
110     * Creates a new filter that combines the specified filters using a logical {@code OR}. If no filters are specified,
111     * the resulting filter accepts nothing.
112     * 
113     * @param filters The filters to combine, may be {@code null}.
114     * @return The new filter, never {@code null}.
115     */
116    public static DependencyFilter orFilter( Collection<DependencyFilter> filters )
117    {
118        if ( filters != null && filters.size() == 1 )
119        {
120            return filters.iterator().next();
121        }
122        else
123        {
124            return new OrDependencyFilter( filters );
125        }
126    }
127
128    /**
129     * Creates a new filter that selects dependencies whose scope matches one or more of the specified classpath types.
130     * A classpath type is a set of scopes separated by either {@code ','} or {@code '+'}.
131     * 
132     * @param classpathTypes The classpath types, may be {@code null} or empty to match no dependency.
133     * @return The new filter, never {@code null}.
134     * @see JavaScopes
135     */
136    public static DependencyFilter classpathFilter( String... classpathTypes )
137    {
138        return classpathFilter( ( classpathTypes != null ) ? Arrays.asList( classpathTypes ) : null );
139    }
140
141    /**
142     * Creates a new filter that selects dependencies whose scope matches one or more of the specified classpath types.
143     * A classpath type is a set of scopes separated by either {@code ','} or {@code '+'}.
144     * 
145     * @param classpathTypes The classpath types, may be {@code null} or empty to match no dependency.
146     * @return The new filter, never {@code null}.
147     * @see JavaScopes
148     */
149    public static DependencyFilter classpathFilter( Collection<String> classpathTypes )
150    {
151        Collection<String> types = new HashSet<String>();
152
153        if ( classpathTypes != null )
154        {
155            for ( String classpathType : classpathTypes )
156            {
157                String[] tokens = classpathType.split( "[+,]" );
158                for ( String token : tokens )
159                {
160                    token = token.trim();
161                    if ( token.length() > 0 )
162                    {
163                        types.add( token );
164                    }
165                }
166            }
167        }
168
169        Collection<String> included = new HashSet<String>();
170        for ( String type : types )
171        {
172            if ( JavaScopes.COMPILE.equals( type ) )
173            {
174                Collections.addAll( included, JavaScopes.COMPILE, JavaScopes.PROVIDED, JavaScopes.SYSTEM );
175            }
176            else if ( JavaScopes.RUNTIME.equals( type ) )
177            {
178                Collections.addAll( included, JavaScopes.COMPILE, JavaScopes.RUNTIME );
179            }
180            else if ( JavaScopes.TEST.equals( type ) )
181            {
182                Collections.addAll( included, JavaScopes.COMPILE, JavaScopes.PROVIDED, JavaScopes.SYSTEM,
183                                    JavaScopes.RUNTIME, JavaScopes.TEST );
184            }
185            else
186            {
187                included.add( type );
188            }
189        }
190
191        Collection<String> excluded = new HashSet<String>();
192        Collections.addAll( excluded, JavaScopes.COMPILE, JavaScopes.PROVIDED, JavaScopes.SYSTEM, JavaScopes.RUNTIME,
193                            JavaScopes.TEST );
194        excluded.removeAll( included );
195
196        return new ScopeDependencyFilter( null, excluded );
197    }
198
199}