KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > filesystems > StreamPool


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.filesystems;
20
21 import org.openide.util.*;
22
23 import java.io.*;
24
25 import java.util.*;
26
27
28 /**
29  * This class keeps info about streams (these streams are registered) that was
30  * not closed yet. Also for every issued stream is hold stracktrace.
31  * Sometimes there is necessary to know who didn`t close stream.
32  *
33  * @author rmatous
34  */

35 final class StreamPool extends Object JavaDoc {
36     /** Whether to keep the stack traces. By default, don't - too expensive. */
37     private static final boolean ANNOTATE_UNCLOSED_STREAMS = Boolean.getBoolean(
38             "org.openide.filesystems.annotateUnclosedStreams"
39         ); // NOI18N
40
private static Map<FileObject, StreamPool> fo2StreamPool = new WeakHashMap<FileObject, StreamPool>();
41     private static Map<FileSystem, StreamPool> fs2StreamPool = new WeakHashMap<FileSystem, StreamPool>();
42     private Set<InputStream> iStreams;
43     private Set<OutputStream> oStreams;
44
45     /** Creates new StreamPool */
46     private StreamPool() {
47     }
48
49     /**
50      * This method creates subclassed NotifyInputStream (extends InputStream).
51      * NotifyInputStream saves stacktrace in constrcuctor (creates new Exception) that
52      * is used in method annotate.
53      * This method also register this NotifyInputStream as
54      * mapping (AbstractFolder, NotifyInputStream) and
55      * mapping (AbstractFolder.getFileSystem(), NotifyInputStream).
56      * If NotifyInputStream is closed then registration is freed.
57      * For fo is also created StreamPool unless it exists yet.
58      * @param fo FileObject that issues is
59      * @return subclassed InputStream that is registered as mentioned above */

60     public static InputStream createInputStream(final AbstractFolder fo)
61     throws FileNotFoundException {
62         InputStream retVal = null;
63
64         synchronized (StreamPool.class) {
65             try {
66                 get(fo).waitForOutputStreamsClosed(2000);
67                 retVal = new NotifyInputStream(fo);
68                 get(fo).iStream().add(retVal);
69                 get(fo.getFileSystem()).iStream().add(retVal);
70             } catch (InterruptedException JavaDoc e) {
71                 ExternalUtil.exception(e);
72             }
73         }
74
75         if ((retVal != null) && (retVal instanceof NotifyInputStream)) {
76             AbstractFileSystem abstractFileSystem = ((AbstractFileSystem) fo.getFileSystem());
77             ((NotifyInputStream) retVal).setOriginal(abstractFileSystem.info.inputStream(fo.getPath()));
78         } else {
79             retVal = new InputStream() {
80                         public int read() throws IOException {
81                             FileAlreadyLockedException alreadyLockedEx = new FileAlreadyLockedException(fo.getPath());
82                             get(fo).annotate(alreadyLockedEx);
83                             throw alreadyLockedEx;
84                         }
85                     };
86         }
87
88         return retVal;
89     }
90
91     /** This method creates subclassed NotifyOutputStream (extends OutputStream).
92      * NotifyOutputStream saves stacktrace in constrcuctor (creates new Exception) that
93      * is used in method annotate.
94      * This method also register this NotifyOutputStream as
95      * mapping (AbstractFolder, NotifyOutputStream) and
96      * mapping (AbstractFolder.getFileSystem(), NotifyOutputStream).
97      * If NotifyOutputStream is closed then registration is freed.
98      * For fo is also created StreamPool unless it exists yet.
99      * @return subclassed OutputStream that is registered as mentioned above
100      * @param fireFileChanged defines if should be fired fileChanged event after close of stream
101      * @param fo FileObject that issues is
102      * */

103     public static OutputStream createOutputStream(final AbstractFolder fo, boolean fireFileChanged)
104     throws IOException {
105         OutputStream retVal = null;
106
107         synchronized (StreamPool.class) {
108             try {
109                 get(fo).waitForInputStreamsClosed(2000);
110                 get(fo).waitForOutputStreamsClosed(2000);
111
112                 retVal = new NotifyOutputStream(fo, fireFileChanged);
113                 get(fo).oStream().add(retVal);
114                 get(fo.getFileSystem()).oStream().add(retVal);
115             } catch (InterruptedException JavaDoc e) {
116                 ExternalUtil.exception(e);
117             }
118         }
119
120         if ((retVal != null) && (retVal instanceof NotifyOutputStream)) {
121             AbstractFileSystem abstractFileSystem = ((AbstractFileSystem) fo.getFileSystem());
122             ((NotifyOutputStream) retVal).setOriginal(abstractFileSystem.info.outputStream(fo.getPath()));
123         } else {
124             retVal = new OutputStream() {
125                         public void write(int b) throws IOException {
126                             FileAlreadyLockedException alreadyLockedEx = new FileAlreadyLockedException(fo.getPath());
127                             get(fo).annotate(alreadyLockedEx);
128                             throw alreadyLockedEx;
129                         }
130                     };
131         }
132
133         return retVal;
134     }
135
136     /**
137      * This method finds StreamPool assiciated with fo or null. This StreamPool is
138      * created by means of createInputStream or createOutputStream.
139      * @param fo FileObject whose StreamPool is looked for
140      * @return StreamPool or null*/

141     public static synchronized StreamPool find(FileObject fo) {
142         return fo2StreamPool.get(fo);
143     }
144
145     /**
146      * This method finds StreamPool assiciated with fs or null. This StreamPool is
147      * created by means of createInputStream or createOutputStream.
148      * @param fs FileSystem whose StreamPool is looked for
149      * @return StreamPool or null*/

150     public static synchronized StreamPool find(FileSystem fs) {
151         return fs2StreamPool.get(fs);
152     }
153
154     /**
155      * Annotates ex with all exceptions of unclosed streams.
156      * @param ex that should be annotated */

157     public void annotate(Exception JavaDoc ex) {
158         if (!ANNOTATE_UNCLOSED_STREAMS) {
159             return;
160         }
161
162         synchronized (StreamPool.class) {
163             if (iStreams != null) {
164                 Iterator itIs = iStreams.iterator();
165                 NotifyInputStream nis;
166
167                 while (itIs.hasNext()) {
168                     nis = (NotifyInputStream) itIs.next();
169
170                     Exception JavaDoc annotation = nis.getException();
171
172                     if (annotation != null) {
173                         ExternalUtil.annotate(ex, annotation);
174                     }
175                 }
176             }
177
178             if (oStreams != null) {
179                 Iterator itOs = oStreams.iterator();
180                 NotifyOutputStream nos;
181
182                 while (itOs.hasNext()) {
183                     nos = (NotifyOutputStream) itOs.next();
184
185                     Exception JavaDoc annotation = nos.getException();
186
187                     if (annotation != null) {
188                         ExternalUtil.annotate(ex, annotation);
189                     }
190                 }
191             }
192         }
193     }
194
195     /**
196      * @return true if there is any InputStream that was not closed yet */

197     public boolean isInputStreamOpen() {
198         return (iStreams != null) && !iStreams.isEmpty();
199     }
200
201     private void waitForInputStreamsClosed(int timeInMs)
202     throws InterruptedException JavaDoc {
203         synchronized (StreamPool.class) {
204             if (isInputStreamOpen()) {
205                 StreamPool.class.wait(timeInMs);
206
207                 if (isInputStreamOpen()) {
208                     throw new InterruptedException JavaDoc();
209                 }
210             }
211         }
212     }
213
214     private void waitForOutputStreamsClosed(int timeInMs)
215     throws InterruptedException JavaDoc {
216         synchronized (StreamPool.class) {
217             if (isOutputStreamOpen()) {
218                 StreamPool.class.wait(timeInMs);
219
220                 if (isOutputStreamOpen()) {
221                     throw new InterruptedException JavaDoc();
222                 }
223             }
224         }
225     }
226
227     /**
228      * @return true if there is any OutputStream that was not closed yet */

229     public boolean isOutputStreamOpen() {
230         return (oStreams != null) && !oStreams.isEmpty();
231     }
232
233     /** All next methods are private (Not visible outside this class)*/
234     private static StreamPool get(FileObject fo) {
235         StreamPool strPool = fo2StreamPool.get(fo);
236
237         if (strPool == null) {
238             fo2StreamPool.put(fo, strPool = new StreamPool());
239         }
240
241         return strPool;
242     }
243
244     private static StreamPool get(FileSystem fs) {
245         StreamPool strPool = fs2StreamPool.get(fs);
246
247         if (strPool == null) {
248             fs2StreamPool.put(fs, strPool = new StreamPool());
249         }
250
251         return strPool;
252     }
253
254     private Set<InputStream> iStream() {
255         if (iStreams == null) {
256             iStreams = new WeakSet<InputStream>();
257         }
258
259         return iStreams;
260     }
261
262     private Set<OutputStream> oStream() {
263         if (oStreams == null) {
264             oStreams = new WeakSet<OutputStream>();
265         }
266
267         return oStreams;
268     }
269
270     /** fireFileChange defines if should be fired fileChanged event after close of stream*/
271     private static void closeOutputStream(AbstractFolder fo, OutputStream os, boolean fireFileChanged) {
272         StreamPool foPool = find(fo);
273         StreamPool fsPool = find(fo.getFileSystem());
274         Set foSet = (foPool != null) ? foPool.oStreams : null;
275         Set fsSet = (fsPool != null) ? fsPool.oStreams : null;
276
277         removeStreams(fsSet, foSet, os);
278         removeStreamPools(fsPool, foPool, fo);
279         fo.outputStreamClosed(fireFileChanged);
280     }
281
282     private static void closeInputStream(AbstractFolder fo, InputStream is) {
283         StreamPool foPool = find(fo);
284         StreamPool fsPool = find(fo.getFileSystem());
285         Set foSet = (foPool != null) ? foPool.iStreams : null;
286         Set fsSet = (fsPool != null) ? fsPool.iStreams : null;
287
288         removeStreams(fsSet, foSet, is);
289         removeStreamPools(fsPool, foPool, fo);
290     }
291
292     private static synchronized void removeStreams(Set fsSet, Set foSet, Object JavaDoc stream) {
293         if (foSet != null) {
294             foSet.remove(stream);
295         }
296
297         if (fsSet != null) {
298             fsSet.remove(stream);
299         }
300     }
301
302     private static synchronized void removeStreamPools(StreamPool fsPool, StreamPool foPool, AbstractFolder fo) {
303         boolean isIStreamEmpty = ((foPool == null) || (foPool.iStreams == null) || foPool.iStreams.isEmpty());
304         boolean isOStreamEmpty = ((foPool == null) || (foPool.oStreams == null) || foPool.oStreams.isEmpty());
305
306         if (isIStreamEmpty && isOStreamEmpty) {
307             fo2StreamPool.remove(fo);
308         }
309
310         isIStreamEmpty = ((fsPool == null) || (fsPool.iStreams == null) || fsPool.iStreams.isEmpty());
311         isOStreamEmpty = ((fsPool == null) || (fsPool.oStreams == null) || fsPool.oStreams.isEmpty());
312
313         if (isIStreamEmpty && isOStreamEmpty) {
314             fs2StreamPool.remove(fo.getFileSystem());
315         }
316     }
317
318     private static final class NotifyOutputStream extends FilterOutputStream {
319         private static final OutputStream emptyOs = new ByteArrayOutputStream();
320         private Exception JavaDoc ex;
321         private boolean closed = false;
322         AbstractFolder fo;
323
324         /** defines if should be fired fileChanged event after close of stream */
325         private boolean fireFileChanged;
326
327         public NotifyOutputStream(AbstractFolder fo, boolean fireFileChanged) {
328             super(emptyOs);
329             this.fo = fo;
330
331             if (ANNOTATE_UNCLOSED_STREAMS) {
332                 ex = new Exception JavaDoc();
333             }
334
335             this.fireFileChanged = fireFileChanged;
336         }
337
338         private void setOriginal(OutputStream os) {
339             out = os;
340         }
341
342         /** Faster implementation of writing than is implemented in
343          * the filter output stream.
344          */

345         public void write(byte[] b, int off, int len) throws IOException {
346             out.write(b, off, len);
347         }
348
349         public void close() throws IOException {
350             if (!closed) {
351                 closed = true;
352                 ex = null;
353                 super.out.flush();
354                 super.close();
355                 closeOutputStream(fo, this, fireFileChanged);
356
357                 synchronized (StreamPool.class) {
358                     StreamPool.class.notifyAll();
359                 }
360             }
361         }
362
363         public Exception JavaDoc getException() {
364             return ex;
365         }
366     }
367
368     private static final class NotifyInputStream extends FilterInputStream {
369         private static final InputStream emptyIs = new ByteArrayInputStream(new byte[0]);
370         private Exception JavaDoc ex;
371         AbstractFolder fo;
372         private boolean closed = false;
373
374         public NotifyInputStream(AbstractFolder fo) {
375             super(emptyIs);
376             this.fo = fo;
377
378             if (ANNOTATE_UNCLOSED_STREAMS) {
379                 ex = new Exception JavaDoc();
380             }
381         }
382
383         private void setOriginal(InputStream is) {
384             in = is;
385         }
386
387         public void close() throws IOException {
388             if (!closed) {
389                 closed = true;
390                 ex = null;
391                 super.close();
392                 closeInputStream(fo, this);
393
394                 synchronized (StreamPool.class) {
395                     if (!StreamPool.get(fo).isInputStreamOpen()) {
396                         StreamPool.class.notifyAll();
397                     }
398                 }
399             }
400         }
401
402         public Exception JavaDoc getException() {
403             return ex;
404         }
405     }
406 }
407
Popular Tags