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