KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > mondrian > util > AbstractMemoryMonitor


1 /*
2 // $Id: //open/mondrian/src/main/mondrian/util/AbstractMemoryMonitor.java#4 $
3 // This software is subject to the terms of the Common Public License
4 // Agreement, available at the following URL:
5 // http://www.opensource.org/licenses/cpl.html.
6 // Copyright (C) 2007-2007 Julian Hyde and others
7 // All Rights Reserved.
8 // You must accept the terms of that agreement to use this software.
9 //
10 */

11 package mondrian.util;
12
13 import mondrian.olap.MondrianProperties;
14 import org.apache.log4j.Logger;
15 import java.util.LinkedList JavaDoc;
16 import java.util.ListIterator JavaDoc;
17
18 /**
19  * Abstract implementation of <code>MemoryMonitor</code>. Base class
20  * for different memory monitoring strategies.
21  *
22  * @author <a>Richard M. Emberson</a>
23  * @since Feb 03 2007
24  * @version $Id: //open/mondrian/src/main/mondrian/util/AbstractMemoryMonitor.java#4 $
25  */

26 public abstract class AbstractMemoryMonitor
27         implements MemoryMonitor, MemoryMonitor.Test {
28
29     /**
30      * Basically, 100 percent.
31      */

32     private static final int MAX_PERCENTAGE = 100;
33
34     /**
35      * Class used to associate <code>Listener</code> and threshold.
36      */

37     static class Entry {
38         final Listener listener;
39         long threshold;
40         Entry(final Listener listener, final long threshold) {
41             this.listener = listener;
42             this.threshold = threshold;
43         }
44         public boolean equals(final Object JavaDoc other) {
45             return (other instanceof Entry) &&
46                    (listener == ((Entry) other).listener);
47         }
48         public int hashCode() {
49             return listener.hashCode();
50         }
51     }
52
53     /**
54      * <code>LinkedList</code> of <code>Entry</code> objects. A
55      * <code>LinkedList</code> was used for quick insertion and
56      * removal.
57      */

58     private final LinkedList JavaDoc<Entry> listeners;
59
60     /**
61      * The current low threshold level. This is the lowest level of any
62      * of the registered <code>Listener</code>s.
63      */

64     private long lowThreshold;
65
66     /**
67      * Constructor of this base class.
68      */

69     protected AbstractMemoryMonitor() {
70         listeners = new LinkedList JavaDoc<Entry>();
71     }
72
73     /**
74      * Returns the <code>Logger</code>.
75      *
76      * @return the <code>Logger</code>.
77      */

78     protected abstract Logger getLogger();
79
80     /**
81      * Returns the current lowest threshold of all registered
82      * <code>Listener</code>s.
83      *
84      * @return the lowest threshold.
85      */

86     protected long getLowThreshold() {
87         return lowThreshold;
88     }
89
90     /**
91      * Returns the default memory notification percentage.
92      *
93      * <p>This is the value of the Mondrian
94      * {@link MondrianProperties#MemoryMonitorThreshold} property.
95      *
96      * @return the default threshold percentage.
97      */

98     public int getDefaultThresholdPercentage() {
99         return MondrianProperties.instance().MemoryMonitorThreshold.get();
100     }
101
102     /**
103      * Adds a <code>Listener</code> using the default threshold percentage.
104      *
105      * <p>If the threshold is below the Java5 memory managment system's
106      * threshold, then the Listener is notified from within this
107      * method.
108      *
109      * @param listener the <code>Listener</code> to be added.
110      * @return <code>true</code> if the <code>Listener</code> was
111      * added and <code>false</code> otherwise.
112      */

113     public boolean addListener(final Listener listener) {
114         return addListener(listener, getDefaultThresholdPercentage());
115     }
116
117     /**
118      * Adds a <code>Listener</code> with the given threshold percentage.
119      *
120      * <p>If the threshold is below the Java5 memory managment system's
121      * threshold, then the Listener is notified from within this
122      * method.
123      *
124      * @param listener the <code>Listener</code> to be added.
125      * @param percentage the threshold percentage for this
126      * <code>Listener</code>.
127      * @return <code>true</code> if the <code>Listener</code> was
128      * added and <code>false</code> otherwise.
129      */

130     public boolean addListener(Listener listener, int percentage) {
131         getLogger().info("addListener enter");
132         try {
133 /*
134             // Should this listener being added be immediately
135             // notified that memory is short.
136             boolean notifyNow = (usagePercentage() >= percentage);
137 */

138
139             final long newThreshold = convertPercentageToThreshold(percentage);
140             Entry e = new Entry(listener, newThreshold);
141
142             synchronized (listeners) {
143                 long prevLowThreshold = generateLowThreshold();
144
145                 // Add the new listener to its proper place in the
146
// list of listeners based upon threshold value.
147
final ListIterator JavaDoc<Entry> iter = listeners.listIterator();
148                 while (iter.hasNext()) {
149                     Entry ee = iter.next();
150                     if (newThreshold <= ee.threshold) {
151                         iter.add(e);
152                         e = null;
153                         break;
154                     }
155                 }
156                 // If not null, then it has not been added yet,
157
// either its the first one or its the biggest.
158
if (e != null) {
159                     listeners.addLast(e);
160                 }
161
162                 // If the new threshold is less than the previous
163
// lowest threshold, then notify the Java5 system
164
// that we are interested in being notified for this
165
// lower value.
166
lowThreshold = generateLowThreshold();
167                 if (lowThreshold < prevLowThreshold) {
168                     notifyNewLowThreshold(lowThreshold);
169                 }
170             }
171 /*
172             if (notifyNow) {
173                 listener.memoryUsageNotification(getUsedMemory(), getMaxMemory());
174             }
175 */

176             return true;
177
178         } finally {
179             getLogger().info("addListener exit");
180         }
181     }
182
183     /**
184      * Updates the percentage threshold of a given <code>Listener</code>.
185      *
186      * <p>If the threshold is below the Java5 memory managment system's
187      * threshold, then the Listener is notified from within this
188      * method.
189      *
190      * @param listener the <code>Listener</code> being updated.
191      * @param percentage new percentage threshold.
192      */

193     public void updateListenerThreshold(Listener listener, int percentage) {
194         getLogger().info("updateListenerThreshold enter");
195         try {
196 /*
197             // Should this listener being added be immediately
198             // notified that memory is short.
199             boolean notifyNow = (usagePercentage() >= percentage);
200 */

201
202             final long newThreshold = convertPercentageToThreshold(percentage);
203
204             synchronized (listeners) {
205                 long prevLowThreshold = generateLowThreshold();
206
207                 Entry e = null;
208                 // Remove the listener from the list of listeners.
209
ListIterator JavaDoc<Entry> iter = listeners.listIterator();
210                 while (iter.hasNext()) {
211                     e = iter.next();
212                     if (e.listener == listener) {
213                         iter.remove();
214                         break;
215                     } else {
216                         e = null;
217                     }
218                 }
219                 // If 'e' is not null, then the listener was found.
220
if (e != null) {
221                     e.threshold = newThreshold;
222
223                     // Add the listener.
224
iter = listeners.listIterator();
225                     while (iter.hasNext()) {
226                         Entry ee = iter.next();
227                         if (newThreshold <= ee.threshold) {
228                             iter.add(e);
229                             break;
230                         }
231                     }
232                     lowThreshold = generateLowThreshold();
233                     if (lowThreshold != prevLowThreshold) {
234                         notifyNewLowThreshold(lowThreshold);
235                     }
236                 }
237             }
238
239 /*
240             if (notifyNow) {
241                 listener.memoryUsageNotification(getUsedMemory(), getMaxMemory());
242             }
243 */

244
245         } finally {
246             getLogger().info("updateListenerThreshold exit");
247         }
248     }
249
250     /**
251      * Removes a <code>Listener</code>.
252      *
253      * @param listener the <code>Listener</code> to be removed.
254      * @return <code>true</code> if <code>Listener</code> was remove and
255      * <code>false</code> otherwise.
256      */

257     public boolean removeListener(Listener listener) {
258         getLogger().info("removeListener enter");
259         try {
260             boolean result = false;
261             synchronized (listeners) {
262                 long prevLowThreshold = generateLowThreshold();
263
264                 final ListIterator JavaDoc<Entry> iter = listeners.listIterator();
265                 while (iter.hasNext()) {
266                     Entry ee = iter.next();
267                     if (listener == ee.listener) {
268                         iter.remove();
269                         result = true;
270                         break;
271                     }
272                 }
273
274                 // If there is a new low threshold, tell Java5
275
lowThreshold = generateLowThreshold();
276                 if (lowThreshold > prevLowThreshold) {
277                     notifyNewLowThreshold(lowThreshold);
278                 }
279
280             }
281             return result;
282         } finally {
283             getLogger().info("removeListener exit");
284         }
285     }
286
287     /**
288      * Removes a <code>Listener</code>s
289      * JVN memory notification.
290      */

291     public void removeAllListener() {
292         getLogger().info("removeAllListener enter");
293         try {
294             listeners.clear();
295             notifyNewLowThreshold(generateLowThreshold());
296         } finally {
297             getLogger().info("removeAllListener exit");
298         }
299     }
300
301     /**
302      * Returns the lowest threshold from the list of <code>Listener</code>s.
303      * If there are no <code>Listener</code>s, then return the maximum
304      * memory usage. Returns <code>Long.MAX_VALUE</code> if there
305      * are no <code>Listener</code>s
306      *
307      * @return the lowest threshold or <code>Long.MAX_VALUE</code>
308      */

309     protected long generateLowThreshold() {
310         // The Long.MAX_VALUE is used to communicate to the
311
// notifyNewLowThreshold method that it should set the value to zero.
312
return listeners.isEmpty()
313                ? Long.MAX_VALUE
314                : listeners.get(0).threshold;
315     }
316
317
318     /**
319      * Notifies all <code>Listener</code>s that memory is running short.
320      *
321      * @param usedMemory the current memory used.
322      * @param maxMemory the maximum memory.
323      */

324     protected void notifyListeners(final long usedMemory,
325                                    final long maxMemory) {
326         synchronized (listeners) {
327             for (Entry e : listeners) {
328                 if (usedMemory >= e.threshold) {
329                     e.listener.memoryUsageNotification(usedMemory,
330                                                        maxMemory);
331                 }
332             }
333         }
334     }
335
336     /**
337      * Derived classes implement this method if they wish to be notified
338      * when there is a new lowest threshold.
339      *
340      * @param newLowThreshold the new low threshold.
341      */

342     protected void notifyNewLowThreshold(final long newLowThreshold) {
343         // empty
344
}
345
346     /**
347      * Returns the maximum memory usage.
348      *
349      * @return the maximum memory usage.
350      */

351     public abstract long getMaxMemory();
352
353     /**
354      * Returns the current memory used.
355      *
356      * @return the current memory used.
357      */

358     public abstract long getUsedMemory();
359
360     /**
361      * Converts a percentage threshold to its corresponding memory value,
362      * ( percentage * maximum-memory / 100 ).
363      *
364      * @param percentage the threshold.
365      * @return the memory value.
366      */

367     protected long convertPercentageToThreshold(final int percentage) {
368         if (percentage < 0 || percentage > MAX_PERCENTAGE) {
369             throw new IllegalArgumentException JavaDoc(
370                     "Percentage not in range: " +percentage);
371         }
372
373         long maxMemory = getMaxMemory();
374         long l = (maxMemory * percentage) / MAX_PERCENTAGE;
375         return l;
376     }
377
378     /**
379      * Converts a memory value to its percentage.
380      *
381      * @param threshold the memory value.
382      * @return the percentage.
383      */

384     protected int convertThresholdToPercentage(final long threshold) {
385         long maxMemory = getMaxMemory();
386         int i = (int) ((MAX_PERCENTAGE * threshold) / maxMemory);
387         return i;
388     }
389
390     /**
391      * Returns how much memory is currently being used as a percentage.
392      *
393      * @return currently used memory as a percentage.
394      */

395     protected int usagePercentage() {
396         return convertThresholdToPercentage(getUsedMemory());
397     }
398
399     public void resetFromTest() {
400         long lowThreshold = generateLowThreshold();
401         notifyNewLowThreshold(lowThreshold);
402     }
403 }
404
405 // End AbstractMemoryMonitor.java
406
Popular Tags