KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > inject > util > AbstractReferenceCache


1 /**
2  * Copyright (C) 2006 Google 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 com.google.inject.util;
18
19 import java.io.IOException JavaDoc;
20 import java.io.ObjectInputStream JavaDoc;
21 import java.util.concurrent.ConcurrentHashMap JavaDoc;
22 import java.util.concurrent.ConcurrentMap JavaDoc;
23
24 /**
25  * Supports cache implementations.
26  *
27  * @author crazybob@google.com (Bob Lee)
28  */

29 abstract class AbstractReferenceCache<K, V> extends ReferenceMap<K, V> {
30
31   private static final long serialVersionUID = 0;
32
33   transient ConcurrentMap JavaDoc<Object JavaDoc, FutureValue<V>> futures =
34       new ConcurrentHashMap JavaDoc<Object JavaDoc, FutureValue<V>>();
35
36   AbstractReferenceCache(ReferenceType keyReferenceType,
37       ReferenceType valueReferenceType) {
38     super(keyReferenceType, valueReferenceType);
39   }
40
41   V internalCreate(K key) {
42     FutureValue<V> futureValue = new FutureValue<V>();
43
44     // use a reference so we get the correct equality semantics.
45
Object JavaDoc keyReference = referenceKey(key);
46     FutureValue<V> previous =
47         futures.putIfAbsent(keyReference, futureValue);
48     if (previous == null) {
49       // winning thread.
50
try {
51         // check one more time (a previous future could have come and gone.)
52
V value = internalGet(key);
53         if (value != null) {
54           futureValue.setValue(value);
55           return value;
56         }
57
58         try {
59           value = create(futureValue, key);
60           if (value == null) {
61             throw new NullPointerException JavaDoc(
62                 "create() returned null for: " + key);
63           }
64           futureValue.setValue(value);
65         } catch (Throwable JavaDoc t) {
66           futureValue.setThrowable(t);
67           rethrow(t);
68         }
69
70         putStrategy().execute(
71             this, keyReference, referenceValue(keyReference, value));
72
73         return value;
74       } finally {
75         futures.remove(keyReference);
76       }
77     } else {
78       if (previous.winningThread() == Thread.currentThread()) {
79         throw new RuntimeException JavaDoc("Circular reference: " + key);
80       }
81
82       // wait for winning thread.
83
return previous.get();
84     }
85   }
86
87   private static void rethrow(Throwable JavaDoc t) {
88     if (t instanceof RuntimeException JavaDoc) {
89       throw (RuntimeException JavaDoc) t;
90     }
91     if (t instanceof Error JavaDoc) {
92       throw (Error JavaDoc) t;
93     }
94     throw new RuntimeException JavaDoc(t);
95   }
96
97   /**
98    * Creates a value for the given key.
99    */

100   abstract V create(FutureValue<V> futureValue, K key);
101
102   /**
103    * {@inheritDoc}
104    *
105    * If this map does not contain an entry for the given key, this method will
106    * create a new value, put it in the map, and return it. The value
107    * is canonical (i.e. only one value will be created for each key).
108    *
109    * @throws NullPointerException if the value is {@code null}
110    * @throws java.util.concurrent.CancellationException if the value creation
111    * is cancelled.
112    */

113   @SuppressWarnings JavaDoc("unchecked")
114   @Override JavaDoc public V get(final Object JavaDoc key) {
115     V value = super.get(key);
116     return (value == null)
117         ? internalCreate((K) key)
118         : value;
119   }
120
121   private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc,
122       ClassNotFoundException JavaDoc {
123     in.defaultReadObject();
124     this.futures = new ConcurrentHashMap JavaDoc<Object JavaDoc, FutureValue<V>>();
125   }
126
127   /**
128    * Synchronizes threads waiting for the same value.
129    */

130   static class FutureValue<V> {
131
132     /** True if the result has been set. */
133     private boolean set = false;
134
135     /** The result is a value. */
136     private V value;
137
138     /** The result is a throwable. */
139     private Throwable JavaDoc t;
140
141     private final Thread JavaDoc winningThread = Thread.currentThread();
142
143     Thread JavaDoc winningThread() {
144       return winningThread;
145     }
146
147     V get() {
148       if (!set) {
149         boolean interrupted = waitUntilSet();
150
151         if (interrupted) {
152           Thread.currentThread().interrupt();
153         }
154       }
155
156       if (t != null) {
157         rethrow(t);
158       }
159       return value;
160     }
161
162     /**
163      * Waits until a value is set.
164      *
165      * @return {@code true} if the thread was interrupted while waiting
166      */

167     private synchronized boolean waitUntilSet() {
168       boolean interrupted = false;
169       while (!set) {
170         try {
171           wait();
172         } catch (InterruptedException JavaDoc e) {
173           interrupted = true;
174         }
175       }
176       return interrupted;
177     }
178
179     synchronized void setValue(V v) {
180       set();
181       value = v;
182     }
183
184     synchronized void setThrowable(Throwable JavaDoc t) {
185       set();
186       this.t = t;
187     }
188
189     private void set() {
190       if (set) {
191         throw new IllegalStateException JavaDoc("Value is already set.");
192       }
193       set = true;
194       notifyAll();
195     }
196   }
197 }
198
Popular Tags