org.apache.wicket.markup.html.form.upload.FileUpload.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.wicket.markup.html.form.upload.FileUpload.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.wicket.markup.html.form.upload;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.fileupload.FileItem;
import org.apache.wicket.util.io.IClusterable;
import org.apache.wicket.Session;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.util.file.Files;
import org.apache.wicket.util.io.IOUtils;
import org.apache.wicket.util.lang.Args;
import org.apache.wicket.util.string.Strings;

/**
 * Model for file uploads. Objects of this class should not be kept between requests, and should
 * therefore be marked as <code>transient</code> if they become a property of an IModel.
 * 
 * @author Jonathan Locke
 */
public class FileUpload implements IClusterable {
    private static final long serialVersionUID = 1L;

    private final FileItem item;

    private transient List<InputStream> inputStreamsToClose;

    /**
     * Constructor
     * 
     * @param item
     *            The uploaded file item
     */
    public FileUpload(final FileItem item) {
        Args.notNull(item, "item");
        this.item = item;
    }

    /**
     * Close the streams which has been opened when getting the InputStream using
     * {@link #getInputStream()}. All the input streams are closed at the end of the request. This
     * is done when the FileUploadField, which is associated with this FileUpload is detached.
     * <p>
     * If an exception is thrown when closing the input streams, we ignore it, because the stream
     * might have been closed already.
     */
    public final void closeStreams() {
        if (inputStreamsToClose != null) {
            for (InputStream inputStream : inputStreamsToClose) {
                IOUtils.closeQuietly(inputStream);
            }

            // Reset the list
            inputStreamsToClose = null;
        }
    }

    /**
     * Deletes temp file from disk
     */
    public void delete() {
        item.delete();
    }

    /**
     * @return Uploaded file as an array of bytes
     */
    public byte[] getBytes() {
        return item.get();
    }

    /**
     * Get the MD5 checksum.
     * 
     * @param algorithm
     *            the digest algorithm, e.g. MD5, SHA-1, SHA-256, SHA-512
     * 
     * @return The cryptographic digest of the file
     */
    public byte[] getDigest(String algorithm) {
        try {
            Args.notEmpty(algorithm, "algorithm");
            MessageDigest digest = java.security.MessageDigest.getInstance(algorithm);

            if (item.isInMemory()) {
                digest.update(getBytes());
                return digest.digest();
            }

            InputStream in = null;

            try {
                in = item.getInputStream();
                byte[] buf = new byte[Math.min((int) item.getSize(), 4096 * 10)];
                int len;
                while (-1 != (len = in.read(buf))) {
                    digest.update(buf, 0, len);
                }
                return digest.digest();
            } catch (IOException ex) {
                throw new WicketRuntimeException("Error while reading input data for " + algorithm + " checksum",
                        ex);
            } finally {
                IOUtils.closeQuietly(in);
            }
        } catch (NoSuchAlgorithmException ex) {
            String error = String.format("Your java runtime does not support digest algorithm [%s]. "
                    + "Please see java.security.MessageDigest.getInstance(\"%s\")", algorithm, algorithm);

            throw new WicketRuntimeException(error, ex);
        }
    }

    /**
     * Get the MD5 checksum.
     * 
     * @return The MD5 checksum of the file
     */
    public byte[] getMD5() {
        return getDigest("MD5");
    }

    /**
     * @since 1.2
     * @return name of uploaded client side file
     */
    public String getClientFileName() {
        String name = item.getName();

        // when uploading from localhost some browsers will specify the entire path, we strip it
        // down to just the file name
        name = Strings.lastPathComponent(name, '/');
        name = Strings.lastPathComponent(name, '\\');

        return name;
    }

    /**
     * @return Content type for upload
     */
    public String getContentType() {
        return item.getContentType();
    }

    /**
     * Get an input stream for the file uploaded. Use this input stream if you can't use
     * {@link #writeTo(File)} for persisting the uploaded file. This can be if you need to react
     * upon the content of the file or need to persist it elsewhere, i.e. a database or external
     * filesystem.
     * <p>
     * <b>PLEASE NOTE!</b><br>
     * The InputStream return will be closed be Wicket at the end of the request. If you need it
     * across a request you need to hold on to this FileUpload instead.
     * 
     * @return Input stream with file contents.
     * @throws IOException
     */
    public InputStream getInputStream() throws IOException {
        if (inputStreamsToClose == null) {
            inputStreamsToClose = new ArrayList<InputStream>();
        }

        InputStream is = item.getInputStream();
        inputStreamsToClose.add(is);

        return is;
    }

    /**
     * @return The upload's size
     */
    public long getSize() {
        return item.getSize();
    }

    /**
     * Saves this file upload to a given file on the server side.
     * 
     * @param file
     *            The file
     * @throws Exception
     */
    public void writeTo(final File file) throws Exception {
        Files.remove(file);
        item.write(file);
    }

    /**
     * Convenience method that copies the input stream returned by {@link #getInputStream()} into a
     * temporary file.
     * <p>
     * Only use this if you actually need a {@link File} to work with, in all other cases use
     * {@link #getInputStream()} or {@link #getBytes()}
     * 
     * @since 1.2
     * 
     * @return temporary file containing the contents of the uploaded file
     * @throws Exception
     */
    public final File writeToTempFile() throws Exception {
        String sessionId = Session.exists() ? Session.get().getId() : "";
        String tempFileName = sessionId + "_" + RequestCycle.get().getStartTime();
        File temp = File.createTempFile(tempFileName, Files.cleanupFilename(item.getFieldName()));
        writeTo(temp);
        return temp;
    }
}