package com.onpositive.gae.baseviewer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.swt.widgets.Display;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.apphosting.api.ApiProxy;
import com.onpositive.commons.ui.tableeditor.Field;
import com.onpositive.commons.ui.tableeditor.Filter;
import com.onpositive.commons.ui.tableeditor.IDataCallback;
import com.onpositive.commons.ui.tableeditor.ISingleCallback;
import com.onpositive.commons.ui.tableeditor.OperationCallback;
import com.onpositive.commons.ui.tableeditor.Query;
import com.onpositive.commons.ui.tableeditor.Sort;
import com.onpositive.gae.baseviewer.Request.ComplexFilter;
import com.onpositive.gae.baseviewer.Request.State;
import com.onpositive.gae.baseviewer.requests.IComplexFacade;
import com.onpositive.gae.baseviewer.requests.IComplexQueryRequest;
import com.onpositive.gae.baseviewer.requests.ReificationRequest;
import com.onpositive.gae.baseviewer.requests.SimpleRequest;
import com.onpositive.gae.tools.GaeBridge;
import com.onpositive.gae.tools.core.CheckLaunchJob;
import com.onpositive.gae.tools.core.DebugServerLaunchManager;
public class BlobStoreDataFacade extends BaseDataFacade {
public static final String BLOBKEY_PROP = "blobKey";
public static final String FILENAME_PROP = "fileName";
public static final String SIZEF_PROP = "size";
public static final String DATE_PROP = "created_at";
public static final String CONTENT_PROP = "content_type";
public BlobStoreDataFacade(String string, IJavaProject project2, boolean b,
IDataCallback ref, ISingleCallback call) {
super(string, project2, b);
kind = "Data_From_Blobstore";
refreshCallback = ref;
singleCall = call;
}
public synchronized void query(final Query query,
final IDataCallback callback) {
lastQuery = query;
objects.clear();
String url = getUrl();
if (url == null) {
return;
}
String string = "Querying data: " + kind + " (" + url + ")";
if (currentJob != null && currentJob.getState() != Job.NONE) {
currentJob.cancel();
try {
currentJob.join();
} catch (InterruptedException e) {
}
}
currentJob = new QueryJob(string, callback, query);
currentJob.schedule();
}
public void add(Object object, OperationCallback callback) {
Request r = new Request();
r.addPart(new Request.AddBlobPart(getUrl(), namespace));
try {
Object[] res = communicate(r, null, new NullProgressMonitor());
if (res.length == 1) {
String url = ((String) res[0]).substring(1);
String resAddr = (String) ((Entity) object)
.getProperty(FILENAME_PROP);
communicate(url, resAddr, new NullProgressMonitor(), callback,
(Entity) object);
} else {
callback.failed(new Exception("Error in data transmitting"));
}
} catch (IOException e) {
callback.failed(e);
}
}
public void communicate(String url, String resAddr,
IProgressMonitor monitor, final OperationCallback cb,
final Entity ent) {
String transformedURL = getUrl(url);
final HttpClient client = new HttpClient();
final PostMethod postMethod = new PostMethod(transformedURL);
File file = new File(resAddr);
try {
// postMethod.setParameter("filename",file.getName());
postMethod.setRequestEntity(new MultipartRequestEntity(
new Part[] { new FilePart(file.getName(), file/*
* ,
* "multipart/form-data"
* , "UTF-8"
*/) },
new HttpMethodParams()));
Job worker = new Job("Uploading blob") {
protected IStatus run(IProgressMonitor monitor) {
try {
client.executeMethod(postMethod);
cb.passed(ent);
} catch (HttpException e) {
cb.failed(e);
e.printStackTrace();
} catch (IOException e) {
cb.failed(e);
e.printStackTrace();
}
return Status.OK_STATUS;
}
};
worker.schedule();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public Field[] determineFields(List<?> results, Map<String, Field> fields) {
if (results.isEmpty()) {
if (this.fields == null) {
GAEField bkProp = new BlobField(BLOBKEY_PROP, true);
bkProp.setType(BlobKey.class);
GAEField fnProp = new BlobField(FILENAME_PROP, true);
fnProp.setType(String.class);
this.fields = new Field[] {/* bkProp, */fnProp };
}
return this.fields;
}
for (Object o : new ArrayList<Object>(results)) {
com.google.appengine.api.datastore.Entity r = (Entity) o;
Map<String, Object> properties = r.getProperties();
for (Entry<String, Object> m : properties.entrySet()) {
String key = m.getKey();
// if (key.equals(BLOBKEY_PROP)) {
// continue;
// }
GAEField f = new BlobField(m.getKey(), true);
GAEField field = (GAEField) fields.get(f.name);
Object value = m.getValue();
if (key.equals(BLOBKEY_PROP)) {
f.setType(BlobKey.class);
}
if (key.equals(FILENAME_PROP)) {
f.setType(String.class);
}
if (key.equals(SIZEF_PROP)) {
f.setType(Long.class);
}
if (key.equals(DATE_PROP)) {
f.setType(Date.class);
}
if (key.equals(CONTENT_PROP)) {
f.setType(String.class);
}
if (field != null) {
f = field;
} else {
fields.put(f.name, f);
}
updateValues(key, value);
}
}
Field[] array = fields.values().toArray(new Field[fields.size()]);
Arrays.sort(array);
BlobStoreDataFacade.this.fields = array;
return array;
}
public class BlobField extends GAEField{
protected BlobField(String name, boolean needsresize) {
super(name, needsresize);
}
@Override
public boolean needsFilter() {
return false;
}
}
private final class QueryJob extends Job {
private final class OrRunnable implements Runnable {
private final IComplexQueryRequest z;
private Boolean completed;
private HashSet<Object> results = new HashSet<Object>();
private OrRunnable(IComplexQueryRequest z) {
this.z = z;
}
public void run() {
z.execute(new IComplexFacade() {
public void query(String kind, Query req, Callback cb,
IProgressMonitor monitor) {
try {
new BaseDataFacade(kind, getProject(), debug)
.query(req, cb, monitor);
} catch (Exception e) {
// e.printStackTrace();
}
}
}, new Callback() {
public boolean objectFetched(Object object) {
if (object instanceof State) {
State c = (State) object;
completed = c.completed;
} else {
results.add(object);
}
return false;
}
}, new NullProgressMonitor());
}
}
private final IDataCallback callback;
private final Query query;
private QueryJob(String name, IDataCallback callback, Query query) {
super(name);
this.callback = callback;
this.query = query;
}
protected IStatus run(IProgressMonitor monitor) {
setStatus("Querying");
completed = false;
Request r = new Request();
ApiProxy.setEnvironmentForCurrentThread(new FakeEnvironment(
getAppId()));
r.addPart(new Request.ViewBlobPart(limit, namespace));
final ArrayList<Entity> results = new ArrayList<Entity>();
callback.start();
objects.clear();
ReadCallback cb = new ReadCallback(callback, results, fieldsMap,
objects);
try {
communicate(r, cb, monitor);
} catch (IOException e) {
callback.failed(e);
}
if (cb.getCm() != null) {
completed = cb.getCm().completed && !cb.reachedLimit;
}
if (cb.getCm() != null && cb.getCm().message != null) {
if (cb.getCm().trace
.startsWith("com.google.appengine.api.datastore.DatastoreNeedIndexException")) {
// let's attempt to remove sorting first
if (query.sort != null && query.sort.property != null
&& query.sort.property.length() > 0) {
callback.removeSort();
query.sort = new Sort("", false);
Thread thread = new Thread() {
public void run() {
query(query, callback);
}
};
thread.setDaemon(true);
thread.start();
return Status.OK_STATUS;
} else {
callback.failed(cb.getCm().message);
}
} else {
callback.failed(cb.getCm().message);
}
}
Field[] determineFields = determineFields(cb.allEntities, fieldsMap);
for (Field f : determineFields) {
if (f.name.equals(Entity.KEY_RESERVED_PROPERTY)) {
f.setType(Key.class);
} else if (f.getType() == null) {
f.setType(String.class);
}
}
callback.fieldsFetched(determineFields);
ArrayList<Entity> results2 = cb.results;
callback.objectsFetched(results2.toArray());
if (completed) {
setStatus("Completed: " + cb.allEntities.size()
+ " entities fetched"
+ (limit != -1 ? " (limit:" + limit + ")" : ""));
} else {
setStatus("Completed: " + cb.allEntities.size()
+ " of ? entities fetched"
+ (limit != -1 ? " (limit:" + limit + ")" : ""));
}
if (results.size() > 0) {
Entity e = (Entity) results.get(0);
if (pm != null) {
pm.setAppId(e.getAppId());
}
}
return Status.OK_STATUS;
}
private IComplexQueryRequest toRequest(Filter f) {
if (f.kind == Filter.COMPLEX_FILTER) {
final ComplexFilter filter = (ComplexFilter) f.value;
final Filter[] parseValue = filter.field.parseValue(filter);
if (parseValue != null) {
return new ReificationRequest(new SimpleRequest(
filter.field.keyKind, new Query(parseValue,
new Sort("", false), limit, 0), limit),
limit) {
protected IComplexQueryRequest toQuery(Object object) {
Entity e = (Entity) object;
Key key = e.getKey();
return new SimpleRequest(kind, new Query(
new Filter[] { new Filter(
filter.field.name, Filter.EQUAL,
key) }, new Sort("", true), 100,
100), 100);
}
public void filter(HashSet<Object> r) {
waitWhileNotDone();
HashSet<Object> toREtain = new HashSet<Object>();
for (Object o : r) {
Entity e = (Entity) o;
Object property = e
.getProperty(filter.field.name);
if (property instanceof Collection) {
Collection c = (Collection) property;
for (Object o1 : c) {
if (matching.contains(property)) {
toREtain.add(o1);
break;
}
}
} else {
if (matching.contains(property)) {
toREtain.add(o);
}
}
}
r.retainAll(toREtain);
}
};
}
return null;
}
return new SimpleRequest(kind, new Query(new Filter[] { f },
new Sort("", false), limit, 0), limit);
}
}
protected void init() {
}
protected String getUrl(String suffix) {
String connectionString = null;
new Check() {
protected void internalRun(IJavaProject project) {
}
}.doCheck(project);
if (debug) {
int port = DebugServerLaunchManager.getPort(project);
if (port == -1) {
CheckLaunchJob checkLaunchJob = new CheckLaunchJob(
"Checking Launch", project, true);
// try {
checkLaunchJob.schedule();
// int a = 0;
long l1 = System.currentTimeMillis();
long l2 = System.currentTimeMillis();
while (checkLaunchJob.getResult() == null && (l2 - l1) <= 30000) {
Thread.yield();
Display.getCurrent().readAndDispatch();
l2 = System.currentTimeMillis();
// a++;
}
// } catch (InterruptedException e) {
// }
port = DebugServerLaunchManager.getPort(project);
if (port == -1) {
return null;
}
}
connectionString = "http://localhost:" + port + "/";
} else {
String appId = GaeBridge.getAppId(project.getProject());
String version = GaeBridge.getVersion(project.getProject());
if (appId == null || version == null) {
throw new RuntimeException();
}
connectionString = "http://" + version + ".latest." + appId
+ ".appspot.com/";
}
return connectionString + suffix;
}
public void store(Object object, OperationCallback callback, String filepath) {
Request r = new Request();
r.addPart(new Request.StoreBlobPart((Entity) object, filepath,
namespace));
try {
Object[] res = communicate(r, null, new NullProgressMonitor());
if (res.length == 1 && ((Integer) res[0]) > 0) {
callback.passed(object);
} else {
callback.failed(new Exception("Error inside data transmitting"));
}
} catch (IOException e) {
callback.failed(e);
}
return;
}
public void refresh() {
Query currentQuery = getCurrentQuery();
updateFilters(currentQuery);
if (refreshCallback != null) {
query(currentQuery, refreshCallback);
}
}
public void delete(Object[] object, OperationCallback callback) {
Request r = new Request();
for (Object o : object) {
r.addPart(new Request.RemoveBlobPart(o, namespace));
}
try {
communicate(r, null, new NullProgressMonitor());
callback.passed(null);
} catch (IOException e) {
callback.failed(e);
}
}
}