1   package jsdsi;
2   
3   import java.math.BigInteger;
4   import java.util.Iterator;
5   
6   import jsdsi.sexp.Sexp;
7   import jsdsi.sexp.SexpParseException;
8   import jsdsi.sexp.SexpUtil;
9   
10  /***
11   * A tag that specifies a range of allowed values.
12   * 
13   * @author Sameer Ajmani
14   * @author Sean Radford
15   * @version $Revision: 1.3.2.1 $ $Date: 2005/11/08 03:12:52 $
16   **/
17  public class RangeTag extends ExprTag {
18      
19      private static final long serialVersionUID = -4840725353015683369L;
20      
21      /***
22       * The ordering parameter: alpha, numeric, time, binary, date.
23       */
24      private transient final RangeOrdering ordering;
25      
26      /***
27       * The upper limit of this range tag.
28       */
29      private transient final String upperLimit;
30      
31      /***
32       * Is the upper limit strict?
33       */
34      private transient final boolean strictUpper;
35      
36      /***
37       * The lower limit of this range tag.
38       */
39      private transient final String lowerLimit;
40      
41      /***
42       * Is the lower limit strict?
43       */
44      private transient final boolean strictLower;
45      
46      /***
47       * Creates a new <code>RangeTag</code> from a given lower and upper
48       * limit.
49       * 
50       * @param  o defines the ordering.
51       * @param  u upper limit.
52       * @param  su is the upper limit strict?
53       * @param  l lower limit.
54       * @param  sl is the lower limit strict?
55       */
56      public RangeTag(String o, String u, boolean su, String l, boolean sl) {
57          assert(o != null) : "null ordering";
58          assert(u != null) : "null upper bound"; // FIXME: allow!
59          assert(l != null) : "null lower bound"; // FIXME: allow!
60          ordering = RangeOrdering.parse(o);
61          assert(ordering.convert(l).compareTo(ordering.convert(u)) <= 0)
62          : "lower bound must be less than or equal to upper bound";
63          upperLimit = u;
64          strictUpper = su;
65          lowerLimit = l;
66          strictLower = sl;
67      }
68      
69      /***
70       * @see jsdsi.Tag#intersect(Tag)
71       **/
72      public Tag intersect(Tag that)
73      {
74          if (that instanceof RangeTag) {
75              return intersect((RangeTag)that);
76          }
77          if (that instanceof StringTag) {
78              return intersect((StringTag)that);
79          }
80          if (that instanceof SetTag) {
81              return that.intersect(this);
82          }
83          return Tag.NULL_TAG;
84      }
85      
86      public Tag intersect(StringTag that)
87      {
88          if (ordering.contains(this, that.getValue())) {
89              return that;
90          }
91          return Tag.NULL_TAG;
92      }
93      
94      public Tag intersect(RangeTag that)
95      {
96          if (this.ordering != that.ordering) {
97              return Tag.NULL_TAG;
98          }
99          return ordering.intersect(this, that);
100     }
101     
102     /***
103      * @see java.lang.Object#equals(Object)
104      */
105     public boolean equals(Object that) {
106         if (that instanceof RangeTag) {
107             RangeTag r = (RangeTag) that;
108             return this.ordering == r.ordering
109                 && this.upperLimit.equals(r.upperLimit)
110             && this.strictUpper == r.strictUpper
111                 && this.lowerLimit.equals(r.lowerLimit)
112             && this.strictLower == r.strictLower;
113         }
114         return false;
115     }
116     
117     /***
118      * @see java.lang.Object#hashCode()
119      */
120     public int hashCode() {
121         return ordering.hashCode()
122         ^ upperLimit.hashCode()
123         ^ lowerLimit.hashCode()
124         ^ (strictUpper ? 1 : 0)
125         ^ (strictLower ? 1 : 0);
126     }
127     
128     /***
129      * @return the ordering of this <code>RangeTag</code>; one of:
130      * <code>"alpha" | "numeric" | "time" | "binary" | "date"</code>.
131      */
132     public String getOrdering() {
133         return ordering.toString();
134     }
135     
136     /***
137      * @return the upper limit of this <code>RangeTag</code>.
138      */
139     public String getUpperLimit() {
140         return upperLimit;
141     }
142     
143     /***
144      * @return the lower limit of this <code>RangeTag</code>.
145      */
146     public String getLowerLimit() {
147         return lowerLimit;
148     }
149     
150     /***
151      * @return <code>true</code> if the upper limit of this 
152      *         <code>RangeTag</code> is strict, <code>false</code> otherwise.
153      */
154     public boolean upperIsStrict() {
155         return strictUpper;
156     }
157     
158     /***
159      * @return <code>true</code> if the lower limit of this 
160      *         <code>RangeTag</code> is strict, <code>false</code> otherwise.
161      */
162     public boolean lowerIsStrict() {
163         return strictLower;
164     }
165     
166     public Sexp toTagSexp() {
167         Sexp[] ss = new Sexp[6];
168         ss[0] = SexpUtil.toSexp("range");
169         ss[1] = SexpUtil.toSexp(getOrdering());
170         ss[2] = SexpUtil.toSexp(lowerIsStrict() ? "g" : "ge");
171         ss[3] = SexpUtil.toSexp(getLowerLimit());
172         ss[4] = SexpUtil.toSexp(upperIsStrict() ? "l" : "le");
173         ss[5] = SexpUtil.toSexp(getUpperLimit());
174         return SexpUtil.toSexp("*", ss);
175     }
176     
177     static RangeTag parseRangeTag(Iterator tbody) throws SexpParseException {
178         String ordering = SexpUtil.getNextString(tbody, "range ordering");
179         // lower strictness and limit
180         String gte = SexpUtil.getNextString(tbody, "range gte");
181         boolean strictLower = gte.equals("g");
182         if (!strictLower && !gte.equals("ge"))
183             throw new SexpParseException(
184                 "range lower strictness is not 'g' or 'ge': " + gte);
185         String lowerLimit = SexpUtil.getNextString(tbody, "range lower limit");
186         // upper strictness and limit
187         String lte = SexpUtil.getNextString(tbody, "range lte");
188         boolean strictUpper = lte.equals("l");
189         if (!strictUpper && !lte.equals("le"))
190             throw new SexpParseException(
191                 "range upper strictness is not 'l' or 'le': " + lte);
192         String upperLimit = SexpUtil.getNextString(tbody, "range upper limit");
193         SexpUtil.checkDone(tbody, "range tag");
194         return new RangeTag(ordering,
195                             upperLimit,
196                             strictUpper,
197                             lowerLimit,
198                             strictLower);
199     }
200     private static abstract class RangeOrdering {
201         public abstract Comparable convert(String s);
202         public boolean contains(RangeTag r, String s)
203         {
204             assert(r.ordering == this);
205             try {
206                 Comparable val = convert(s);
207                 int lc = convert(r.lowerLimit).compareTo(val);
208                 if (lc > 0 || (lc == 0 && r.strictLower)) {
209                     return false;
210                 }
211                 int uc = convert(r.upperLimit).compareTo(val);
212                 if (uc < 0 || (uc == 0 && r.strictUpper)) {
213                     return false;
214                 }
215                 return true;
216             } catch (IllegalArgumentException e) {
217                 // convert() failed, so fail safely
218                 return false;
219             }
220         }
221         public Tag intersect(RangeTag r, RangeTag that)
222         {
223             assert(r.ordering == this);
224             assert(that.ordering == this);
225             try {
226                 String  ll, ul;
227                 boolean sl, su;
228                 int lc = convert(r.lowerLimit).compareTo
229                     (convert(that.lowerLimit));
230                 if (lc > 0 || (lc == 0 && r.strictLower)) {
231                     ll = r.lowerLimit;
232                     sl = r.strictLower;
233                 } else {
234                     ll = that.lowerLimit;
235                     sl = that.strictLower;
236                 }
237                 int uc = convert(r.upperLimit).compareTo
238                     (convert(that.upperLimit));
239                 if (uc < 0 || (uc == 0 && r.strictUpper)) {
240                     ul = r.upperLimit;
241                     su = r.strictUpper;
242                 } else {
243                     ul = that.upperLimit;
244                     su = that.strictUpper;
245                 }
246                 if (convert(ll).compareTo(convert(ul)) > 0) {
247                     // lower limit greater than upper limit
248                     return Tag.NULL_TAG;
249                 }
250                 return new RangeTag(this.toString(), ul, su, ll, sl);
251             } catch (IllegalArgumentException e) {
252                 // convert() failed, so fail safely
253                 return Tag.NULL_TAG;
254             }
255         }
256         
257         public static RangeOrdering ALPHA = new RangeOrdering() {
258             public Comparable convert(String s)
259             {
260                 return s;
261             }
262             public String toString()
263             {
264                 return "alpha";
265             }
266         };
267         
268         public static RangeOrdering BINARY = new RangeOrdering() {
269             public Comparable convert(String s)
270             {
271                 return new BigInteger(s.getBytes());
272             }
273             public String toString()
274             {
275                 return "binary";
276             }
277         };
278         
279         public static RangeOrdering NUMERIC = new RangeOrdering() {
280             public Comparable convert(String s)
281             {
282                 try {
283                     return new Float(Float.parseFloat(s));
284                 } catch (NumberFormatException e) {
285                     throw new IllegalArgumentException("bad float:"+s);
286                 }
287             }
288             public String toString()
289             {
290                 return "numeric";
291             }
292         };
293         
294         public static RangeOrdering TIME = new RangeOrdering() {
295             public Comparable convert(String s)
296             {
297                 try {
298                     return SexpUtil.parseDate(s);
299                 } catch (SexpParseException e) {
300                     throw new IllegalArgumentException("bad date: "+s);
301                 }
302             }
303             public String toString()
304             {
305                 return "time";
306             }
307         };
308         
309         public static RangeOrdering DATE = new RangeOrdering() {
310             public Comparable convert(String s)
311             {
312                 try {
313                     return SexpUtil.parseDate(s);
314                 } catch (SexpParseException e) {
315                     throw new IllegalArgumentException("bad date: "+s);
316                 }
317             }
318             public String toString()
319             {
320                 return "date";
321             }
322         };
323         
324         public static RangeOrdering parse(String name)
325         {
326             if (name.equals("alpha")) {
327                 return ALPHA;
328             }
329             if (name.equals("numeric")) {
330                 return NUMERIC;
331             }
332             if (name.equals("time")) {
333                 return TIME;
334             }
335             if (name.equals("binary")) {
336                 return BINARY;
337             }
338             if (name.equals("date")) {
339                 return DATE;
340             }
341             throw new IllegalArgumentException(name);
342         }
343     }
344 }
This page was automatically generated by Maven