View Javadoc

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    // Constructors
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    // Public methods
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    // Protected classes
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     // Constructors
112 
113     /***
114      * @param prefix <code>String</code> object.
115      */
116     AttributeNamePredicate(String prefix) {
117       this.prefix = prefix + ".";
118     }
119 
120     // Public methods
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   } // AttributeNamePredicate class
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     // Constructors
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   } // AttributeNameCutter class
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     // Public methods
176 
177     /***
178      * 
179      */
180     public Object transform(Object input) {
181       return predicate.toString() + input.toString();
182     }
183 
184   } // AttributeNameAdder class
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 } // AttributeNameWrapper class