KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jac > wrappers > CacheWrapper


1 /*
2   Copyright (C) 2001 Renaud Pawlak <renaud@aopsys.com>
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU Lesser General Public License as
6   published by the Free Software Foundation; either version 2 of the
7   License, or (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12   GNU Lesser General Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public License
15   along with this program; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */

17
18 package org.objectweb.jac.wrappers;
19
20 import org.aopalliance.intercept.ConstructorInvocation;
21 import org.aopalliance.intercept.MethodInvocation;
22 import org.objectweb.jac.core.AspectComponent;
23 import org.objectweb.jac.core.Interaction;
24 import org.objectweb.jac.core.Wrapper;
25
26 import java.util.Vector JavaDoc;
27
28 /**
29  * <code>CacheWrapper</code> implements a wrapper that caches the wrappee
30  * methods results so that it can avoid the wrappee computations. It
31  * can improve performances of complex computations.
32  *
33  * <p>Please make sure to use the rigth wrapping method.
34  *
35  * <p>For example, if you have a <code>Matrix</code> class:
36  *
37  * <ul><pre>
38  * public class Matrix {
39  * invert();
40  * ...
41  * }
42  * </pre></ul>
43  *
44  * <p>An instance of <code>Matrix</code> must be wrapped with
45  * <code>stateCache</code> since the result depends on the matrix
46  * state:
47  *
48  * <ul><pre>
49  * CacheWrapper cw = new CacheWrapper();
50  * a_matrix.wrap(cw, "stateCache", "invert");
51  * </pre></ul>
52  *
53  * <p>However, when the state of the matrix is modified, the cache
54  * should be cleared since its values are not valid anymore. This can
55  * be done by using the wrapping method <code>clearCache</code>.
56  *
57  * <ul><pre>
58  * a_matrix.wrap(cw, "clearCache", new String[] { "set", "mul", "div", "add" } );
59  * </pre></ul>
60  */

