1 /*
2 * Copyright (c) 2005-2007 Creative Sphere Limited.
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 *
10 * Creative Sphere - initial API and implementation
11 *
12 */
13 package org.abstracthorizon.mercury.maildir.file;
14
15 import java.io.IOException;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.Set;
19
20 import javax.mail.internet.SharedInputStream;
21
22
23 /**
24 * Pool of shared input stream instance. Since each instance uses RandomAccessFile from
25 * java.io package it is important managing these resources.
26 *
27 * @author Daniel Sendula
28 */
29 public class SharedInputStreamPool {
30
31 /** Pool default instance */
32 protected static SharedInputStreamPool defaultInstance = new SharedInputStreamPool();
33
34 /** Set of opened <code>SharedInputStreamImpl</code>s */
35 protected Set<SharedInputStream> files = new HashSet<SharedInputStream>();
36
37 /** Maximum number of files */
38 protected int maxFiles = 200;
39
40 /** Timeout for removing not closed files */
41 protected int timeout = 1000; // one secs
42
43 /**
44 * Default constructor.
45 */
46 public SharedInputStreamPool() {
47 }
48
49 /**
50 * This method returns default instance
51 * @return default instance
52 */
53 public static SharedInputStreamPool getDefaultInstance() {
54 return defaultInstance;
55 }
56
57 /**
58 * This method creates new <code>SharedInputStreamImpl</code> instance.
59 *
60 * @param fileProvider file provider
61 * @param start start of the stream
62 * @param len end of the stream
63 * @return new <code>SharedInputStreamImpl</code> instance
64 */
65 public SharedInputStreamImpl newStream(FileProvider fileProvider, long start, long len) {
66 return new SharedInputStreamImpl(this, fileProvider, start, len);
67 }
68
69 /**
70 * This is callback method used by <code>SharedInputStreamImpl</code> to register
71 * that stream is now opened. This is called each time <code>RandomAccessFile</code>
72 * is created over the stream. It is possible for stream to be implicitly "clsoed"
73 * and (re)opened several times.
74 *
75 * @param stream stream that is opened
76 */
77 protected synchronized void opened(SharedInputStreamImpl stream) {
78 files.add(stream);
79 int size = files.size();
80 if (size > maxFiles) {
81 int removed = 0;
82 int timeout = this.timeout * (size/maxFiles) * 2;
83 Iterator<SharedInputStream> it = files.iterator();
84 long now = System.currentTimeMillis();
85 SharedInputStreamImpl oldest = stream;
86 SharedInputStreamImpl s = null;
87 while (it.hasNext()) {
88 s = (SharedInputStreamImpl)it.next();
89 if ((now - stream.lastAccessed) < timeout) {
90 try {
91 s.closeImpl();
92 } catch (IOException ignore) {
93 }
94 it.remove();
95 removed++;
96 } else if ((removed == 0) && (s.lastAccessed <= oldest.lastAccessed)) {
97 oldest = stream;
98 }
99 } // while
100 if (removed == 0) {
101 closed(oldest);
102 }
103 }
104 }
105
106 /**
107 * This is callback method used by <code>SharedInputStreamImpl</code>
108 * to register that stream is now closed.
109 * This is called each time <code>RandomAccessFile</code> used by the stream is released.
110 * It is possible for stream to be implicitly "clsoed"
111 * and (re)opened several times.
112 * @param stream stream that is closed
113 */
114 protected synchronized void closed(SharedInputStreamImpl stream) {
115 files.remove(stream);
116 }
117
118 /**
119 * Method that implicitly releases all <code>RandomAccessFile</code>s from all
120 * streams that use given <code>FileProvider</code>
121 * @param provider file provider whos <code>SharedInputStreamImpl</code> belongs to
122 */
123 public synchronized void closeWithProvider(FileProvider provider) {
124 Iterator<SharedInputStream> it = files.iterator();
125 SharedInputStreamImpl s = null;
126 while (it.hasNext()) {
127 s = (SharedInputStreamImpl)it.next();
128 if (s.fileProvider == provider) {
129 try {
130 s.closeImpl();
131 } catch (IOException ignore) {
132 }
133 it.remove();
134 }
135 } // while
136 }
137 }