Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 287   Methods: 15
NCLOC: 220   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
CacheListenerAdaptor.java 65.2% 74.4% 66.7% 70.9%
coverage coverage
 1    /*
 2    * JBoss, Home of Professional Open Source
 3    * Copyright 2005, JBoss Inc., and individual contributors as indicated
 4    * by the @authors tag. See the copyright.txt in the distribution for a
 5    * full listing of individual contributors.
 6    *
 7    * This is free software; you can redistribute it and/or modify it
 8    * under the terms of the GNU Lesser General Public License as
 9    * published by the Free Software Foundation; either version 2.1 of
 10    * the License, or (at your option) any later version.
 11    *
 12    * This software is distributed in the hope that it will be useful,
 13    * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 15    * Lesser General Public License for more details.
 16    *
 17    * You should have received a copy of the GNU Lesser General Public
 18    * License along with this software; if not, write to the Free
 19    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 20    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 21    */
 22   
 23    package org.jboss.cache.pojo.impl;
 24   
 25    import static org.jboss.cache.pojo.impl.InternalConstant.POJOCACHE_OPERATION;
 26    import static org.jboss.cache.pojo.impl.InternalConstant.POJOCACHE_STATUS;
 27    import static org.jboss.cache.notifications.event.Event.Type.TRANSACTION_COMPLETED;
 28    import static org.jboss.cache.notifications.event.Event.Type.TRANSACTION_REGISTERED;
 29   
 30    import java.lang.reflect.Field;
 31    import java.util.Collection;
 32    import java.util.HashSet;
 33    import java.util.List;
 34    import java.util.Map;
 35    import java.util.Set;
 36    import java.util.regex.Pattern;
 37   
 38    import javax.transaction.Transaction;
 39   
 40    import org.apache.commons.logging.Log;
 41    import org.apache.commons.logging.LogFactory;
 42    import org.jboss.cache.Fqn;
 43    import org.jboss.cache.notifications.annotation.CacheListener;
 44    import org.jboss.cache.notifications.annotation.NodeModified;
 45    import org.jboss.cache.notifications.annotation.TransactionCompleted;
 46    import org.jboss.cache.notifications.annotation.TransactionRegistered;
 47    import org.jboss.cache.notifications.event.NodeModifiedEvent;
 48    import org.jboss.cache.notifications.event.TransactionalEvent;
 49    import org.jboss.cache.notifications.event.NodeModifiedEvent.ModificationType;
 50    import org.jboss.cache.pojo.PojoCache;
 51    import org.jboss.cache.pojo.interceptors.PojoTxLockInterceptor;
 52    import org.jboss.cache.pojo.notification.NotificationContext;
 53    import org.jboss.cache.pojo.notification.event.AttachedEvent;
 54    import org.jboss.cache.pojo.notification.event.DetachedEvent;
 55    import org.jboss.cache.pojo.notification.event.Event;
 56    import org.jboss.cache.pojo.notification.event.FieldModifiedEvent;
 57    import org.jboss.cache.pojo.notification.event.ListModifiedEvent;
 58    import org.jboss.cache.pojo.notification.event.MapModifiedEvent;
 59    import org.jboss.cache.pojo.notification.event.SetModifiedEvent;
 60    import org.jboss.cache.pojo.notification.event.TransactionCompletedEvent;
 61    import org.jboss.cache.pojo.notification.event.TransactionRegisteredEvent;
 62   
 63    // $Id: CacheListenerAdaptor.java,v 1.8 2007/07/03 01:32:25 jgreene Exp $
 64   
 65    /**
 66    * Adapts the core cache listener API into the POJO listener API.
 67    *
 68    * @author Jason T. Greene
 69    */
 70    @CacheListener
 71    public class CacheListenerAdaptor
 72    {
 73    private static final HashSet<String> internalKeys = new HashSet<String>();
 74    private static final Log log = LogFactory.getLog(CacheListenerAdaptor.class);
 75   
 76    static
 77    {
 78  77 internalKeys.add(POJOCACHE_STATUS);
 79  77 internalKeys.add(POJOCACHE_OPERATION);
 80  77 internalKeys.add(PojoInstance.KEY);
 81  77 internalKeys.add(PojoReference.KEY);
 82  77 internalKeys.add(PojoTxLockInterceptor.LOCK_KEY);
 83    }
 84   
 85    private PojoCacheImpl cache;
 86    private NotificationDispatcher dispatcher = new NotificationDispatcher();
 87   
 88  499 public CacheListenerAdaptor(PojoCacheImpl cache)
 89    {
 90  499 this.cache = cache;
 91    }
 92   
 93  174 public PojoCache getPojoCache()
 94    {
 95  174 return this.cache;
 96    }
 97   
 98  4 private FieldModifiedEvent createModifyEvent(NotificationContext context, Fqn fqn, String key, Object value, boolean local)
 99    {
 100  4 if (value instanceof PojoReference)
 101  2 value = cache.find(((PojoReference) value).getFqn().toString());
 102   
 103  4 Object o = cache.find(fqn.toString());
 104    // Detached
 105  4 if (o == null)
 106  0 return null;
 107   
 108  4 Field f;
 109  4 try
 110    {
 111  4 f = o.getClass().getDeclaredField(key);
 112    }
 113    catch (NoSuchFieldException e)
 114    {
 115  0 if (log.isWarnEnabled())
 116  0 log.warn("Could not get field " + key + " on class " + o.getClass());
 117  0 return null;
 118    }
 119   
 120  4 return new FieldModifiedEvent(context, o, f, value, local);
 121    }
 122   
 123  272 private NotificationContext createContext(final TransactionalEvent event)
 124    {
 125  272 return new NotificationContext()
 126    {
 127   
 128  174 public PojoCache getPojoCache()
 129    {
 130  174 return CacheListenerAdaptor.this.getPojoCache();
 131    }
 132   
 133  112 public Transaction getTransaction()
 134    {
 135  112 return event.getTransaction();
 136    }
 137    };
 138    }
 139   
 140  272 private void sendNotification(Event notification, Set<NotificationDispatcher.Entry> listeners)
 141    {
 142  272 if (notification == null)
 143  0 return;
 144   
 145  272 if (listeners == null)
 146  272 dispatcher.dispatch(notification);
 147    else
 148  0 dispatcher.dispatch(notification, listeners);
 149    }
 150   
 151  98 @TransactionCompleted
 152    @TransactionRegistered
 153    public void handleTransaction(TransactionalEvent event)
 154    {
 155  98 if (event.getType() == TRANSACTION_COMPLETED)
 156    {
 157  49 boolean successful = ((org.jboss.cache.notifications.event.TransactionCompletedEvent) event).isSuccessful();
 158  49 sendNotification(new TransactionCompletedEvent(createContext(event), successful, event.isOriginLocal()), null);
 159    }
 160  49 else if (event.getType() == TRANSACTION_REGISTERED)
 161    {
 162  49 sendNotification(new TransactionRegisteredEvent(createContext(event), event.isOriginLocal()), null);
 163    }
 164    }
 165   
 166  1198 @NodeModified
 167    public void nodeModified(NodeModifiedEvent event)
 168    {
 169  1198 Map<Object, Object> data = event.getData();
 170  1198 boolean pre = event.isPre();
 171  1198 Fqn fqn = event.getFqn();
 172  1198 ModificationType modType = event.getModificationType();
 173  1198 boolean isLocal = event.isOriginLocal();
 174   
 175  1198 if (pre)
 176  600 return;
 177   
 178    //System.out.println(fqn + " " + modType + " " + data);
 179   
 180    // If we are filtering, don't load as much as possible
 181  598 Set<NotificationDispatcher.Entry> matched = null;
 182  598 if (dispatcher.hasFilters())
 183    {
 184  0 matched = matchListeners(fqn);
 185  0 if (matched != null && matched.isEmpty())
 186  0 return;
 187    }
 188   
 189  598 if (modType == ModificationType.PUT_DATA)
 190    {
 191  508 if ("ATTACHED".equals(data.get(POJOCACHE_STATUS)))
 192    {
 193  97 Object o = cache.find(fqn.toString());
 194  97 sendNotification(new AttachedEvent(createContext(event), o, isLocal), matched);
 195    }
 196  411 else if ("DETACHING".equals(data.get(POJOCACHE_STATUS)))
 197    {
 198  14 Object o = cache.find(fqn.toString());
 199  14 sendNotification(new DetachedEvent(createContext(event), o, isLocal), matched);
 200    }
 201  397 else if (data.containsKey(POJOCACHE_OPERATION))
 202    {
 203  59 Object collection = cache.find(fqn.getParent().toString());
 204  59 if (collection instanceof List)
 205    {
 206  45 int i = Integer.parseInt(fqn.getLastElementAsString());
 207  45 ListModifiedEvent.Operation operation = ListModifiedEvent.Operation.valueOf(data.get(POJOCACHE_OPERATION).toString());
 208  45 Object value = cache.find(fqn.toString());
 209  45 sendNotification(new ListModifiedEvent(createContext(event), (List) collection, operation, i, value, isLocal), matched);
 210    }
 211  14 else if (collection instanceof Set)
 212    {
 213  7 SetModifiedEvent.Operation operation = SetModifiedEvent.Operation.valueOf(data.get(POJOCACHE_OPERATION).toString());
 214  7 Object value = cache.find(fqn.toString());
 215  7 sendNotification(new SetModifiedEvent(createContext(event), (Set) collection, operation, value, isLocal), matched);
 216    }
 217  7 else if (collection instanceof Map)
 218    {
 219  7 MapModifiedEvent.Operation operation = MapModifiedEvent.Operation.valueOf(data.get(POJOCACHE_OPERATION).toString());
 220  7 Object value = cache.find(fqn.toString());
 221  7 sendNotification(new MapModifiedEvent(createContext(event), (Map) collection, operation, fqn.getLastElement(), value, isLocal), matched);
 222    }
 223    }
 224  338 else if ("ATTACHED".equals(cache.getCache().get(fqn, POJOCACHE_STATUS)))
 225    {
 226  21 for (Map.Entry entry : data.entrySet())
 227    {
 228  21 String key = entry.getKey().toString();
 229  21 Object value = entry.getValue();
 230   
 231  21 if (internalKeys.contains(key))
 232  17 continue;
 233   
 234  4 sendNotification(createModifyEvent(createContext(event), fqn, key, value, isLocal), matched);
 235    }
 236    }
 237    }
 238  90 else if (modType == ModificationType.REMOVE_DATA)
 239    {
 240  0 for (Map.Entry entry : data.entrySet())
 241    {
 242  0 String key = entry.getKey().toString();
 243  0 if (internalKeys.contains(key))
 244  0 continue;
 245   
 246  0 sendNotification(createModifyEvent(createContext(event), fqn, key, null, isLocal), matched);
 247    }
 248    }
 249    }
 250   
 251  0 private Set<NotificationDispatcher.Entry> matchListeners(Fqn fqn)
 252    {
 253  0 PojoInstance instance = (PojoInstance) cache.getCache().get(fqn, PojoInstance.KEY);
 254  0 if (instance != null)
 255  0 return dispatcher.getListenerEntries(instance.getReferences());
 256   
 257  0 return null;
 258    }
 259   
 260  0 public boolean isEmpty()
 261    {
 262  0 return dispatcher.isEmpty();
 263    }
 264   
 265  0 public Collection<Object> getListeners()
 266    {
 267  0 return dispatcher.getListeners();
 268    }
 269   
 270  0 public void addListener(Object listener)
 271    {
 272  0 dispatcher.add(listener);
 273    }
 274   
 275  50 public void addListener(Object listener, Pattern pattern)
 276    {
 277  50 if (pattern == null)
 278  50 dispatcher.add(listener);
 279    else
 280  0 dispatcher.add(listener, pattern);
 281    }
 282   
 283  0 public void removeListener(Object listener)
 284    {
 285  0 dispatcher.remove(listener);
 286    }
 287    }