I can write to the blobstore smaller files, but when I try larger writes I'm getting errrors (done in task). I'm not sure as to why I'm getting FileWriteChannel writeChannel throwing "java.io.IOException" yet. Its a bit vague on its reason why theres a problem. Is there a time limit thats not being traced?
I decode on the fly and write to blobstore. I am having good success with smaller to medium <5MB files, but when I go larger, streaming the writes are causing problem above. This works perfectly on the dev side. But I'm wondering if there is a time limit in the filewrite not showing up. This is done in a task.
My class thats throwing the error:
package org.gonevertical.core.server.jdo.data.base64;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.gonevertical.core.client.ui.admin.blobs.BlobData;
import org.gonevertical.core.client.ui.admin.blobs.FileByteData;
import org.gonevertical.core.client.ui.admin.blobs.file.FileData;
import org.gonevertical.core.client.ui.admin.thingstuff.ThingStuffData;
import org.gonevertical.core.client.ui.admin.thingstufftype.ThingStuffTypeData;
import org.gonevertical.core.client.ui.admin.thingtype.ThingTypeData;
import org.gonevertical.core.server.ServerPersistence;
import org.gonevertical.core.server.db.Db_Thing;
import org.gonevertical.core.server.jdo.data.ThingStuffJdo;
import com.google.appengine.api.blobstore.BlobKey;
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.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Text;
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.FinalizationException;
import com.google.appengine.api.files.LockException;
public class WriteBase64 {
private static final Logger log = Logger.getLogger(WriteBase64.class.getName());
private final char[] BASE64ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
private int[] toInt = new int[128];
private ServerPersistence sp;
private FileByteData fbd;
private AppEngineFile file;
private FileWriteChannel writeChannel;
private FileService fileService;
private long newfileThingId;
private String filename;
private boolean success;
public WriteBase64(ServerPersistence sp) {
this.sp = sp;
for (int i=0; i < BASE64ALPHA.length; i++){
toInt[BASE64ALPHA[i]] = i;
}
}
public boolean decodeToBlob(FileByteData fbd) {
this.fbd = fbd;
if (fbd == null) {
return false;
}
// init the filewriting
success = initBlobWrite();
if (success == false) {
return false;
}
decode();
if (success == false) {
return false;
}
// close and create a newFileThingId
close();
return success;
}
public long getThingId() {
return newfileThingId;
}
private void close() {
try {
writeChannel.closeFinally();
} catch (IllegalStateException e) {
log.severe("close(): Error 6:" + e.toString());
e.printStackTrace();
} catch (IOException e) {
log.severe("close(): Error 7:" + e.toString());
e.printStackTrace();
}
BlobKey blobKey = fileService.getBlobKey(file);
if (blobKey == null) {
log.severe("close(): Blobkey was null. trying workaround.");
blobKey = tryfindingBlobKey();
if (blobKey == null) {
success = false;
log.severe("close(): Blobkey was null.");
return;
}
}
// create file thing
Db_Thing dbT = new Db_Thing(sp);
long fid = dbT.createThing(ThingTypeData.TYPE_BLOBS);
setNewFileThingId(fid);
// link file to parentthingid
ThingStuffJdo tsj = new ThingStuffJdo(sp);
//tsj.saveStuff_ThingLink(fbd.getLinkTypeId(), fbd.getLinkToThingId(), fid); // this can't be done here, due to not saving the links
BlobData blobData = new BlobData();
blobData.setKey(blobKey.getKeyString());
FileData fileData = new FileData();
fileData.setBlobData(blobData);
ThingStuffData tsd = new ThingStuffData();
tsd.setParentThingId(fid);
tsd.setStuffTypeId(ThingStuffTypeData.THINGSTUFFTYPE_BLOB);
tsd.setFileData(fileData);
tsj.saveUniqueStuffTypeIdForParentThingId(tsd);
//log.info("newFileThingId=" + newfileThingId);
}
private BlobKey tryfindingBlobKey() {
// TODO!!!!
return null;
}
private void setNewFileThingId(long fid) {
this.newfileThingId = fid;
}
private boolean initBlobWrite() {
if (fbd == null) {
return false;
}
// WORKAROUND - this will help, when blobkey is found to be null
filename = fbd.getFileName();
//filename = StringUtils.getRandomString(5) + "_" + filename;
fileService = FileServiceFactory.getFileService();
try {
file = fileService.createNewBlobFile(fbd.getContentType(), filename);
success = true;
log.info("initBlobWrite(): INFO: success in setting up file.");
} catch (IOException e) {
success = false;
log.severe("initBlobWrite(): Error 1:" + e.toString());
e.printStackTrace();
}
boolean lock = true;
try {
writeChannel = fileService.openWriteChannel(file, lock);
success = true;
log.info("initBlobWrite(): INFO: success in setting up writechannel.");
} catch (FileNotFoundException e) {
success = false;
log.severe("initBlobWrite(): Error 2:" + e.toString());
e.printStackTrace();
} catch (FinalizationException e) {
success = false;
log.severe("initBlobWrite(): Error 2.5:" + e.toString());
e.printStackTrace();
} catch (LockException e) {
success = false;
log.severe("initBlobWrite(): Error 3:" + e.toString());
e.printStackTrace();
} catch (IOException e) {
success = false;
log.severe("initBlobWrite(): Error 4:" + e.toString());
e.printStackTrace();
}
return success;
}
/**
* query the chunks, start to middle chunks must be divisible by 4, except end
*
* @return
*/
private void decode() {
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
try {
Query q = new Query("BlobTmpJdo");
q.addFilter("key", FilterOperator.EQUAL, fbd.getKey());
q.addSort("index");
PreparedQuery e = datastore.prepare(q);
Iterator<Entity> itr = e.asIterator();
while (itr.hasNext()) {
Entity entity = itr.next();
Text tb64 = (Text) entity.getProperty("base64");
if (tb64 != null) {
String b64 = tb64.getValue();
//log.info("query(): index=" + entity.getProperty("index") + " base64=" + tb64.getValue());
decode(b64);
if (success == false) { // quit going forward if a process has failed
// break; // TODO enable in the future
}
} else {
// TODO deal with error
log.warning("query(): index=" + entity.getProperty("index") + " base64=" + tb64);
}
}
} catch (Exception e) {
success = false;
log.log(Level.SEVERE, "", e);
e.printStackTrace();
}
}
private void decode(String b64) {
ByteArrayOutputStream out = null;
try {
out = null;
int mask = 0xFF;
int index = 0;
for (int i=0; i < b64.length(); i+=4) {
if (out == null) {
out = new ByteArrayOutputStream();
}
int c0 = toInt[b64.charAt(i)]; // char 1
int c1 = toInt[b64.charAt(i + 1)]; // char 2
byte b1 = (byte) (((c0 << 2) | (c1 >> 4)) & mask);
out.write(b1);
index++;
if (index >= b64.length()) {
break;
}
int c2 = toInt[b64.charAt(i + 2)]; // char 3
byte b2 = (byte) (((c1 << 4) | (c2 >> 2)) & mask);
out.write(b2);
index++;
if (index >= b64.length()) {
break;
}
int c3 = toInt[b64.charAt(i + 3)]; // char 4
byte b3 = (byte) (((c2 << 6) | c3) & mask);
out.write(b3);
}
} catch (Exception e) {
success = false;
log.severe("decode(b64): ERROR: can't decode base64.");
return;
}
if (out != null) {
writeToBlob(out);
}
}
private void writeToBlob(ByteArrayOutputStream out) {
if (out == null) {
log.info("writeToBlob(): INFO: ByteArrayOutputStream is null.");
return;
}
if (out.toByteArray() == null) {
log.info("writeToBlob(): INFO: ByteArrayOutputStream out.toByteArray() is null.");
return;
}
if (out.toByteArray().length == 0) {
log.info("writeToBlob(): INFO: ByteArrayOutputStream out.toByteArray().length is 0.");
return;
}
ByteBuffer bb = ByteBuffer.wrap(out.toByteArray());
try {
writeChannel.write(bb);
log.info("writeToBlob(): INFO: success in writing bytes");
} catch (IOException e) {
success = false;
log.severe("writeToBlob(): Error 5: " + e.toString());
//e.printStackTrace();
}
}
}
Brandon Donnelson