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    }