EMMA Coverage Report (generated Sun May 02 20:42:29 CEST 2010)
[all classes][hu.netmind.beankeeper.object.impl]

COVERAGE SUMMARY FOR SOURCE FILE [WeakMap.java]

nameclass, %method, %block, %line, %
WeakMap.java100% (2/2)100% (11/11)99%  (269/271)98%  (63/64)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class WeakMap100% (1/1)100% (7/7)99%  (245/247)98%  (55/56)
get (Object): Object 100% (1/1)97%  (74/76)93%  (13/14)
<static initializer> 100% (1/1)100% (4/4)100% (1/1)
WeakMap (SnapshotLogger): void 100% (1/1)100% (27/27)100% (8/8)
clear (): void 100% (1/1)100% (83/83)100% (20/20)
getListener (): WeakMapListener 100% (1/1)100% (3/3)100% (1/1)
put (Object, Object, Object): void 100% (1/1)100% (50/50)100% (10/10)
setListener (WeakMapListener): void 100% (1/1)100% (4/4)100% (2/2)
     
class WeakMap$Entry100% (1/1)100% (4/4)100% (24/24)100% (8/8)
WeakMap$Entry (WeakMap, Reference, Object, Object): void 100% (1/1)100% (15/15)100% (5/5)
getId (): Object 100% (1/1)100% (3/3)100% (1/1)
getReference (): Reference 100% (1/1)100% (3/3)100% (1/1)
getValue (): Object 100% (1/1)100% (3/3)100% (1/1)

1/**
2 * Copyright (C) 2006 NetMind Consulting Bt.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 3 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18 
19package hu.netmind.beankeeper.object.impl;
20 
21import java.util.HashMap;
22import java.util.Map;
23import java.util.Iterator;
24import java.lang.ref.ReferenceQueue;
25import java.lang.ref.Reference;
26import java.lang.ref.WeakReference;
27import java.util.List;
28import java.util.ArrayList;
29import org.apache.log4j.Logger;
30import hu.netmind.beankeeper.logging.SnapshotLogger;
31 
32/**
33 * This is exactly like weak hashmap, but this implementation disregards
34 * the object's <code>equals()</code> and <code>hashCode()</code> methods,
35 * and uses object equality for testing. This means it will only return
36 * an entry, if the object given as key exactly matches the key in the map.
37 * This is not so trivial, since the <code>hashCode()</code> need not to be 
38 * unique between objects, and we can't refer to the object directly
39 * either, because then this wouldn't be a weak map.<br>
40 * <i>Note</i>: Ok, this is not an implementation of Map, if you wish
41 * you can write the necessary methods.
42 * @author Brautigam Robert
43 * @version Revision: $Revision$
44 */
45public class WeakMap
46{
47   private static Logger logger = Logger.getLogger(WeakMap.class);
48   
49   private Map objectMap;
50   private Map referenceMap;
51   private ReferenceQueue queue;
52   private WeakMapListener listener = null;
53   private SnapshotLogger snapshotLogger = null;
54 
55   public WeakMap(SnapshotLogger snapshotLogger)
56   {
57      this.snapshotLogger=snapshotLogger;
58      objectMap = new HashMap();
59      referenceMap = new HashMap();
60      queue = new ReferenceQueue();
61   }
62 
63   public void setListener(WeakMapListener listener)
64   {
65      this.listener=listener;
66   }
67   public WeakMapListener getListener()
68   {
69      return listener;
70   }
71   
72   /**
73    * Put an object with a key to the map.
74    * @param key The object which will be referred weakly, may not be null.
75    * @param value The value to the key.
76    * @param id Some identifier which does not refer to the key.
77    */
78   public void put(Object key, Object value, Object id)
79   {
80      Integer hashCode = new Integer(System.identityHashCode(key));
81      // Clear some entries
82      clear();
83      // Make entries
84      WeakReference ref = new WeakReference(key,queue);
85      List entries = (List) objectMap.get(hashCode);
86      if ( entries == null )
87      {
88         entries = new ArrayList();
89         objectMap.put(hashCode,entries);
90      }
91      entries.add(new Entry(ref,value,id));
92      referenceMap.put(ref,hashCode);
93   }
94 
95   /**
96    * Clear obsolete entries.
97    */
98   private void clear()
99   {
100      // Clear obsolate entries
101      Reference ref = null;
102      while ( (ref=queue.poll()) != null )
103      {
104         // Clear that ref's entries
105         Integer hashCode = (Integer) referenceMap.remove(ref);
106         List entries = (List) objectMap.get(hashCode);
107         if ( entries != null )
108         {
109            // We need to find the entry and clear it
110            Iterator iterator = entries.iterator();
111            boolean deleted = false;
112            while ( (iterator.hasNext()) && (!deleted) )
113            {
114               Entry entry = (Entry) iterator.next();
115               if ( entry.getReference() == ref )
116               {
117                  iterator.remove();
118                  deleted=true;
119                  // Notify
120                  if ( getListener() != null )
121                     getListener().notifyValueLeave(entry.getId());
122               }
123            }
124         }
125         if ( entries.size() == 0 )
126            objectMap.remove(hashCode);
127      }
128      // Profile
129      snapshotLogger.log("weakmap","Current map sizes: "+objectMap.size()+","+referenceMap.size());
130   }
131 
132   /**
133    * Get a value for the given key.
134    * @param key The key object.
135    * @return The value for exatcly the given object instance.
136    */
137   public Object get(Object key)
138   {
139      if ( key == null )
140         return null;
141      // Clear some entries
142      clear();
143      // After all entries are cleared it is still possible that now the gc
144      // run and objects possibly became gc'd. This is not a problem,
145      // since we're going to use '==' operator. == never lies.
146      Integer hashCode = new Integer(System.identityHashCode(key));
147      List entries = (List) objectMap.get(hashCode);
148      if ( entries == null )
149      {
150         logger.debug("weak map did not find object of hashcode: "+hashCode+". Number of codes in map: "+objectMap.size());
151         return null;
152      }
153      for ( int i=0; i<entries.size(); i++ )
154      {
155         Entry entry = (Entry) entries.get(i);
156         // This is the thing that's making sure the key fits.
157         // We get the referenced object and see if it is ==. Note,
158         // that the referenced object may be gc'd by this time, it does not
159         // matter, it will be null, our key is not.
160         if ( entry.getReference().get() == key )
161            return entry.getValue();
162      }
163      logger.debug("weak map did not find object with equality, altough there were "+entries.size()+" objects of same identity hash code: "+hashCode);
164      return null;
165   }
166 
167   public class Entry
168   {
169      private Reference ref;
170      private Object value;
171      private Object id;
172      
173      public Entry(Reference ref, Object value, Object id)
174      {
175         this.ref=ref;
176         this.value=value;
177         this.id=id;
178      }
179      public Reference getReference()
180      {
181         return ref;
182      }
183      public Object getValue()
184      {
185         return value;
186      }
187      public Object getId()
188      {
189         return id;
190      }
191   }
192}
193 
194 

[all classes][hu.netmind.beankeeper.object.impl]
EMMA 2.0.5312debian (C) Vladimir Roubtsov