61
62 public class CacheWrapper extends Wrapper {
63
64    /** Store the keys for the cache. */
65    protected Vector JavaDoc cacheKeys = new Vector JavaDoc();
66    /** Store the cached values. */
67    protected Vector JavaDoc cacheValues = new Vector JavaDoc();
68
69    public CacheWrapper (AspectComponent ac) {
70       super(ac);
71    }
72    
73    /**
74     * This wrapping method seeks in the cache wether the couple
75     * (method, args) has already been called on the wrappee
76     * object. If yes, it returns the value from the cache. Otherwise
77     * it calls the wrappee object and memorizes the result in the
78     * cache.
79     *
80     * <p>This wrapper can be used on objects that have complex, but
81     * state independant computation to perform. For instance,
82     * <code>cache</code> could wrap a computational object that would
83     * be able to invert a matrix so that the inversion of a given
84     * matrix would be done only once.
85     *
86     * <p>NOTE: if the wrappee function depends on the the object
87     * state the values returned by the <code>statelessCache</code>
88     * will be wrong. In this case, use the <cache>stateCache</cache>
89     * wrapping method.
90     *
91     * @see CacheWrapper#stateCache(Interaction)
92     */

93     
94    public Object JavaDoc statelessCache(Interaction interaction) {
95       Object JavaDoc[] key = new Object JavaDoc[] { interaction.method, interaction.args };
96       int i;
97       if((i = isCacheHit(key)) != -1) {
98          return getCacheValue(i);
99       }
100       Object JavaDoc ret;
101       setCacheValue(key, ret = proceed(interaction));
102       return ret;
103    }
104
105    /**
106     * This wrapping method seeks in the cache wether the triple
107     * (wrappe, method, args) has already been called on the wrappee
108     * object when wrappee was in the same state. If yes, it returns
109     * the value from the cache. Otherwise it calls the wrappee object
110     * and memorizes the result in the cache.
111     *
112     * <p>This wrapper can be used on objects that have complex state
113     * dependant computation to perform. For instance,
114     * <code>cache</code> could wrap the invert method of a matrix
115     * object. If you invert this matrix three times, then the third
116     * inversion result will be found in the cache.
117     *
118     * <p>NOTE: if the wrappee method computation does not depend on
119     * the wrappee state, then you should use the
120     * <code>statelessCache</code> method for better performance and
121     * hits rate.
122     *
123     * @see CacheWrapper#statelessCache(Interaction)
124     */

125     
126    public Object JavaDoc stateCache(Interaction interaction) {
127       System.out.println("-> Testing the cache...");
128       Object JavaDoc[] key = new Object JavaDoc[] { interaction.method, interaction.args,
129                                     interaction.wrappee };
130       int i;
131       if((i = isCacheHit(key)) != -1) {
132          System.out.println("-> Cache hit!");
133          return getCacheValue(i);
134       }
135       System.out.println("-> Cache miss.");
136       Object JavaDoc ret;
137       setCacheValue(key, ret = proceed(interaction));
138       return ret;
139    }
140
141    /**
142     * Clear the cache.
143     *
144     * <p>This method should wrap all the methods that change the state
145     * of the wrappee in a case of a state cache.
146     *
147     * @return the value returned by the wrapped method
148     */

149
150    public Object JavaDoc clearCache(Interaction interaction) {
151       cacheKeys.clear();
152       cacheValues.clear();
153       return proceed(interaction);
154    }
155
156    /**
157     * Add a (method, args) key and its value into the cache.
158     *
159     * @param key the key to find the value in the cache
160     * @param value the cached value
161     *
162     * @see CacheWrapper#getCacheValue(Object[])
163     */

164    
165    protected void setCacheValue(Object JavaDoc[] key, Object JavaDoc value) {
166       cacheKeys.add(key);
167       cacheValues.add(value);
168    }
169
170    /**
171     * Get the memorized value of the method when called with the
172     * given (method, args) key.
173     *
174     * @param key the key
175     * @return the cached value that matches the key
176     *
177     * @see CacheWrapper#setCacheValue(Object[],Object)
178     */

179    protected Object JavaDoc getCacheValue(Object JavaDoc[] key) {
180       return getCacheValue(isCacheHit(key));
181    }
182
183    /**
184     * Get a cached value.
185     *
186     * @param index the index in the cache
187     * @return the cached value
188     */

189
190    protected Object JavaDoc getCacheValue(int index) {
191       if (index == -1) return null;
192       return cacheValues.get(index);
193    }
194
195    /**
196     * Returns the index of a key in the cache, -1 if not found.
197     *
198     * @param key a complex key
199     * @return the location of the key
200     */

201
202    protected int isCacheHit(Object JavaDoc[] key) {
203       for (int i = 0; i < cacheKeys.size(); i ++) {
204          boolean same = true;
205          Object JavaDoc[] cur_key = (Object JavaDoc[])cacheKeys.get(i);
206          if (cur_key.length != key.length) {
207             System.out.println("A");
208             same = false;
209             break;
210          }
211          if(!cur_key[0].equals(key[0])) {
212             System.out.println("B");
213             same = false;
214             break;
215          }
216          if (((Object JavaDoc[])cur_key[1]).length != ((Object JavaDoc[])key[1]).length) {
217             System.out.println("C");
218             same = false;
219             break;
220          }
221          for (int j = 0; j < ((Object JavaDoc[])cur_key[1]).length; j++) {
222             if(!((Object JavaDoc[])cur_key[1])[j].equals(((Object JavaDoc[])key[1])[j])) {
223                System.out.println("D" + ((Object JavaDoc[])cur_key[1])[j] + ((Object JavaDoc[])key[1])[j]);
224                same = false;
225                break;
226             }
227          }
228          if (key.length == 3) {
229             if(cur_key[2] != key[2]) {
230                System.out.println("E");
231                same = false;
232                break;
233             }
234          }
235          if (same) {
236             return i;
237          }
238       }
239       return -1;
240    }
241
242 /* (non-Javadoc)
243  * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
244  */

245 public Object JavaDoc invoke(MethodInvocation invocation) throws Throwable JavaDoc {
246     // TODO Auto-generated method stub
247
return null;
248 }
249
250 /* (non-Javadoc)
251  * @see org.aopalliance.intercept.ConstructorInterceptor#construct(org.aopalliance.intercept.ConstructorInvocation)
252  */

253 public Object JavaDoc construct(ConstructorInvocation invocation) throws Throwable JavaDoc {
254     // TODO Auto-generated method stub
255
return null;
256 }
257
258 }
259
260
261
262
263
264
Popular Tags