001package org.eclipse.aether.util.graph.traverser; 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.LinkedHashSet; 026import java.util.Set; 027 028import org.eclipse.aether.collection.DependencyCollectionContext; 029import org.eclipse.aether.collection.DependencyTraverser; 030import org.eclipse.aether.graph.Dependency; 031 032import static java.util.Objects.requireNonNull; 033 034/** 035 * A dependency traverser that combines zero or more other traversers using a logical {@code AND}. The resulting 036 * traverser enables processing of child dependencies if and only if all constituent traversers request traversal. 037 */ 038public final class AndDependencyTraverser 039 implements DependencyTraverser 040{ 041 042 private final Set<? extends DependencyTraverser> traversers; 043 044 private int hashCode; 045 046 /** 047 * Creates a new traverser from the specified traversers. Prefer 048 * {@link #newInstance(DependencyTraverser, DependencyTraverser)} if any of the input traversers might be 049 * {@code null}. 050 * 051 * @param traversers The traversers to combine, may be {@code null} but must not contain {@code null} elements. 052 */ 053 public AndDependencyTraverser( DependencyTraverser... traversers ) 054 { 055 if ( traversers != null && traversers.length > 0 ) 056 { 057 this.traversers = new LinkedHashSet<>( Arrays.asList( traversers ) ); 058 } 059 else 060 { 061 this.traversers = Collections.emptySet(); 062 } 063 } 064 065 /** 066 * Creates a new traverser from the specified traversers. 067 * 068 * @param traversers The traversers to combine, may be {@code null} but must not contain {@code null} elements. 069 */ 070 public AndDependencyTraverser( Collection<? extends DependencyTraverser> traversers ) 071 { 072 if ( traversers != null && !traversers.isEmpty() ) 073 { 074 this.traversers = new LinkedHashSet<>( traversers ); 075 } 076 else 077 { 078 this.traversers = Collections.emptySet(); 079 } 080 } 081 082 private AndDependencyTraverser( Set<DependencyTraverser> traversers ) 083 { 084 if ( traversers != null && !traversers.isEmpty() ) 085 { 086 this.traversers = traversers; 087 } 088 else 089 { 090 this.traversers = Collections.emptySet(); 091 } 092 } 093 094 /** 095 * Creates a new traverser from the specified traversers. 096 * 097 * @param traverser1 The first traverser to combine, may be {@code null}. 098 * @param traverser2 The second traverser to combine, may be {@code null}. 099 * @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}