KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > iiop > rmi > WorkCacheManager


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.iiop.rmi;
23
24
25 import java.lang.ref.SoftReference JavaDoc;
26
27 import java.lang.reflect.Method JavaDoc;
28 import java.lang.reflect.Constructor JavaDoc;
29 import java.lang.reflect.InvocationTargetException JavaDoc;
30
31 import java.util.Map JavaDoc;
32 import java.util.HashMap JavaDoc;
33 import java.util.WeakHashMap JavaDoc;
34
35
36 /**
37  * Instances of this class cache the most complex analyse types.
38  *
39  * The analyse types cached are:
40  * <ul>
41  * <li><code>InterfaceAnalysis</code> for interfaces.</li>
42  * <li><code>ValueAnalysis</code> for value types.</li>
43  * <li><code>ExceptionAnalysis</code> for exceptions.</li>
44  * </ul>
45  *
46  * Besides caching work already done, this caches work in progress,
47  * as we need to know about this to handle cyclic graphs of analyses.
48  * When a thread re-enters the <code>getAnalysis()</code> metohd, an
49  * unfinished analysis will be returned if the same thread is already
50  * working on this analysis.
51  *
52  * @author <a HREF="mailto:osh@sparre.dk">Ole Husgaard</a>
53  * @version $Revision: 37459 $
54  */

55 class WorkCacheManager
56 {
57    // Constants -----------------------------------------------------
58

59    // Attributes ----------------------------------------------------
60

61    // Static --------------------------------------------------------
62

63    private static final org.jboss.logging.Logger logger =
64                org.jboss.logging.Logger.getLogger(WorkCacheManager.class);
65
66    // Constructors --------------------------------------------------
67

68    /**
69     * Create a new work cache manager.
70     *
71     * @param cls The class of the analysis type we cache here.
72     */

73    WorkCacheManager(Class JavaDoc cls)
74    {
75       logger.debug("Class: " + cls.getName());
76       // Find the constructor and initializer.
77
try {
78          constructor = cls.getDeclaredConstructor(new Class JavaDoc[]{Class JavaDoc.class});
79          initializer = cls.getDeclaredMethod("doAnalyze", null);
80       } catch (NoSuchMethodException JavaDoc ex) {
81          throw new IllegalArgumentException JavaDoc("Bad Class: " + ex.toString());
82       }
83
84       workDone = new WeakHashMap JavaDoc();
85       workInProgress = new HashMap JavaDoc();
86    }
87
88
89    // Package private -----------------------------------------------
90

91    /**
92     * Returns an analysis.
93     * If the calling thread is currently doing an analysis of this
94     * class, an unfinished analysis is returned.
95     */

96    ContainerAnalysis getAnalysis(Class JavaDoc cls)
97       throws RMIIIOPViolationException
98    {
99       ContainerAnalysis ret;
100
101       synchronized (this) {
102          ret = lookupDone(cls);
103          if (ret != null)
104             return ret;
105
106          // is it work-in-progress?
107
InProgress inProgress = (InProgress)workInProgress.get(cls);
108          if (inProgress != null) {
109             if (inProgress.thread == Thread.currentThread())
110                return inProgress.analysis; // return unfinished
111

112             // Do not wait for the other thread: We may deadlock
113
// Double work is better that deadlock...
114
}
115
116          ret = createWorkInProgress(cls);
117       }
118
119       // Do the work
120
doTheWork(cls, ret);
121
122       // We did it
123
synchronized (this) {
124          workInProgress.remove(cls);
125          workDone.put(cls, new SoftReference JavaDoc(ret));
126          notifyAll();
127       }
128
129       return ret;
130    }
131
132    // Private -------------------------------------------------------
133

134    /**
135     * The analysis constructor of our analysis class.
136     * This constructor takes a single argument of type <code>Class</code>.
137     */

138    Constructor JavaDoc constructor;
139
140    /**
141     * The analysis initializer of our analysis class.
142     * This method takes no arguments, and is named doAnalyze.
143     */

144    Method JavaDoc initializer;
145
146    /**
147     * This maps the classes of completely done analyses to soft
148     * references of their analysis.
149     */

150    Map JavaDoc workDone;
151
152    /**
153     * This maps the classes of analyses in progress to their
154     * analysis.
155     */

156    Map JavaDoc workInProgress;
157
158    /**
159     * Lookup an analysis in the fully done map.
160     */

161    private ContainerAnalysis lookupDone(Class JavaDoc cls)
162    {
163       SoftReference JavaDoc ref = (SoftReference JavaDoc)workDone.get(cls);
164       if (ref == null)
165          return null;
166       ContainerAnalysis ret = (ContainerAnalysis)ref.get();
167       if (ret == null)
168          workDone.remove(cls); // clear map entry if soft ref. was cleared.
169
return ret;
170    }
171
172    /**
173     * Create new work-in-progress.
174     */

175    private ContainerAnalysis createWorkInProgress(Class JavaDoc cls)
176    {
177       ContainerAnalysis analysis;
178       try {
179          analysis = (ContainerAnalysis)constructor.newInstance(new Object JavaDoc[]{cls});
180       } catch (InstantiationException JavaDoc ex) {
181          throw new RuntimeException JavaDoc(ex.toString());
182       } catch (IllegalAccessException JavaDoc ex) {
183          throw new RuntimeException JavaDoc(ex.toString());
184       } catch (InvocationTargetException JavaDoc ex) {
185          throw new RuntimeException JavaDoc(ex.toString());
186       }
187
188       workInProgress.put(cls, new InProgress(analysis, Thread.currentThread()));
189
190       return analysis;
191    }
192
193    private void doTheWork(Class JavaDoc cls, ContainerAnalysis ret)
194       throws RMIIIOPViolationException
195    {
196       try {
197          initializer.invoke(ret, new Object JavaDoc[]{});
198       } catch (Throwable JavaDoc t) {
199          synchronized (this) {
200             workInProgress.remove(cls);
201          }
202          if (t instanceof InvocationTargetException JavaDoc) // unwrap
203
t = ((InvocationTargetException JavaDoc)t).getTargetException();
204
205          if (t instanceof RMIIIOPViolationException)
206             throw (RMIIIOPViolationException)t;
207          if (t instanceof RuntimeException JavaDoc)
208             throw (RuntimeException JavaDoc)t;
209          if (t instanceof Error JavaDoc)
210             throw (Error JavaDoc)t;
211          throw new RuntimeException JavaDoc(t.toString());
212       }
213    }
214
215    /**
216     * A simple aggregate of work-in-progress, and the thread doing the work.
217     */

218    private static class InProgress
219    {
220       ContainerAnalysis analysis;
221       Thread JavaDoc thread;
222
223       InProgress(ContainerAnalysis analysis, Thread JavaDoc thread)
224       {
225          this.analysis = analysis;
226          this.thread = thread;
227       }
228    }
229 }
230
231
Popular Tags