001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.util.graph.selector; 020 021import java.util.Arrays; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.Iterator; 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 032import static java.util.Objects.requireNonNull; 033 034/** 035 * A dependency selector that combines zero or more other selectors using a logical {@code AND}. The resulting selector 036 * selects a given dependency if and only if all constituent selectors do so. 037 */ 038public final class AndDependencySelector implements DependencySelector { 039 040 private final Set<? extends DependencySelector> selectors; 041 042 private final 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 if (selectors != null && selectors.length > 0) { 052 this.selectors = new LinkedHashSet<>(Arrays.asList(selectors)); 053 } else { 054 this.selectors = Collections.emptySet(); 055 } 056 this.hashCode = 17 * 31 + this.selectors.hashCode(); 057 } 058 059 /** 060 * Creates a new selector from the specified selectors. 061 * 062 * @param selectors the selectors to combine, may be {@code null} but must not contain {@code null} elements 063 */ 064 public AndDependencySelector(Collection<? extends DependencySelector> selectors) { 065 if (selectors != null && !selectors.isEmpty()) { 066 this.selectors = new LinkedHashSet<>(selectors); 067 } else { 068 this.selectors = Collections.emptySet(); 069 } 070 this.hashCode = 17 * 31 + this.selectors.hashCode(); 071 } 072 073 private AndDependencySelector(Set<DependencySelector> selectors) { 074 if (selectors != null && !selectors.isEmpty()) { 075 this.selectors = selectors; 076 } else { 077 this.selectors = Collections.emptySet(); 078 } 079 this.hashCode = 17 * 31 + this.selectors.hashCode(); 080 } 081 082 /** 083 * Creates a new selector from the specified selectors. 084 * 085 * @param selector1 the first selector to combine, may be {@code null} 086 * @param selector2 the second selector to combine, may be {@code null} 087 * @return the combined selector or {@code null} if both selectors were {@code null} 088 */ 089 public static DependencySelector newInstance(DependencySelector selector1, DependencySelector selector2) { 090 if (selector1 == null) { 091 return selector2; 092 } else if (selector2 == null || selector2.equals(selector1)) { 093 return selector1; 094 } 095 return new AndDependencySelector(selector1, selector2); 096 } 097 098 public boolean selectDependency(Dependency dependency) { 099 requireNonNull(dependency, "dependency cannot be null"); 100 for (DependencySelector selector : selectors) { 101 if (!selector.selectDependency(dependency)) { 102 return false; 103 } 104 } 105 return true; 106 } 107 108 public DependencySelector deriveChildSelector(DependencyCollectionContext context) { 109 requireNonNull(context, "context cannot be null"); 110 int seen = 0; 111 Set<DependencySelector> childSelectors = null; 112 113 for (DependencySelector selector : selectors) { 114 DependencySelector childSelector = selector.deriveChildSelector(context); 115 if (childSelectors != null) { 116 if (childSelector != null) { 117 childSelectors.add(childSelector); 118 } 119 } else if (selector != childSelector) { 120 childSelectors = new LinkedHashSet<>(); 121 if (seen > 0) { 122 for (DependencySelector s : selectors) { 123 if (childSelectors.size() >= seen) { 124 break; 125 } 126 childSelectors.add(s); 127 } 128 } 129 if (childSelector != null) { 130 childSelectors.add(childSelector); 131 } 132 } else { 133 seen++; 134 } 135 } 136 137 if (childSelectors == null) { 138 return this; 139 } 140 if (childSelectors.size() <= 1) { 141 if (childSelectors.isEmpty()) { 142 return null; 143 } 144 return childSelectors.iterator().next(); 145 } 146 return new AndDependencySelector(childSelectors); 147 } 148 149 @Override 150 public boolean equals(Object obj) { 151 if (this == obj) { 152 return true; 153 } else if (null == obj || !getClass().equals(obj.getClass())) { 154 return false; 155 } 156 157 AndDependencySelector that = (AndDependencySelector) obj; 158 return selectors.equals(that.selectors); 159 } 160 161 @Override 162 public int hashCode() { 163 return hashCode; 164 } 165 166 @Override 167 public String toString() { 168 StringBuilder builder = 169 new StringBuilder().append(this.getClass().getSimpleName()).append('('); 170 Iterator<? extends DependencySelector> iterator = this.selectors.iterator(); 171 while (iterator.hasNext()) { 172 final DependencySelector selector = iterator.next(); 173 builder.append(selector.toString()); 174 if (iterator.hasNext()) // not last 175 { 176 builder.append(" && "); 177 } 178 } 179 return builder.append(')').toString(); 180 } 181}