KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > baseadaptor > bundlefile > MRUBundleFileList


1 /*******************************************************************************
2  * Copyright (c) 2005, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.osgi.baseadaptor.bundlefile;
13
14 import java.io.IOException JavaDoc;
15 import org.eclipse.osgi.framework.eventmgr.*;
16
17 /**
18  * A simple/quick/small implementation of an MRU (Most Recently Used) list to keep
19  * track of open BundleFiles. The MRU will use the file limit specified by the property
20  * "osgi.bundlefile.limit" by default unless the MRU is constructed with a specific
21  * file limit.
22  * @since 3.2
23  */

24 public class MRUBundleFileList implements EventDispatcher{
25     private static final String JavaDoc PROP_FILE_LIMIT = "osgi.bundlefile.limit"; //$NON-NLS-1$
26
private static final int MIN = 10;
27     private static final int PROP_FILE_LIMIT_VALUE;
28     static {
29         int propValue = 0;
30         try {
31             String JavaDoc prop = BundleFile.secureAction.getProperty(PROP_FILE_LIMIT);
32             if (prop != null)
33                 propValue = Integer.parseInt(prop);
34         } catch (NumberFormatException JavaDoc e) {
35             //MRU will be disabled
36
}
37         PROP_FILE_LIMIT_VALUE = propValue;
38     }
39     // list of open bundle files
40
final private BundleFile[] bundleFileList;
41     // list of open bundle files use stamps
42
final private long[] useStampList;
43     // the limit of open files to allow before least used bundle file is closed
44
final private int fileLimit; // value < MIN will disable MRU
45
final private EventManager bundleFileCloserManager;
46     final private EventListeners bundleFileCloser;
47     // the current number of open bundle files
48
private int numOpen = 0;
49     // the current use stamp
50
private long curUseStamp = 0;
51
52     public MRUBundleFileList() {
53         this(PROP_FILE_LIMIT_VALUE);
54     }
55
56     public MRUBundleFileList(int fileLimit) {
57         // only enable the MRU if the initFileLimit is > MIN
58
this.fileLimit = fileLimit;
59         if (fileLimit >= MIN) {
60             this.bundleFileList = new BundleFile[fileLimit];
61             this.useStampList = new long[fileLimit];
62             this.bundleFileCloserManager = new EventManager("Bundle File Closer"); //$NON-NLS-1$
63
this.bundleFileCloser = new EventListeners();
64             this.bundleFileCloser.addListener(this, this);
65         } else {
66             this.bundleFileList = null;
67             this.useStampList = null;
68             this.bundleFileCloserManager = null;
69             this.bundleFileCloser = null;
70         }
71     }
72
73     /**
74      * Adds a BundleFile which is about to be opened to the MRU list. If
75      * the number of open BundleFiles == the fileLimit then the least
76      * recently used BundleFile is closed.
77      * @param bundleFile the bundle file about to be opened.
78      */

79     public void add(BundleFile bundleFile) {
80         if (fileLimit < MIN)
81             return; // MRU is disabled
82
BundleFile toRemove = null;
83         synchronized (this) {
84             if (bundleFile.getMruIndex() >= 0)
85                 return; // do nothing; someone is trying add a bundleFile that is already in an MRU list
86
int index = 0; // default to the first slot
87
if (numOpen < fileLimit) {
88                 // numOpen does not exceed the fileLimit
89
// find the first null slot to use in the MRU
90
for (int i = 0; i < fileLimit; i++)
91                     if (bundleFileList[i] == null) {
92                         index = i;
93                         break;
94                     }
95             } else {
96                 // numOpen has reached the fileLimit
97
// find the least recently used bundleFile and close it
98
// and use it slot for the new bundleFile to be opened.
99
index = 0;
100                 for (int i = 1; i < fileLimit; i++)
101                     if (useStampList[i] < useStampList[index])
102                         index = i;
103                 toRemove = bundleFileList[index];
104                 if (toRemove.getMruIndex() != index)
105                     throw new IllegalStateException JavaDoc("The BundleFile has the incorrect mru index: " + index + " != " + toRemove.getMruIndex()); //$NON-NLS-1$//$NON-NLS-2$
106
removeInternal(toRemove);
107             }
108             // found an index to place to bundleFile to be opened
109
bundleFileList[index] = bundleFile;
110             bundleFile.setMruIndex(index);
111             incUseStamp(index);
112             numOpen++;
113         }
114         // must not close the toRemove bundle file while holding the lock of another bundle file (bug 161976)
115
// This queue the bundle file for close asynchronously.
116
closeBundleFile(toRemove);
117     }
118
119     /**
120      * Removes a bundle file which is about to be closed
121      * @param bundleFile the bundle file about to be closed
122      * @return true if the bundleFile existed in the MRU; false otherwise
123      */

124     public boolean remove(BundleFile bundleFile) {
125         if (fileLimit < MIN)
126             return false; // MRU is disabled
127
synchronized (this) {
128             int index = bundleFile.getMruIndex();
129             if ((index >= 0 && index < fileLimit) && bundleFileList[index] == bundleFile) {
130                 removeInternal(bundleFile);
131                 return true;
132             }
133         }
134         return false;
135     }
136
137     // must be called while synchronizing "this"
138
private void removeInternal(BundleFile bundleFile) {
139         int index = bundleFile.getMruIndex();
140         bundleFile.setMruIndex(-1);
141         bundleFileList[index] = null;
142         useStampList[index] = -1;
143         numOpen--;
144     }
145
146     /**
147      * Increments the use stamp of a bundle file
148      * @param bundleFile the bundle file to increment the use stamp for
149      */

150     public void use(BundleFile bundleFile) {
151         if (fileLimit < MIN)
152             return; // MRU is disabled
153
synchronized (this) {
154             int index = bundleFile.getMruIndex();
155             if ((index >= 0 && index < fileLimit) && bundleFileList[index] == bundleFile)
156                 incUseStamp(index);
157         }
158     }
159
160     // must be called while synchronizing "this"
161
private void incUseStamp(int index) {
162         if (curUseStamp == Long.MAX_VALUE) {
163             // we hit the curUseStamp max better reset all the stamps
164
for (int i = 0; i < fileLimit; i++)
165                 useStampList[i] = 0;
166             curUseStamp = 0;
167         }
168         useStampList[index] = ++curUseStamp;
169     }
170
171     public final void dispatchEvent(Object JavaDoc eventListener, Object JavaDoc listenerObject, int eventAction, Object JavaDoc eventObject) {
172         try {
173             ((BundleFile) eventObject).close();
174         } catch (IOException JavaDoc e) {
175             // TODO should log ??
176
}
177     }
178
179     private void closeBundleFile(BundleFile toRemove) {
180         if (toRemove == null)
181             return;
182         /* queue to hold set of listeners */
183         ListenerQueue queue = new ListenerQueue(bundleFileCloserManager);
184         /* add bundle file closer to the queue */
185         queue.queueListeners(bundleFileCloser, this);
186         /* dispatch event to set of listeners */
187         queue.dispatchEventAsynchronous(0, toRemove);
188     }
189
190     /**
191      * Closes the bundle file closer thread for the MRU list
192      */

193     public void shutdown() {
194         if (bundleFileCloserManager != null)
195             bundleFileCloserManager.close();
196     }
197 }
198
Popular Tags