View Javadoc
1   package org.eclipse.aether.util.graph.traverser;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   * 
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Arrays;
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.LinkedHashSet;
26  import java.util.Set;
27  
28  import org.eclipse.aether.collection.DependencyCollectionContext;
29  import org.eclipse.aether.collection.DependencyTraverser;
30  import org.eclipse.aether.graph.Dependency;
31  
32  import static java.util.Objects.requireNonNull;
33  
34  /**
35   * A dependency traverser that combines zero or more other traversers using a logical {@code AND}. The resulting
36   * traverser enables processing of child dependencies if and only if all constituent traversers request traversal.
37   */
38  public final class AndDependencyTraverser
39      implements DependencyTraverser
40  {
41  
42      private final Set<? extends DependencyTraverser> traversers;
43  
44      private int hashCode;
45  
46      /**
47       * Creates a new traverser from the specified traversers. Prefer
48       * {@link #newInstance(DependencyTraverser, DependencyTraverser)} if any of the input traversers might be
49       * {@code null}.
50       * 
51       * @param traversers The traversers to combine, may be {@code null} but must not contain {@code null} elements.
52       */
53      public AndDependencyTraverser( DependencyTraverser... traversers )
54      {
55          if ( traversers != null && traversers.length > 0 )
56          {
57              this.traversers = new LinkedHashSet<>( Arrays.asList( traversers ) );
58          }
59          else
60          {
61              this.traversers = Collections.emptySet();
62          }
63      }
64  
65      /**
66       * Creates a new traverser from the specified traversers.
67       * 
68       * @param traversers The traversers to combine, may be {@code null} but must not contain {@code null} elements.
69       */
70      public AndDependencyTraverser( Collection<? extends DependencyTraverser> traversers )
71      {
72          if ( traversers != null && !traversers.isEmpty() )
73          {
74              this.traversers = new LinkedHashSet<>( traversers );
75          }
76          else
77          {
78              this.traversers = Collections.emptySet();
79          }
80      }
81  
82      private AndDependencyTraverser( Set<DependencyTraverser> traversers )
83      {
84          if ( traversers != null && !traversers.isEmpty() )
85          {
86              this.traversers = traversers;
87          }
88          else
89          {
90              this.traversers = Collections.emptySet();
91          }
92      }
93  
94      /**
95       * Creates a new traverser from the specified traversers.
96       * 
97       * @param traverser1 The first traverser to combine, may be {@code null}.
98       * @param traverser2 The second traverser to combine, may be {@code null}.
99       * @return The combined traverser or {@code null} if both traversers were {@code null}.
100      */
101     public static DependencyTraverser newInstance( DependencyTraverser traverser1, DependencyTraverser traverser2 )
102     {
103         if ( traverser1 == null )
104         {
105             return traverser2;
106         }
107         else if ( traverser2 == null || traverser2.equals( traverser1 ) )
108         {
109             return traverser1;
110         }
111         return new AndDependencyTraverser( traverser1, traverser2 );
112     }
113 
114     public boolean traverseDependency( Dependency dependency )
115     {
116         requireNonNull( dependency, "dependency cannot be null" );
117         for ( DependencyTraverser traverser : traversers )
118         {
119             if ( !traverser.traverseDependency( dependency ) )
120             {
121                 return false;
122             }
123         }
124         return true;
125     }
126 
127     public DependencyTraverser deriveChildTraverser( DependencyCollectionContext context )
128     {
129         requireNonNull( context, "context cannot be null" );
130         int seen = 0;
131         Set<DependencyTraverser> childTraversers = null;
132 
133         for ( DependencyTraverser traverser : traversers )
134         {
135             DependencyTraverser childTraverser = traverser.deriveChildTraverser( context );
136             if ( childTraversers != null )
137             {
138                 if ( childTraverser != null )
139                 {
140                     childTraversers.add( childTraverser );
141                 }
142             }
143             else if ( traverser != childTraverser )
144             {
145                 childTraversers = new LinkedHashSet<>();
146                 if ( seen > 0 )
147                 {
148                     for ( DependencyTraverser s : traversers )
149                     {
150                         if ( childTraversers.size() >= seen )
151                         {
152                             break;
153                         }
154                         childTraversers.add( s );
155                     }
156                 }
157                 if ( childTraverser != null )
158                 {
159                     childTraversers.add( childTraverser );
160                 }
161             }
162             else
163             {
164                 seen++;
165             }
166         }
167 
168         if ( childTraversers == null )
169         {
170             return this;
171         }
172         if ( childTraversers.size() <= 1 )
173         {
174             if ( childTraversers.isEmpty() )
175             {
176                 return null;
177             }
178             return childTraversers.iterator().next();
179         }
180         return new AndDependencyTraverser( childTraversers );
181     }
182 
183     @Override
184     public boolean equals( Object obj )
185     {
186         if ( this == obj )
187         {
188             return true;
189         }
190         else if ( null == obj || !getClass().equals( obj.getClass() ) )
191         {
192             return false;
193         }
194 
195         AndDependencyTraverser that = (AndDependencyTraverser) obj;
196         return traversers.equals( that.traversers );
197     }
198 
199     @Override
200     public int hashCode()
201     {
202         if ( hashCode == 0 )
203         {
204             int hash = 17;
205             hash = hash * 31 + traversers.hashCode();
206             hashCode = hash;
207         }
208         return hashCode;
209     }
210 
211 }