View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.geronimo.javamail.store.nntp.newsrc;
21  
22  import java.io.IOException;
23  import java.io.Writer;
24  
25  /**
26   * Represent a single Range in a newsrc file. A Range can be either a single
27   * number (start == end) or a span of article numbers.
28   */
29  public class Range {
30      // the low end of the range
31      int start;
32  
33      // the high end of the range (start and end are inclusive);
34      int end;
35  
36      /**
37       * Construct a Range item for a single digit range.
38       * 
39       * @param spot
40       *            The location of the singleton.
41       */
42      public Range(int spot) {
43          this(spot, spot);
44      }
45  
46      /**
47       * Construct a Range item.
48       * 
49       * @param start
50       *            The starting point of the Range.
51       * @param end
52       *            The Range end point (which may be equal to the starting
53       *            point).
54       */
55      public Range(int start, int end) {
56          this.start = start;
57          this.end = end;
58      }
59  
60      /**
61       * Parse a section of a .newsrc range string into a single Range item. The
62       * range is either a single number, or a pair of numbers separated by a
63       * hyphen.
64       * 
65       * @param range
66       *            The range string.
67       * 
68       * @return A constructed Range item, or null if there is a parsing error.
69       */
70      static public Range parse(String range) {
71          // a range from a newsrc file is either a single number or in the format
72          // 'nnnn-mmmm'. We need
73          // to figure out which type this is.
74          int marker = range.indexOf('-');
75  
76          try {
77              if (marker != -1) {
78                  String rangeStart = range.substring(0, marker).trim();
79                  String rangeEnd = range.substring(marker + 1).trim();
80  
81                  int start = Integer.parseInt(rangeStart);
82                  int end = Integer.parseInt(rangeEnd);
83  
84                  if (start >= 0 && end >= 0) {
85                      return new Range(start, end);
86                  }
87              } else {
88                  // use the entire token
89                  int start = Integer.parseInt(range);
90                  // and start and the end are the same
91                  return new Range(start, start);
92  
93              }
94          } catch (NumberFormatException e) {
95          }
96          // return null for any bad values
97          return null;
98      }
99  
100     /**
101      * Get the starting point for the Range.
102      * 
103      * @return The beginning of the mark range.
104      */
105     public int getStart() {
106         return start;
107     }
108 
109     /**
110      * Set the starting point for a Range.
111      * 
112      * @param start
113      *            The new start value.
114      */
115     public void setStart(int start) {
116         this.start = start;
117     }
118 
119     /**
120      * Get the ending point for the Range.
121      * 
122      * @return The end of the mark range.
123      */
124     public int getEnd() {
125         return end;
126     }
127 
128     /**
129      * Set the ending point for a Range.
130      * 
131      * @param end
132      *            The new end value.
133      */
134     public void setEnd(int end) {
135         this.end = end;
136     }
137 
138     /**
139      * Test if a range contains a point value.
140      * 
141      * @param target
142      *            The article location to test.
143      * 
144      * @return True if the target is between the start and end values,
145      *         inclusive.
146      */
147     public boolean contains(int target) {
148         return target >= start && target <= end;
149     }
150 
151     /**
152      * Test if one range is completely contained within another Range.
153      * 
154      * @param other
155      *            The other test range.
156      * 
157      * @return true if the other start and end points are contained within this
158      *         range.
159      */
160     public boolean contains(Range other) {
161         return contains(other.getStart()) && contains(other.getEnd());
162     }
163 
164     /**
165      * Tests if two ranges overlap
166      * 
167      * @param other
168      *            The other test range.
169      * 
170      * @return true if the start or end points of either range are contained
171      *         within the range of the other.
172      */
173     public boolean overlaps(Range other) {
174         return other.contains(start) || other.contains(end) || contains(other.getStart()) || contains(other.getEnd());
175     }
176 
177     /**
178      * Test if two ranges exactly abutt each other.
179      * 
180      * @param other
181      *            The other Range to test.
182      * 
183      * @return true if the end of one range abutts the start of the other range.
184      */
185     public boolean abutts(Range other) {
186         return other.getStart() == end + 1 || other.getEnd() == start - 1;
187     }
188 
189     /**
190      * Tests if a single point abutts either the start or end of this Range.
191      * 
192      * @param article
193      *            The point to test.
194      * 
195      * @return true if test point is equal to start - 1 or end + 1.
196      */
197     public boolean abutts(int article) {
198         return article == start - 1 || article == end + 1;
199     }
200 
201     /**
202      * Test if a point is below the test Range.
203      * 
204      * @param article
205      *            The point to test.
206      * 
207      * @return true if the entire range is less than the test point.
208      */
209     public boolean lessThan(int article) {
210         return end < article;
211     }
212 
213     /**
214      * Test if another Range is less than this Range.
215      * 
216      * @param other
217      *            The other Range to test.
218      * 
219      * @return true if the other Range lies completely below this Range.
220      */
221     public boolean lessThan(Range other) {
222         return end < other.start;
223     }
224 
225     /**
226      * Test if a point is above the test Range.
227      * 
228      * @param article
229      *            The point to test.
230      * 
231      * @return true if the entire range is greater than the test point.
232      */
233     public boolean greaterThan(int article) {
234         return start > article;
235     }
236 
237     /**
238      * Test if another Range is greater than this Range.
239      * 
240      * @param other
241      *            The other Range to test.
242      * 
243      * @return true if the other Range lies completely below this Range.
244      */
245     public boolean greaterThan(Range other) {
246         return start > other.end;
247     }
248 
249     /**
250      * Merge another Range into this one. Merging will increase the bounds of
251      * this Range to encompass the entire span of the two. If the Ranges do not
252      * overlap, the newly created range will include the gap between the two.
253      * 
254      * @param other
255      *            The Range to merge.
256      */
257     public void merge(Range other) {
258         if (other.start < start) {
259             start = other.start;
260         }
261 
262         if (other.end > end) {
263             end = other.end;
264         }
265     }
266 
267     /**
268      * Split a range at a given split point. Splitting will truncate at the
269      * split location - 1 and return a new range beginning at location + 1; This
270      * code assumes that the split location is at neither end poing.
271      * 
272      * @param location
273      *            The split location. Location must be in the range start <
274      *            location < end.
275      * 
276      * @return A new Range object for the split portion of the range.
277      */
278     public Range split(int location) {
279         int newEnd = end;
280 
281         end = location - 1;
282 
283         return new Range(location + 1, newEnd);
284     }
285 
286     /**
287      * Save an individual range element to a newsrc file. The range is expressed
288      * either as a single number, or a hypenated pair of numbers.
289      * 
290      * @param out
291      *            The output writer used to save the data.
292      * 
293      * @exception IOException
294      */
295     public void save(Writer out) throws IOException {
296         // do we have a single data point range?
297         if (start == end) {
298             out.write(Integer.toString(start));
299         } else {
300             out.write(Integer.toString(start));
301             out.write("-");
302             out.write(Integer.toString(end));
303         }
304     }
305 
306     /**
307      * Convert a Range into String form. Used mostly for debugging.
308      * 
309      * @return The String representation of the Range.
310      */
311     public String toString() {
312         if (start == end) {
313             return Integer.toString(start);
314         } else {
315             return Integer.toString(start) + "-" + Integer.toString(end);
316         }
317     }
318 }