1 package pl.aislib.fm;
2
3 import java.util.Enumeration;
4 import java.util.Iterator;
5 import java.util.LinkedList;
6 import java.util.List;
7 import java.util.NoSuchElementException;
8
9 /***
10 * Wrapper for attribute names.
11 *
12 * @author <a href="mailto:chmielu@ais.pl">Pawel Chmielewski</a>, AIS.PL
13 * @version $Revision: 1.4 $
14 * @since AISLIB 0.4
15 */
16 public class AttributeNameWrapper {
17
18 /***
19 * Predicate.
20 */
21 private AttributeNamePredicate predicate;
22
23 /***
24 * Cutter.
25 */
26 private AttributeNameCutter cutter;
27
28 /***
29 * Adder.
30 */
31 private AttributeNameAdder adder;
32
33
34
35 /***
36 * Creates a new <code>AttributeNameWrapper</code> instance.
37 *
38 * @param prefix <code>String</code> object.
39 */
40 protected AttributeNameWrapper(String prefix) {
41 predicate = new AttributeNamePredicate(prefix);
42 cutter = new AttributeNameCutter(predicate);
43 adder = new AttributeNameAdder();
44 }
45
46
47
48 /***
49 * @param name <code>String</code> object.
50 * @return <code>String</code> object.
51 */
52 public String wrap(String name) {
53 return (String) adder.transform(name);
54 }
55
56 /***
57 * @param name <code>String</code> object.
58 * @return <code>String</code> object.
59 */
60 public String unwrap(String name) {
61 return (String) cutter.transform(name);
62 }
63
64 /***
65 * @param namesEnumeration <code>Enumeration</code> object.
66 * @return <code>Iterator</code> object.
67 */
68 public Iterator unwrap(Enumeration namesEnumeration) {
69 Iterator namesIterator = new EnumerationIterator(namesEnumeration);
70 Iterator appNamesIterator = new FilterIterator(namesIterator, predicate);
71 return new TransformIterator(appNamesIterator, cutter);
72 }
73
74 /***
75 * @param name <code>String</code> object.
76 * @return true if predicate is true.
77 */
78 public boolean match(String name) {
79 return predicate.evaluate(name);
80 }
81
82 /***
83 * @param namesEnumeration <code>Enumeration</code> object.
84 * @return <code>Iterator</code> object.
85 */
86 public Iterator getMatched(Enumeration namesEnumeration) {
87 List result = new LinkedList();
88 while (namesEnumeration.hasMoreElements()) {
89 String attrName = (String) namesEnumeration.nextElement();
90 if (match(attrName)) {
91 result.add(attrName);
92 }
93 }
94 return result.iterator();
95 }
96
97
98
99 /***
100 * Class of predicates starting with a given prefix.
101 *
102 * @author <a href="mailto:chmielu@ais.pl">Pawel Chmielewski</a>, AIS.PL
103 */
104 protected class AttributeNamePredicate {
105
106 /***
107 * Prefix string.
108 */
109 private String prefix;
110
111
112
113 /***
114 * @param prefix <code>String</code> object.
115 */
116 AttributeNamePredicate(String prefix) {
117 this.prefix = prefix + ".";
118 }
119
120
121
122 /***
123 *
124 */
125 public boolean evaluate(Object obj) {
126 return obj.toString().startsWith(prefix);
127 }
128
129 /***
130 * @see java.lang.Object#toString()
131 */
132 public String toString() {
133 return prefix;
134 }
135
136 }
137
138 /***
139 * Class of transformers cutting predicate evaluation object to a given length.
140 *
141 * @author <a href="mailto:chmielu@ais.pl">Pawel Chmielewski</a>, AIS.PL
142 */
143 class AttributeNameCutter {
144
145 /***
146 * Length to which predicate evaluation is cut.
147 */
148 private int predicateLength;
149
150
151
152 /***
153 * @param predicate <code>Predicate</code> object.
154 */
155 public AttributeNameCutter(AttributeNamePredicate predicate) {
156 predicateLength = predicate.toString().length();
157 }
158
159 public Object transform(Object input) {
160 if (predicate.evaluate(input)) {
161 return input.toString().substring(predicateLength);
162 }
163 return input;
164 }
165
166 }
167
168 /***
169 * Inner class of transformers adding string to predicate evaluation object.
170 *
171 * @author <a href="mailto:chmielu@ais.pl">Pawel Chmielewski</a>, AIS.PL
172 */
173 class AttributeNameAdder {
174
175
176
177 /***
178 *
179 */
180 public Object transform(Object input) {
181 return predicate.toString() + input.toString();
182 }
183
184 }
185
186 class EnumerationIterator implements Iterator {
187
188 private Enumeration enumeration;
189
190 EnumerationIterator(Enumeration enumeration) {
191 this.enumeration = enumeration;
192 }
193
194 /***
195 * @see java.util.Iterator#remove()
196 */
197 public void remove() {
198 throw new UnsupportedOperationException();
199 }
200
201 /***
202 * @see java.util.Iterator#hasNext()
203 */
204 public boolean hasNext() {
205 return enumeration.hasMoreElements();
206 }
207
208 /***
209 * @see java.util.Iterator#next()
210 */
211 public Object next() {
212 return enumeration.nextElement();
213 }
214 }
215
216 class FilterIterator implements Iterator {
217
218 /*** The iterator being used */
219 private Iterator iterator;
220 /*** The predicate being used */
221 private AttributeNamePredicate predicate;
222 /*** The next object in the iteration */
223 private Object nextObject;
224 /*** Whether the next object has been calculated yet */
225 private boolean nextObjectSet = false;
226
227 /***
228 * Constructs a new <code>FilterIterator</code> that will not function
229 * until {@link #setPredicate(Predicate) setPredicate} is invoked.
230 *
231 * @param iterator the iterator to use
232 */
233 /***
234 * Constructs a new <code>FilterIterator</code> that will use the
235 * given iterator and predicate.
236 *
237 * @param iterator the iterator to use
238 * @param predicate the predicate to use
239 */
240 public FilterIterator(Iterator iterator, AttributeNamePredicate predicate) {
241 this.iterator = iterator;
242 this.predicate = predicate;
243 }
244
245
246 /***
247 * Returns true if the underlying iterator contains an object that
248 * matches the predicate.
249 *
250 * @return true if there is another object that matches the predicate
251 */
252 public boolean hasNext() {
253 if (nextObjectSet) {
254 return true;
255 } else {
256 return setNextObject();
257 }
258 }
259
260 /***
261 * Returns the next object that matches the predicate.
262 *
263 * @return the next object which matches the given predicate
264 * @throws NoSuchElementException if there are no more elements that
265 * match the predicate
266 */
267 public Object next() {
268 if (!nextObjectSet) {
269 if (!setNextObject()) {
270 throw new NoSuchElementException();
271 }
272 }
273 nextObjectSet = false;
274 return nextObject;
275 }
276
277 /***
278 * Removes from the underlying collection of the base iterator the last
279 * element returned by this iterator.
280 * This method can only be called
281 * if <code>next()</code> was called, but not after
282 * <code>hasNext()</code>, because the <code>hasNext()</code> call
283 * changes the base iterator.
284 *
285 * @throws IllegalStateException if <code>hasNext()</code> has already
286 * been called.
287 */
288 public void remove() {
289 if (nextObjectSet) {
290 throw new IllegalStateException("remove() cannot be called");
291 }
292 iterator.remove();
293 }
294
295
296 /***
297 * Set nextObject to the next object. If there are no more
298 * objects then return false. Otherwise, return true.
299 */
300 private boolean setNextObject() {
301 while (iterator.hasNext()) {
302 Object object = iterator.next();
303 if (predicate.evaluate(object)) {
304 nextObject = object;
305 nextObjectSet = true;
306 return true;
307 }
308 }
309 return false;
310 }
311 }
312
313 class TransformIterator implements Iterator {
314
315 /*** The iterator being used */
316 private Iterator iterator;
317 /*** The transformer being used */
318 private AttributeNameCutter transformer;
319
320 /***
321 * Constructs a new <code>TransformIterator</code> that will use the
322 * given iterator and transformer. If the given transformer is null,
323 * then objects will not be transformed.
324 *
325 * @param iterator the iterator to use
326 * @param transformer the transformer to use
327 */
328 public TransformIterator(Iterator iterator, AttributeNameCutter transformer) {
329 this.iterator = iterator;
330 this.transformer = transformer;
331 }
332
333 /***
334 * @see java.util.Iterator#hasNext()
335 */
336 public boolean hasNext() {
337 return iterator.hasNext();
338 }
339
340 /***
341 * Gets the next object from the iteration, transforming it using the
342 * current transformer. If the transformer is null, no transformation
343 * occurs and the object from the iterator is returned directly.
344 *
345 * @return the next object
346 * @throws java.util.NoSuchElementException if there are no more elements
347 */
348 public Object next() {
349 return transform(iterator.next());
350 }
351
352 /***
353 * @see java.util.Iterator#remove()
354 */
355 public void remove() {
356 iterator.remove();
357 }
358
359
360 /***
361 * Transforms the given object using the transformer.
362 * If the transformer is null, the original object is returned as-is.
363 *
364 * @param source the object to transform
365 * @return the transformed object
366 */
367 protected Object transform(Object source) {
368 if (transformer != null) {
369 return transformer.transform(source);
370 }
371 return source;
372 }
373 }
374 }