/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.vesalainen.parsers.sql.dsql;
import com.google.appengine.api.NamespaceManager;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.tools.remoteapi.RemoteApiInstaller;
import com.google.appengine.tools.remoteapi.RemoteApiOptions;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;
/**
* @author Timo Vesalainen
*/
public abstract class DatastoreProxy<T> implements Runnable, InvocationHandler
{
private String server;
private int port = 443;
private String user;
private String password;
private BlockingQueue<MethodCall> queue = new SynchronousQueue<>();
private Semaphore semaphore = new Semaphore(0);
private Thread thread;
private Class<T> cls;
private T proxy;
private String namespace;
public DatastoreProxy(String server, String namespace, String user, String password, Class<T> cls)
{
this.server = server;
this.namespace = namespace;
this.user = user;
this.password = password;
this.cls = cls;
}
public void start() throws InterruptedException
{
thread = new Thread(this, getClass().getName());
thread.setDaemon(true);
thread.start();
proxy = (T) Proxy.newProxyInstance(
cls.getClassLoader(),
new Class<?>[]
{
cls
},
this);
}
public T getProxy()
{
return proxy;
}
public void stop()
{
thread.interrupt();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
MethodCall mc = new MethodCall(proxy, method, args);
queue.put(mc);
semaphore.acquire();
if (mc.succeeded())
{
return mc.getReturnValue();
}
else
{
throw mc.getThrowable();
}
}
@Override
public void run()
{
try
{
RemoteApiInstaller installer = new RemoteApiInstaller();
RemoteApiOptions options = new RemoteApiOptions();
options.server(server, port);
options.credentials(user, password);
installer.install(options);
if (namespace != null)
{
NamespaceManager.set(namespace);
}
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
T engine = create(datastore);
while (true)
{
MethodCall mc = queue.take();
try
{
Object rv = mc.invoke(engine);
mc.setReturnValue(rv);
}
catch (InvocationTargetException ex)
{
mc.setThrowable(ex.getCause());
}
semaphore.release();
}
}
catch (InterruptedException ex)
{
}
catch (IOException ex)
{
throw new IllegalArgumentException(ex);
}
}
protected abstract T create(DatastoreService datastore);
private static class MethodCall
{
private Object proxy;
private Method method;
private Object[] args;
private Object returnValue;
private Throwable throwable;
public MethodCall(Object proxy, Method method, Object[] args)
{
this.proxy = proxy;
this.method = method;
this.args = args;
}
public Object invoke(Object obj) throws InvocationTargetException
{
try
{
return method.invoke(obj, args);
}
catch (IllegalAccessException ex)
{
throw new IllegalArgumentException(ex);
}
}
public boolean succeeded()
{
return throwable == null;
}
public Object[] getArgs()
{
return args;
}
public Method getMethod()
{
return method;
}
public Object getProxy()
{
return proxy;
}
public Object getReturnValue()
{
return returnValue;
}
public void setReturnValue(Object returnValue)
{
this.returnValue = returnValue;
}
public Throwable getThrowable()
{
return throwable;
}
public void setThrowable(Throwable throwable)
{
this.throwable = throwable;
}
}
}