001package org.eclipse.aether.util.graph.selector; 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.DependencySelector; 030import org.eclipse.aether.graph.Dependency; 031 032/** 033 * A dependency selector that combines zero or more other selectors using a logical {@code AND}. The resulting selector 034 * selects a given dependency if and only if all constituent selectors do so. 035 */ 036public final class AndDependencySelector 037 implements DependencySelector 038{ 039 040 private final Set<? extends DependencySelector> selectors; 041 042 private int hashCode; 043 044 /** 045 * Creates a new selector from the specified selectors. Prefer 046 * {@link #newInstance(DependencySelector, DependencySelector)} if any of the input selectors might be {@code null}. 047 * 048 * @param selectors The selectors to combine, may be {@code null} but must not contain {@code null} elements. 049 */ 050 public AndDependencySelector( DependencySelector... selectors ) 051 { 052 if ( selectors != null && selectors.length > 0 ) 053 { 054 this.selectors = new LinkedHashSet<DependencySelector>( Arrays.asList( selectors ) ); 055 } 056 else 057 { 058 this.selectors = Collections.emptySet(); 059 } 060 } 061 062 /** 063 * Creates a new selector from the specified selectors. 064 * 065 * @param selectors The selectors to combine, may be {@code null} but must not contain {@code null} elements. 066 */ 067 public AndDependencySelector( Collection<? extends DependencySelector> selectors ) 068 { 069 if ( selectors != null && !selectors.isEmpty() ) 070 { 071 this.selectors = new LinkedHashSet<DependencySelector>( selectors ); 072 } 073 else 074 { 075 this.selectors = Collections.emptySet(); 076 } 077 } 078 079 private AndDependencySelector( Set<DependencySelector> selectors ) 080 { 081 if ( selectors != null && !selectors.isEmpty() ) 082 { 083 this.selectors = selectors; 084 } 085 else 086 { 087 this.selectors = Collections.emptySet(); 088 } 089 } 090 091 /** 092 * Creates a new selector from the specified selectors. 093 * 094 * @param selector1 The first selector to combine, may be {@code null}. 095 * @param selector2 The second selector to combine, may be {@code null}. 096 * @return The combined selector or {@code null} if both selectors were {@code null}. 097 */ 098 public static DependencySelector newInstance( DependencySelector selector1, DependencySelector selector2 ) 099 { 100 if ( selector1 == null ) 101 { 102 return selector2; 103 } 104 else if ( selector2 == null || selector2.equals( selector1 ) ) 105 { 106 return selector1; 107 } 108 return new AndDependencySelector( selector1, selector2 ); 109 } 110 111 public boolean selectDependency( Dependency dependency ) 112 { 113 for ( DependencySelector selector : selectors ) 114 { 115 if ( !selector.selectDependency( dependency ) ) 116 { 117 return false; 118 } 119 } 120 return true; 121 } 122 123 public DependencySelector deriveChildSelector( DependencyCollectionContext context ) 124 { 125 int seen = 0; 126 Set<DependencySelector> childSelectors = null; 127 128 for ( DependencySelector selector : selectors ) 129 { 130 DependencySelector childSelector = selector.deriveChildSelector( context ); 131 if ( childSelectors != null ) 132 { 133 if ( childSelector != null ) 134 { 135 childSelectors.add( childSelector ); 136 } 137 } 138 else if ( selector != childSelector ) 139 { 140 childSelectors = new LinkedHashSet<DependencySelector>(); 141 if ( seen > 0 ) 142 { 143 for ( DependencySelector s : selectors ) 144 { 145 if ( childSelectors.size() >= seen ) 146 { 147 break; 148 } 149 childSelectors.add( s ); 150 } 151 } 152 if ( childSelector != null ) 153 { 154 childSelectors.add( childSelector ); 155 } 156 } 157 else 158 { 159 seen++; 160 } 161 } 162 163 if ( childSelectors == null ) 164 { 165 return this; 166 } 167 if ( childSelectors.size() <= 1 ) 168 { 169 if ( childSelectors.isEmpty() ) 170 { 171 return null; 172 } 173 return childSelectors.iterator().next(); 174 } 175 return new AndDependencySelector( childSelectors ); 176 } 177 178 @Override 179 public boolean equals( Object obj ) 180 { 181 if ( this == obj ) 182 { 183 return true; 184 } 185 else if ( null == obj || !getClass().equals( obj.getClass() ) ) 186 { 187 return false; 188 } 189 190 AndDependencySelector that = (AndDependencySelector) obj; 191 return selectors.equals( that.selectors ); 192 } 193 194 @Override 195 public int hashCode() 196 { 197 if ( hashCode == 0 ) 198 { 199 int hash = 17; 200 hash = hash * 31 + selectors.hashCode(); 201 hashCode = hash; 202 } 203 return hashCode; 204 } 205 206}