1 | package com.hammurapi.common; |
2 | |
3 | import java.lang.ref.Reference; |
4 | import java.lang.ref.ReferenceQueue; |
5 | import java.lang.ref.WeakReference; |
6 | import java.util.ArrayList; |
7 | import java.util.Iterator; |
8 | import java.util.LinkedList; |
9 | import java.util.List; |
10 | |
11 | /** |
12 | * Maintains weak references to objects. Removes cleared entries in |
13 | * getIdentity() method. |
14 | * @author Pavel Vlasov |
15 | * |
16 | */ |
17 | public class WeakIdentityManager implements IdentityManager<Object> { |
18 | |
19 | private static ReferenceQueue<Object> rq = new ReferenceQueue<Object>(); |
20 | |
21 | private static long[] counter = {0}; |
22 | |
23 | private static class Entry extends WeakReference<Object> { |
24 | String identity; |
25 | |
26 | Entry(Object obj) { |
27 | super(obj, rq); |
28 | identity="wim_"+Long.toString(counter[0]++, Character.MAX_RADIX); |
29 | } |
30 | } |
31 | |
32 | private static List<IdentityExtractor<?>> extractors = new ArrayList<IdentityExtractor<?>>(); |
33 | |
34 | static { |
35 | Thread reaper = new Thread("Removes cleared references") { |
36 | |
37 | @Override |
38 | public void run() { |
39 | while (true) { |
40 | try { |
41 | Reference<? extends Object> removed = rq.remove(); |
42 | if (removed instanceof Entry) { |
43 | synchronized (counter) { |
44 | Iterator<Entry> it = entries.iterator(); |
45 | while (it.hasNext()) { |
46 | Entry entry = it.next(); |
47 | if (removed==entry) { |
48 | it.remove(); |
49 | break; |
50 | } |
51 | } |
52 | } |
53 | } |
54 | } catch (InterruptedException e) { |
55 | return; // Time to exit. |
56 | } |
57 | } |
58 | } |
59 | }; |
60 | |
61 | reaper.setDaemon(true); |
62 | reaper.start(); |
63 | } |
64 | |
65 | private static LinkedList<Entry> entries = new LinkedList<Entry>(); |
66 | |
67 | @SuppressWarnings("unchecked") |
68 | public Object getIdentity(Object obj) { |
69 | if (obj==null) { |
70 | return null; |
71 | } |
72 | if (obj instanceof Identifiable) { |
73 | return ((Identifiable<Object>) obj).getIdentity(); |
74 | } |
75 | for (IdentityExtractor<?> ie: extractors) { |
76 | Object identity = ie.getIdentity(obj); |
77 | if (identity!=null) { |
78 | return identity; |
79 | } |
80 | } |
81 | synchronized (counter) { |
82 | Iterator<Entry> it = entries.iterator(); |
83 | while (it.hasNext()) { |
84 | Entry entry = it.next(); |
85 | Object eObj = entry.get(); |
86 | if (eObj==null) { |
87 | it.remove(); |
88 | } else if (eObj==obj) { |
89 | return entry.identity; |
90 | } |
91 | } |
92 | Entry entry = new Entry(obj); |
93 | entries.add(entry); |
94 | return entry.identity; |
95 | } |
96 | } |
97 | |
98 | } |