001 package org.apache.ojb.broker.query;
002
003 /* Copyright 2002-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 import java.util.Enumeration;
019 import java.util.Hashtable;
020 import java.util.Vector;
021
022 /**
023 * Class to build selection criteria for searches
024 * Search Filter Class (Abstract)
025 * This class builds a search filter tree, specifing how names and
026 * values are to be compared when searching a database.
027 * It just builds internal structures, and needs to be extended
028 * to return a search filter string or other object that can be
029 * used by the database to perform the actual search.
030 */
031 public abstract class SearchFilter
032 {
033 // Define the operators
034 // Binary operators have bit 8 set
035 // Logical operators have bit 9 set
036 public static final int AND = 0x200; // Logical operator
037 public static final int OR = 0x201; // Logical operator
038 public static final int NOT = 0x2; // Unary operator
039 public static final int IN = 0x3;
040 public static final int NOT_IN = 0x4;
041 public static final int LIKE = 0x109; // Binary operator
042 public static final int EQUAL = 0x10A; // Binary operator
043 public static final int NOT_EQUAL = 0x10B; // Binary operator
044 public static final int LESS_THAN = 0x10C; // Binary operator
045 public static final int GREATER_THAN = 0x10D; // Binary operator
046 public static final int GREATER_EQUAL = 0x10E; // Binary operator
047 public static final int LESS_EQUAL = 0x10F; // Binary operator
048 // Define a mask for the binary and logical operators
049 // private static final int BINARY_OPER_MASK = 0x100;
050 // private static final int LOGICAL_OPER_MASK = 0x200;
051 protected static final int BINARY_OPER_MASK = 0x100;
052 protected static final int LOGICAL_OPER_MASK = 0x200;
053 // Define the current search filter
054 protected SearchBase m_filter = null;
055
056 /**
057 * Create an empty search filter.
058 *
059 */
060 // -----------------------------------------------------------
061 public SearchFilter()
062 {
063 }
064
065 /**
066 * Change the search filter to one that specifies an element to
067 * match or not match one of a list of values.
068 * The old search filter is deleted.
069 *
070 * @param ElementName is the name of the element to be matched
071 * @param values is a vector of possible matches
072 * @param oper is the IN or NOT_IN operator to indicate how to matche
073 */
074 public void matchList(String ElementName, Vector values, int oper)
075 {
076 // Delete the old search filter
077 m_filter = null;
078 // If not NOT_IN, assume IN
079 // (Since ints are passed by value, it is OK to change it)
080 if (oper != NOT_IN)
081 {
082 oper = IN;
083 // Convert the vector of match strings to an array of strings
084 }
085 String[] value_string_array = new String[values.size()];
086 values.copyInto(value_string_array);
087 // Create a leaf node for this list and store it as the filter
088 m_filter = new SearchBaseLeaf(ElementName, oper, value_string_array);
089 }
090
091 /**
092 * Change the search filter to one that specifies an element to not
093 * match one of a list of values.
094 * The old search filter is deleted.
095 *
096 * @param ElementName is the name of the element to be matched
097 * @param values is an array of possible matches
098 * @param oper is the IN or NOT_IN operator to indicate how to matche
099 */
100 public void matchList(String ElementName, String[] values, int oper)
101 {
102 // Delete the old search filter
103 m_filter = null;
104 // If not NOT_IN, assume IN
105 // (Since ints are passed by value, it is OK to change it)
106 if (oper != NOT_IN)
107 {
108 oper = IN;
109 // Create a leaf node for this list and store it as the filter
110 }
111 m_filter = new SearchBaseLeaf(ElementName, oper, values);
112 }
113
114 /**
115 * Change the search filter to one that specifies an element to not
116 * match one of a list of integer values.
117 * The old search filter is deleted.
118 *
119 * @param ElementName is the name of the element to be matched
120 * @param values is an array of possible integer matches
121 * @param oper is the IN or NOT_IN operator to indicate how to matche
122 */
123 public void matchList(String ElementName, int[] values, int oper)
124 {
125 // Delete the old search filter
126 m_filter = null;
127 // If not NOT_IN, assume IN
128 // (Since ints are passed by value, it is OK to change it)
129 if (oper != NOT_IN)
130 {
131 oper = IN;
132 // Create a leaf node for this list and store it as the filter
133 }
134 m_filter = new SearchBaseLeafInt(ElementName, oper, values);
135 }
136
137 /**
138 * Change the search filter to one that specifies an element to not
139 * match one single value.
140 * The old search filter is deleted.
141 *
142 * @param ElementName is the name of the element to be matched
143 * @param value is the value to not be matched
144 * @param oper is the IN or NOT_IN operator to indicate how to matche
145 */
146 public void matchValue(String ElementName, String value, int oper)
147 {
148 // Delete the old search filter
149 m_filter = null;
150 // If not NOT_IN, assume IN
151 // (Since ints are passed by value, it is OK to change it)
152 if (oper != NOT_IN)
153 {
154 oper = IN;
155 // Create a String array in which to hold the one name,
156 // and put that name in the array
157 }
158 String[] ValueArray = new String[1];
159 ValueArray[0] = value;
160 // Create a leaf node for this list and store it as the filter
161 m_filter = new SearchBaseLeaf(ElementName, oper, ValueArray);
162 }
163
164 /**
165 * -----------------------------------------------------------
166 * @param ElementName
167 * @param value
168 * @param oper
169 */
170 public void matchValue(String ElementName, int value, int oper)
171 {
172 // Delete the old search filter
173 m_filter = null;
174 // If not NOT_IN, assume IN
175 // (Since ints are passed by value, it is OK to change it)
176 if (oper != NOT_IN)
177 {
178 oper = IN;
179 // Create a leaf node for this list and store it as the filter
180 }
181 m_filter = new SearchBaseLeafInt(ElementName, oper, new int[]
182 {
183 value
184 });
185 }
186
187 /**
188 * Change the search filter to one that compares an element name to a value.
189 * The old search filter is deleted.
190 *
191 * @param ElementName is the name of the element to be tested
192 * @param value is the value to be compared against
193 * @param oper is the binary comparison operator to be used
194 * @exception DBException
195 */
196 public void compareFilter(String ElementName, String value, int oper) throws DBException
197 {
198 // Delete the old search filter
199 m_filter = null;
200 // If this is not a binary operator, throw an exception
201 if ((oper & BINARY_OPER_MASK) == 0)
202 {
203 throw new DBException();
204 // Create a SearchBaseLeafComparison node and store it as the filter
205 }
206 m_filter = new SearchBaseLeafComparison(ElementName, oper, value);
207 }
208
209 /**
210 * Change the search filter to one that specifies a set of elements and their values
211 * that must match, and the operator to use to combine the elements.
212 * Each key is compared for an equal match to the value, and all
213 * comparisons are combined by the specified logical operator (OR or AND).
214 * The old search filter is deleted.
215 *
216 * @param elements is a hashtable holding key-value pairs
217 * @param combine_op is the logical operator to be used to combine the comparisons
218 * @param compare_op is the binary operator to be used for the comparisons
219 * @exception DBException
220 */
221 public void matchSet(Hashtable elements, int combine_op, int compare_op) throws DBException
222 {
223 // Delete the old search filter
224 m_filter = null;
225 // If combine_op is not a logical operator, throw an exception
226 if ((combine_op & LOGICAL_OPER_MASK) == 0)
227 {
228 throw new DBException();
229 // If compare_op is not a binary operator, throw an exception
230 }
231 if ((compare_op & BINARY_OPER_MASK) == 0)
232 {
233 throw new DBException();
234 // Create a vector that will hold the comparison nodes for all elements in the hashtable
235 }
236 Vector compareVector = new Vector();
237 // For each of the elements in the hashtable, create a comparison node for the match
238 for (Enumeration e = elements.keys(); e.hasMoreElements();)
239 {
240 // Get the element name from the enumerator
241 // and its value
242 String elementName = (String) e.nextElement();
243 String elementValue = (String) elements.get(elementName);
244 // Create a comparison node for this list and store it as the filter
245 SearchBaseLeafComparison comparenode = new SearchBaseLeafComparison(elementName,
246 compare_op, elementValue);
247 // Add this leaf node to the vector
248 compareVector.addElement(comparenode);
249 }
250 // Now return a node that holds this set of leaf nodes
251 m_filter = new SearchBaseNode(combine_op, compareVector);
252 }
253
254 /**
255 * Change the search filter to one that specifies a set of elements and their values
256 * that must match, and the operator to use to combine the elements.
257 * Each element name is compared for an equal match to the value, and all
258 * comparisons are combined by the specified logical operator (OR or AND).
259 * The old search filter is deleted.
260 *
261 * @param ElementNames is an array of names of elements to be tested
262 * @param ElementValues is an array of values for the corresponding element
263 * @param op is the logical operator to be used to combine the comparisons
264 * @exception DBException
265 */
266 public void matchSet(String[] ElementNames, String[] ElementValues, int op) throws DBException
267 {
268 // Delete the old search filter
269 m_filter = null;
270 // If this is not a logical operator, throw an exception
271 if ((op & LOGICAL_OPER_MASK) == 0)
272 {
273 throw new DBException();
274 // Create a vector that will hold the leaf nodes for all elements in the hashtable
275 }
276 Vector leafVector = new Vector();
277 // For each of the elements in the array, create a leaf node for the match
278 int numnames = ElementNames.length;
279 for (int i = 0; i < numnames; i++)
280 {
281 // Create a leaf node for this list and store it as the filter
282 SearchBaseLeaf leafnode = new SearchBaseLeaf(ElementNames[i], IN, ElementValues[i]);
283 // Add this leaf node to the vector
284 leafVector.addElement(leafnode);
285 }
286 // Now return a node that holds this set of leaf nodes
287 m_filter = new SearchBaseNode(op, leafVector);
288 }
289
290 /**
291 * Combine other search filters with this one, using the specific operator.
292 *
293 * @param new_filters is a vector of SearchFilter classes to be combined
294 * @param op is the logical operator to be used to combine the filters
295 * @exception DBException
296 */
297 public void combine(Vector new_filters, int op) throws DBException
298 {
299 // If this is not a logical operator, throw an exception
300 if ((op & LOGICAL_OPER_MASK) == 0)
301 {
302 throw new DBException();
303 // Create a new vector consisting of just the filters
304 // from the SearchFilter classes in new_filters
305 }
306 Vector filters = new Vector();
307 // Now add in all the nodes of the new filters
308 for (Enumeration e = new_filters.elements(); e.hasMoreElements();)
309 {
310 // Get the search filter from the vector
311 SearchFilter f = (SearchFilter) e.nextElement();
312 filters.addElement(f.getFilter());
313 }
314 // Create a node for this list and return it
315 m_filter = new SearchBaseNode(op, m_filter, filters);
316 }
317
318 /**
319 * Combine one other search filters with this one, using the specific operator.
320 *
321 * @param new_filter is the SearchFilter class to be combined
322 * @param op is the logical operator to be used to combine the filters
323 * @exception DBException
324 */
325 public void combine(SearchFilter new_filter, int op) throws DBException
326 {
327 // If this is not a logical operator, throw an exception
328 if ((op & LOGICAL_OPER_MASK) == 0)
329 {
330 throw new DBException();
331 // Create a new vector consisting of just the filters
332 // from the SearchFilter classes in new_filters
333 }
334 Vector filters = new Vector();
335 filters.addElement(new_filter.getFilter());
336 // Create a node for this list and return it
337 m_filter = new SearchBaseNode(op, m_filter, filters);
338 }
339
340 /**
341 * Static method to convert a binary operator into a string.
342 *
343 * @param oper is the binary comparison operator to be converted
344 */
345 protected static String ConvertBinaryOperator(int oper)
346 {
347 // Convert the operator into the proper string
348 String oper_string;
349 switch (oper)
350 {
351 default:
352 case EQUAL:
353 oper_string = "=";
354 break;
355 case LIKE:
356 oper_string = "LIKE";
357 break;
358 case NOT_EQUAL:
359 oper_string = "!=";
360 break;
361 case LESS_THAN:
362 oper_string = "<";
363 break;
364 case GREATER_THAN:
365 oper_string = ">";
366 break;
367 case GREATER_EQUAL:
368 oper_string = ">=";
369 break;
370 case LESS_EQUAL:
371 oper_string = "<=";
372 break;
373 }
374 return oper_string;
375 }
376
377 /**
378 * Get the actual filter out of the class.
379 * This is only needed when combining filters together
380 * and one instantiation has to get the filter from another.
381 * However, I do not know how to protect it from outside use.
382 * @return
383 *
384 */
385 protected SearchBase getFilter()
386 {
387 return m_filter;
388 }
389
390 /**
391 * Converts this search filter into a search string for use by a database.
392 *
393 */
394
395 /**
396 * -----------------------------------------------------------
397 * @return
398 */
399 public abstract String toString();
400
401 /**
402 * SearchBase is the base node class for the parse tree
403 * This class holds the binary operator
404 *
405 */
406 // ===============================================================
407 protected class SearchBase
408 {
409 // Define the operator to be used for this group
410 public int oper;
411
412 /**
413 * Constructor.
414 * This is protected so only the subclasses can instantiate it
415 *
416 */
417 // ------------------------------------------------------------
418 protected SearchBase()
419 {
420 }
421
422 }
423
424 /**
425 * SearchBaseLeafComparison holds a leaf of the search tree
426 * This class holds an element name, a binary operator, and a value to be compared
427 */
428 // ===============================================================
429 protected class SearchBaseLeafComparison extends SearchBase
430 {
431 // Define the element name
432 public String elementName;
433 // Only operators allowed are binary operators
434 // Define the comparison value
435 public String value;
436
437 /**
438 * Constructor.
439 *
440 * @param ElementName is the name of the element to be tested
441 * @param oper is the binary operator to be used for the comparison
442 * @param value is the value to be used for the comparison
443 */
444 SearchBaseLeafComparison(String ElementName, int oper, String value)
445 {
446 this.elementName = ElementName;
447 this.oper = oper;
448 this.value = value;
449 }
450
451 }
452
453 /**
454 * SearchBaseLeaf holds a leaf of the search tree
455 * This class holds an element name, and a vector of possible matches.
456 * It searches for an element of the given name that matches at least
457 * one of the strings in the array (IN), or does not match any (NOT_IN)
458 *
459 */
460 // ===============================================================
461 protected class SearchBaseLeaf extends SearchBase
462 {
463 // Define the element name
464 public String elementName;
465 // Only operators allowed are IN and NOT_IN
466 // Define the vector of possible matches
467 public String[] matches;
468
469 /**
470 * Constructor.
471 *
472 * @param ElementName is the name of the element to be tested
473 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
474 * @param matches is an array of String values to be matched
475 */
476 SearchBaseLeaf(String ElementName, int oper, String[] matches)
477 {
478 this.elementName = ElementName;
479 this.oper = oper;
480 this.matches = matches;
481 }
482
483 /**
484 * Constructor for only one value.
485 *
486 * @param ElementName is the name of the element to be tested
487 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
488 * @param match is a string value to be matched
489 */
490 SearchBaseLeaf(String ElementName, int oper, String match)
491 {
492 this.elementName = ElementName;
493 this.oper = oper;
494 this.matches = new String[1];
495 this.matches[0] = match;
496 }
497
498 }
499
500 /**
501 * SearchBaseLeafInt holds a leaf of the search tree with integers
502 * This class holds an element name, and a vector of possible matches.
503 * It searches for an element of the given name that matches at least
504 * one of the integers in the array (IN), or does not match any (NOT_IN)
505 */
506 // ===============================================================
507 protected class SearchBaseLeafInt extends SearchBase
508 {
509 // Define the element name
510 public String elementName;
511 // Only operators allowed are IN and NOT_IN
512 // Define the vector of possible matches
513 public int[] matches;
514
515 /**
516 * Constructor.
517 *
518 * @param ElementName is the name of the element to be tested
519 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
520 * @param matches is an array of integer values to be matched
521 */
522 SearchBaseLeafInt(String ElementName, int oper, int[] matches)
523 {
524 this.elementName = ElementName;
525 this.oper = oper;
526 this.matches = matches;
527 }
528
529 /**
530 * Constructor for only one value.
531 *
532 * @param ElementName is the name of the element to be tested
533 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
534 * @param match is an int value to be matched
535 */
536 SearchBaseLeafInt(String ElementName, int oper, int match)
537 {
538 this.elementName = ElementName;
539 this.oper = oper;
540 this.matches = new int[1];
541 this.matches[0] = match;
542 }
543
544 }
545
546 /**
547 * Define the class to represent a node of the search tree
548 * This class holds an operator and a vector other nodes.
549 */
550 // ===============================================================
551 protected class SearchBaseNode extends SearchBase
552 {
553 // Define the vector of other nodes
554 public Vector nodes;
555
556 /**
557 * Constructor.
558 * Store a list of filters and an operator for combining them.
559 *
560 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
561 * @param new_filters is a vector of filters to be combined
562 */
563 SearchBaseNode(int oper, Vector new_filters)
564 {
565 this.oper = oper;
566 this.nodes = new_filters;
567 }
568
569 /**
570 * Constructor for a specific filter and a vector of new ones.
571 * Store a list of filters and an operator for combining them.
572 *
573 * @param oper is the operator (IN or NOT_IN) to be used for the comparison
574 * @param filter is the first filter to be combined
575 * @param new_filters is a vector of filters to be combined
576 */
577 SearchBaseNode(int oper, Object filter, Vector new_filters)
578 {
579 // Store the operator
580 this.oper = oper;
581 // Create a vector and add in the first filter as the initial node (if present)
582 nodes = new Vector();
583 if (filter != null)
584 {
585 nodes.addElement(filter);
586 // Now add in all the nodes of the new filters
587 }
588 for (Enumeration e = new_filters.elements(); e.hasMoreElements();)
589 {
590 nodes.addElement(e.nextElement());
591 }
592 }
593
594 }
595 }