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.version; 020 021import java.util.Arrays; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.HashSet; 025import java.util.Set; 026import java.util.stream.Collectors; 027 028import org.eclipse.aether.version.Version; 029import org.eclipse.aether.version.VersionRange; 030 031/** 032 * A union of version ranges. 033 */ 034public final class UnionVersionRange implements VersionRange { 035 036 private final Set<VersionRange> ranges; 037 038 private final Bound lowerBound; 039 040 private final Bound upperBound; 041 042 /** 043 * Creates union {@link VersionRange}s out of passed in {@link VersionRange} instances. 044 * 045 * @param ranges The ranges, may be empty array or even {@code null}. 046 */ 047 public static VersionRange from(VersionRange... ranges) { 048 if (ranges == null || ranges.length == 0) { 049 return from(Collections.emptySet()); 050 } 051 return from(Arrays.asList(ranges)); 052 } 053 054 /** 055 * Creates union {@link VersionRange}s out of passed in {@link VersionRange} collection. 056 * 057 * @param ranges The ranges, may be empty collection or even {@code null}. 058 */ 059 public static VersionRange from(Collection<? extends VersionRange> ranges) { 060 if (ranges != null && ranges.size() == 1) { 061 return ranges.iterator().next(); 062 } 063 return new UnionVersionRange(ranges); 064 } 065 066 private UnionVersionRange(Collection<? extends VersionRange> ranges) { 067 if (ranges == null || ranges.isEmpty()) { 068 this.ranges = Collections.emptySet(); 069 lowerBound = null; 070 upperBound = null; 071 } else { 072 this.ranges = new HashSet<>(ranges); 073 Bound lowerBound = null, upperBound = null; 074 for (VersionRange range : this.ranges) { 075 Bound lb = range.getLowerBound(); 076 if (lb == null) { 077 lowerBound = null; 078 break; 079 } else if (lowerBound == null) { 080 lowerBound = lb; 081 } else { 082 int c = lb.getVersion().compareTo(lowerBound.getVersion()); 083 if (c < 0 || (c == 0 && !lowerBound.isInclusive())) { 084 lowerBound = lb; 085 } 086 } 087 } 088 for (VersionRange range : this.ranges) { 089 Bound ub = range.getUpperBound(); 090 if (ub == null) { 091 upperBound = null; 092 break; 093 } else if (upperBound == null) { 094 upperBound = ub; 095 } else { 096 int c = ub.getVersion().compareTo(upperBound.getVersion()); 097 if (c > 0 || (c == 0 && !upperBound.isInclusive())) { 098 upperBound = ub; 099 } 100 } 101 } 102 this.lowerBound = lowerBound; 103 this.upperBound = upperBound; 104 } 105 } 106 107 @Override 108 public boolean containsVersion(Version version) { 109 for (VersionRange range : ranges) { 110 if (range.containsVersion(version)) { 111 return true; 112 } 113 } 114 return false; 115 } 116 117 @Override 118 public Bound getLowerBound() { 119 return lowerBound; 120 } 121 122 @Override 123 public Bound getUpperBound() { 124 return upperBound; 125 } 126 127 @Override 128 public boolean equals(Object obj) { 129 if (obj == this) { 130 return true; 131 } else if (obj == null || !getClass().equals(obj.getClass())) { 132 return false; 133 } 134 135 UnionVersionRange that = (UnionVersionRange) obj; 136 137 return ranges.equals(that.ranges); 138 } 139 140 @SuppressWarnings("checkstyle:magicnumber") 141 @Override 142 public int hashCode() { 143 return 97 * ranges.hashCode(); 144 } 145 146 @Override 147 public String toString() { 148 return ranges.stream().map(VersionRange::toString).collect(Collectors.joining(", ")); 149 } 150}