Optimize FileHandler's logic (#639)

* optimize FileHandler's logic

* fix code style

* fix: maybe happen OOM when file upload, see #529

* refactor: HashMap -> ConcurrentHashMap

* remove unused class
pull/662/head
bestsort 2020-03-14 10:05:53 +08:00 committed by GitHub
parent 153f8ebbef
commit 1d020ff550
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 58 additions and 67 deletions

View File

@ -0,0 +1,15 @@
package run.halo.app.exception;
/**
* repeat type exception
* @author bestsort
* @date 3/13/20 5:03 PM
*/
public class RepeatTypeException extends ServiceException {
public RepeatTypeException(String message) {
super(message);
}
public RepeatTypeException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -148,7 +148,8 @@ public class AliOssFileHandler implements FileHandler {
}
@Override
public boolean supportType(String type) {
return AttachmentType.ALIOSS.name().equalsIgnoreCase(type);
public AttachmentType getAttachmentType() {
return AttachmentType.ALIOSS;
}
}

View File

@ -132,7 +132,7 @@ public class BaiduBosFileHandler implements FileHandler {
}
@Override
public boolean supportType(String type) {
return AttachmentType.BAIDUBOS.name().equalsIgnoreCase(type);
public AttachmentType getAttachmentType() {
return AttachmentType.BAIDUBOS;
}
}

View File

@ -7,6 +7,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;
import run.halo.app.exception.FileOperationException;
import run.halo.app.model.enums.AttachmentType;
import run.halo.app.model.support.UploadResult;
import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR;
@ -73,10 +74,8 @@ public interface FileHandler {
void delete(@NonNull String key);
/**
* Checks if the given type is supported.
*
* @param type attachment type
* @return true if supported; false otherwise
* Get attachment type is supported.
* @return attachment type
*/
boolean supportType(@Nullable String type);
}
AttachmentType getAttachmentType();
}

View File

@ -9,12 +9,13 @@ import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import run.halo.app.exception.FileOperationException;
import run.halo.app.exception.RepeatTypeException;
import run.halo.app.model.entity.Attachment;
import run.halo.app.model.enums.AttachmentType;
import run.halo.app.model.support.UploadResult;
import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
/**
* File handler manager.
@ -29,7 +30,7 @@ public class FileHandlers {
/**
* File handler container.
*/
private final Collection<FileHandler> fileHandlers = new LinkedList<>();
private final ConcurrentHashMap<AttachmentType, FileHandler> fileHandlers = new ConcurrentHashMap<>(16);
public FileHandlers(ApplicationContext applicationContext) {
// Add all file handler
@ -47,31 +48,9 @@ public class FileHandlers {
*/
@NonNull
public UploadResult upload(@NonNull MultipartFile file, @NonNull AttachmentType attachmentType) {
Assert.notNull(attachmentType, "Attachment type must not be null");
return upload(file, attachmentType.name());
return getSupportedType(attachmentType).upload(file);
}
/**
* Uploads files.
*
* @param file multipart file must not be null
* @param type store type
* @return upload result
* @throws FileOperationException throws when fail to delete attachment or no available file handler to upload it
*/
@NonNull
public UploadResult upload(@NonNull MultipartFile file, @Nullable String type) {
Assert.notNull(file, "Multipart file must not be null");
for (FileHandler fileHandler : fileHandlers) {
if (fileHandler.supportType(type)) {
return fileHandler.upload(file);
}
}
throw new FileOperationException("No available file handlers to upload the file").setErrorData(type);
}
/**
* Deletes attachment.
@ -81,26 +60,8 @@ public class FileHandlers {
*/
public void delete(@NonNull Attachment attachment) {
Assert.notNull(attachment, "Attachment must not be null");
delete(attachment.getType().name(), attachment.getFileKey());
}
/**
* Deletes attachment.
*
* @param key file key
* @throws FileOperationException throws when fail to delete attachment or no available file handler to delete it
*/
public void delete(@Nullable String type, @NonNull String key) {
for (FileHandler fileHandler : fileHandlers) {
if (fileHandler.supportType(type)) {
// Delete the file
fileHandler.delete(key);
return;
}
}
throw new FileOperationException("No available file handlers to delete the file").setErrorData(type);
getSupportedType(attachment.getType())
.delete(attachment.getFileKey());
}
/**
@ -112,8 +73,21 @@ public class FileHandlers {
@NonNull
public FileHandlers addFileHandlers(@Nullable Collection<FileHandler> fileHandlers) {
if (!CollectionUtils.isEmpty(fileHandlers)) {
this.fileHandlers.addAll(fileHandlers);
for (FileHandler handler : fileHandlers) {
if (this.fileHandlers.containsKey(handler.getAttachmentType())) {
throw new RepeatTypeException("Same attachment type implements must be unique");
}
this.fileHandlers.put(handler.getAttachmentType(), handler);
}
}
return this;
}
private FileHandler getSupportedType(AttachmentType type) {
FileHandler handler = fileHandlers.getOrDefault(type, fileHandlers.get(AttachmentType.LOCAL));
if (handler == null) {
throw new FileOperationException("No available file handlers to operate the file").setErrorData(type);
}
return handler;
}
}

View File

@ -214,8 +214,8 @@ public class LocalFileHandler implements FileHandler {
}
@Override
public boolean supportType(String type) {
return AttachmentType.LOCAL.name().equalsIgnoreCase(type);
public AttachmentType getAttachmentType() {
return AttachmentType.LOCAL;
}
private boolean generateThumbnail(BufferedImage originalImage, Path thumbPath, String extension) {
@ -234,6 +234,9 @@ public class LocalFileHandler implements FileHandler {
result = true;
} catch (Throwable t) {
log.warn("Failed to generate thumbnail: " + thumbPath, t);
} finally {
// Disposes of this graphics context and releases any system resources that it is using.
originalImage.getGraphics().dispose();
}
return result;
}

View File

@ -177,7 +177,7 @@ public class QiniuOssFileHandler implements FileHandler {
}
@Override
public boolean supportType(String type) {
return AttachmentType.QINIUOSS.name().equalsIgnoreCase(type);
public AttachmentType getAttachmentType() {
return AttachmentType.QINIUOSS;
}
}

View File

@ -165,8 +165,8 @@ public class SmmsFileHandler implements FileHandler {
}
@Override
public boolean supportType(String type) {
return AttachmentType.SMMS.name().equalsIgnoreCase(type);
public AttachmentType getAttachmentType() {
return AttachmentType.SMMS;
}
/**

View File

@ -163,7 +163,7 @@ public class TencentCosFileHandler implements FileHandler {
}
@Override
public boolean supportType(String type) {
return AttachmentType.TENCENTCOS.name().equalsIgnoreCase(type);
public AttachmentType getAttachmentType() {
return AttachmentType.TENCENTCOS;
}
}

View File

@ -128,7 +128,7 @@ public class UpOssFileHandler implements FileHandler {
}
@Override
public boolean supportType(String type) {
return AttachmentType.UPOSS.name().equalsIgnoreCase(type);
public AttachmentType getAttachmentType() {
return AttachmentType.UPOSS;
}
}

View File

@ -934,7 +934,6 @@ public class ThemeServiceImpl implements ThemeService {
return true;
}
}
return false;
}
}