1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.cache;
17
18 import java.util.StringTokenizer;
19 import java.io.ByteArrayOutputStream;
20 import java.io.ObjectOutputStream;
21 import java.io.ObjectInputStream;
22 import java.io.FileOutputStream;
23 import java.io.FileInputStream;
24 import java.io.BufferedInputStream;
25 import java.io.BufferedOutputStream;
26 import java.io.Serializable;
27 import java.io.IOException;
28 import java.io.File;
29
30
31
32
33
34
35 public class ShareableFileStash extends BaseStash implements Stash {
36 protected int _numDirectories = 10;
37 protected File _rootdir = null;
38 protected int _maxFilenameLength = 128;
39
40
41
42
43
44 public ShareableFileStash(String root, int numdirs) {
45 _rootdir = new File(root);
46 _numDirectories = numdirs;
47 }
48
49
50
51
52
53 public ShareableFileStash(File root, int numdirs) {
54 _rootdir = root;
55 _numDirectories = numdirs;
56 }
57
58
59
60
61
62
63 public ShareableFileStash(File root, int numdirs, int maxfilenamelength) {
64 _rootdir = root;
65 _numDirectories = numdirs;
66 _maxFilenameLength = maxfilenamelength;
67 }
68
69
70
71
72
73
74 public ShareableFileStash(String root, int numdirs, int maxfilenamelength) {
75 _rootdir = new File(root);
76 _numDirectories = numdirs;
77 _maxFilenameLength = maxfilenamelength;
78 }
79
80 protected byte[] getSerializedForm(Serializable val) {
81 byte[] serform = null;
82 if(null == val) {
83 return null;
84 }
85 ByteArrayOutputStream byout = null;
86 ObjectOutputStream out = null;
87 try {
88 byout = new ByteArrayOutputStream();
89 out = new ObjectOutputStream(byout);
90 out.writeObject(val);
91 out.flush();
92 serform = byout.toByteArray();
93 } catch(IOException e) {
94 serform = null;
95 } finally {
96 try {
97 byout.close();
98 } catch(Exception e) {
99 }
100 try {
101 out.close();
102 } catch(Exception e) {
103 }
104 }
105 return serform;
106 }
107
108 protected synchronized Serializable readFromFile(File file) {
109 ObjectInputStream oin = null;
110 try {
111 oin = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)));
112 return(Serializable)(oin.readObject());
113 } catch(Exception e) {
114 return null;
115 } finally {
116 try {
117 oin.close();
118 } catch(Exception e) {
119 }
120 }
121 }
122
123 protected File getFile(Serializable key, boolean mkdirs) {
124 String keystr = key.toString();
125 char[] chars = keystr.toCharArray();
126 StringBuffer buf = new StringBuffer();
127 File parent = new File(_rootdir,String.valueOf(Math.abs(keystr.hashCode()%_numDirectories)));
128 for(int i=0;i<chars.length;i++) {
129 if((chars[i] >= 'a' && chars[i] <= 'z') ||
130 (chars[i] >= 'A' && chars[i] <= 'Z') ||
131 (chars[i] >= '0' && chars[i] <= '9')) {
132 if(buf.length() >= _maxFilenameLength) {
133 buf.append("_");
134 parent = new File(parent,buf.toString());
135 buf.setLength(0);
136 }
137 buf.append(chars[i]);
138 } else {
139 if(buf.length() + 5 >= _maxFilenameLength) {
140 buf.append("_");
141 parent = new File(parent,buf.toString());
142 buf.setLength(0);
143 }
144 buf.append("_");
145 buf.append(Integer.toHexString((int)chars[i]));
146 }
147 }
148 if(buf.length() == 0) {
149 buf.append("_");
150 }
151 if(mkdirs) {
152 parent.mkdirs();
153 }
154 return new File(parent,buf.toString());
155 }
156
157 public int canStore(Serializable key, Serializable val, Long expiresAt, Long cost, Serializable group, byte[] serialized) {
158 if(null == serialized) {
159 serialized = getSerializedForm(val);
160 }
161 if(null == serialized) {
162 return Stash.NO;
163 } else {
164 return Stash.YES;
165 }
166 }
167
168 public boolean store(Serializable key, Serializable val, Long expiresAt, Long cost, Serializable group, byte[] serialized) {
169 if(null == serialized) {
170 serialized = getSerializedForm(val);
171 }
172 if(null == serialized) {
173 return false;
174 }
175
176 File cachefile = getFile(key,true);
177 if(null == cachefile) {
178 return false;
179 }
180
181 BufferedOutputStream fout = null;
182 try {
183 fout = new BufferedOutputStream(new FileOutputStream(cachefile));
184 fout.write(serialized);
185 fout.flush();
186 } catch(Exception e) {
187 try {
188 fout.close();
189 } catch(Exception ex) {
190 }
191 fout = null;
192 try {
193 cachefile.delete();
194 } catch(Exception ex) {
195 }
196 return false;
197 } finally {
198 try {
199 fout.close();
200 } catch(Exception e) {
201 }
202 }
203 return true;
204 }
205
206 public Serializable retrieve(Serializable key) {
207 File cachefile = getFile(key,false);
208 if(cachefile.exists()) {
209 return readFromFile(cachefile);
210 } else {
211 return null;
212 }
213 }
214
215 public boolean contains(Serializable key) {
216 File cachefile = getFile(key,false);
217 return cachefile.exists();
218 }
219
220 public float capacity() {
221 return 0;
222 }
223
224 public void clear(Serializable key) {
225 File cachefile = getFile(key,false);
226 cachefile.delete();
227 }
228
229 public synchronized void clear() {
230 File f = getMoveToLoc();
231 try {
232 f.getParentFile().mkdirs();
233 } catch(NullPointerException e) {
234
235 }
236 _rootdir.renameTo(f);
237 _rootdir.mkdirs();
238 Thread t = new Thread(new RecursiveFileDeleter(f));
239 t.start();
240 }
241
242 public boolean wantsSerializedForm() {
243 return true;
244 }
245
246 public void unsetCache() {
247 }
248
249 public void setCache(Cache c) {
250 }
251
252 protected File getMoveToLoc() {
253 File parent = _rootdir.getAbsoluteFile().getParentFile();
254 for(int i=0;i<100;i++) {
255 String fname = String.valueOf(System.currentTimeMillis() % 100000000L);
256 File f = new File(parent,fname);
257 if(!f.exists()) {
258 return f;
259 }
260 try {
261 Thread.currentThread().sleep(17);
262 } catch(Exception e) {
263
264 }
265 }
266 throw new RuntimeException("Couldn't create a temp file to move the shareable file stash to.");
267 }
268 }
269
270 class RecursiveFileDeleter implements Runnable {
271 private File _root = null;
272
273 public RecursiveFileDeleter(File root) {
274 _root = root;
275 }
276
277 public void run() {
278 boolean success = recursiveDelete(_root);
279 if(!success) {
280 System.err.println("Unable to fully delete the file at \"" + _root + "\". Please delete it manually.");
281 }
282 }
283
284 boolean recursiveDelete(File f) {
285 if(f.isDirectory()) {
286 File[] files = f.listFiles();
287 for(int i=0;i<files.length;i++) {
288 if(files[i].isFile()) {
289 if(!files[i].delete()) {
290 return false;
291 }
292 } else {
293 if(!recursiveDelete(files[i])) {
294 return false;
295 }
296 }
297 }
298 }
299 return f.delete();
300 }
301 }
302
303
304