001    /*
002     * This file is part of the Echo Point Project.  This project is a
003     * collection of Components that have extended the Echo Web Application
004     * Framework Version 3.
005     *
006     * Version: MPL 1.1
007     *
008     * The contents of this file are subject to the Mozilla Public License Version
009     * 1.1 (the "License"); you may not use this file except in compliance with
010     * the License. You may obtain a copy of the License at
011     * http://www.mozilla.org/MPL/
012     *
013     * Software distributed under the License is distributed on an "AS IS" basis,
014     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
015     * for the specific language governing rights and limitations under the
016     * License.
017     */
018    package echopoint.tucana.event;
019    
020    import org.apache.commons.io.IOUtils;
021    
022    import java.io.BufferedInputStream;
023    import java.io.BufferedOutputStream;
024    import java.io.File;
025    import java.io.FileInputStream;
026    import java.io.FileOutputStream;
027    
028    /**
029     * A default implementation of an {@link UploadCallback} that saves the
030     * uploaded file(s) to a specified directory.
031     *
032     * <p><b>Note:</b> Development of this component was sponsored by <a
033     * href='http://tcnbroadcasting.com/index.jsp' target='_top'>TCN
034     * Broadcasting</a>.  We are grateful for their support and sponsorship.</p>
035     *
036     * @author Rakesh 2008-11-9
037     * @version $Id: DefaultUploadCallback.java 106 2009-02-03 16:00:33Z sptrakesh $
038     */
039    public class DefaultUploadCallback extends UploadCallbackAdapter
040    {
041      private static final long serialVersionUID = 1l;
042    
043      /** The file separator character to use. */
044      protected static final String FILE_SEPARATOR =
045          System.getProperty( "file.separator" );
046    
047      /** The system default temporary directory. */
048      protected static final String TEMP_DIR =
049          System.getProperty( "java.io.tmpdir" );
050    
051      /** The directory to which uploaded files are to be saved. */
052      private File directory;
053    
054      /** Default constructor to allow sub-classing. */
055      protected DefaultUploadCallback() {}
056    
057      /**
058       * Create a new callback handler that saves files to the specified directory.
059       *
060       * @param directory The directory to which files are to be saved.
061       * @throws IllegalArgumentException If the file specified is not a directory.
062       */
063      public DefaultUploadCallback( final File directory ) throws IllegalArgumentException
064      {
065        setDirectory( directory );
066      }
067    
068      /**
069       * Over-ridden to save the contents of the uploaded file to {@link #directory}.
070       * Client-code should ideally wrap this method in a try-catch clause to
071       * handle file copying errors and update the UI as appropriate.
072       *
073       * {@inheritDoc}
074       * @throws RuntimeException If errors are encountered while copying the
075       *   uploaded file to the specified directory.
076       */
077      @Override
078      public void uploadSucceeded( final UploadFinishEvent event )
079      {
080        final File temp = getTempFile();
081        final File file = getFileName( event.getFileName() );
082    
083        try
084        {
085          event.getFileItem().write( temp );
086    
087          if ( ! temp.renameTo( file ) )
088          {
089            BufferedOutputStream bos =
090                new BufferedOutputStream( new FileOutputStream( file ) );
091            BufferedInputStream bis =
092                new BufferedInputStream( new FileInputStream( temp ) );
093            IOUtils.copy( bis, bos );
094            bis.close();
095            bos.close();
096            temp.delete();
097            logger.log( level, "Rename of temp file to " + file.getAbsolutePath() +
098                " failed.  Recopied from source." );
099          }
100    
101          event.getFileItem().delete();
102    
103          logger.log( level, "Copied upload file contents to: " +
104              file.getAbsolutePath() );
105        }
106        catch ( Exception e )
107        {
108          throw new RuntimeException( "Error copying uploaded file!", e );
109        }
110    
111        super.uploadSucceeded( event );
112      }
113    
114      /**
115       * Return a file object that represents the uploaded file that is to be
116       * saved.
117       *
118       * @param name The file name of the uploaded file.
119       * @return The new file object that represents the file to be saved.
120       */
121      protected File getFileName( final String name )
122      {
123        return new File( directory.getAbsolutePath() + FILE_SEPARATOR + name );
124      }
125    
126      /**
127       * Return a temporary file to which the contents of the uploaded file will
128       * be initially written.  This file will then be moved to the proper
129       * destination file.  This ensures atomic creation of the new file.
130       *
131       * @return The temporary file to create.
132       */
133      protected File getTempFile()
134      {
135        return new File( directory.getAbsolutePath() + FILE_SEPARATOR +
136            "echopoint.tempfile." + System.currentTimeMillis() + ".tmp" );
137      }
138    
139      /**
140       * Accessor for property 'directory'.
141       *
142       * @return Value for property 'directory'.
143       */
144      public File getDirectory()
145      {
146        return directory;
147      }
148    
149      /**
150       * Mutator for property 'directory'.
151       *
152       * @param directory Value to set for property 'directory'.
153       * @throws IllegalArgumentException If the file specified is not a directory.
154       */
155      public void setDirectory( final File directory ) throws IllegalArgumentException
156      {
157        if ( ! directory.isDirectory() )
158        {
159          throw new IllegalArgumentException( "File specified must be a directory!" );
160        }
161    
162        this.directory = directory;
163      }
164    }