1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package net.sf.ehcache.terracotta;
18
19 import java.lang.ref.Reference;
20 import java.lang.ref.ReferenceQueue;
21 import java.lang.ref.WeakReference;
22 import java.util.HashSet;
23 import java.util.Set;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
26
27 /***
28 * A poor man's implementation of a WeakIdentityConcurrentMap to hold the CacheManager associated ExecutorServices
29 * @param <K> The key type
30 * @param <V> The value type
31 * @author Alex Snaps
32 */
33 final class WeakIdentityConcurrentMap<K, V> {
34
35 private ConcurrentMap<WeakReference<K>, V> map = new ConcurrentHashMap<WeakReference<K>, V>();
36 private ReferenceQueue<K> queue = new ReferenceQueue<K>();
37
38 private final CleanUpTask<V> cleanUpTask;
39
40 /***
41 * Constructor
42 * @param cleanUpTask
43 */
44 WeakIdentityConcurrentMap(final CleanUpTask<V> cleanUpTask) {
45 this.cleanUpTask = cleanUpTask;
46 }
47
48 /***
49 * Puts into the underlying
50 * @param key
51 * @param value
52 * @return
53 */
54 V putIfAbsent(K key, V value) {
55 cleanUp();
56 return map.putIfAbsent(new IdentityWeakReference<K>(key, queue), value);
57 }
58
59 /***
60 * @param key
61 * @return
62 */
63 V get(K key) {
64 cleanUp();
65 return map.get(new IdentityWeakReference<K>(key));
66 }
67
68 /***
69 *
70 */
71 void cleanUp() {
72
73 Reference<? extends K> reference;
74 while ((reference = queue.poll()) != null) {
75 final V value = map.remove(reference);
76 if (value != null) {
77 cleanUpTask.cleanUp(value);
78 }
79 }
80 }
81
82 /***
83 *
84 * @return
85 */
86 Set<K> keySet() {
87 cleanUp();
88 K k;
89 final HashSet<K> ks = new HashSet<K>();
90 for (WeakReference<K> weakReference : map.keySet()) {
91 k = weakReference.get();
92 if (k != null) {
93 ks.add(k);
94 }
95 }
96 return ks;
97 }
98
99 /***
100 * @param <T>
101 */
102 private static final class IdentityWeakReference<T> extends WeakReference<T> {
103
104 private final int hashCode;
105
106 /***
107 * @param reference
108 */
109 IdentityWeakReference(T reference) {
110 this(reference, null);
111 }
112
113 /***
114 * @param reference
115 * @param referenceQueue
116 */
117 IdentityWeakReference(T reference, ReferenceQueue<T> referenceQueue) {
118 super(reference, referenceQueue);
119 this.hashCode = (reference == null) ? 0 : System.identityHashCode(reference);
120 }
121
122 /***
123 * {@inheritDoc}
124 */
125 @Override
126 public boolean equals(Object o) {
127 if (this == o) {
128 return true;
129 }
130 if (!(o instanceof IdentityWeakReference<?>)) {
131 return false;
132 } else {
133 IdentityWeakReference<?> wr = (IdentityWeakReference<?>)o;
134 Object got = get();
135 return (got != null && got == wr.get());
136 }
137 }
138
139 /***
140 * {@inheritDoc}
141 */
142 @Override
143 public int hashCode() {
144 return hashCode;
145 }
146 }
147
148 /***
149 * @param <T>
150 */
151 static interface CleanUpTask<T> {
152
153 /***
154 * @param object
155 */
156 void cleanUp(T object);
157 }
158 }