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 */
019 package org.apache.felix.framework.util;
020
021 import org.osgi.framework.Version;
022
023 public class VersionRange
024 {
025 private final Version m_low;
026 private final boolean m_isLowInclusive;
027 private final Version m_high;
028 private final boolean m_isHighInclusive;
029 public static final VersionRange infiniteRange = new VersionRange(Version.emptyVersion, true, null, true);
030
031 public VersionRange(
032 Version low, boolean isLowInclusive,
033 Version high, boolean isHighInclusive)
034 {
035 m_low = low;
036 m_isLowInclusive = isLowInclusive;
037 m_high = high;
038 m_isHighInclusive = isHighInclusive;
039 }
040
041 public Version getLow()
042 {
043 return m_low;
044 }
045
046 public boolean isLowInclusive()
047 {
048 return m_isLowInclusive;
049 }
050
051 public Version getHigh()
052 {
053 return m_high;
054 }
055
056 public boolean isHighInclusive()
057 {
058 return m_isHighInclusive;
059 }
060
061 public boolean isInRange(Version version)
062 {
063 // We might not have an upper end to the range.
064 if (m_high == null)
065 {
066 return (version.compareTo(m_low) >= 0);
067 }
068 else if (isLowInclusive() && isHighInclusive())
069 {
070 return (version.compareTo(m_low) >= 0) && (version.compareTo(m_high) <= 0);
071 }
072 else if (isHighInclusive())
073 {
074 return (version.compareTo(m_low) > 0) && (version.compareTo(m_high) <= 0);
075 }
076 else if (isLowInclusive())
077 {
078 return (version.compareTo(m_low) >= 0) && (version.compareTo(m_high) < 0);
079 }
080 return (version.compareTo(m_low) > 0) && (version.compareTo(m_high) < 0);
081 }
082
083 public boolean intersects(VersionRange vr)
084 {
085 // Check to see if the passed in floor is less than or equal to
086 // this ceiling and the passed in ceiling is greater than or
087 // equal to this floor.
088 boolean isFloorLessThanCeiling = false;
089 if ((m_high == null)
090 || (m_high.compareTo(vr.getLow()) > 0)
091 || ((m_high.compareTo(vr.getLow()) == 0)
092 && m_isHighInclusive && vr.isLowInclusive()))
093 {
094 isFloorLessThanCeiling = true;
095 }
096 boolean isCeilingGreaterThanFloor = false;
097 if ((vr.getHigh() == null)
098 || (m_low.compareTo(vr.getHigh()) < 0)
099 || ((m_low.compareTo(vr.getHigh()) == 0)
100 && m_isLowInclusive && vr.isHighInclusive()))
101 {
102 isCeilingGreaterThanFloor = true;
103 }
104 return isFloorLessThanCeiling && isCeilingGreaterThanFloor;
105 }
106
107 public VersionRange intersection(VersionRange vr)
108 {
109 if (!intersects(vr))
110 {
111 return null;
112 }
113
114 VersionRange floor = (m_low.compareTo(vr.getLow()) > 0) ? this : vr;
115 boolean floorInclusive = (getLow().equals(vr.getLow()))
116 ? (isLowInclusive() & vr.isLowInclusive())
117 : floor.isLowInclusive();
118
119 VersionRange ceiling;
120 boolean ceilingInclusive;
121 if (vr.getHigh() == null)
122 {
123 ceiling = this;
124 ceilingInclusive = ceiling.isHighInclusive();
125 }
126 else if (m_high == null)
127 {
128 ceiling = vr;
129 ceilingInclusive = ceiling.isHighInclusive();
130 }
131 else if (m_high.compareTo(vr.getHigh()) > 0)
132 {
133 ceiling = vr;
134 ceilingInclusive = ceiling.isHighInclusive();
135 }
136 else if (m_high.compareTo(vr.getHigh()) < 0)
137 {
138 ceiling = this;
139 ceilingInclusive = ceiling.isHighInclusive();
140 }
141 else
142 {
143 ceiling = this;
144 ceilingInclusive = (isHighInclusive() & vr.isHighInclusive());
145 }
146
147 return new VersionRange(
148 floor.getLow(), floorInclusive, ceiling.getHigh(), ceilingInclusive);
149 }
150
151 public static VersionRange parse(String range)
152 {
153 // Check if the version is an interval.
154 if (range.indexOf(',') >= 0)
155 {
156 String s = range.substring(1, range.length() - 1);
157 String vlo = s.substring(0, s.indexOf(',')).trim();
158 String vhi = s.substring(s.indexOf(',') + 1, s.length()).trim();
159 return new VersionRange (
160 new Version(vlo), (range.charAt(0) == '['),
161 new Version(vhi), (range.charAt(range.length() - 1) == ']'));
162 }
163 else
164 {
165 return new VersionRange(new Version(range), true, null, false);
166 }
167 }
168
169 public boolean equals(Object obj)
170 {
171 if (obj == null)
172 {
173 return false;
174 }
175 if (getClass() != obj.getClass())
176 {
177 return false;
178 }
179 final VersionRange other = (VersionRange) obj;
180 if (m_low != other.m_low && (m_low == null || !m_low.equals(other.m_low)))
181 {
182 return false;
183 }
184 if (m_isLowInclusive != other.m_isLowInclusive)
185 {
186 return false;
187 }
188 if (m_high != other.m_high && (m_high == null || !m_high.equals(other.m_high)))
189 {
190 return false;
191 }
192 if (m_isHighInclusive != other.m_isHighInclusive)
193 {
194 return false;
195 }
196 return true;
197 }
198
199 public int hashCode()
200 {
201 int hash = 5;
202 hash = 97 * hash + (m_low != null ? m_low.hashCode() : 0);
203 hash = 97 * hash + (m_isLowInclusive ? 1 : 0);
204 hash = 97 * hash + (m_high != null ? m_high.hashCode() : 0);
205 hash = 97 * hash + (m_isHighInclusive ? 1 : 0);
206 return hash;
207 }
208
209 public String toString()
210 {
211 if (m_high != null)
212 {
213 StringBuffer sb = new StringBuffer();
214 sb.append(m_isLowInclusive ? '[' : '(');
215 sb.append(m_low.toString());
216 sb.append(',');
217 sb.append(m_high.toString());
218 sb.append(m_isHighInclusive ? ']' : ')');
219 return sb.toString();
220 }
221 else
222 {
223 return m_low.toString();
224 }
225 }
226 }