View Javadoc

1   /*
2    * $Id: LocalFileStore.java,v 1.3 2004/09/06 11:29:24 mch Exp $
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           //find the temporary file area as assigned by the operating system
80           rootDir = File.createTempFile("LocalFileStore","Root" ); //create file in temporary area
81           rootDir.delete();    //don't need the file
82  
83           //create directory LocalFileStore off temporary area.  NB we could use
84           //the created file above as a directory name, but that means that two
85           //created file stores would not overlap.
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)); //chop off 'file://'
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          //shouldn't happen as this is a generated string...
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       //remove colons, spaces and slashes from filename
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          //@todo - borrow from somwhere
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          //@todo - borrow from somwhere
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; //not a path
218       }
219       
220       String path = "";
221       //navigate up the file until we reach the root
222       while ((file != null) && (!file.equals(rootDir))) {
223          path = "/"+file.getName()+path;
224          file = file.getParentFile();
225       }
226 
227       //check it's all OK
228       if (file == null) {
229          throw new StoreException("File "+file+" not in local file store "+this);
230       }
231 
232       return path.substring(1); //chop off initial slash
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          //same store so make a file
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       //transfer
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          //remove colons, spaces and slashes from filename
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 $Log: LocalFileStore.java,v $
372 Revision 1.3  2004/09/06 11:29:24  mch
373 Added comments
374 
375 Revision 1.2  2004/06/14 23:08:53  jdt
376 Merge from branches
377 
378 ClientServerSplit_JDT
379 
380 and
381 
382 MySpaceClientServerSplit_JDT
383 
384 
385 
386 MySpace now split into a client/delegate jar
387 
388 astrogrid-myspace-<version>.jar
389 
390 and a server/manager war
391 
392 astrogrid-myspace-server-<version>.war
393 
394 Revision 1.1.2.1  2004/06/14 22:33:21  jdt
395 Split into delegate jar and server war.
396 Delegate: astrogrid-myspace-SNAPSHOT.jar
397 Server/Manager: astrogrid-myspace-server-SNAPSHOT.war
398 
399 Package names unchanged.
400 If you regenerate the axis java/wsdd/wsdl files etc you'll need
401 to move some files around to ensure they end up in the client
402 or the server as appropriate.
403 As of this check-in the tests/errors/failures is 162/1/22 which
404 matches that before the split.
405 
406 Revision 1.9  2004/05/03 08:55:53  mch
407 Fixes to getFiles(), introduced getSize(), getOwner() etc to StoreFile
408 
409 Revision 1.8  2004/04/23 11:38:19  mch
410 Fixes to return correct AGSL plus change to File model for It05 delegate
411 
412 Revision 1.7  2004/04/06 15:40:46  mch
413 Minor change to javadoc
414 
415 Revision 1.6  2004/03/22 10:25:42  mch
416 Added VoSpaceClient, StoreDelegate, some minor changes to StoreClient interface
417 
418 Revision 1.5  2004/03/19 12:39:37  mch
419 Added StoreAdminClient implementation to LocalFileStore
420 
421 Revision 1.4  2004/03/17 15:17:29  mch
422 Added putBytes
423 
424 Revision 1.3  2004/03/14 13:30:08  mch
425 Fix for unix rootDir not created and so not being deleted
426 
427 Revision 1.2  2004/03/13 22:58:43  mch
428 Fixed nul pointer exception when path is empty
429 
430 Revision 1.1  2004/03/04 12:51:31  mch
431 Moved delegate implementations into subpackages
432 
433 Revision 1.4  2004/03/02 11:53:35  mch
434 Fixes to copy and move tests
435 
436 Revision 1.3  2004/03/02 00:15:39  mch
437 Renamed MyspaceIt04Delegate from misleading ServerDelegate
438 
439 Revision 1.2  2004/03/01 22:38:46  mch
440 Part II of copy from It4.1 datacenter + updates from myspace meetings + test fixes
441 
442 Revision 1.1  2004/03/01 15:15:04  mch
443 Updates to Store delegates after myspace meeting
444 
445  */
446