View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.portals.bridges.jsf;
18  
19  import java.util.AbstractSet;
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.Enumeration;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.NoSuchElementException;
27  import java.util.Set;
28  
29  /***
30   * <p>
31   * Helper Map implementation for use with different Attribute Maps.
32   * </p>
33   * <p>
34   * See MyFaces project for servlet implementation.
35   * </p>
36   * 
37   * @author <a href="dlestrat@apache.org">David Le Strat </a>
38   *  
39   */
40  public abstract class AbstractAttributeMap implements Map
41  {
42      private Set keySet;
43  
44      private Collection values;
45  
46      private Set entrySet;
47  
48      /***
49       * @see java.util.Map#clear()
50       */
51      public void clear()
52      {
53          List names = new ArrayList();
54          for (Enumeration e = getAttributeNames(); e.hasMoreElements();)
55          {
56              names.add(e.nextElement());
57          }
58  
59          for (Iterator it = names.iterator(); it.hasNext();)
60          {
61              removeAttribute((String) it.next());
62          }
63      }
64  
65      /***
66       * @see java.util.Map#containsKey(java.lang.Object)
67       */
68      public boolean containsKey(Object key)
69      {
70          return getAttribute(key.toString()) != null;
71      }
72  
73      /***
74       * @see java.util.Map#containsValue(java.lang.Object)
75       */
76      public boolean containsValue(Object findValue)
77      {
78          if (findValue == null)
79          {
80              return false;
81          }
82  
83          for (Enumeration e = getAttributeNames(); e.hasMoreElements();)
84          {
85              Object value = getAttribute((String) e.nextElement());
86              if (findValue.equals(value))
87              {
88                  return true;
89              }
90          }
91  
92          return false;
93      }
94  
95      /***
96       * @see java.util.Map#entrySet()
97       */
98      public Set entrySet()
99      {
100         return (entrySet != null) ? entrySet : (entrySet = new EntrySet());
101     }
102 
103     /***
104      * @see java.util.Map#get(java.lang.Object)
105      */
106     public Object get(Object key)
107     {
108         return getAttribute(key.toString());
109     }
110 
111     /***
112      * @see java.util.Map#isEmpty()
113      */
114     public boolean isEmpty()
115     {
116         return !getAttributeNames().hasMoreElements();
117     }
118 
119     /***
120      * @see java.util.Map#keySet()
121      */
122     public Set keySet()
123     {
124         return (keySet != null) ? keySet : (keySet = new KeySet());
125     }
126 
127     /***
128      * @see java.util.Map#put(java.lang.Object, java.lang.Object)
129      */
130     public Object put(Object key, Object value)
131     {
132         String localKey = key.toString();
133         Object retval = getAttribute(localKey);
134         setAttribute(localKey, value);
135         return retval;
136     }
137 
138     /***
139      * @see java.util.Map#putAll(java.util.Map)
140      */
141     public void putAll(Map t)
142     {
143         for (Iterator it = t.entrySet().iterator(); it.hasNext();)
144         {
145             Entry entry = (Entry) it.next();
146             setAttribute(entry.getKey().toString(), entry.getValue());
147         }
148     }
149 
150     /***
151      * @see java.util.Map#remove(java.lang.Object)
152      */
153     public Object remove(Object key)
154     {
155         String localKey = key.toString();
156         Object retval = getAttribute(localKey);
157         removeAttribute(localKey);
158         return retval;
159     }
160 
161     /***
162      * @see java.util.Map#size()
163      */
164     public int size()
165     {
166         int size = 0;
167         for (Enumeration e = getAttributeNames(); e.hasMoreElements();)
168         {
169             size++;
170             e.nextElement();
171         }
172         return size;
173     }
174 
175     /***
176      * @see java.util.Map#values()
177      */
178     public Collection values()
179     {
180         return (values != null) ? values : (values = new Values());
181     }
182 
183     /***
184      * <p>
185      * Gets an attribute given a key.
186      * </p>
187      * 
188      * @param key The key.
189      * @return The attribute.
190      */
191     abstract protected Object getAttribute(String key);
192 
193     /***
194      * <p>
195      * Sets an attribute given a key/value.
196      * </p>
197      * 
198      * @param key The key.
199      * @param value The value.
200      */
201     abstract protected void setAttribute(String key, Object value);
202 
203     /***
204      * <p>
205      * Removes an attribute.
206      * </p>
207      * 
208      * @param key The key.
209      */
210     abstract protected void removeAttribute(String key);
211 
212     /***
213      * <p>
214      * Gets the attributes names.
215      * </p>
216      * 
217      * @return An enumeration of attributes names.
218      */
219     abstract protected Enumeration getAttributeNames();
220 
221     private class KeySet extends AbstractSet
222     {
223         public Iterator iterator()
224         {
225             return new KeyIterator();
226         }
227 
228         public boolean isEmpty()
229         {
230             return AbstractAttributeMap.this.isEmpty();
231         }
232 
233         public int size()
234         {
235             return AbstractAttributeMap.this.size();
236         }
237 
238         public boolean contains(Object o)
239         {
240             return AbstractAttributeMap.this.containsKey(o);
241         }
242 
243         public boolean remove(Object o)
244         {
245             return AbstractAttributeMap.this.remove(o) != null;
246         }
247 
248         public void clear()
249         {
250             AbstractAttributeMap.this.clear();
251         }
252     }
253 
254     private class KeyIterator implements Iterator
255     {
256         protected final Enumeration _e = getAttributeNames();
257 
258         protected Object _currentKey;
259 
260         public void remove()
261         {
262             // remove() may cause ConcurrentModificationException.
263             // We could throw an exception here, but not throwing an exception
264             //   allows one call to remove() to succeed
265             if (_currentKey == null)
266             {
267                 throw new NoSuchElementException("You must call next() at least once");
268             }
269             AbstractAttributeMap.this.remove(_currentKey);
270         }
271 
272         public boolean hasNext()
273         {
274             return _e.hasMoreElements();
275         }
276 
277         public Object next()
278         {
279             return _currentKey = _e.nextElement();
280         }
281     }
282 
283     private class Values extends KeySet
284     {
285         public Iterator iterator()
286         {
287             return new ValuesIterator();
288         }
289 
290         public boolean contains(Object o)
291         {
292             return AbstractAttributeMap.this.containsValue(o);
293         }
294 
295         public boolean remove(Object o)
296         {
297             if (o == null)
298             {
299                 return false;
300             }
301 
302             for (Iterator it = iterator(); it.hasNext();)
303             {
304                 if (o.equals(it.next()))
305                 {
306                     it.remove();
307                     return true;
308                 }
309             }
310 
311             return false;
312         }
313     }
314 
315     private class ValuesIterator extends KeyIterator
316     {
317         public Object next()
318         {
319             super.next();
320             return AbstractAttributeMap.this.get(_currentKey);
321         }
322     }
323 
324     private class EntrySet extends KeySet
325     {
326         public Iterator iterator()
327         {
328             return new EntryIterator();
329         }
330 
331         public boolean contains(Object o)
332         {
333             if (!(o instanceof Entry))
334             {
335                 return false;
336             }
337 
338             Entry entry = (Entry) o;
339             Object key = entry.getKey();
340             Object value = entry.getValue();
341             if (key == null || value == null)
342             {
343                 return false;
344             }
345 
346             return value.equals(AbstractAttributeMap.this.get(key));
347         }
348 
349         public boolean remove(Object o)
350         {
351             if (!(o instanceof Entry))
352             {
353                 return false;
354             }
355 
356             Entry entry = (Entry) o;
357             Object key = entry.getKey();
358             Object value = entry.getValue();
359             if (key == null || value == null || !value.equals(AbstractAttributeMap.this.get(key)))
360             {
361                 return false;
362             }
363 
364             return AbstractAttributeMap.this.remove(((Entry) o).getKey()) != null;
365         }
366     }
367 
368     /***
369      * Not very efficient since it generates a new instance of
370      * <code>Entry</code> for each element and still internaly uses the
371      * <code>KeyIterator</code>. It is more efficient to use the
372      * <code>KeyIterator</code> directly.
373      */
374     private class EntryIterator extends KeyIterator
375     {
376         public Object next()
377         {
378             super.next();
379             // Must create new Entry every time--value of the entry must stay
380             // linked to the same attribute name
381             return new EntrySetEntry(_currentKey);
382         }
383     }
384 
385     private class EntrySetEntry implements Entry
386     {
387         private final Object _currentKey;
388 
389         public EntrySetEntry(Object currentKey)
390         {
391             _currentKey = currentKey;
392         }
393 
394         public Object getKey()
395         {
396             return _currentKey;
397         }
398 
399         public Object getValue()
400         {
401             return AbstractAttributeMap.this.get(_currentKey);
402         }
403 
404         public Object setValue(Object value)
405         {
406             return AbstractAttributeMap.this.put(_currentKey, value);
407         }
408     }
409 }