Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 292   Methods: 22
NCLOC: 231   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
CachedSetImpl.java 83.3% 93.7% 100% 92.2%
coverage coverage
 1    /*
 2    * JBoss, the OpenSource J2EE webOS
 3    *
 4    * Distributable under LGPL license.
 5    * See terms of license at gnu.org.
 6    */
 7    package org.jboss.cache.pojo.collection;
 8   
 9    import static org.jboss.cache.pojo.impl.InternalConstant.POJOCACHE_OPERATION;
 10   
 11    import java.util.AbstractSet;
 12    import java.util.Collection;
 13    import java.util.Collections;
 14    import java.util.HashSet;
 15    import java.util.Iterator;
 16    import java.util.Set;
 17   
 18    import org.jboss.cache.Cache;
 19    import org.jboss.cache.CacheException;
 20    import org.jboss.cache.CacheSPI;
 21    import org.jboss.cache.Fqn;
 22    import org.jboss.cache.Node;
 23    import org.jboss.cache.NodeSPI;
 24    import org.jboss.cache.pojo.annotation.Reentrant;
 25    import org.jboss.cache.pojo.impl.PojoCacheImpl;
 26    import org.jboss.cache.pojo.interceptors.dynamic.AbstractCollectionInterceptor;
 27    import org.jboss.cache.pojo.util.AopUtil;
 28    import org.jboss.cache.pojo.util.CacheApiUtil;
 29    import org.jboss.cache.pojo.util.Null;
 30   
 31    /**
 32    * Set implementation that uses a cache as an underlying backend store.
 33    * Set data is stored in children nodes named based on the attached Object's hash code
 34    * in hexidecimal string form.
 35    * If there are conflicts between two Objects with the same hash code, then a
 36    * counter (upper 32 bits of 64) is used.
 37    *
 38    * @author Ben Wang
 39    * @author Scott Marlow
 40    * @author Jussi Pyorre
 41    */
 42    @Reentrant
 43    public class CachedSetImpl extends AbstractSet
 44    {
 45    private PojoCacheImpl pojoCache;
 46    private Cache<Object, Object> cache;
 47    private AbstractCollectionInterceptor interceptor;
 48   
 49  66 public CachedSetImpl(PojoCacheImpl cache, AbstractCollectionInterceptor interceptor)
 50    {
 51  66 this.pojoCache = cache;
 52  66 this.cache = pojoCache.getCache();
 53  66 this.interceptor = interceptor;
 54    }
 55   
 56  295 private Set<Node> getNodeChildren()
 57    {
 58  295 return CacheApiUtil.getNodeChildren(cache, getFqn());
 59    }
 60   
 61  805 private Fqn getFqn()
 62    {
 63    // Cannot cache this as this can be reset
 64  805 return interceptor.getFqn();
 65    }
 66   
 67    // java.util.Set implementation
 68   
 69  158 public boolean add(Object o)
 70    {
 71  158 o = Null.toNullObject(o);
 72  158 int hashCode = o.hashCode();
 73  158 int size = size();
 74  174 for (int i = 0; i < size + 1; i++)
 75    {
 76  174 Object key = toLong(hashCode, i);
 77  174 Object o2 = getNoUnmask(key);
 78  174 if (o2 == null)
 79    {
 80  152 attach(key, o, true);
 81  152 return true;
 82    }
 83  22 if (o.equals(o2))
 84    {
 85  6 return false;
 86    }
 87    }
 88    // should never reach here
 89  0 throw new CacheException();
 90    }
 91   
 92  3 public void clear()
 93    {
 94  3 Set<Node> children = getNodeChildren();
 95  3 for (Node n : children)
 96    {
 97  9 pojoCache.detach(n.getFqn());
 98    }
 99    }
 100   
 101  25 public boolean contains(Object o)
 102    {
 103  25 o = Null.toNullObject(o);
 104  25 int hashCode = o.hashCode();
 105  25 int size = size();
 106  25 for (int i = 0; i < size; i++)
 107    {
 108  25 Object key = toLong(hashCode, i);
 109  25 Object o2 = getNoUnmask(key);
 110  25 if (o2 == null)
 111    {
 112  6 return false;
 113    }
 114  19 if (o.equals(o2))
 115    {
 116  19 return true;
 117    }
 118    }
 119  0 return false;
 120    }
 121   
 122  41 public Iterator iterator()
 123    {
 124  41 Node node = cache.getRoot().getChild(getFqn());
 125  41 if (node == null)
 126    {
 127  0 return Collections.EMPTY_SET.iterator();
 128    }
 129  41 return new IteratorImpl(node);
 130    }
 131   
 132  42 public boolean remove(Object o)
 133    {
 134  42 o = Null.toNullObject(o);
 135  42 int hashCode = o.hashCode();
 136  42 int size = size();
 137  42 boolean removed = false;
 138  42 Object oldkey = null;
 139  42 for (int i = 0; i < size; i++)
 140    {
 141  71 Object key = toLong(hashCode, i);
 142  71 Object o2 = getNoUnmask(key);
 143  71 if (o2 == null)
 144    {
 145  23 break;
 146    }
 147  48 if (removed)
 148    {
 149    // move o2 to old key
 150  3 detach(key);
 151  3 attach(oldkey, o2);
 152    }
 153  48 if (o.equals(o2))
 154    {
 155  41 detach(key, true);
 156  41 removed = true;
 157    }
 158  48 oldkey = key;
 159    }
 160  42 return removed;
 161    }
 162   
 163  292 public int size()
 164    {
 165  292 Set<Node> children = getNodeChildren();
 166  292 return (children == null) ? 0 : children.size();
 167    }
 168   
 169  3 public String toString()
 170    {
 171  3 StringBuffer buf = new StringBuffer();
 172  3 for (Iterator it = iterator(); it.hasNext();)
 173    {
 174  7 Object key = it.next();
 175  7 buf.append("[").append(key).append("]");
 176  4 if (it.hasNext()) buf.append(", ");
 177    }
 178   
 179  3 return buf.toString();
 180    }
 181   
 182    /**
 183    * Return a long with "count" as the high 32 bits.
 184    * TODO should be able to use java.lang.Long, but some CacheLoader don't
 185    * support non-String keys
 186    */
 187  270 private String toLong(long hashCode, long count)
 188    {
 189  270 long key = (hashCode & 0xFFFFL) | (count << 32);
 190  270 return Long.toHexString(key);
 191    }
 192   
 193   
 194  3 private Object attach(Object key, Object pojo)
 195    {
 196  3 return attach(key, pojo, false);
 197    }
 198   
 199  155 private Object attach(Object key, Object pojo, boolean add)
 200    {
 201  155 Fqn fqn = AopUtil.constructFqn(getFqn(), key);
 202  155 Object o = pojoCache.attach(fqn, pojo);
 203  155 if (add)
 204  152 pojoCache.getCache().put(fqn, POJOCACHE_OPERATION, "ADD");
 205   
 206  155 return o;
 207    }
 208   
 209  3 private Object detach(Object key)
 210    {
 211  3 return detach(key, false);
 212    }
 213   
 214  44 private Object detach(Object key, boolean remove)
 215    {
 216  44 Fqn fqn = AopUtil.constructFqn(getFqn(), key);
 217  44 if (remove)
 218  41 pojoCache.getCache().put(fqn, POJOCACHE_OPERATION, "REMOVE");
 219   
 220  44 return pojoCache.detach(fqn);
 221    }
 222   
 223  270 private Object getNoUnmask(Object key)
 224    {
 225  270 return pojoCache.getObject(AopUtil.constructFqn(getFqn(), key));
 226    }
 227   
 228  1 public int hashCode()
 229    {
 230  1 int result = super.hashCode();
 231  1 result = 29 * result + cache.hashCode();
 232  1 result = 29 * result + interceptor.hashCode();
 233  1 return result;
 234    }
 235   
 236  6 public boolean equals(Object o)
 237    {
 238  6 if (o == this)
 239    {
 240  0 return true;
 241    }
 242   
 243  6 try
 244    {
 245  6 return super.equals(o);
 246    }
 247    catch (ClassCastException e)
 248    {
 249  0 return false;
 250    }
 251    catch (NullPointerException unused)
 252    {
 253  0 return false;
 254    }
 255    }
 256   
 257    private class IteratorImpl implements Iterator
 258    {
 259    private Iterator<NodeSPI> iterator;
 260   
 261    private Node node;
 262    private Object o;
 263   
 264  41 private IteratorImpl(Node node)
 265    {
 266  41 Collection<NodeSPI> children = new HashSet<NodeSPI>(((NodeSPI) node).getChildrenDirect());
 267  41 iterator = children.iterator();
 268    }
 269   
 270  111 public boolean hasNext()
 271    {
 272  111 return iterator.hasNext();
 273    }
 274   
 275  92 public Object next()
 276    {
 277  92 node = iterator.next();
 278  91 o = Null.toNullValue(pojoCache.getObject(node.getFqn()));
 279  91 return o;
 280    }
 281   
 282  29 public void remove() throws IllegalStateException
 283    {
 284  29 if (node == null)
 285    {
 286  1 throw new IllegalStateException();
 287    }
 288  28 CachedSetImpl.this.remove(o);
 289    }
 290   
 291    }
 292    }