Project Report: fawkez

Packagesummary org.jcoderz.commons.connector.file

org.jcoderz.commons.connector.file.FsConnectionImpl

LineHitsNoteSource
1  /*
2   * $Id: FsConnectionImpl.java 1011 2008-06-16 17:57:36Z amandel $
3   *
4   * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5   *
6   * Redistribution and use in source and binary forms, with or without
7   * modification, are permitted provided that the following conditions are
8   * met:
9   *
10   *    * Redistributions of source code must retain the above copyright
11   *      notice, this list of conditions and the following disclaimer.
12   *    * Redistributions in binary form must reproduce the above
13   *      copyright notice, this list of conditions and the following
14   *      disclaimer in the documentation and/or other materials
15   *      provided with the distribution.
16   *    * Neither the name of the jCoderZ.org Project nor the names of
17   *      its contributors may be used to endorse or promote products
18   *      derived from this software without specific prior written
19   *      permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   */
33  package org.jcoderz.commons.connector.file;
34   
35  import java.io.File;
36  import java.io.FileFilter;
37  import java.io.FileInputStream;
38  import java.io.FileNotFoundException;
39  import java.io.FileOutputStream;
40  import java.io.IOException;
41  import java.io.RandomAccessFile;
42  import java.nio.channels.FileChannel;
43  import java.util.HashSet;
44  import java.util.Iterator;
45  import java.util.Properties;
46  import java.util.Random;
47  import java.util.Set;
48  import java.util.logging.Level;
49  import java.util.logging.Logger;
50   
51  import javax.resource.ResourceException;
52  import javax.resource.spi.SecurityException;
53   
54  import org.jcoderz.commons.connector.ConnectionBase;
55  import org.jcoderz.commons.connector.ConnectionNotificationListener;
56  import org.jcoderz.commons.util.IoUtil;
57   
58   
59  /**
60   * Implements the File System Connection.
61   * This connection handle provides physical interraction to the File System.
62   * This behavior is not really conform to the JCA specification, but satisfy
63   * requirenments to provide set of base operations on the underlying File
64   * System.
65   *
66   */
67  class FsConnectionImpl
68        extends ConnectionBase
69        implements FsConnection
70  {
71     public static final String TMP_FILE_PREFIX = "FWK";
72     public static final String TMP_FILE_SUFFIX = "fwk";
73   
74   
75     /** The full qualified name of this class. */
76     private static final String CLASSNAME = FsConnectionImpl.class.getName();
77   
78     /** The logger to use. */
79     private static final Logger logger = Logger.getLogger(CLASSNAME);
80   
81     /** Random instance to use for generating of backup file names. */
82     private static final Random RANDOM = new Random();
83   
84     /** Helds closable instances. */
85     private final Set mCloseables = new HashSet();
86   
87     /** Random handle for debug logging. */
88     private final int mIndex;
89     /** To string holder. */
90     private final String mStringified;
91   
92     /** The file temp dir. **/
93     private final File mTmpDir;
94   
95     private final long mFileTransferChunkSize;
96   
97     /**
98      * Constructor.
99      * @param cnl The listener interesting on this connection.
100      * @param props Configuration properties.
101      */
102     public FsConnectionImpl (ConnectionNotificationListener cnl,
103           Properties props)
104     {
105        super(cnl);
106        synchronized (RANDOM)
107        {
108           mIndex = RANDOM.nextInt(Integer.MAX_VALUE);
109           mStringified = "FsConnectionImpl[" + mIndex + "]";
110        }
111   
112        String tmp = null;
113        if (props != null)
114        {
115           tmp = props.getProperty(FsConnectionFactory.PROP_TEMP_DIR);
116        }
117        if (tmp == null)
118        {
119           tmp = System.getProperty("java.io.tmpdir");
120        }
121        mTmpDir = new File(tmp);
122   
123        if (props != null)
124        {
125            mFileTransferChunkSize
126                = Long.getLong(FsConnectionFactory.PROP_FILE_TRANSFER_CHUNK_SIZE,
127                    FsConnectionFactory.FILE_TRANSFER_CHUNK_SIZE_DEF_VALUE)
128                    .longValue();
129        }
130        else
131        {
132            mFileTransferChunkSize
133                = FsConnectionFactory.FILE_TRANSFER_CHUNK_SIZE_DEF_VALUE;
134        }
135   
136        if (logger.isLoggable(Level.FINER))
137        {
138           logger.finer("Created FsConnection with attributes TempDir " + mTmpDir
139                 + ", FileTransferChunkSize " + mFileTransferChunkSize);
140        }
141     }
142   
143     /** {@inheritDoc} */
144     public void close ()
145           throws ResourceException
146     {
147        logger.entering(CLASSNAME, "close");
148        setClosed();
149   
150        // be sure that all file access handles are closed
151        closeAllCloseables();
152        logger.exiting(CLASSNAME, "close");
153     }
154   
155     /** {@inheritDoc} */
156     public boolean isExists (String file)
157           throws ResourceException
158     {
159        final String method = "isExists";
160        logger.entering(CLASSNAME, method, file);
161        assertValid();
162   
163        final boolean result = isFileExists(new File(file));
164   
165        logger.exiting(CLASSNAME, method, Boolean.valueOf(result));
166        return result;
167     }
168   
169     static javax.resource.spi.SecurityException
170           createReadAccessSecurityException (String file,
171                 java.lang.SecurityException se)
172     {
173        final javax.resource.spi.SecurityException rse
174              = new javax.resource.spi.SecurityException(
175                 "The SecurityManager denies read access to the file '"
176                       + file + "' or to the parent derectory.");
177        se.initCause(se);
178        return rse;
179     }
180   
181     /** {@inheritDoc} */
182     public boolean deleteFile (String file)
183           throws ResourceException
184     {
185        assertValid();
186        return deleteFile(new File(file));
187     }
188   
189     /** {@inheritDoc} */
190     public String [] listFiles (final String dir)
191           throws ResourceException
192     {
193        final String method = "listFiles";
194        logger.entering(CLASSNAME, method, dir);
195        assertValid();
196   
197        final File file = new File(dir);
198        final String [] result;
199   
200        try
201        {
202           result = file.list();
203        }
204        catch (java.lang.SecurityException se)
205        {
206           final javax.resource.spi.SecurityException rse
207                 = new javax.resource.spi.SecurityException("The SecurityManager "
208                       + "denies read access to the directory '" + dir + "'.");
209           rse.initCause(se);
210           logger.throwing(CLASSNAME, method, rse);
211           throw rse;
212        }
213   
214        logger.exiting(CLASSNAME, method, result);
215        return result;
216     }
217   
218     /** {@inheritDoc} */
219     public void renameFile (final String from, final String to)
220           throws ResourceException
221     {
222        final String method = "rename";
223        logger.entering(CLASSNAME, method, new Object [] {from, to});
224        assertValid();
225   
226        moveFile(from, to);
227        logger.exiting(CLASSNAME, method);
228     }
229   
230     /** {@inheritDoc} */
231 (1)   public (1)void moveFile (final String src, final String dest)
232           throws ResourceException
233     {
234        final String method = "move";
235        logger.entering(CLASSNAME, method, new Object [] {src, dest});
236        assertValid();
237   
238        final File srcFile = new File(src);
239        final File destFile = new File(dest);
240   
241        ResourceException re = null;
242        File backupFile = null;
243   
244        if (!isFileExists(srcFile))
245        {
246           re = new ResourceException("File '" + srcFile.toString()
247                 + "' does not exist.");
248           logger.throwing(CLASSNAME, method, re);
249           throw re;
250        }
251   
252        if (!srcFile.canWrite())
253        {
254           re = new ResourceException("File '" + srcFile.toString()
255                 + "' is not writable.");
256           logger.throwing(CLASSNAME, method, re);
257           throw re;
258        }
259   
260        if (isFileExists(destFile))
261        {
262   
263           if (!destFile.canWrite())
264           {
265              re = new ResourceException("The destination file '"
266                    + destFile.toString() + "' does already exist and is not "
267                    + "writable.");
268              logger.throwing(CLASSNAME, method, re);
269              throw re;
270           }
271   
272           backupFile = getBackupFile(destFile);
273           re = rename(destFile, backupFile);
274   
275           if (re != null)
276           {
277              logger.throwing(CLASSNAME, method, re);
278              throw re;
279           }
280        }
281        else
282        {
283           createParentDirs(destFile);
284        }
285   
286        re = rename(srcFile, destFile);
287   
288        if (re != null)
289        {
290           if (backupFile != null)
291           {
292              // rollback
293              final ResourceException e = rename(backupFile, destFile);
294              if (e != null)
295              {
296                 logger.log(Level.WARNING, "Error while file renaming.", e);
297              }
298           }
299   
300           logger.throwing(CLASSNAME, method, re);
301           throw re;
302        }
303   
304        if (backupFile != null && !backupFile.delete())
305        {
306           re = new ResourceException("Could not delete file '"
307                 + backupFile.toString() + "'.");
308   
309           logger.throwing(CLASSNAME, method, re);
310           throw re;
311        }
312   
313        logger.exiting(CLASSNAME, method);
314     }
315   
316     /** {@inheritDoc} */
317     public String createTempFile ()
318           throws ResourceException
319     {
320        final String method = "createTempFile";
321        logger.entering(CLASSNAME, method);
322        assertValid();
323   
324        final String result = createNewFile(null);
325   
326        logger.exiting(CLASSNAME, method, result);
327        return result;
328     }
329   
330     /** {@inheritDoc} */
331     public String createTempFile (final String dir)
332           throws ResourceException
333     {
334        final String method = "createTempFile";
335        logger.entering(CLASSNAME, method, dir);
336        assertValid();
337   
338        final File f = new File(dir);
339        if (!isFileExists(f) || !f.isDirectory())
340        {
341           final ResourceException re = new ResourceException(
342              "Failed to create a new file. A directory named '" + dir
343                 + "' does not exist.");
344   
345           logger.throwing(CLASSNAME, method, re);
346           throw re;
347        }
348   
349        final String result = createNewFile(dir);
350   
351        logger.exiting(CLASSNAME, method, result);
352        return result;
353     }
354   
355     /** {@inheritDoc} */
356     public boolean createFile (String file)
357           throws ResourceException
358     {
359        final String method = "createFile";
360        logger.entering(CLASSNAME, method, file);
361        assertValid();
362   
363        final File f = new File(file);
364   
365        // check if the file does already exist
366        if (isFileExists(f))
367        {
368           final ResourceException re = new ResourceException(
369              "Failed to create a new file. A file named '" + file
370                 + "' does already exist.");
371           logger.throwing(CLASSNAME, method, re);
372           throw re;
373        }
374   
375        // check all necessary parent directories do exist.
376        createParentDirs(f);
377   
378        final boolean result;
379        try
380        {
381           result = f.createNewFile();
382        }
383        catch (IOException e)
384        {
385           final ResourceException re = new ResourceException(
386                 "Failed to create a new file '" + file + "'.");
387           re.initCause(e);
388           logger.throwing(CLASSNAME, method, re);
389           throw re;
390        }
391        catch (java.lang.SecurityException se)
392        {
393           final javax.resource.spi.SecurityException rse
394              = new javax.resource.spi.SecurityException(
395                    "Failed to create a new file.");
396           rse.initCause(se);
397           logger.throwing(CLASSNAME, method, rse);
398 (2)         throw rse;
399        }
400   
401        logger.exiting(CLASSNAME, method, Boolean.valueOf(result));
402   
403        return result;
404     }
405   
406     /**
407      * @param method
408      * @throws ResourceException
409      * @throws SecurityException
410      */
411     private void createParentDirs (final File f)
412 (3)         throws (3)ResourceException, SecurityException
413     {
414        final String method = "createParentDirs";
415        logger.entering(CLASSNAME, method, f);
416        final File parent = f.getParentFile();
417        if (!isFileExists(parent))
418        {
419           // if not -> creates all missing parent directories
420           try
421           {
422              if (!parent.mkdirs())
423              {
424                 final ResourceException re = new ResourceException("Failed to "
425                       + "create all necessary file directories: "
426                          + parent.toString());
427                 logger.throwing(CLASSNAME, method, re);
428                 throw re;
429              }
430              logger.finer("Created all necessary parant directories "
431                    + parent.toString());
432           }
433           catch (java.lang.SecurityException se)
434           {
435              final javax.resource.spi.SecurityException rse
436                    = new javax.resource.spi.SecurityException("Failed to create "
437                          + "all necessary file directories: "
438                          + parent.toString());
439              rse.initCause(se);
440              logger.throwing(CLASSNAME, method, rse);
441              throw rse;
442           }
443        }
444        logger.exiting(CLASSNAME, method);
445     }
446   
447     /** {@inheritDoc} */
448     public String renameToTempFile (String file)
449           throws ResourceException
450     {
451        final String method = "renameToTempFile";
452        logger.entering(CLASSNAME, method, file);
453        assertValid();
454   
455        final String result;
456        try
457        {
458           final File tempFile = createTempFileInTempDir();
459 (4)         tempFile.delete();
460           final File srcFile = new File(file);
461   
462           if (srcFile.renameTo(tempFile))
463           {
464              result = tempFile.getAbsolutePath();
465           }
466           else
467           {
468              final ResourceException re = new ResourceException(
469                    "The rename operation failed.");
470              logger.throwing(CLASSNAME, method, re);
471 (5)            throw re;
472           }
473        }
474        catch (SecurityException se)