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  /**
33   * A dependency traverser that combines zero or more other traversers using a logical {@code AND}. The resulting
34   * traverser enables processing of child dependencies if and only if all constituent traversers request traversal.
35   */
36  public final class AndDependencyTraverser
37      implements DependencyTraverser
38  {
39  
40      private final Set<? extends DependencyTraverser> traversers;
41  
42      private int hashCode;
43  
44      /**
45       * Creates a new traverser from the specified traversers. Prefer
46       * {@link #newInstance(DependencyTraverser, DependencyTraverser)} if any of the input traversers might be
47       * {@code null}.
48       * 
49       * @param traversers The traversers to combine, may be {@code null} but must not contain {@code null} elements.
50       */
51      public AndDependencyTraverser( DependencyTraverser... traversers )
52      {
53          if ( traversers != null && traversers.length > 0 )
54          {
55              this.traversers = new LinkedHashSet<DependencyTraverser>( Arrays.asList( traversers ) );
56          }
57          else
58          {
59              this.traversers = Collections.emptySet();
60          }
61      }
62  
63      /**
64       * Creates a new traverser from the specified traversers.
65       * 
66       * @param traversers The traversers to combine, may be {@code null} but must not contain {@code null} elements.
67       */
68      public AndDependencyTraverser( Collection<? extends DependencyTraverser> traversers )
69      {
70          if ( traversers != null && !traversers.isEmpty() )
71          {
72              this.traversers = new LinkedHashSet<DependencyTraverser>( traversers );
73          }
74          else
75          {
76              this.traversers = Collections.emptySet();
77          }
78      }
79  
80      private AndDependencyTraverser( Set<DependencyTraverser> traversers )
81      {
82          if ( traversers != null && !traversers.isEmpty() )
83          {
84              this.traversers = traversers;
85          }
86          else
87          {
88              this.traversers = Collections.emptySet();
89          }
90      }
91  
92      /**
93       * Creates a new traverser from the specified traversers.
94       * 
95       * @param traverser1 The first traverser to combine, may be {@code null}.
96       * @param traverser2 The second traverser to combine, may be {@code null}.
97       * @return The combined traverser or {@code null} if both traversers were {@code null}.
98       */
99      public static DependencyTraverser newInstance( DependencyTraverser traverser1, DependencyTraverser traverser2 )
100     {
101         if ( traverser1 == null )
102         {
103             return traverser2;
104         }
105         else if ( traverser2 == null || traverser2.equals( traverser1 ) )
106         {
107             return traverser1;
108         }
109         return new AndDependencyTraverser( traverser1, traverser2 );
110     }
111 
112     public boolean traverseDependency( Dependency dependency )
113     {
114         for ( DependencyTraverser traverser : traversers )
115         {
116             if ( !traverser.traverseDependency( dependency ) )
117             {
118                 return false;
119             }
120         }
121         return true;
122     }
123 
124     public DependencyTraverser deriveChildTraverser( DependencyCollectionContext context )
125     {
126         int seen = 0;
127         Set<DependencyTraverser> childTraversers = null;
128 
129         for ( DependencyTraverser traverser : traversers )
130         {
131             DependencyTraverser childTraverser = traverser.deriveChildTraverser( context );
132             if ( childTraversers != null )
133             {
134                 if ( childTraverser != null )
135                 {
136                     childTraversers.add( childTraverser );
137                 }
138             }
139             else if ( traverser != childTraverser )
140             {
141                 childTraversers = new LinkedHashSet<DependencyTraverser>();
142                 if ( seen > 0 )
143                 {
144                     for ( DependencyTraverser s : traversers )
145                     {
146                         if ( childTraversers.size() >= seen )
147                         {
148                             break;
149                         }
150                         childTraversers.add( s );
151                     }
152                 }
153                 if ( childTraverser != null )
154                 {
155                     childTraversers.add( childTraverser );
156                 }
157             }
158             else
159             {
160                 seen++;
161             }
162         }
163 
164         if ( childTraversers == null )
165         {
166             return this;
167         }
168         if ( childTraversers.size() <= 1 )
169         {
170             if ( childTraversers.isEmpty() )
171             {
172                 return null;
173             }
174             return childTraversers.iterator().next();
175         }
176         return new AndDependencyTraverser( childTraversers );
177     }
178 
179     @Override
180     public boolean equals( Object obj )
181     {
182         if ( this == obj )
183         {
184             return true;
185         }
186         else if ( null == obj || !getClass().equals( obj.getClass() ) )
187         {
188             return false;
189         }
190 
191         AndDependencyTraverser that = (AndDependencyTraverser) obj;
192         return traversers.equals( that.traversers );
193     }
194 
195     @Override
196     public int hashCode()
197     {
198         if ( hashCode == 0 )
199         {
200             int hash = 17;
201             hash = hash * 31 + traversers.hashCode();
202             hashCode = hash;
203         }
204         return hashCode;
205     }
206 
207 }