1
2
3
4
5
6 package org.astrogrid.store.delegate.local;
7 import org.astrogrid.store.delegate.*;
8
9 import java.io.*;
10
11 import java.net.MalformedURLException;
12 import java.net.URL;
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15 import org.astrogrid.community.User;
16 import org.astrogrid.config.SimpleConfig;
17 import org.astrogrid.io.Piper;
18 import org.astrogrid.store.Agsl;
19
20 /***
21 * This is ClientStore implementation for reaching local files directly.
22 * Because of this, it can be used to test applications
23 * against myspace delegates but without actually needing access to a myspace
24 * service. It basically stores files locally, with a root directory given in the
25 * configuration, or off the working directory if none is given.
26 *
27 * @author: M Hill
28 */
29
30 public class LocalFileStore extends StoreDelegate implements StoreAdminClient {
31
32
33
34 /*** The root directory for this file store instance */
35 private File rootDir = null;
36
37 static private Log log = LogFactory.getLog(LocalFileStore.class);
38
39 /***
40 * Class for filtering filenames based on the given criteria
41 */
42 private class CriteriaFilenameFilter implements FilenameFilter
43 {
44 String criteria = null;
45
46 public CriteriaFilenameFilter(String givenCriteria)
47 {
48 this.criteria = givenCriteria;
49 }
50
51 public boolean accept(File dir, String name)
52 {
53 if (criteria.equals("*"))
54 {
55 return true;
56 }
57 else
58 {
59 throw new UnsupportedOperationException();
60 }
61 }
62 }
63
64
65 /***
66 * Creates a StoreClient that can be used to list, copy, delete, etc files
67 * on disk. The root is determined from the configuration root,
68 * or creates one off the system-dependent
69 * temporary directory (as the owner will always be able to create one there
70 * even if they can't in the working directory)
71 */
72 public LocalFileStore() throws IOException {
73
74 super(User.ANONYMOUS);
75
76 String root = SimpleConfig.getSingleton().getString("LocalFileStoreRoot", null);
77
78 if (root == null) {
79
80 rootDir = File.createTempFile("LocalFileStore","Root" );
81 rootDir.delete();
82
83
84
85
86 rootDir = new File(rootDir.getParentFile(), "LocalFileStore");
87 if (rootDir.exists() && (!rootDir.isDirectory())) {
88 boolean success = rootDir.delete();
89 if (!success) {
90 throw new IOException("LocalFileStore ["+rootDir+"] is not a directory and yet cannot be deleted to make room for the local store");
91 }
92 }
93
94 if (!rootDir.exists()) {
95 rootDir.mkdir();
96 }
97 }
98 }
99
100 /*** As the empty constructor, but creates a subdirectory off the normal
101 * root with the name given. This allows us to create several local stores
102 * in the local filespace
103 */
104 public LocalFileStore(String name) throws IOException {
105 this();
106
107 rootDir = new File(rootDir, name);
108 if (!rootDir.exists()) {
109 rootDir.mkdir();
110 }
111 log.debug("LocalFileStore["+name+"] created at "+rootDir);
112 }
113
114 /*** As the named constructor, but uses the given Agsl that defines the name
115 * Could do with better checking that the agsl is correct for this type...
116 * @deprecated - you should be using StoreDelegateFactory anyway... */
117 public LocalFileStore(Agsl agsl) throws IOException {
118 this(agsl.getEndpoint().substring(7));
119 }
120
121 /*** Creates a local file store with the given file as the root
122 */
123 public LocalFileStore(File givenRoot) {
124 super(User.ANONYMOUS);
125
126 this.rootDir = givenRoot;
127 }
128
129 /***
130 * Returns the endpoint
131 */
132 public Agsl getEndpoint() {
133 String s = Agsl.SCHEME+":file://"+rootDir.getName();
134 try {
135 return new Agsl(s);
136 } catch (MalformedURLException mue) {
137
138 throw new RuntimeException("Program error: generating bad url '"+s+"'",mue);
139 }
140 }
141
142 /***
143 * Puts the given string into the given location
144 * now done via putBytes()
145 public void putString(String contents, String targetPath, boolean append) throws IOException {
146
147 //remove colons, spaces and slashes from filename
148 File target = makeLocalPath(targetPath);
149
150 DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(target, append)));
151 out.writeBytes(contents);
152 out.close();
153 }
154
155 /**
156 * Puts the given bytes into the given location
157 */
158 public void putBytes(byte[] bytes, int offset, int length, String targetPath, boolean append) throws IOException {
159
160
161 File target = makeLocalPath(targetPath);
162
163 DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(target, append)));
164 out.write(bytes, offset, length);
165 out.close();
166
167 }
168
169
170 /***
171 * Gets the url to stream. Note that in this case, it can only return a file
172 * url - the localfilestore does not know if this file is also published via
173 * eg http.
174 */
175 public URL getUrl(String sourcePath) throws IOException {
176 return makeLocalPath(sourcePath).toURL();
177 }
178
179 /***
180 * Returns a tree representation of the files that match the expression.
181 */
182 public StoreFile getFiles(String filter) throws IOException {
183
184 if (!filter.equals("*")) {
185
186 throw new UnsupportedOperationException("Can only filter * for now");
187 }
188 return new LocalFile(this, rootDir);
189 }
190
191 /***
192 * Returns a list of the children of the given folder */
193 public StoreFile[] getChildren(StoreFile folder, String filter) {
194
195 if (!filter.equals("*")) {
196
197 throw new UnsupportedOperationException("Can only filter * for now");
198 }
199
200 return new LocalFile(this, new File(folder.getPath())).listFiles();
201 }
202
203 /***
204 * Returns the parent of the given file
205 */
206 public StoreFile getParent(StoreFile child) {
207 return new LocalFile(this, new File(child.getPath()).getParentFile());
208 }
209
210 /***
211 * Returns the full path, within the context of this server, to the given
212 * file, including the filename
213 */
214 public String getServerPath(File file) throws StoreException
215 {
216 if (file.equals(rootDir)) {
217 return null;
218 }
219
220 String path = "";
221
222 while ((file != null) && (!file.equals(rootDir))) {
223 path = "/"+file.getName()+path;
224 file = file.getParentFile();
225 }
226
227
228 if (file == null) {
229 throw new StoreException("File "+file+" not in local file store "+this);
230 }
231
232 return path.substring(1);
233 }
234
235 /***
236 * Returns the file representation of that at the given server path */
237 public StoreFile getFile(String path) {
238
239 File f = makeLocalPath(path);
240 if (!f.exists()) {
241 return null;
242 } else {
243 return new LocalFile(this, f);
244 }
245 }
246
247 /***
248 * Create a container
249 */
250 public void newFolder(String targetPath) throws IOException {
251 File newFolder = new File(rootDir, targetPath);
252 newFolder.mkdir();
253 }
254
255 /***
256 * Streaming output - returns a stream that can be used to output to the given
257 * location
258 */
259 public OutputStream putStream(String targetPath, boolean append) throws IOException {
260
261 File target = makeLocalPath(targetPath);
262
263 return new FileOutputStream(target, append);
264 }
265
266 /***
267 * Delete a file
268 */
269 public void delete(String deletePath) throws IOException {
270 File fileToDel = makeLocalPath(deletePath);
271 boolean success = fileToDel.delete();
272 if (!success) {
273 throw new IOException("'"+this+"' failed to delete '"+deletePath+"' (don't know why, possibly file open/locked)");
274 }
275 }
276
277 /***
278 * Gets a file's contents as a stream
279 */
280 public InputStream getStream(String sourcePath) throws IOException {
281 File source = makeLocalPath(sourcePath);
282
283 return new FileInputStream(source);
284 }
285
286 /***
287 * Copies the contents of the file at the given source url to the given location
288 * done in StoreDelegate
289 public void putUrl(URL source, String targetPath, boolean append) throws IOException {
290
291 File target = makeLocalPath(targetPath);
292
293 InputStream in = source.openStream();
294 OutputStream out = new FileOutputStream(target);
295
296 Piper.bufferedPipe(in, out);
297
298 in.close();
299 out.close();
300 }
301
302 /**
303 * Copy a file
304 */
305 public void copy(String sourcePath, Agsl target) throws IOException {
306
307 InputStream in = new FileInputStream(makeLocalPath(sourcePath));
308 OutputStream out = null;
309
310 if (target.getEndpoint().equals("file://"+rootDir.getName())) {
311
312 out = new FileOutputStream(makeLocalPath(target.getPath()), false);
313 }
314 else {
315 StoreClient targetStore = StoreDelegateFactory.createDelegate(getOperator(), target);
316 out = targetStore.putStream(target.getPath(), false);
317 }
318
319
320 Piper.bufferedPipe(in, out);
321 in.close();
322 out.close();
323
324 }
325
326
327 /***
328 * Takes the server path and returns the representation on the local
329 * filesystem
330 */
331 protected File makeLocalPath(String path)
332 {
333 if (path != null) {
334
335 path = path.replace(':','_');
336 path = path.replaceAll("////","_");
337 path = path.replace(' ','_');
338 path = path.replace('?','_');
339 path = path.replace('&','_');
340 path = path.replace('=','_');
341 }
342 return new File(rootDir, path);
343 }
344
345
346 /*** USer friendly representation of this store */
347 public String toString() {
348 return "LocalFileStore ["+rootDir.getName()+"]";
349 }
350
351 /***
352 * Delete a user - this does nothing on a local file store at the moment,
353 * as I'm a bit iffy about deleting directory structures that might have
354 * valuable data in it for now.
355 */
356 public void deleteUser(User delUser) {
357 log.warn("User "+delUser+" filespace not deleted");
358 }
359
360 /***
361 * Create a new user - creates a directory 'individual@community'
362 */
363 public void createUser(User newUser) throws IOException {
364 newFolder(newUser.getUserId()+"@"+newUser.getCommunity());
365 }
366
367
368 }
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446