package org.activityinfo.server.attachment;
/*
* #%L
* ActivityInfo Server
* %%
* Copyright (C) 2009 - 2013 UNICEF
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;
import com.google.appengine.api.files.GSFileOptions.GSFileOptionsBuilder;
import com.google.common.io.ByteStreams;
import com.google.inject.Inject;
import org.activityinfo.server.util.blob.BlobService;
import org.activityinfo.service.DeploymentConfiguration;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.channels.Channels;
import java.nio.charset.Charset;
public class AppEngineAttachmentService implements AttachmentService {
private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
private final BlobService blobService;
private final String attachmentRoot;
@Inject
public AppEngineAttachmentService(BlobService blobService, DeploymentConfiguration config) {
this.blobService = blobService;
this.attachmentRoot = config.getProperty("attachment.blob.root", "/gs/activityinfo-attachments");
}
@Override
public void serveAttachment(String blobId, HttpServletResponse response) throws IOException {
BlobKey blobKey = blobKey(blobId);
blobstoreService.serve(blobKey, response);
}
private BlobKey blobKey(String blobId) {
BlobKey blobKey = blobstoreService.createGsBlobKey("/gs/activityinfo-attachments/" + blobId);
return blobKey;
}
@Override
public void upload(String key, FileItem fileItem, InputStream uploadingStream) {
try {
GSFileOptionsBuilder builder = new GSFileOptionsBuilder().setBucket("activityinfo-attachments")
.setKey(key)
.setContentDisposition("attachment; filename=\"" +
fileItem.getName() + "\"")
.setMimeType(fileItem.getContentType());
FileService fileService = FileServiceFactory.getFileService();
AppEngineFile writableFile = fileService.createNewGSFile(builder.build());
boolean lock = true;
FileWriteChannel writeChannel = fileService.openWriteChannel(writableFile, lock);
OutputStream os = Channels.newOutputStream(writeChannel);
ByteStreams.copy(fileItem.getInputStream(), os);
os.flush();
writeChannel.closeFinally();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void delete(String key) {
blobstoreService.delete(blobKey(key));
}
@Override
public FileItemFactory createFileItemFactory() {
return new FileItemFactory() {
@Override
public FileItem createItem(String fieldName, String contentType, boolean isFormField, String fileName) {
return new InMemoryFileItem(fieldName, contentType, isFormField, fileName);
}
};
}
private static class InMemoryFileItem implements FileItem {
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
private boolean formField;
private String fieldName;
private String contentType;
private String fileName;
public InMemoryFileItem(String fieldName, String contentType, boolean isFormField, String fileName) {
this.fieldName = fieldName;
this.contentType = contentType;
this.formField = isFormField;
this.fileName = fileName;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(baos.toByteArray());
}
@Override
public String getContentType() {
return contentType;
}
@Override
public String getName() {
return fileName;
}
@Override
public boolean isInMemory() {
return true;
}
@Override
public long getSize() {
return baos.size();
}
@Override
public byte[] get() {
return baos.toByteArray();
}
@Override
public String getString(String encoding) throws UnsupportedEncodingException {
return new String(baos.toByteArray(), Charset.forName(encoding));
}
@Override
public String getString() {
return new String(baos.toByteArray());
}
@Override
public void write(File file) throws Exception {
throw new UnsupportedOperationException();
}
@Override
public void delete() {
baos.reset();
}
@Override
public String getFieldName() {
return fieldName;
}
@Override
public void setFieldName(String name) {
this.fieldName = name;
}
@Override
public boolean isFormField() {
return formField;
}
@Override
public void setFormField(boolean state) {
this.formField = state;
}
@Override
public OutputStream getOutputStream() throws IOException {
return baos;
}
}
}