001package com.hammurapi.common; 002 003import java.lang.ref.Reference; 004import java.lang.ref.ReferenceQueue; 005import java.lang.ref.WeakReference; 006import java.util.ArrayList; 007import java.util.Iterator; 008import java.util.LinkedList; 009import java.util.List; 010 011/** 012 * Maintains weak references to objects. Removes cleared entries in 013 * getIdentity() method. 014 * @author Pavel Vlasov 015 * 016 */ 017public class WeakIdentityManager implements IdentityManager<Object> { 018 019 private static ReferenceQueue<Object> rq = new ReferenceQueue<Object>(); 020 021 private static long[] counter = {0}; 022 023 private static class Entry extends WeakReference<Object> { 024 String identity; 025 026 Entry(Object obj) { 027 super(obj, rq); 028 identity="wim_"+Long.toString(counter[0]++, Character.MAX_RADIX); 029 } 030 } 031 032 private static List<IdentityExtractor<?>> extractors = new ArrayList<IdentityExtractor<?>>(); 033 034 static { 035 Thread reaper = new Thread("Removes cleared references") { 036 037 @Override 038 public void run() { 039 while (true) { 040 try { 041 Reference<? extends Object> removed = rq.remove(); 042 if (removed instanceof Entry) { 043 synchronized (counter) { 044 Iterator<Entry> it = entries.iterator(); 045 while (it.hasNext()) { 046 Entry entry = it.next(); 047 if (removed==entry) { 048 it.remove(); 049 break; 050 } 051 } 052 } 053 } 054 } catch (InterruptedException e) { 055 return; // Time to exit. 056 } 057 } 058 } 059 }; 060 061 reaper.setDaemon(true); 062 reaper.start(); 063 } 064 065 private static LinkedList<Entry> entries = new LinkedList<Entry>(); 066 067 @SuppressWarnings("unchecked") 068 public Object getIdentity(Object obj) { 069 if (obj==null) { 070 return null; 071 } 072 if (obj instanceof Identifiable) { 073 return ((Identifiable<Object>) obj).getIdentity(); 074 } 075 for (IdentityExtractor<?> ie: extractors) { 076 Object identity = ie.getIdentity(obj); 077 if (identity!=null) { 078 return identity; 079 } 080 } 081 synchronized (counter) { 082 Iterator<Entry> it = entries.iterator(); 083 while (it.hasNext()) { 084 Entry entry = it.next(); 085 Object eObj = entry.get(); 086 if (eObj==null) { 087 it.remove(); 088 } else if (eObj==obj) { 089 return entry.identity; 090 } 091 } 092 Entry entry = new Entry(obj); 093 entries.add(entry); 094 return entry.identity; 095 } 096 } 097 098}