1 /***
2 * LikeStringFilter.java
3 *
4 * This file is part of the creme library.
5 * The creme library intends to ease the development effort of large
6 * applications by providing easy to use support classes.
7 *
8 * Copyright (C) 2002 Denis Bregeon
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * contact information: dbregeon@sourceforge.net
25 */
26 package org.jcreme.filters;
27
28 import java.io.Serializable;
29 import java.util.StringTokenizer;
30
31 /***
32 * A filter that filters strings based on a comparison operator (which can
33 * basically be LIKE or NOT_LIKE) , and a stem that given strings have to be
34 * 'like' or 'not like'.
35 *
36 * @author $Author: dbregeon $
37 * @version $Revision: 1.4 $
38 */
39 public class LikeStringFilter implements Filter, Serializable {
40 static final long serialVersionUID = -146567890525271208L;
41
42 /***
43 * The comparison operator used in this filter.
44 */
45 private final StringComparisonOperator operator;
46
47 /***
48 * The stem used to filter strings. It is made of letters and two special
49 * characters : % standing for any number of letters, and _ standing for one
50 * letter.
51 */
52 private final String stem;
53
54 /***
55 * Creates new LikeStringComparator
56 *
57 * @param op
58 * The operator to be applied.
59 * @param stem
60 * The stem to be used to filter strings.
61 * @throws IllegalArgumentException
62 * In case any of the passed in parameters is null, which is not
63 * wanted here.
64 */
65 public LikeStringFilter(StringComparisonOperator op, String stem)
66 throws IllegalArgumentException {
67 if ((op == null) || (stem == null)) {
68 throw new IllegalArgumentException("Null is not a valid value.");
69 }
70 this.operator = op;
71 this.stem = stem;
72 }
73
74 /***
75 * Tells whether the given object 'passes' the filter or not.
76 *
77 * @return True if the passed in parameter is accepted by the filter, false
78 * otherwise.
79 * @param obj
80 * The object you want to 'test'.
81 */
82 public boolean accept(final Object obj) {
83 boolean result = (obj != null) && (obj instanceof String);
84 if (result) {
85 final String str = (String) obj;
86 final StringTokenizer tokenizer = new StringTokenizer(this.stem,
87 "_%", true);
88 String current = null;
89 int index = 0;
90 while ((result) && (tokenizer.hasMoreTokens())
91 && (index <= str.length())) {
92 current = tokenizer.nextToken();
93
94
95 if ("_".equals(current)) {
96 index++;
97 } else if (!"%".equals(current)) {
98
99 result = str.substring(index,
100 Math.min(index + current.length(), str.length()))
101 .equals(current);
102 if (result) {
103 index += current.length();
104 }
105 } else if ("%".equals(current)) {
106 while ((tokenizer.hasMoreTokens()) && ("%".equals(current))) {
107 current = tokenizer.nextToken();
108 }
109 if (("%".equals(current)) && (!tokenizer.hasMoreTokens())) {
110 index = str.length();
111 } else if ("_".equals(current)) {
112 index++;
113 } else {
114 final int tmp = str.indexOf(current, index);
115 result = result && (tmp != -1);
116 if (result) {
117 index = tmp + current.length();
118 }
119 }
120 }
121 }
122 result = result && (index == str.length());
123 if (this.operator == StringComparisonOperator.NOT_LIKE) {
124 result = !result;
125 }
126 }
127 return result;
128 }
129
130 /***
131 * Gives access to the comparison operator used by the filter.
132 *
133 * @return The comparison operator used by this filter.
134 */
135 public ComparisonOperator getOperator() {
136 return this.operator;
137 }
138
139 /***
140 * Gives access to the stem used by this filter.
141 *
142 * @return The stem used by this filter.
143 */
144 public String getStem() {
145 return this.stem;
146 }
147
148 /***
149 * Gives a SQL-like string representation of this filter.
150 *
151 * @return the string representation of the filter.
152 */
153 public String toString() {
154 return this.operator + " '" + this.stem + "'";
155 }
156
157 /***
158 * Overloads the 'dummy' implementation in Object, so that it returns true
159 * only if the passed in parameter is a filter of the same kind as this one,
160 * and accepts exactly the same objects.
161 *
162 * @return True if the passed in object is a LikeStringFilter that accepts
163 * exactly the same objects as this one.
164 * @param o
165 * The object to be compared to this one.
166 */
167 public boolean equals(final Object o) {
168 boolean result = false;
169 if (o instanceof LikeStringFilter) {
170 final LikeStringFilter filter = (LikeStringFilter) o;
171 result = ((this.operator == filter.getOperator()) && (this.stem
172 .equals(filter.getStem())));
173 }
174 return result;
175 }
176
177 /***
178 * Overloads the 'dummy' implementation in Object so that it fulfills the
179 * implicit hashCode contract, i.e. same filters have the same hashCode and
180 * different ones have different hashCodes.
181 *
182 * @return The hash code for this filter.
183 */
184 public int hashCode() {
185 return this.operator.hashCode() ^ this.stem.hashCode();
186 }
187
188 /***
189 * This forces override of the Object class clone method. it makes a deep
190 * copy so a change in a subfilter does not affect the cloned version.
191 *
192 * @return the cloned object.
193 */
194 public Object clone() {
195 Object result = null;
196 try {
197 result = super.clone();
198 } catch (CloneNotSupportedException e) {
199 e.printStackTrace();
200 }
201 return result;
202 }
203 }