Source code: ojb/broker/query/SearchFilter.java
1 /**
2 * ***********************************
3 * This program was prepared by the Regents of the University of California at
4 * Los Alamos National Laboratory (the University) under Contract No.
5 * W-7405-ENG-36 with the U.S. Department of Energy (DOE). The University has
6 * certain rights in the program pursuant to the contract and the program
7 * should not be copied or distributed outside your organization. All rights
8 * in the program are reserved by the DOE and the University. Neither the
9 * U.S. Government nor the University makes any warranty, express or implied,
10 * or assumes any liability or responsibility for the use of this software.
11 * **********************************
12 */
13 package ojb.broker.query;
14
15 import java.util.Enumeration;
16 import java.util.Hashtable;
17 import java.util.Vector;
18
19 /**
20 * Class to build selection criteria for searches
21 * Search Filter Class (Abstract)
22 * This class builds a search filter tree, specifing how names and
23 * values are to be compared when searching a database.
24 * It just builds internal structures, and needs to be extended
25 * to return a search filter string or other object that can be
26 * used by the database to perform the actual search.
27 */
28 public abstract class SearchFilter
29 {
30 // Define the operators
31 // Binary operators have bit 8 set
32 // Logical operators have bit 9 set
33 public static final int AND = 0x200; // Logical operator
34 public static final int OR = 0x201; // Logical operator
35 public static final int NOT = 0x2; // Unary operator
36 public static final int IN = 0x3;
37 public static final int NOT_IN = 0x4;
38 public static final int LIKE = 0x109; // Binary operator
39 public static final int EQUAL = 0x10A; // Binary operator
40 public static final int NOT_EQUAL = 0x10B; // Binary operator
41 public static final int LESS_THAN = 0x10C; // Binary operator
42 public static final int GREATER_THAN = 0x10D; // Binary operator
43 public static final int GREATER_EQUAL = 0x10E; // Binary operator
44 public static final int LESS_EQUAL = 0x10F; // Binary operator
45 // Define a mask for the binary and logical operators
46 // private static final int BINARY_OPER_MASK = 0x100;
47 // private static final int LOGICAL_OPER_MASK = 0x200;
48 protected static final int BINARY_OPER_MASK = 0x100;
49 protected static final int LOGICAL_OPER_MASK = 0x200;
50 // Define the current search filter
51 protected SearchBase filter = null;
52
53 /**
54 * Create an empty search filter.
55 *
56 */
57 // -----------------------------------------------------------
58 public SearchFilter()
59 {
60 }
61
62 /**
63 * Change the search filter to one that specifies an element to
64 * match or not match one of a list of values.
65 * The old search filter is deleted.
66 *
67 * @param ElementName is the name of the element to be matched
68 * @param values is a vector of possible matches
69 * @param oper is the IN or NOT_IN operator to indicate how to matche
70 */
71 public void matchList(String ElementName, Vector values, int oper)
72 {
73 // Delete the old search filter
74 filter = null;
75 // If not NOT_IN, assume IN
76 // (Since ints are passed by value, it is OK to change it)
77 if (oper != NOT_IN)
78 {
79 oper = IN;
80 // Convert the vector of match strings to an array of strings
81 }
82 String[] value_string_array = new String[values.size()];
83 values.copyInto(value_string_array);
84 // Create a leaf node for this list and store it as the filter
85 filter = new SearchBaseLeaf(ElementName, oper, value_string_array);
86 }
87
88 /**
89 * Change the search filter to one that specifies an element to not
90 * match one of a list of values.
91 * The old search filter is deleted.
92 *
93 * @param ElementName is the name of the element to be matched
94 * @param values is an array of possible matches
95 * @param oper is the IN or NOT_IN operator to indicate how to matche
96 */
97 public void matchList(String ElementName, String[] values, int oper)
98 {
99 // Delete the old search filter
100 filter = null;
101 // If not NOT_IN, assume IN
102 // (Since ints are passed by value, it is OK to change it)
103 if (oper != NOT_IN)
104 {
105 oper = IN;
106 // Create a leaf node for this list and store it as the filter
107 }
108 filter = new SearchBaseLeaf(ElementName, oper, values);
109 }
110
111 /**
112 * Change the search filter to one that specifies an element to not
113 * match one of a list of integer values.
114 * The old search filter is deleted.
115 *
116 * @param ElementName is the name of the element to be matched
117 * @param values is an array of possible integer matches
118 * @param oper is the IN or NOT_IN operator to indicate how to matche
119 */
120 public void matchList(String ElementName, int[] values, int oper)
121 {
122 // Delete the old search filter
123 filter = null;
124 // If not NOT_IN, assume IN
125 // (Since ints are passed by value, it is OK to change it)
126 if (oper != NOT_IN)
127 {
128 oper = IN;
129 // Create a leaf node for this list and store it as the filter
130 }
131 filter = new SearchBaseLeafInt(ElementName, oper, values);
132 }
133
134 /**
135 * Change the search filter to one that specifies an element to not
136 * match one single value.
137 * The old search filter is deleted.
138 *
139 * @param ElementName is the name of the element to be matched
140 * @param value is the value to not be matched
141 * @param oper is the IN or NOT_IN operator to indicate how to matche
142 */
143 public void matchValue(String ElementName, String value, int oper)
144 {
145 // Delete the old search filter
146 filter = null;
147 // If not NOT_IN, assume IN
148 // (Since ints are passed by value, it is OK to change it)
149 if (oper != NOT_IN)
150 {
151 oper = IN;
152 // Create a String array in which to hold the one name,
153 // and put that name in the array
154 }
155 String[] ValueArray = new String[1];
156 ValueArray[0] = value;
157 // Create a leaf node for this list and store it as the filter
158 filter = new SearchBaseLeaf(ElementName, oper, ValueArray);
159 }
160
161 /**
162 * -----------------------------------------------------------
163 * @param ElementName
164 * @param value
165 * @param oper
166 */
167 public void matchValue(String ElementName, int value, int oper)
168 {
169 // Delete the old search filter
170 filter = null;
171 // If not NOT_IN, assume IN
172 // (Since ints are passed by value, it is OK to change it)
173 if (oper != NOT_IN)
174 {
175 oper = IN;
176 // Create a leaf node for this list and store it as the filter
177 }
178 filter = new SearchBaseLeafInt(ElementName, oper, new int[]
179 {
180 value
181 });
182 }
183
184 /**
185 * Change the search filter to one that compares an element name to a value.
186 * The old search filter is deleted.
187 *
188 * @param ElementName is the name of the element to be tested
189 * @param value is the value to be compared against
190 * @param oper is the binary comparison operator to be used
191 * @exception gov.lanl.Database.DBException
192 */
193 public void compareFilter(String ElementName, String value, int oper) throws DBException
194 {
195 // Delete the old search filter
196 filter = null;
197 // If this is not a binary operator, throw an exception
198 if ((oper & BINARY_OPER_MASK) == 0)
199 {
200 throw new DBException();
201 // Create a SearchBaseLeafComparison node and store it as the filter
202 }
203 filter = new SearchBaseLeafComparison(ElementName, oper, value);
204 }
205
206 /**
207 * Change the search filter to one that specifies a set of elements and their values
208 * that must match, and the operator to use to combine the elements.
209 * Each key is compared for an equal match to the value, and all
210 * comparisons are combined by the specified logical operator (OR or AND).
211 * The old search filter is deleted.
212 *
213 * @param Elements is a hashtable holding key-value pairs
214 * @param combine_op is the logical operator to be used to combine the comparisons
215 * @param compare_op is the binary operator to be used for the comparisons
216 * @exception gov.lanl.Utilty.DBException
217 */
218 public void matchSet(Hashtable elements, int combine_op, int compare_op) throws DBException
219 {
220 // Delete the old search filter
221 filter = null;
222 // If combine_op is not a logical operator, throw an exception
223 if ((combine_op & LOGICAL_OPER_MASK) == 0)
224 {
225 throw new DBException();
226 // If compare_op is not a binary operator, throw an exception
227 }
228 if ((compare_op & BINARY_OPER_MASK) == 0)
229 {
230 throw new DBException();
231 // Create a vector that will hold the comparison nodes for all elements in the hashtable
232 }
233 Vector compareVector = new Vector();
234 // For each of the elements in the hashtable, create a comparison node for the match
235 for (Enumeration e = elements.keys(); e.hasMoreElements();)
236 {
237 // Get the element name from the enumerator
238 // and its value
239 String elementName = (String) e.nextElement();
240 String elementValue = (String) elements.get(elementName);
241 // Create a comparison node for this list and store it as the filter
242 SearchBaseLeafComparison comparenode = new SearchBaseLeafComparison(elementName,
243 compare_op, elementValue);
244 // Add this leaf node to the vector
245 compareVector.addElement(comparenode);
246 }
247 // Now return a node that holds this set of leaf nodes
248 filter = new SearchBaseNode(combine_op, compareVector);
249 }
250
251 /**
252 * Change the search filter to one that specifies a set of elements and their values
253 * that must match, and the operator to use to combine the elements.
254 * Each element name is compared for an equal match to the value, and all
255 * comparisons are combined by the specified logical operator (OR or AND).
256 * The old search filter is deleted.
257 *
258 * @param ElementNames is an array of names of elements to be tested
259 * @param ElementValues is an array of values for the corresponding element
260 * @param oper is the logical operator to be used to combine the comparisons
261 * @exception gov.lanl.Database.DBException
262 */
263 public void matchSet(String[] ElementNames, String[] ElementValues, int op) throws DBException
264 {
265 // Delete the old search filter
266 filter = null;
267 // If this is not a logical operator, throw an exception
268 if ((op & LOGICAL_OPER_MASK) == 0)
269 {
270 throw new DBException();
271 // Create a vector that will hold the leaf nodes for all elements in the hashtable
272 }
273 Vector leafVector = new Vector();
274 // For each of the elements in the array, create a leaf node for the match
275 int numnames = ElementNames.length;
276 for (int i = 0; i < numnames; i++)
277 {
278 // Create a leaf node for this list and store it as the filter
279 SearchBaseLeaf leafnode = new SearchBaseLeaf(ElementNames[i], IN, ElementValues[i]);
280 // Add this leaf node to the vector
281 leafVector.addElement(leafnode);
282 }
283 // Now return a node that holds this set of leaf nodes
284 filter = new SearchBaseNode(op, leafVector);
285 }
286
287 /**
288 * Combine other search filters with this one, using the specific operator.
289 *
290 * @param new_filters is a vector of SearchFilter classes to be combined
291 * @param op is the logical operator to be used to combine the filters
292 * @exception gov.lanl.Database.DBException
293 */
294 public void combine(Vector new_filters, int op) throws DBException
295 {
296 // If this is not a logical operator, throw an exception
297 if ((op & LOGICAL_OPER_MASK) == 0)
298 {
299 throw new DBException();
300 // Create a new vector consisting of just the filters
301 // from the SearchFilter classes in new_filters
302 }
303 Vector filters = new Vector();
304 // Now add in all the nodes of the new filters
305 for (Enumeration e = new_filters.elements(); e.hasMoreElements();)
306 {
307 // Get the search filter from the vector
308 SearchFilter f = (SearchFilter) e.nextElement();
309 filters.addElement(f.getFilter());
310 }
311 // Create a node for this list and return it
312 filter = new SearchBaseNode(op, filter, filters);
313 }
314
315 /**
316 * Combine one other search filters with this one, using the specific operator.
317 *
318 * @param new_filter is the SearchFilter class to be combined
319 * @param op is the logical operator to be used to combine the filters
320 * @exception gov.lanl.Database.DBException
321 */
322 public void combine(SearchFilter new_filter, int op) throws DBException
323 {
324 // If this is not a logical operator, throw an exception
325 if ((op & LOGICAL_OPER_MASK) == 0)
326 {
327 throw new DBException();
328 // Create a new vector consisting of just the filters
329 // from the SearchFilter classes in new_filters
330 }
331 Vector filters = new Vector();
332 filters.addElement(new_filter.getFilter());
333 // Create a node for this list and return it
334 filter = new SearchBaseNode(op, filter, filters);
335 }
336
337 /**
338 * Static method to convert a binary operator into a string.
339 *
340 * @param oper is the binary comparison operator to be converted
341 * @return
342 */
343 protected static String ConvertBinaryOperator(int oper)
344 {
345 // Convert the operator into the proper string
346 String oper_string;
347 switch (oper)
348 {
349 default:
350 case EQUAL:
351 oper_string = "=";
352 break;
353 case LIKE:
354 oper_string = "LIKE";
355 break;
356 case NOT_EQUAL:
357 oper_string = "!=";
358 break;
359 case LESS_THAN:
360 oper_string = "<";
361 break;
362 case GREATER_THAN:
363 oper_string = ">";
364 break;
365 case GREATER_EQUAL:
366 oper_string = ">=";
367 break;
368 case LESS_EQUAL:
369 oper_string = "<=";
370 break;
371 }
372 return oper_string;
373 }
374
375 /**
376 * Get the actual filter out of the class.
377 * This is only needed when combining filters together
378 * and one instantiation has to get the filter from another.
379 * However, I do not know how to protect it from outside use.
380 * @return
381 *
382 */
383 protected SearchBase getFilter()
384 {
385 return filter;
386 }
387
388 /**
389 * Converts this search filter into a search string for use by a database.
390 *
391 */
392
393 /**
394 * -----------------------------------------------------------
395 * @return
396 */
397 public abstract String toString();
398
399 /**
400 * SearchBase is the base node class for the parse tree
401 * This class holds the binary operator
402 *
403 */
404 // ===============================================================
405 protected class SearchBase
406 {
407 // Define the operator to be used for this group
408 public int oper;
409
410 /**
411 * Constructor.
412 * This is protected so only the subclasses can instantiate it
413 *
414 */
415 // ------------------------------------------------------------
416 protected SearchBase()
417 {
418 }
419
420 }
421
422 /**
423 * SearchBaseLeafComparison holds a leaf of the search tree
424 * This class holds an element name, a binary operator, and a value to be compared
425 */
426 // ===============================================================
427 protected class SearchBaseLeafComparison extends SearchBase
428 {
429 // Define the element name
430 public String elementName;
431 // Only operators allowed are binary operators
432 // Define the comparison value
433 public String value;
434
435 /**
436 * Constructor.
437 *
438 * @param ElementName is the name of the element to be tested
439 * @param oper is the binary operator to be used for the comparison
440 * @param value is the value to be used for the comparison
441 */
442 SearchBaseLeafComparison(String ElementName, int oper, String value)
443 {
444 this.elementName = ElementName;
445 this.oper = oper;
446 this.value = value;
447 }
448
449 }
450
451 /**
452 * SearchBaseLeaf holds a leaf of the search tree
453 * This class holds an element name, and a vector of possible matches.
454 * It searches for an element of the given name that matches at least
455 * one of the strings in the array (IN), or does not match any (NOT_IN)
456 *
457 */
458 // ===============================================================
459 protected class SearchBaseLeaf extends SearchBase
460 {
461 // Define the element name
462 public String elementName;
463 // Only operators allowed are IN and NOT_IN
464 // Define the vector of possible matches
465 public String[] matches;
466
467 /**
468 * Constructor.
469 *
470 * @param ElementName is the name of the element to be tested
471 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
472 * @param matches is an array of String values to be matched
473 */
474 SearchBaseLeaf(String ElementName, int oper, String[] matches)
475 {
476 this.elementName = ElementName;
477 this.oper = oper;
478 this.matches = matches;
479 }
480
481 /**
482 * Constructor for only one value.
483 *
484 * @param ElementName is the name of the element to be tested
485 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
486 * @param match is a string value to be matched
487 */
488 SearchBaseLeaf(String ElementName, int oper, String match)
489 {
490 this.elementName = ElementName;
491 this.oper = oper;
492 this.matches = new String[1];
493 this.matches[0] = match;
494 }
495
496 }
497
498 /**
499 * SearchBaseLeafInt holds a leaf of the search tree with integers
500 * This class holds an element name, and a vector of possible matches.
501 * It searches for an element of the given name that matches at least
502 * one of the integers in the array (IN), or does not match any (NOT_IN)
503 */
504 // ===============================================================
505 protected class SearchBaseLeafInt extends SearchBase
506 {
507 // Define the element name
508 public String elementName;
509 // Only operators allowed are IN and NOT_IN
510 // Define the vector of possible matches
511 public int[] matches;
512
513 /**
514 * Constructor.
515 *
516 * @param ElementName is the name of the element to be tested
517 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
518 * @param matches is an array of integer values to be matched
519 */
520 SearchBaseLeafInt(String ElementName, int oper, int[] matches)
521 {
522 this.elementName = ElementName;
523 this.oper = oper;
524 this.matches = matches;
525 }
526
527 /**
528 * Constructor for only one value.
529 *
530 * @param ElementName is the name of the element to be tested
531 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
532 * @param match is an int value to be matched
533 */
534 SearchBaseLeafInt(String ElementName, int oper, int match)
535 {
536 this.elementName = ElementName;
537 this.oper = oper;
538 this.matches = new int[1];
539 this.matches[0] = match;
540 }
541
542 }
543
544 /**
545 * Define the class to represent a node of the search tree
546 * This class holds an operator and a vector other nodes.
547 */
548 // ===============================================================
549 protected class SearchBaseNode extends SearchBase
550 {
551 // Define the vector of other nodes
552 public Vector nodes;
553
554 /**
555 * Constructor.
556 * Store a list of filters and an operator for combining them.
557 *
558 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
559 * @param new_filters is a vector of filters to be combined
560 */
561 SearchBaseNode(int oper, Vector new_filters)
562 {
563 this.oper = oper;
564 this.nodes = new_filters;
565 }
566
567 /**
568 * Constructor for a specific filter and a vector of new ones.
569 * Store a list of filters and an operator for combining them.
570 *
571 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
572 * @param filter is the first filter to be combined
573 * @param new_filters is a vector of filters to be combined
574 */
575 SearchBaseNode(int oper, Object filter, Vector new_filters)
576 {
577 // Store the operator
578 this.oper = oper;
579 // Create a vector and add in the first filter as the initial node (if present)
580 nodes = new Vector();
581 if (filter != null)
582 {
583 nodes.addElement(filter);
584 // Now add in all the nodes of the new filters
585 }
586 for (Enumeration e = new_filters.elements(); e.hasMoreElements();)
587 {
588 nodes.addElement(e.nextElement());
589 }
590 }
591
592 }
593 }