Coverage Report - org.apache.myfaces.shared.util.SubKeyMap
 
Classes in this File Line Coverage Branch Coverage Complexity
SubKeyMap
78%
32/41
50%
11/22
2.32
SubKeyMap$Entries
100%
24/24
77%
14/18
2.32
SubKeyMap$Entry
50%
8/16
8%
1/12
2.32
SubKeyMap$EntryIterator
61%
8/13
0%
0/2
2.32
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.myfaces.shared.util;
 20  
 
 21  
 import java.util.AbstractMap;
 22  
 import java.util.AbstractSet;
 23  
 import java.util.ArrayList;
 24  
 import java.util.Iterator;
 25  
 import java.util.List;
 26  
 import java.util.Map;
 27  
 import java.util.Set;
 28  
 
 29  
 /**
 30  
  * NOTE: Class copied from trinidad to be used on FlashImpl.
 31  
  * 
 32  
  * Map that wraps another to provide an isolated namespace using
 33  
  * a prefix.  This is especially handy for storing properties on
 34  
  * the session in a structured manner without putting them into
 35  
  * a true "Map" - because storing in a Map breaks session failover.
 36  
  * (Session failover won't trigger on mutations of contained objects.)
 37  
  * <p>
 38  
  * Note that there is a potential design flaw;  if you create a SubKeyMap
 39  
  * for "mypackage.foo" and for "mypackage.foo.bar", all the keys in the
 40  
  * latter will actually show up in the former (prefixed by ".bar").  This
 41  
  * "flaw" is actually relied on by PageFlowScopeMap (since it provides
 42  
  * a handy way to clear out all descendents), so don't "fix" it!
 43  
  */
 44  124
 public final class SubKeyMap<V> extends AbstractMap<String, V>
 45  
 {
 46  
     public SubKeyMap(Map<String, Object> base, String prefix)
 47  60
     {
 48  60
         if (base == null)
 49  
         {
 50  0
             throw new NullPointerException();
 51  
         }
 52  60
         if (prefix == null)
 53  
         {
 54  0
             throw new NullPointerException();
 55  
         }
 56  
 
 57  
         // Optimize the scenario where we're wrapping another SubKeyMap
 58  60
         if (base instanceof SubKeyMap)
 59  
         {
 60  0
             _base = ((SubKeyMap) base)._base;
 61  0
             _prefix = ((SubKeyMap) base)._prefix + prefix;
 62  
         }
 63  
         else
 64  
         {
 65  60
             _base = base;
 66  60
             _prefix = prefix;
 67  
         }
 68  60
         _keyBuffer = new StringBuilder(32);
 69  60
     }
 70  
 
 71  
     @Override
 72  
     public boolean isEmpty()
 73  
     {
 74  44
         return entrySet().isEmpty();
 75  
     }
 76  
 
 77  
     @Override
 78  
     public V get(Object key)
 79  
     {
 80  45
         key = _getBaseKey(key);
 81  45
         return (V) _base.get(key);
 82  
     }
 83  
 
 84  
     @Override
 85  
     public V put(String key, V value)
 86  
     {
 87  13
         key = _getBaseKey(key);
 88  13
         return (V) _base.put(key, value);
 89  
     }
 90  
 
 91  
     @Override
 92  
     public V remove(Object key)
 93  
     {
 94  28
         key = _getBaseKey(key);
 95  28
         return (V) _base.remove(key);
 96  
     }
 97  
 
 98  
     @Override
 99  
     public boolean containsKey(Object key)
 100  
     {
 101  7
         if (!(key instanceof String))
 102  
         {
 103  0
             return false;
 104  
         }
 105  
 
 106  7
         return _base.containsKey(_getBaseKey(key));
 107  
     }
 108  
 
 109  
     @Override
 110  
     public Set<Map.Entry<String, V>> entrySet()
 111  
     {
 112  78
         if (_entrySet == null)
 113  
         {
 114  29
             _entrySet = new Entries<V>();
 115  
         }
 116  78
         return _entrySet;
 117  
     }
 118  
 
 119  
     private String _getBaseKey(Object key)
 120  
     {
 121  93
         if (key == null)
 122  
         {
 123  0
             throw new NullPointerException();
 124  
         }
 125  
         // Yes, I want a ClassCastException if it's not a String
 126  
         //return _prefix + ((String) key);
 127  93
         _keyBuffer.setLength(0);
 128  93
         _keyBuffer.append(_prefix);
 129  93
         _keyBuffer.append((String) key);
 130  93
         return _keyBuffer.toString();
 131  
     }
 132  
 
 133  
     private List<String> _gatherKeys()
 134  
     {
 135  15
         List<String> list = new ArrayList<String>();
 136  15
         for (String key : _base.keySet())
 137  
         {
 138  9
             if (key != null && key.startsWith(_prefix))
 139  
             {
 140  9
                 list.add(key);
 141  
             }
 142  9
         }
 143  
 
 144  15
         return list;
 145  
     }
 146  
 
 147  
     //
 148  
     // Set implementation for SubkeyMap.entrySet()
 149  
     //
 150  
     private class Entries<V> extends AbstractSet<Map.Entry<String, V>>
 151  
     {
 152  
         public Entries()
 153  29
         {
 154  29
         }
 155  
 
 156  
         @Override
 157  
         public Iterator<Map.Entry<String, V>> iterator()
 158  
         {
 159  
             // Sadly, if you just try to use a filtering approach
 160  
             // on the iterator, you'll get concurrent modification
 161  
             // exceptions.  Consequently, gather the keys in a list
 162  
             // and iterator over that.
 163  15
             List<String> keyList = _gatherKeys();
 164  15
             return new EntryIterator<V>(keyList.iterator());
 165  
         }
 166  
 
 167  
         @Override
 168  
         public int size()
 169  
         {
 170  14
             int size = 0;
 171  14
             for (String key : _base.keySet())
 172  
             {
 173  6
                 if (key != null && key.startsWith(_prefix))
 174  
                 {
 175  6
                     size++;
 176  
                 }
 177  6
             }
 178  
 
 179  14
             return size;
 180  
         }
 181  
 
 182  
         @Override
 183  
         public boolean isEmpty()
 184  
         {
 185  44
             Iterator<String> keys = _base.keySet().iterator();
 186  50
             while (keys.hasNext())
 187  
             {
 188  12
                 String key = keys.next();
 189  
                 // Short-circuit:  the default implementation would always
 190  
                 // need to iterate to find the total size.
 191  12
                 if (key != null && key.startsWith(_prefix))
 192  
                 {
 193  6
                     return false;
 194  
                 }
 195  6
             }
 196  
 
 197  38
             return true;
 198  
         }
 199  
 
 200  
         @Override
 201  
         public void clear()
 202  
         {
 203  5
             Iterator<String> keys = _base.keySet().iterator();
 204  11
             while (keys.hasNext())
 205  
             {
 206  6
                 String key = keys.next();
 207  6
                 if (key != null && key.startsWith(_prefix))
 208  
                 {
 209  5
                     keys.remove();
 210  
                 }
 211  6
             }
 212  5
         }
 213  
     }
 214  
 
 215  9
     private class EntryIterator<V> implements Iterator<Map.Entry<String, V>>
 216  
     {
 217  
         public EntryIterator(Iterator<String> iterator)
 218  15
         {
 219  15
             _iterator = iterator;
 220  15
         }
 221  
 
 222  
         public boolean hasNext()
 223  
         {
 224  18
             return _iterator.hasNext();
 225  
         }
 226  
 
 227  
         public Map.Entry<String, V> next()
 228  
         {
 229  9
             String baseKey = _iterator.next();
 230  9
             _currentKey = baseKey;
 231  9
             return new Entry<V>(baseKey);
 232  
         }
 233  
 
 234  
         public void remove()
 235  
         {
 236  0
             if (_currentKey == null)
 237  
             {
 238  0
                 throw new IllegalStateException();
 239  
             }
 240  
 
 241  0
             _base.remove(_currentKey);
 242  
 
 243  0
             _currentKey = null;
 244  0
         }
 245  
 
 246  
         private Iterator<String> _iterator;
 247  
         private String _currentKey;
 248  
     }
 249  
 
 250  3
     private class Entry<V> implements Map.Entry<String, V>
 251  
     {
 252  
         public Entry(String baseKey)
 253  9
         {
 254  9
             _baseKey = baseKey;
 255  9
         }
 256  
 
 257  
         public String getKey()
 258  
         {
 259  3
             if (_key == null)
 260  
             {
 261  3
                 _key = _baseKey.substring(_prefix.length());
 262  
             }
 263  3
             return _key;
 264  
         }
 265  
 
 266  
         public V getValue()
 267  
         {
 268  6
             return (V) _base.get(_baseKey);
 269  
         }
 270  
 
 271  
         public V setValue(V value)
 272  
         {
 273  0
             return (V) _base.put(_baseKey, value);
 274  
         }
 275  
 
 276  
         @SuppressWarnings("unchecked")
 277  
         @Override
 278  
         public boolean equals(Object o)
 279  
         {
 280  0
             if (!(o instanceof Map.Entry))
 281  
             {
 282  0
                 return false;
 283  
             }
 284  0
             Map.Entry<String, V> e = (Map.Entry<String, V>) o;
 285  0
             return _equals(getKey(), e.getKey())
 286  
                     && _equals(getValue(), e.getValue());
 287  
         }
 288  
 
 289  
         @Override
 290  
         public int hashCode()
 291  
         {
 292  0
             Object key = getKey();
 293  0
             Object value = getValue();
 294  0
             return ((key == null) ? 0 : key.hashCode())
 295  
                     ^ ((value == null) ? 0 : value.hashCode());
 296  
         }
 297  
 
 298  
         private String _baseKey;
 299  
         private String _key;
 300  
     }
 301  
 
 302  
     static private boolean _equals(Object a, Object b)
 303  
     {
 304  0
         if (a == null)
 305  
         {
 306  0
             return b == null;
 307  
         }
 308  0
         return a.equals(b);
 309  
     }
 310  
 
 311  
     private final Map<String, Object> _base;
 312  
     private final String _prefix;
 313  
     private Set<Map.Entry<String, V>> _entrySet;
 314  
     private StringBuilder _keyBuffer;
 315  
 
 316  
 }