View Javadoc

1   /***
2    * $Id: Workspace.java,v 1.1 2005/03/22 13:00:41 mch Exp $
3    */
4   
5   package org.astrogrid.utils;
6   
7   import java.io.File;
8   import java.io.IOException;
9   import org.apache.commons.logging.LogFactory;
10  import org.astrogrid.cfg.ConfigFactory;
11  
12  /***
13   * A temporary filespace manager for
14   * service instances.  Actually just a set of helper methods for creating
15   * and removing directories in the temporary workspace.  Create one of these
16   * to manage one temporary directory - once 'close' is called, it should not
17   * be used again.
18   * <p>
19   * NB the 'close' operation is not threadsafe (ie if other methods are called
20   * while the close operation is running, behaviour is undefined....)
21   * <p>
22   * NB2 - File has a method .createTempFile() that might be better used...
23   */
24  
25  public class Workspace
26  {
27     /*** Key to workspace directory specified in configuration file */
28     public static final String WORKSPACE_DIRECTORY_KEY = "WorkspaceDirectory";
29  
30     /*** public marker as to whether workspace should tidy up when closed -
31      * for debugging purposes it is sometimes useful to leave temporary files
32      * for examination
33      */
34     public static boolean PERSIST = false;
35  
36     /*** File representation of this workspace instance */
37     private File workspaceFile = null;
38  
39     /***
40      * Creates a temporary directory using File.createTempFile()
41      * method
42      */
43     public Workspace() throws IOException
44     {
45        this((String) null);
46     }
47  
48     /*** default workroot, if no other is provided - a directory called <tt>workspaces</tt> in the current directory */
49    public static final String DEFAULT_WORKSPACE_DIRECTORY = System.getProperty("user.dir") + System.getProperty("file.separator") + "workspaces";
50     
51     /***
52      * Creates a temporary directory with the name prefixed by the given workspaceId
53      * in the workspace directory given in the configuration file
54      * @modified nww - altered default behaviour - if no workRoot given, place workspace in <tt><i>working-dir<i>/workspaces</tt>
55      * Necessary because otherwise creating a workspace called 'test' will delete all your test classes, etc.
56      */
57     public Workspace(String workspaceId) throws IOException
58     {
59        //see if a working root has been specified
60        File workRoot = new File (ConfigFactory.getCommonConfig().getString( WORKSPACE_DIRECTORY_KEY, DEFAULT_WORKSPACE_DIRECTORY  ));
61                   
62        // check working root exists, create if necessary
63        if (!workRoot.exists()) {
64           workRoot.mkdirs();
65        }
66        assert workRoot.exists() :
67                "Working root '"+workRoot.getAbsolutePath()
68                   +"' given by configuration key '"
69                   +WORKSPACE_DIRECTORY_KEY+"' does not exist, and could not be created";
70        
71        assert workRoot.isDirectory() :
72                "Working root '"+workRoot.getAbsolutePath()
73                   +"' given by configuration key '"
74                   +WORKSPACE_DIRECTORY_KEY+"' is not a directory";
75        
76        if (workspaceId == null)
77        {
78           workspaceFile = File.createTempFile("Workspace","", workRoot); //creates a FILE with a unique name
79           workspaceFile.delete(); //remove FILE so that DIR gets made below
80        }
81        else
82        {
83           workspaceFile = new File(workRoot,workspaceId);
84        }
85    
86  
87        if (workspaceFile.exists())
88        {
89           throw new IllegalArgumentException("Workspace '"+workspaceId+"' already in use");
90        }
91  
92        boolean createdOK = workspaceFile.mkdir();
93        
94        if (!createdOK) {
95           throw new IOException("Directory "+workspaceFile+" did not create OK - can't tell why");
96        }
97           
98  
99        if (!PERSIST)
100       {
101          workspaceFile.deleteOnExit();
102       }
103       
104       LogFactory.getLog(Workspace.class).debug("Workspace created at "+workspaceFile);
105    }
106 
107    /***
108     * Use when you've finished with the space and you want to tidy up.  NB no
109     * other operations are possible after this - it is best to leave it to the
110     * garbage collector to close() as part of the finalise(), to avoid other
111     * unknown references to it trying to use it after close.
112     */
113    public synchronized void close() throws IOException
114    {
115       if (isClosed()) { throw new IllegalStateException("Trying to close a closed workspace"); }
116 
117       if (!PERSIST) { empty(); }
118 
119       //attempt at threadsafetying but haven't thought about it properly - MCH
120       File tempFile = workspaceFile;
121       workspaceFile = null;
122 
123       if (!PERSIST) { tempFile.delete(); }
124    }
125 
126    /*** Returns true if the workspace has been closed down - ie should not
127     * be used any longer.  The best way to deal with closure safely is to
128     * let the garbage collector do it through the finalize method
129     */
130    public boolean isClosed()
131    {
132       return (workspaceFile == null);
133    }
134 
135    /***
136     * Called by teh garbage collector when there are no more references to
137     * it - check it's been closed and close if not
138     */
139    protected void finalize() throws Throwable
140    {
141       try  {
142         close();
143       }
144       finally
145       {
146          super.finalize();
147       }
148    }
149 
150    /***
151     * Deletes the contents of the workspace
152     */
153    public void empty() throws IOException
154    {
155       if (isClosed()) { throw new IllegalStateException("Trying to empty a closed workspace"); }
156 
157       emptyDirectory(workspaceFile);
158    }
159 
160    /***
161     * So you need to make a temporary file in the workspace - this returns
162     * a reference to it given a filename
163     */
164    public File makeWorkFile(String filename) throws IOException
165    {
166       if (isClosed()) { throw new IllegalStateException("Trying to create a new file in a closed workspace"); }
167 
168       File file = new File(workspaceFile.getAbsolutePath() + File.separator + filename);
169       if (file.createNewFile() == false)
170       {
171          throw new IOException("File '"+filename+"' already exists");
172       }
173       return file;
174    }
175 
176    /***
177     * Auto generate temp file
178     */
179    public File makeTempFile(String prefix, String suffix) throws IOException
180    {
181       return File.createTempFile(prefix, suffix, workspaceFile);
182    }
183 
184    /***
185     * Auto generate temp file
186     */
187    public File makeTempFile(String prefix) throws IOException
188    {
189       return File.createTempFile(prefix, "", workspaceFile);
190    }
191 
192    /***
193     * Auto generate new directory
194     */
195    public File makeTempDir(String prefix) throws IOException
196    {
197       File newFile = File.createTempFile(prefix, "", workspaceFile);
198       newFile.delete();
199       newFile.mkdir();
200       return newFile;
201    }
202 
203    /***
204     * General purpose method that deletes the contents of the given directory
205     */
206    public static void emptyDirectory(File dir) throws IOException
207    {
208       assert dir != null : "Null File given as directory";
209 
210       if (!dir.exists())
211       {
212          throw new IOException("'"+dir + "' does not exist");
213       }
214       if (!dir.isDirectory())
215       {
216          throw new IOException("'"+dir + "' is not a directory");
217       }
218 
219       File[] contents = dir.listFiles();
220       for (int i = 0; i < contents.length; i++)
221       {
222           removeFileOrDir(contents[i]);
223       }
224    }
225 
226    /***
227     * Deletes the given path - if the path refers to a directory, the directory
228     * is emptied and removed, so it will recursively remove a tree.
229     */
230    protected static void removeFileOrDir(File fod) throws IOException
231    {
232       //if it's a directory, empty it first
233       if (fod.isDirectory())
234       {
235          emptyDirectory(fod);
236       }
237 
238       //delete it
239       fod.delete();
240 
241       //check it's worked
242       if (fod.exists())
243       {
244          throw new IOException("Couldn't delete '"+fod+"' (don't know why)");
245       }
246    }
247    
248    /***
249     * temporary Test harness
250     */
251    public static void main(String[] args) throws IOException {
252       Workspace ws = new Workspace("TestId");
253       ws.makeTempDir("wibble");
254       ws.close();
255    }
256 }
257 
258 /*
259 $Log: Workspace.java,v $
260 Revision 1.1  2005/03/22 13:00:41  mch
261 Seperated utils from common
262 
263 Revision 1.7  2004/03/12 16:49:00  mch
264 Added debug logging, more robust close?
265 
266  */
267 
268