View Javadoc

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