001 package com.hammurapi.util;
002
003 import java.lang.ref.Reference;
004 import java.lang.ref.ReferenceQueue;
005 import java.lang.ref.WeakReference;
006 import java.util.ArrayList;
007 import java.util.Iterator;
008 import java.util.LinkedList;
009 import java.util.List;
010
011 /**
012 * Maintains weak references to objects. Removes cleared entries in
013 * getIdentity() method.
014 * @author Pavel Vlasov
015 *
016 */
017 public 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 }