All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
act.util.UploadFileStorageService Maven / Gradle / Ivy
package act.util;
/*-
* #%L
* ACT Framework
* %%
* Copyright (C) 2014 - 2017 ActFramework
* %%
* 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%
*/
import act.Act;
import act.app.App;
import org.apache.commons.fileupload.FileItemStream;
import org.osgl.$;
import org.osgl.storage.ISObject;
import org.osgl.storage.IStorageService;
import org.osgl.storage.KeyGenerator;
import org.osgl.storage.KeyNameProvider;
import org.osgl.storage.impl.FileSystemService;
import org.osgl.storage.impl.SObject;
import org.osgl.util.C;
import org.osgl.util.E;
import org.osgl.util.IO;
import org.osgl.util.S;
import java.io.*;
import java.util.Map;
public class UploadFileStorageService extends FileSystemService {
public static final KeyNameProvider ACT_STORAGE_KEY_NAME_PROVIDER = new KeyNameProvider() {
@Override
public String newKeyName() {
return Act.cuid();
}
};
private int inMemoryCacheThreshold;
public UploadFileStorageService(Map conf, int inMemoryCacheThreshold) {
super(conf);
this.setKeyNameProvider(ACT_STORAGE_KEY_NAME_PROVIDER);
this.inMemoryCacheThreshold = inMemoryCacheThreshold;
}
public static UploadFileStorageService create(App app) {
File tmp = app.tmpDir();
if (!tmp.exists() && !tmp.mkdirs()) {
throw E.unexpected("Cannot create tmp dir");
}
Map conf = C.newMap("storage.fs.home.dir", Files.file(app.tmpDir(), "uploads").getAbsolutePath(),
"storage.keygen", KeyGenerator.Predefined.BY_DATE.name());
conf.put(IStorageService.CONF_ID, "__upload");
conf.put("storage.storeSuffix", "false");
return new UploadFileStorageService(conf, app.config().uploadInMemoryCacheThreshold());
}
public static ISObject store(FileItemStream fileItemStream, App app) {
UploadFileStorageService ss = app.uploadFileStorageService();
try {
return ss._store(fileItemStream);
} catch (IOException e) {
throw E.ioException(e);
}
}
private ISObject _store(FileItemStream fileItemStream) throws IOException {
String filename = fileItemStream.getName();
String key = newKey(filename);
File tmpFile = getFile(key);
InputStream input = fileItemStream.openStream();
ThresholdingByteArrayOutputStream output = new ThresholdingByteArrayOutputStream(inMemoryCacheThreshold, tmpFile);
IO.copy(input, output);
ISObject retVal;
if (output.exceedThreshold) {
retVal = getFull(key);
} else {
int size = output.written;
if (0 == size) {
return null;
}
byte[] buf = output.buf();
retVal = SObject.of(key, buf, size);
}
if (S.notBlank(filename)) {
retVal.setFilename(filename);
}
String contentType = fileItemStream.getContentType();
if (null != contentType) {
retVal.setContentType(contentType);
}
return retVal;
}
private String newKey(String filename) {
if (S.blank(filename)) {
return S.concat(Act.cuid(), "tmp");
}
return S.pathConcat(getKey(Act.cuid()), '/', filename);
}
/**
* The idea come from apache-commons-IO's `ThresholdingOutputStream`
*
* Before threshold exceeded the data is written into internal byte array buffer, once
* threshold is reached then the internal byte array buffer will be dumped into the
* second output stream and remaining written will be redirected to the second output
* stream also
*/
private static class ThresholdingByteArrayOutputStream extends ByteArrayOutputStream {
private int threshold;
private int written;
private boolean exceedThreshold;
private File file;
private OutputStream fileOutputStream;
public ThresholdingByteArrayOutputStream(int threshold, File file) {
if (threshold < 1024) {
threshold = 1024;
}
buf = new byte[threshold];
this.threshold = threshold;
this.file = $.requireNotNull(file);
}
@Override
public synchronized void write(int b) {
if (!checkThresholding(1)) {
super.write(b);
} else {
try {
fileOutputStream.write(b);
} catch (IOException e) {
throw E.ioException(e);
}
}
written++;
}
@Override
public synchronized void write(byte[] b, int off, int len) {
if (!checkThresholding(len)) {
super.write(b, off, len);
} else {
try {
fileOutputStream.write(b, off, len);
} catch (IOException e) {
throw E.ioException(e);
}
}
written += len;
}
@Override
public void flush() throws IOException {
if (exceedThreshold) {
fileOutputStream.flush();
}
}
@Override
public void close() throws IOException {
if (exceedThreshold) {
IO.close(fileOutputStream);
}
}
byte[] buf() {
return this.buf;
}
private boolean checkThresholding(int bytes) {
if (!exceedThreshold && (written + bytes > threshold)) {
exceedThreshold = true;
fileOutputStream = createFileOutputStream();
try {
fileOutputStream.write(buf, 0, written);
} catch (IOException e) {
throw E.ioException(e);
}
}
return exceedThreshold;
}
private OutputStream createFileOutputStream() {
File dir = file.getParentFile();
if (!dir.exists() && !dir.mkdirs()) {
throw E.ioException("Cannot create dir: " + dir.getAbsolutePath());
}
return IO.buffered(IO.outputStream(file));
}
}
}