Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 360   Methods: 21
NCLOC: 212   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
CachedType.java 78.6% 70.6% 57.1% 70.1%
coverage coverage
 1    package org.jboss.cache.pojo.impl;
 2   
 3    import org.jboss.aop.Advisor;
 4    import org.jboss.aop.joinpoint.FieldInvocation;
 5    import org.jboss.cache.pojo.interceptors.PojoBeginInterceptor;
 6    import org.jboss.cache.pojo.memory.FieldPersistentReference;
 7    import org.jboss.cache.pojo.memory.PersistentReference;
 8   
 9    import java.lang.ref.WeakReference;
 10    import java.lang.reflect.Field;
 11    import java.lang.reflect.Method;
 12    import java.lang.reflect.Modifier;
 13    import java.util.ArrayList;
 14    import java.util.Arrays;
 15    import java.util.HashMap;
 16    import java.util.HashSet;
 17    import java.util.Iterator;
 18    import java.util.List;
 19    import java.util.Map;
 20    import java.util.Set;
 21    import java.util.WeakHashMap;
 22   
 23    /**
 24    * Represent a cached object type, e.g., whether it is <b>primitive</b> or not.
 25    * Note: need to pay special attention not to leak classloader.
 26    *
 27    * @author <a href="mailto:harald@gliebe.de">Harald Gliebe</a>
 28    * @author Ben Wang
 29    */
 30   
 31    public class CachedType
 32    {
 33    // Types that are considered "primitive".
 34    private static final Set immediates =
 35    new HashSet(Arrays.asList(new Object[]{
 36    String.class,
 37    Boolean.class,
 38    Double.class,
 39    Float.class,
 40    Integer.class,
 41    Long.class,
 42    Short.class,
 43    Character.class,
 44    Byte.class,
 45    Boolean.TYPE,
 46    Double.TYPE,
 47    Float.TYPE,
 48    Integer.TYPE,
 49    Long.TYPE,
 50    Short.TYPE,
 51    Character.TYPE,
 52    Byte.TYPE,
 53    Class.class}));
 54   
 55    private WeakReference<Class> type;
 56    private boolean immutable;
 57    private boolean immediate;
 58    // This map caches the class that contains no annotation.
 59    private static Map CachedClassWithNoAnnotation_ = new WeakHashMap();
 60    private static Map CachedClassWithAnnotation_ = new WeakHashMap();
 61   
 62    // Java fields . Will use special FieldPersistentReference to prevent classloader leakage.
 63    private List fields = new ArrayList();
 64    private Map fieldMap = new HashMap();// Name -> CachedAttribute
 65   
 66  0 public CachedType()
 67    {
 68    }
 69   
 70  2012 public CachedType(Class type)
 71    {
 72  2012 this.type = new WeakReference<Class>(type);
 73  2012 analyze();
 74    }
 75   
 76  15596 public Class getType()
 77    {
 78  15596 return type.get();
 79    }
 80   
 81    // determines if the object should be stored in the Nodes map or as a subnode
 82  24807 public boolean isImmediate()
 83    {
 84  24807 return immediate;
 85    }
 86   
 87  2012 private static boolean isImmediate(Class clazz)
 88    {
 89  2012 return immediates.contains(clazz);
 90    }
 91   
 92  0 public boolean isImmutable()
 93    {
 94  0 return immutable;
 95    }
 96   
 97  4266 public List getFields()
 98    {
 99  4266 return fields;
 100    }
 101   
 102  0 public Field getField(String name)
 103    {
 104  0 FieldPersistentReference ref = (FieldPersistentReference) fieldMap.get(name);
 105  0 if (ref == null) return null;
 106  0 return (Field) ref.get();
 107    }
 108   
 109    /*
 110    public List getAttributes()
 111    {
 112    return attributes;
 113    }
 114   
 115    public CachedAttribute getAttribute(Method m)
 116    {
 117    return (CachedAttribute) attributeMap.get(m);
 118    }
 119   
 120    protected void setAttributes(List attributes)
 121    {
 122    this.attributes = attributes;
 123   
 124    attributeMap.clear();
 125   
 126    // TODO: is a class with no set methods immutable ?
 127    this.immutable = true;
 128   
 129    for (Iterator i = attributes.iterator(); i.hasNext();) {
 130    CachedAttribute attribute = (CachedAttribute) i.next();
 131    if (attribute.getGet() != null) {
 132    attributeMap.put(attribute.getGet(), attribute);
 133    }
 134    if (attribute.getSet() != null) {
 135    attributeMap.put(attribute.getSet(), attribute);
 136    immutable = false;
 137    }
 138    }
 139    }
 140    */
 141   
 142  0 public String toString()
 143    {
 144  0 StringBuffer sb = new StringBuffer();
 145  0 sb.append(getType().getName()).append(" {\n");
 146    /*
 147    for (Iterator i = attributes.iterator(); i.hasNext();) {
 148    CachedAttribute attr = (CachedAttribute) i.next();
 149    sb
 150    .append("\t")
 151    .append(attr.getType().getLastElementAsString())
 152    .append(" ")
 153    .append(attr.getLastElementAsString())
 154    .append(" [")
 155    .append(attr.getGet() == null
 156    ? "<no get>"
 157    : attr.getGet().getLastElementAsString())
 158    .append(", ")
 159    .append(attr.getSet() == null
 160    ? "<no set>"
 161    : attr.getSet().getLastElementAsString())
 162    .append("]\n");
 163    }
 164    */
 165  0 sb.append("}, immutable =").append(immutable);
 166  0 return sb.toString();
 167    }
 168   
 169    /* ---------------------------------------- */
 170   
 171  2012 private void analyze()
 172    {
 173   
 174    /*
 175    // We intercept all fields now (instead of setter methods) so there is no need to
 176    // track the individual fields.
 177    HashMap attributes = new HashMap();
 178    Method[] methods = type.getMethods();
 179    for (int i = 0; i < methods.length; i++) {
 180    Method method = methods[i];
 181    if (isGet(method)) {
 182    CachedAttribute attribute =
 183    getAttribute(method, attributes, true);
 184    attribute.setGet(method);
 185    attribute.setType(method.getReturnType());
 186    } else if (isSet(method)) {
 187    CachedAttribute attribute =
 188    getAttribute(method, attributes, true);
 189    attribute.setSet(method);
 190    attribute.setType(method.getParameterTypes()[0]);
 191    }
 192    }
 193    this.setAttributes(new ArrayList(attributes.values()));
 194    */
 195  2012 analyzeFields(getType());
 196   
 197  2012 immediate = isImmediate(getType());
 198   
 199    }
 200   
 201  5761 private void analyzeFields(Class clazz)
 202    {
 203  5761 if (clazz == null)
 204    {
 205  2012 return;
 206    }
 207   
 208  3749 analyzeFields(clazz.getSuperclass());
 209   
 210  3749 Field[] classFields = clazz.getDeclaredFields();
 211  3749 for (int i = 0; i < classFields.length; i++)
 212    {
 213  14519 Field f = classFields[i];
 214  10166 if (isPrimitiveNonReplicatable(f)) continue;
 215   
 216  4353 f.setAccessible(true);
 217   
 218  4353 FieldPersistentReference persistentRef = new FieldPersistentReference(f, PersistentReference.REFERENCE_SOFT);
 219   
 220  4353 fields.add(persistentRef);
 221  4353 fieldMap.put(f.getName(), persistentRef);
 222    }
 223    }
 224   
 225    /**
 226    * We check whether this class has any field annotation declaration. We assume that there is only
 227    * one such declaring class per vm and it is static.
 228    */
 229  5935 public static boolean hasAnnotation(Class clazz, Advisor advisor, CachedType type)
 230    {
 231    // It is ok that we don't synchronize it here.
 232  5935 if (CachedClassWithNoAnnotation_.get(clazz) != null)
 233    {
 234  5818 return false;
 235    }
 236  117 else if (CachedClassWithAnnotation_.get(clazz) != null)
 237    {
 238  15 return true;
 239    }
 240   
 241  102 for (Iterator i = type.getFields().iterator(); i.hasNext();)
 242    {
 243  521 Field field = (Field) (((FieldPersistentReference) i.next())).get();
 244    // check for non-replicatable types
 245  521 if (CachedType.hasFieldAnnotation(field, advisor))
 246    {
 247  1 synchronized (CachedClassWithAnnotation_)
 248    {
 249  1 CachedClassWithAnnotation_.put(clazz, clazz.getName());
 250    }
 251  1 return true;
 252    }
 253    }
 254   
 255    // This obj class doesn't have field annotation. It is ok that multiple threads
 256    // put it repeatedly actually.
 257  101 synchronized (CachedClassWithNoAnnotation_)
 258    {
 259  101 CachedClassWithNoAnnotation_.put(clazz, clazz.getName());
 260    }
 261  101 return false;
 262    }
 263   
 264  29050 public static boolean isPrimitiveNonReplicatable(Field f)
 265    {
 266  29050 int mods = f.getModifiers();
 267    /**
 268    * The following modifiers are ignored in the cache, i.e., they will not be stored in the cache.
 269    * Whenever, user trying to access these fields, it will be accessed from the in-memory version.
 270    */
 271  29050 if (Modifier.isStatic(mods)
 272    || Modifier.isTransient(mods))
 273    {
 274  10190 return true;
 275    }
 276   
 277  18860 if (!PojoBeginInterceptor.getReplicateFinalField() && Modifier.isFinal(mods))
 278    {
 279  17 return true;
 280    }
 281   
 282  18843 return false;
 283    }
 284   
 285   
 286    /**
 287    * Check if we have @Transient annotation.
 288    *
 289    * @param invocation
 290    * @return true if @Transient is present.
 291    */
 292  0 private static boolean hasTransientAnnotation(FieldInvocation invocation)
 293    {
 294  0 Object obj = invocation.resolveAnnotation(org.jboss.cache.pojo.annotation.Transient.class);
 295  0 if (obj != null)
 296    {
 297  0 return true;
 298    }
 299  0 return false;
 300    }
 301   
 302  521 private static boolean hasFieldAnnotation(Field field, Advisor advisor)
 303    {
 304  521 return hasTransientAnnotation(field, advisor) || hasSerializableAnnotation(field, advisor);
 305    }
 306   
 307  537 public static boolean hasTransientAnnotation(Field field, Advisor advisor)
 308    {
 309  537 Object obj = advisor.resolveAnnotation(field, org.jboss.cache.pojo.annotation.Transient.class);
 310  537 if (obj != null)
 311    {
 312  5 return true;
 313    }
 314  532 return false;
 315    }
 316   
 317  526 public static boolean hasSerializableAnnotation(Field field, Advisor advisor)
 318    {
 319  526 Object obj = advisor.resolveAnnotation(field, org.jboss.cache.pojo.annotation.Serializable.class);
 320  526 if (obj != null)
 321    {
 322  6 return true;
 323    }
 324  520 return false;
 325    }
 326   
 327  0 public static boolean hasSerializableAnnotation(FieldInvocation invocation)
 328    {
 329  0 Object obj = invocation.resolveAnnotation(org.jboss.cache.pojo.annotation.Serializable.class);
 330  0 if (obj != null)
 331    {
 332  0 return true;
 333    }
 334  0 return false;
 335    }
 336   
 337    /*
 338    * converts a get/set method to an attribute name
 339    */
 340  0 protected static String attributeName(String methodName)
 341    {
 342  0 return methodName.substring(3, 4).toLowerCase()
 343    + methodName.substring(4);
 344    }
 345   
 346  0 protected static boolean isGet(Method method)
 347    {
 348  0 return method.getName().startsWith("get")
 349    && method.getParameterTypes().length == 0
 350    && method.getReturnType() != Void.TYPE;
 351    }
 352   
 353  0 protected static boolean isSet(Method method)
 354    {
 355  0 return method.getName().startsWith("set")
 356    && method.getParameterTypes().length == 1
 357    && method.getReturnType() == Void.TYPE;
 358    }
 359   
 360    }// CachedType