package org.yaac.server.file;
import static com.google.common.base.Strings.isNullOrEmpty;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.yaac.server.delegate.MemcacheServiceDelegate;
import org.yaac.server.util.AutoBeanUtil;
import org.yaac.shared.file.FileDownloadPath;
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.datastore.Blob;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Text;
/**
* @author Max Zhu (thebbsky@gmail.com)
*
*/
// TODO : try to provide download file name based on field name?
public class FileDownloadServlet extends HttpServlet {
private static final String PARAM_PATH = "path";
/**
*
*/
private static final long serialVersionUID = 1L;
private final Logger logger;
private final MemcacheServiceDelegate memcache;
@Inject
FileDownloadServlet(Logger logger, MemcacheServiceDelegate memcache) {
super();
this.logger = logger;
this.memcache = memcache;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@SuppressWarnings("rawtypes")
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String encodedPath = req.getParameter(PARAM_PATH);
// info is mandatory
if (isNullOrEmpty(encodedPath)) {
logger.severe("Can't download file with empty path");
return;
}
FileDownloadPath path = AutoBeanUtil.decode(FileDownloadPath.class, encodedPath);
switch(path.getType()) {
case BLOBSTORE_BLOB:
BlobstoreService blobstore = BlobstoreServiceFactory.getBlobstoreService();
BlobKey blobKey = new BlobKey(path.getKeyStr());
blobstore.serve(blobKey, resp);
break;
case DATASTORE_BLOB:
case DATASTORE_TEXT:
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Key key = KeyFactory.stringToKey(path.getKeyStr());
try {
Entity entity = datastore.get(key);
Object property = entity.getProperty(path.getFieldName());
if (property instanceof Blob) {
serve(((Blob) property).getBytes(), resp);
} else if (property instanceof Text) {
serve(((Text) property).getValue().getBytes(), resp);
} else if (property instanceof List) {
Object obj = ((List) property).get(path.getIndex());
if (obj instanceof Blob) {
serve(((Blob) obj).getBytes(), resp);
} else if (obj instanceof Text) {
serve(((Text) obj).getValue().getBytes(), resp);
}
}
} catch (EntityNotFoundException e) {
e.printStackTrace();
logger.log(Level.SEVERE, e.getMessage(), e);
}
break;
case MEMCACHE:
String cacheKey = path.getKeyStr();
byte [] cache = (byte[]) memcache.get(cacheKey);
if (cache == null) {
serve("Cache expired, please upload again".getBytes(), resp);
} else {
serve(cache, resp);
}
break;
}
}
private void serve(byte[] bytes, HttpServletResponse resp) throws IOException {
resp.setContentType("application/octet-stream");
resp.setContentLength(bytes.length);
resp.getOutputStream().write(bytes);
}
}