/* * #%L * Wisdom-Framework * %% * Copyright (C) 2013 - 2014 Wisdom Framework * %% * Licensed 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. * #L% */ package org.wisdom.framework.vertx.file; import io.vertx.core.AsyncResult; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.file.AsyncFile; import io.vertx.core.file.OpenOptions; import io.vertx.core.http.HttpServerFileUpload; import io.vertx.core.streams.Pump; import org.apache.commons.io.FileUtils; import org.slf4j.LoggerFactory; import org.wisdom.api.http.Result; import java.io.*; /** * An implementation of {@link org.wisdom.api.http.FileItem} storing the uploaded file on disk. This class is not * responsible of reading the file upload, but only to store the data to a file on disk. */ public class DiskFileUpload extends VertxFileUpload { /** * Proposed default MINSIZE as 16 KB. */ public static final long MINSIZE = 0x4000; /** * Should delete file on exit (in normal exit) */ public static boolean deleteOnExitTemporaryFile = true; /** * System temp directory */ public static String baseDirectory = null; /** * The prefix used to create files. */ public static final String prefix = "FUp_"; /** * The created file. */ private final File file; /** * The async file used fro transferring the data to the disk. Once the transfer is done, this field is not used. */ private AsyncFile async; /** * The Vert.X instance. */ private final Vertx vertx; /** * Creates an instance of {@link org.wisdom.framework.vertx.file.DiskFileUpload}. * * @param vertx the Vert.X instance * @param upload the Vert.X file upload object * @param errorHandler the error handler */ public DiskFileUpload(Vertx vertx, HttpServerFileUpload upload, Handler<Result> errorHandler) { super(upload, errorHandler); this.file = tempFile(upload); this.vertx = vertx; } /** * Deletes the created file. */ public void cleanup() { FileUtils.deleteQuietly(file); } /** * A new chunk has arrived, save it on disk. * * @param buffer the chunk */ @Override public void push(final Buffer buffer) { if (async == null) { upload.pause(); vertx.fileSystem().open(file.getAbsolutePath(), new OpenOptions().setCreate(true), new Handler<AsyncResult<AsyncFile>>() { @Override public void handle(AsyncResult<AsyncFile> event) { async = event.result(); async.exceptionHandler(new Handler<Throwable>() { @Override public void handle(Throwable event) { LoggerFactory .getLogger(this.getClass().getName()) .error("Cannot write into {}", file.getAbsolutePath(), event); } }); async.write(buffer); Pump.pump(upload, async).start(); upload.resume(); } }); } } /** * Upload completed, close the async file. */ @Override public void close() { vertx.runOnContext(event -> async.close()); } /** * Creates a temporary file. * * @return a new Temp File from getDiskFilename(), default prefix, postfix and baseDirectory */ static synchronized File tempFile(HttpServerFileUpload upload) { String newpostfix; String diskFilename = new File(upload.filename()).getName(); newpostfix = '_' + diskFilename; File tmpFile; try { if (baseDirectory == null) { // create a temporary file tmpFile = File.createTempFile(prefix, newpostfix); } else { tmpFile = File.createTempFile(prefix, newpostfix, new File( baseDirectory)); } if (deleteOnExitTemporaryFile) { tmpFile.deleteOnExit(); } return tmpFile; } catch (IOException e) { // Really bad, can't create the tmp file. throw new IllegalStateException(e); } } /** * Gets the bytes. * * @return the full content of the file. */ @Override public byte[] bytes() { try { return FileUtils.readFileToByteArray(file); } catch (IOException e) { return null; } } /** * Opens an input stream on the file. * * @return an input stream to read the content of the uploaded item. */ @Override public InputStream stream() { try { return new FileInputStream(file); } catch (FileNotFoundException e) { return null; } } /** * Provides a hint as to whether or not the file contents will be read from memory. * * @return {@literal true} if the file content is in memory. */ @Override public boolean isInMemory() { return false; } /** * Gets the size of the uploaded item. * * @return the size of the uploaded file. */ @Override public long size() { return file.length(); } /** * Gets a {@link java.io.File} object for this uploaded file. This file is a <strong>temporary</strong> file. * Depending on how is handled the file upload, the file may already exist, or not (in-memory) and then is created. * * @return a file object * @since 0.7.1 */ @Override public File toFile() { return file; } }