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