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    }