View Javadoc

    1   /*
    2    * Copyright 2012 The Netty Project
    3    *
    4    * The Netty Project licenses this file to you under the Apache License,
    5    * version 2.0 (the "License"); you may not use this file except in compliance
    6    * with the License. You may obtain a copy of the License at:
    7    *
    8    *   http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    13   * License for the specific language governing permissions and limitations
    14   * under the License.
    15   */
    16  package org.jboss.netty.handler.codec.http.multipart;
    17
    18  import java.io.File;
    19  import java.io.FileInputStream;
    20  import java.io.FileOutputStream;
    21  import java.io.IOException;
    22  import java.io.InputStream;
    23  import java.nio.ByteBuffer;
    24  import java.nio.channels.FileChannel;
    25  import java.nio.charset.Charset;
    26
    27  import org.jboss.netty.buffer.ChannelBuffer;
    28  import org.jboss.netty.buffer.ChannelBuffers;
    29  import org.jboss.netty.handler.codec.http.HttpConstants;
    30
    31  /**
    32   * Abstract Disk HttpData implementation
    33   */
    34  public abstract class AbstractDiskHttpData extends AbstractHttpData {
    35
    36      protected File file;
    37      private boolean isRenamed;
    38      private FileChannel fileChannel;
    39
    40      public AbstractDiskHttpData(String name, Charset charset, long size) {
    41          super(name, charset, size);
    42      }
    43
    44      /**
    45       *
    46       * @return the real DiskFilename (basename)
    47       */
    48      protected abstract String getDiskFilename();
    49      /**
    50       *
    51       * @return the default prefix
    52       */
    53      protected abstract String getPrefix();
    54      /**
    55       *
    56       * @return the default base Directory
    57       */
    58      protected abstract String getBaseDirectory();
    59      /**
    60       *
    61       * @return the default postfix
    62       */
    63      protected abstract String getPostfix();
    64      /**
    65       *
    66       * @return True if the file should be deleted on Exit by default
    67       */
    68      protected abstract boolean deleteOnExit();
    69
    70      /**
    71       *
    72       * @return a new Temp File from getDiskFilename(), default prefix, postfix and baseDirectory
    73       * @throws IOException
    74       */
    75      private File tempFile() throws IOException {
    76          String newpostfix = null;
    77          String diskFilename = getDiskFilename();
    78          if (diskFilename != null) {
    79              newpostfix = "_" + diskFilename;
    80          } else {
    81              newpostfix = getPostfix();
    82          }
    83          File tmpFile;
    84          if (getBaseDirectory() == null) {
    85              // create a temporary file
    86              tmpFile = File.createTempFile(getPrefix(), newpostfix);
    87          } else {
    88              tmpFile = File.createTempFile(getPrefix(), newpostfix, new File(
    89                      getBaseDirectory()));
    90          }
    91          if (deleteOnExit()) {
    92              tmpFile.deleteOnExit();
    93          }
    94          return tmpFile;
    95      }
    96
    97      public void setContent(ChannelBuffer buffer) throws IOException {
    98          if (buffer == null) {
    99              throw new NullPointerException("buffer");
    100         }
    101         size = buffer.readableBytes();
    102         if (definedSize > 0 && definedSize < size) {
    103             throw new IOException("Out of size: " + size + " > " + definedSize);
    104         }
    105         if (file == null) {
    106             file = tempFile();
    107         }
    108         if (buffer.readableBytes() == 0) {
    109             // empty file
    110             file.createNewFile();
    111             return;
    112         }
    113         FileOutputStream outputStream = new FileOutputStream(file);
    114         FileChannel localfileChannel = outputStream.getChannel();
    115         ByteBuffer byteBuffer = buffer.toByteBuffer();
    116         int written = 0;
    117         while (written < size) {
    118             written += localfileChannel.write(byteBuffer);
    119         }
    120         buffer.readerIndex(buffer.readerIndex() + written);
    121         localfileChannel.force(false);
    122         localfileChannel.close();
    123         completed = true;
    124     }
    125
    126     public void addContent(ChannelBuffer buffer, boolean last)
    127             throws IOException {
    128         if (buffer != null) {
    129             int localsize = buffer.readableBytes();
    130             if (definedSize > 0 && definedSize < size + localsize) {
    131                 throw new IOException("Out of size: " + (size + localsize) +
    132                         " > " + definedSize);
    133             }
    134             ByteBuffer byteBuffer = buffer.toByteBuffer();
    135             int written = 0;
    136             if (file == null) {
    137                 file = tempFile();
    138             }
    139             if (fileChannel == null) {
    140                 FileOutputStream outputStream = new FileOutputStream(file);
    141                 fileChannel = outputStream.getChannel();
    142             }
    143             while (written < localsize) {
    144                 written += fileChannel.write(byteBuffer);
    145             }
    146             size += localsize;
    147             buffer.readerIndex(buffer.readerIndex() + written);
    148         }
    149         if (last) {
    150             if (file == null) {
    151                 file = tempFile();
    152             }
    153             if (fileChannel == null) {
    154                 FileOutputStream outputStream = new FileOutputStream(file);
    155                 fileChannel = outputStream.getChannel();
    156             }
    157             fileChannel.force(false);
    158             fileChannel.close();
    159             fileChannel = null;
    160             completed = true;
    161         } else {
    162             if (buffer == null) {
    163                 throw new NullPointerException("buffer");
    164             }
    165         }
    166     }
    167
    168     public void setContent(File file) throws IOException {
    169         if (this.file != null) {
    170             delete();
    171         }
    172         this.file = file;
    173         size = file.length();
    174         isRenamed = true;
    175         completed = true;
    176     }
    177
    178     public void setContent(InputStream inputStream) throws IOException {
    179         if (inputStream == null) {
    180             throw new NullPointerException("inputStream");
    181         }
    182         if (file != null) {
    183             delete();
    184         }
    185         file = tempFile();
    186         FileOutputStream outputStream = new FileOutputStream(file);
    187         FileChannel localfileChannel = outputStream.getChannel();
    188         byte[] bytes = new byte[4096 * 4];
    189         ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
    190         int read = inputStream.read(bytes);
    191         int written = 0;
    192         while (read > 0) {
    193             byteBuffer.position(read).flip();
    194             written += localfileChannel.write(byteBuffer);
    195             read = inputStream.read(bytes);
    196         }
    197         localfileChannel.force(false);
    198         localfileChannel.close();
    199         size = written;
    200         if (definedSize > 0 && definedSize < size) {
    201             file.delete();
    202             file = null;
    203             throw new IOException("Out of size: " + size + " > " + definedSize);
    204         }
    205         isRenamed = true;
    206         completed = true;
    207     }
    208
    209     public void delete() {
    210         if (! isRenamed) {
    211             if (file != null) {
    212                 file.delete();
    213             }
    214         }
    215     }
    216
    217     public byte[] get() throws IOException {
    218         if (file == null) {
    219             return new byte[0];
    220         }
    221         return readFrom(file);
    222     }
    223
    224     public ChannelBuffer getChannelBuffer() throws IOException {
    225         if (file == null) {
    226             return ChannelBuffers.EMPTY_BUFFER;
    227         }
    228         byte[] array = readFrom(file);
    229         return ChannelBuffers.wrappedBuffer(array);
    230     }
    231
    232     public ChannelBuffer getChunk(int length) throws IOException {
    233         if (file == null || length == 0) {
    234             return ChannelBuffers.EMPTY_BUFFER;
    235         }
    236         if (fileChannel == null) {
    237             FileInputStream  inputStream = new FileInputStream(file);
    238             fileChannel = inputStream.getChannel();
    239         }
    240         int read = 0;
    241         ByteBuffer byteBuffer = ByteBuffer.allocate(length);
    242         while (read < length) {
    243             int readnow = fileChannel.read(byteBuffer);
    244             if (readnow == -1) {
    245                 fileChannel.close();
    246                 fileChannel = null;
    247                 break;
    248             } else {
    249                 read += readnow;
    250             }
    251         }
    252         if (read == 0) {
    253             return ChannelBuffers.EMPTY_BUFFER;
    254         }
    255         byteBuffer.flip();
    256         ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(byteBuffer);
    257         buffer.readerIndex(0);
    258         buffer.writerIndex(read);
    259         return buffer;
    260     }
    261
    262     public String getString() throws IOException {
    263         return getString(HttpConstants.DEFAULT_CHARSET);
    264     }
    265
    266     public String getString(Charset encoding) throws IOException {
    267         if (file == null) {
    268             return "";
    269         }
    270         if (encoding == null) {
    271             byte[] array = readFrom(file);
    272             return new String(array, HttpConstants.DEFAULT_CHARSET.name());
    273         }
    274         byte[] array = readFrom(file);
    275         return new String(array, encoding.name());
    276     }
    277
    278     public boolean isInMemory() {
    279         return false;
    280     }
    281
    282     public boolean renameTo(File dest) throws IOException {
    283         if (dest == null) {
    284             throw new NullPointerException("dest");
    285         }
    286         if (!file.renameTo(dest)) {
    287             // must copy
    288             FileInputStream inputStream = new FileInputStream(file);
    289             FileOutputStream outputStream = new FileOutputStream(dest);
    290             FileChannel in = inputStream.getChannel();
    291             FileChannel out = outputStream.getChannel();
    292             int chunkSize = 8196;
    293             long position = 0;
    294             while (position < size) {
    295                 if (chunkSize < size - position) {
    296                     chunkSize = (int) (size - position);
    297                 }
    298                 position += in.transferTo(position, chunkSize , out);
    299             }
    300             in.close();
    301             out.close();
    302             if (position == size) {
    303                 file.delete();
    304                 file = dest;
    305                 isRenamed = true;
    306                 return true;
    307             } else {
    308                 dest.delete();
    309                 return false;
    310             }
    311         }
    312         file = dest;
    313         isRenamed = true;
    314         return true;
    315     }
    316
    317     /**
    318      * Utility function
    319      * @param src
    320      * @return the array of bytes
    321      * @throws IOException
    322      */
    323     private static byte[] readFrom(File src) throws IOException {
    324         long srcsize = src.length();
    325         if (srcsize > Integer.MAX_VALUE) {
    326             throw new IllegalArgumentException(
    327                     "File too big to be loaded in memory");
    328         }
    329         FileInputStream inputStream = new FileInputStream(src);
    330         FileChannel fileChannel = inputStream.getChannel();
    331         byte[] array = new byte[(int) srcsize];
    332         ByteBuffer byteBuffer = ByteBuffer.wrap(array);
    333         int read = 0;
    334         while (read < srcsize) {
    335             read += fileChannel.read(byteBuffer);
    336         }
    337         fileChannel.close();
    338         return array;
    339     }
    340
    341     public File getFile() throws IOException {
    342         return file;
    343     }
    344
    345 }