Changed Java packages com.google.gridworks.* to com.google.refine.* and modified other code just enough to start grefine up without error. Much remains to be done. Do not check out the code just yet.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@1288 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-09-22 17:04:10 +00:00
parent a40a09b391
commit edb23eb263
854 changed files with 42529 additions and 42531 deletions

View File

@ -1,243 +0,0 @@
package com.google.gridworks.appengine;
import static com.google.appengine.api.urlfetch.FetchOptions.Builder.allowTruncate;
import java.io.ByteArrayOutputStream;
import java.net.InetAddress;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLSession;
import org.apache.http.Header;
import org.apache.http.HttpConnectionMetrics;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
import com.google.appengine.api.urlfetch.HTTPHeader;
import com.google.appengine.api.urlfetch.HTTPMethod;
import com.google.appengine.api.urlfetch.HTTPRequest;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
class AppEngineClientConnection implements ManagedClientConnection {
// Managed is the composition of ConnectionReleaseTrigger,
// HttpClientConnection, HttpConnection, HttpInetConnection
private HttpRoute _route;
private Object _state;
private boolean _reuseable;
public AppEngineClientConnection(HttpRoute route, Object state) {
_route = route;
_state = state;
}
// ManagedClientConnection methods
public HttpRoute getRoute() {
return _route;
}
public Object getState() {
return _state;
}
public SSLSession getSSLSession() {
return null;
}
public boolean isSecure() {
// XXX maybe parse the url to see if it's https?
return false;
}
public boolean isMarkedReusable() {
return _reuseable;
}
public void markReusable() {
_reuseable = true;
}
public void layerProtocol(HttpContext context, HttpParams params) {
return;
}
public void open(HttpRoute route, HttpContext context, HttpParams params) {
return;
}
public void setIdleDuration(long duration, TimeUnit unit) {
return;
}
public void setState(Object state) {
_state = state;
}
public void tunnelProxy(HttpHost next, boolean secure, HttpParams params) {
return;
}
public void tunnelTarget(boolean secure, HttpParams params) {
return;
}
public void unmarkReusable() {
_reuseable = false;
}
// ConnectionReleaseTrigger methods
public void releaseConnection() {
return;
}
public void abortConnection() {
return;
}
// HttpClientConnection methods
private HTTPRequest _appengine_hrequest;
private HTTPResponse _appengine_hresponse;
public void flush() {
return;
}
public boolean isResponseAvailable(int timeout) {
// XXX possibly use Async fetcher
return true;
}
public void receiveResponseEntity(org.apache.http.HttpResponse apache_response) {
byte[] data = _appengine_hresponse.getContent();
if (data != null) {
apache_response.setEntity(new ByteArrayEntity(data));
}
}
public HttpResponse receiveResponseHeader() {
URLFetchService ufs = URLFetchServiceFactory.getURLFetchService();
try {
_appengine_hresponse = ufs.fetch(_appengine_hrequest);
} catch (java.io.IOException e) {
throw new RuntimeException(e);
}
org.apache.http.HttpResponse apache_response =
new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 0),
_appengine_hresponse.getResponseCode(),
null);
for (HTTPHeader h : _appengine_hresponse.getHeaders()) {
apache_response.addHeader(h.getName(), h.getValue());
}
return apache_response;
}
public void sendRequestEntity(org.apache.http.HttpEntityEnclosingRequest request) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
org.apache.http.HttpEntity ent = request.getEntity();
if (ent != null) {
try {
ent.writeTo(os);
} catch (java.io.IOException e) {
throw new RuntimeException(e);
}
}
_appengine_hrequest.setPayload(os.toByteArray());
}
public void sendRequestHeader(org.apache.http.HttpRequest apache_request) {
URL request_url;
HttpHost host = _route.getTargetHost();
String protocol = host.getSchemeName();
String addr = host.getHostName();
int port = host.getPort();
String path = apache_request.getRequestLine().getUri();
try {
request_url = new URL(protocol, addr, port, path);
} catch (java.net.MalformedURLException e) {
throw new RuntimeException(e);
}
HTTPMethod method = HTTPMethod.valueOf(apache_request.getRequestLine().getMethod());
_appengine_hrequest = new HTTPRequest(request_url, method, allowTruncate()
.doNotFollowRedirects());
Header[] apache_headers = apache_request.getAllHeaders();
for (int i = 0; i < apache_headers.length; i++) {
Header h = apache_headers[i];
_appengine_hrequest
.setHeader(new HTTPHeader(h.getName(), h.getValue()));
}
}
// HttpConnection methods
public void close() {
return;
}
public HttpConnectionMetrics getMetrics() {
return null;
}
public int getSocketTimeout() {
return -1;
}
public boolean isOpen() {
return true;
}
public boolean isStale() {
return false;
}
public void setSocketTimeout(int timeout) {
return;
}
public void shutdown() {
return;
}
// HttpInetConnection methods
public InetAddress getLocalAddress() {
return null;
}
public int getLocalPort() {
return -1;
}
public InetAddress getRemoteAddress() {
return null;
}
public int getRemotePort() {
return -1;
}
}

View File

@ -1,76 +0,0 @@
package com.google.gridworks.appengine;
import java.net.InetAddress;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SocketFactory;
import org.apache.http.params.HttpParams;
public class AppEngineClientConnectionManager implements ClientConnectionManager {
private SchemeRegistry schemes;
class NoopSocketFactory implements SocketFactory {
public Socket connectSocket(Socket sock, String host, int port, InetAddress addr, int lport, HttpParams params) {
return null;
}
public Socket createSocket() {
return null;
}
public boolean isSecure(Socket sock) {
return false;
}
}
public AppEngineClientConnectionManager() {
SocketFactory noop_sf = new NoopSocketFactory();
schemes = new SchemeRegistry();
schemes.register(new Scheme("http", noop_sf, 80));
schemes.register(new Scheme("https", noop_sf, 443));
}
public void closeExpiredConnections() {
return;
}
public void closeIdleConnections(long idletime, TimeUnit tunit) {
return;
}
public ManagedClientConnection getConnection(HttpRoute route, Object state) {
return new AppEngineClientConnection(route, state);
}
public SchemeRegistry getSchemeRegistry() {
return schemes;
}
public void releaseConnection(ManagedClientConnection conn, long valid, TimeUnit tuint) {
return;
}
public ClientConnectionRequest requestConnection(final HttpRoute route, final Object state) {
return new ClientConnectionRequest() {
public void abortRequest() {
return;
}
public ManagedClientConnection getConnection(long idletime, TimeUnit tunit) {
return AppEngineClientConnectionManager.this.getConnection(route, state);
}
};
}
public void shutdown() {
return;
}
}

View File

@ -1,373 +0,0 @@
package com.google.gridworks.broker;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import javax.jdo.Extent;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Transaction;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.appengine.api.datastore.Text;
import com.google.gridworks.appengine.AppEngineClientConnectionManager;
import com.google.gridworks.broker.GridworksBroker;
public class AppEngineGridworksBrokerImpl extends GridworksBroker {
protected static final Logger logger = LoggerFactory.getLogger("gridworks.broker.appengine");
PersistenceManagerFactory pmfInstance;
@Override
public void init(ServletConfig config) throws Exception {
super.init(config);
pmfInstance = JDOHelper.getPersistenceManagerFactory("transactional");
}
@Override
public void destroy() throws Exception {
}
// ---------------------------------------------------------------------------------
protected HttpClient getHttpClient() {
ClientConnectionManager cm = new AppEngineClientConnectionManager();
return new DefaultHttpClient(cm, null);
}
// ---------------------------------------------------------------------------------
protected void expire(HttpServletResponse response) throws Exception {
// TODO: implement
}
protected void startProject(HttpServletResponse response, String pid, String uid, String lock, byte[] data, String metadata, List<String> transformations) throws Exception {
// TODO: implement
}
protected void expireLocks(HttpServletResponse response) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
Extent<Lock> extent = pm.getExtent(Lock.class, false);
try {
for (Lock lock : extent) {
if (lock.timestamp + LOCK_DURATION < System.currentTimeMillis()) {
Transaction tx = pm.currentTransaction();
try {
tx.begin();
pm.deletePersistent(lock);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
}
}
} finally {
extent.closeAll();
}
respond(response, OK);
} finally {
pm.close();
}
}
protected void getState(HttpServletResponse response, String pid, String uid, int rev) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
// TODO: implement
respond(response, lockToJSON(getLock(pm,pid)));
} finally {
pm.close();
}
}
protected void obtainLock(HttpServletResponse response, String pid, String uid, int locktype, String lockvalue) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
// TODO: implement
try {
Lock lock = getLock(pm, pid);
if (lock == null) {
Transaction tx = pm.currentTransaction();
try {
tx.begin();
lock = new Lock(Long.toHexString(tx.hashCode()), pid, uid);
pm.makePersistent(lock);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
}
respond(response, lockToJSON(lock));
} finally {
pm.close();
}
}
protected void releaseLock(HttpServletResponse response, String pid, String uid, String lid) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
Lock lock = getLock(pm, pid);
if (lock != null) {
if (!lock.id.equals(lid)) {
throw new RuntimeException("Lock id doesn't match, can't release the lock");
}
if (!lock.uid.equals(uid)) {
throw new RuntimeException("User id doesn't match the lock owner, can't release the lock");
}
Transaction tx = pm.currentTransaction();
try {
tx.begin();
pm.deletePersistent(lock);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
}
respond(response, OK);
} finally {
pm.close();
}
}
// ----------------------------------------------------------------------------------------------------
protected void startProject(HttpServletResponse response, String pid, String uid, String lid, String data) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
checkLock(pm, pid, uid, lid);
Project project = getProject(pm, pid);
if (project != null) {
throw new RuntimeException("Project '" + pid + "' already exists");
}
Transaction tx = pm.currentTransaction();
try {
tx.begin();
project = new Project(pid, data);
pm.makePersistent(project);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
respond(response, OK);
} finally {
pm.close();
}
}
protected void addTransformations(HttpServletResponse response, String pid, String uid, String lid, List<String> transformations) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
checkLock(pm, pid, uid, lid);
Project project = getProject(pm, pid);
if (project == null) {
throw new RuntimeException("Project '" + pid + "' not found");
}
Transaction tx = pm.currentTransaction();
try {
for (String s : transformations) {
project.transformations.add(new Text(s));
}
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
respond(response, OK);
} finally {
pm.close();
}
}
// ---------------------------------------------------------------------------------
protected void openProject(HttpServletResponse response, String pid) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
Project project = getProject(pm, pid);
Writer w = response.getWriter();
JSONWriter writer = new JSONWriter(w);
writer.object();
writer.key("data"); writer.value(project.data.toString());
writer.key("transformations");
writer.array();
for (Text s : project.transformations) {
writer.value(s.toString());
}
writer.endArray();
writer.endObject();
w.flush();
w.close();
} finally {
pm.close();
}
}
protected void getHistory(HttpServletResponse response, String pid, int tindex) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
Project project = getProject(pm, pid);
Writer w = response.getWriter();
JSONWriter writer = new JSONWriter(w);
writer.object();
writer.key("transformations");
writer.array();
int size = project.transformations.size();
for (int i = tindex; i < size; i++) {
writer.value(project.transformations.get(i).toString());
}
writer.endArray();
writer.endObject();
w.flush();
w.close();
} finally {
pm.close();
}
}
// ---------------------------------------------------------------------------------
Project getProject(PersistenceManager pm, String pid) {
Project project = pm.getObjectById(Project.class, pid);
if (project == null) {
throw new RuntimeException("Project '" + pid + "' is not managed by this broker");
}
return project;
}
@PersistenceCapable
static class Project {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
String pid;
@Persistent
List<Text> transformations = new ArrayList<Text>();
@Persistent
Text data;
Project(String pid, String data) {
this.pid = pid;
this.data = new Text(data);
}
}
// ---------------------------------------------------------------------------------
Lock getLock(PersistenceManager pm, String pid) {
return pm.getObjectById(Lock.class, pid);
}
void checkLock(PersistenceManager pm, String pid, String uid, String lid) {
Lock lock = getLock(pm, pid);
if (lock == null) {
throw new RuntimeException("No lock was found with the given Lock id '" + lid + "', you have to have a valid lock on a project in order to start it");
}
if (!lock.pid.equals(pid)) {
throw new RuntimeException("Lock '" + lid + "' is for another project: " + pid);
}
if (!lock.uid.equals(uid)) {
throw new RuntimeException("Lock '" + lid + "' is owned by another user: " + uid);
}
}
JSONObject lockToJSON(Lock lock) throws JSONException {
JSONObject o = new JSONObject();
if (lock != null) {
o.put("lock_id", lock.id);
o.put("project_id", lock.pid);
o.put("user_id", lock.uid);
o.put("timestamp", lock.timestamp);
}
return o;
}
@PersistenceCapable
static class Lock {
@Persistent
String id;
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
String pid;
@Persistent
String uid;
@Persistent
long timestamp;
Lock(String id, String pid, String uid) {
this.id = id;
this.pid = pid;
this.uid = uid;
this.timestamp = System.currentTimeMillis();
}
}
}

View File

@ -0,0 +1,243 @@
package com.google.refine.appengine;
import static com.google.appengine.api.urlfetch.FetchOptions.Builder.allowTruncate;
import java.io.ByteArrayOutputStream;
import java.net.InetAddress;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLSession;
import org.apache.http.Header;
import org.apache.http.HttpConnectionMetrics;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
import com.google.appengine.api.urlfetch.HTTPHeader;
import com.google.appengine.api.urlfetch.HTTPMethod;
import com.google.appengine.api.urlfetch.HTTPRequest;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
class AppEngineClientConnection implements ManagedClientConnection {
// Managed is the composition of ConnectionReleaseTrigger,
// HttpClientConnection, HttpConnection, HttpInetConnection
private HttpRoute _route;
private Object _state;
private boolean _reuseable;
public AppEngineClientConnection(HttpRoute route, Object state) {
_route = route;
_state = state;
}
// ManagedClientConnection methods
public HttpRoute getRoute() {
return _route;
}
public Object getState() {
return _state;
}
public SSLSession getSSLSession() {
return null;
}
public boolean isSecure() {
// XXX maybe parse the url to see if it's https?
return false;
}
public boolean isMarkedReusable() {
return _reuseable;
}
public void markReusable() {
_reuseable = true;
}
public void layerProtocol(HttpContext context, HttpParams params) {
return;
}
public void open(HttpRoute route, HttpContext context, HttpParams params) {
return;
}
public void setIdleDuration(long duration, TimeUnit unit) {
return;
}
public void setState(Object state) {
_state = state;
}
public void tunnelProxy(HttpHost next, boolean secure, HttpParams params) {
return;
}
public void tunnelTarget(boolean secure, HttpParams params) {
return;
}
public void unmarkReusable() {
_reuseable = false;
}
// ConnectionReleaseTrigger methods
public void releaseConnection() {
return;
}
public void abortConnection() {
return;
}
// HttpClientConnection methods
private HTTPRequest _appengine_hrequest;
private HTTPResponse _appengine_hresponse;
public void flush() {
return;
}
public boolean isResponseAvailable(int timeout) {
// XXX possibly use Async fetcher
return true;
}
public void receiveResponseEntity(org.apache.http.HttpResponse apache_response) {
byte[] data = _appengine_hresponse.getContent();
if (data != null) {
apache_response.setEntity(new ByteArrayEntity(data));
}
}
public HttpResponse receiveResponseHeader() {
URLFetchService ufs = URLFetchServiceFactory.getURLFetchService();
try {
_appengine_hresponse = ufs.fetch(_appengine_hrequest);
} catch (java.io.IOException e) {
throw new RuntimeException(e);
}
org.apache.http.HttpResponse apache_response =
new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 0),
_appengine_hresponse.getResponseCode(),
null);
for (HTTPHeader h : _appengine_hresponse.getHeaders()) {
apache_response.addHeader(h.getName(), h.getValue());
}
return apache_response;
}
public void sendRequestEntity(org.apache.http.HttpEntityEnclosingRequest request) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
org.apache.http.HttpEntity ent = request.getEntity();
if (ent != null) {
try {
ent.writeTo(os);
} catch (java.io.IOException e) {
throw new RuntimeException(e);
}
}
_appengine_hrequest.setPayload(os.toByteArray());
}
public void sendRequestHeader(org.apache.http.HttpRequest apache_request) {
URL request_url;
HttpHost host = _route.getTargetHost();
String protocol = host.getSchemeName();
String addr = host.getHostName();
int port = host.getPort();
String path = apache_request.getRequestLine().getUri();
try {
request_url = new URL(protocol, addr, port, path);
} catch (java.net.MalformedURLException e) {
throw new RuntimeException(e);
}
HTTPMethod method = HTTPMethod.valueOf(apache_request.getRequestLine().getMethod());
_appengine_hrequest = new HTTPRequest(request_url, method, allowTruncate()
.doNotFollowRedirects());
Header[] apache_headers = apache_request.getAllHeaders();
for (int i = 0; i < apache_headers.length; i++) {
Header h = apache_headers[i];
_appengine_hrequest
.setHeader(new HTTPHeader(h.getName(), h.getValue()));
}
}
// HttpConnection methods
public void close() {
return;
}
public HttpConnectionMetrics getMetrics() {
return null;
}
public int getSocketTimeout() {
return -1;
}
public boolean isOpen() {
return true;
}
public boolean isStale() {
return false;
}
public void setSocketTimeout(int timeout) {
return;
}
public void shutdown() {
return;
}
// HttpInetConnection methods
public InetAddress getLocalAddress() {
return null;
}
public int getLocalPort() {
return -1;
}
public InetAddress getRemoteAddress() {
return null;
}
public int getRemotePort() {
return -1;
}
}

View File

@ -0,0 +1,76 @@
package com.google.refine.appengine;
import java.net.InetAddress;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SocketFactory;
import org.apache.http.params.HttpParams;
public class AppEngineClientConnectionManager implements ClientConnectionManager {
private SchemeRegistry schemes;
class NoopSocketFactory implements SocketFactory {
public Socket connectSocket(Socket sock, String host, int port, InetAddress addr, int lport, HttpParams params) {
return null;
}
public Socket createSocket() {
return null;
}
public boolean isSecure(Socket sock) {
return false;
}
}
public AppEngineClientConnectionManager() {
SocketFactory noop_sf = new NoopSocketFactory();
schemes = new SchemeRegistry();
schemes.register(new Scheme("http", noop_sf, 80));
schemes.register(new Scheme("https", noop_sf, 443));
}
public void closeExpiredConnections() {
return;
}
public void closeIdleConnections(long idletime, TimeUnit tunit) {
return;
}
public ManagedClientConnection getConnection(HttpRoute route, Object state) {
return new AppEngineClientConnection(route, state);
}
public SchemeRegistry getSchemeRegistry() {
return schemes;
}
public void releaseConnection(ManagedClientConnection conn, long valid, TimeUnit tuint) {
return;
}
public ClientConnectionRequest requestConnection(final HttpRoute route, final Object state) {
return new ClientConnectionRequest() {
public void abortRequest() {
return;
}
public ManagedClientConnection getConnection(long idletime, TimeUnit tunit) {
return AppEngineClientConnectionManager.this.getConnection(route, state);
}
};
}
public void shutdown() {
return;
}
}

View File

@ -0,0 +1,373 @@
package com.google.refine.broker;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import javax.jdo.Extent;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Transaction;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.appengine.api.datastore.Text;
import com.google.refine.appengine.AppEngineClientConnectionManager;
import com.google.refine.broker.GridworksBroker;
public class AppEngineGridworksBrokerImpl extends GridworksBroker {
protected static final Logger logger = LoggerFactory.getLogger("gridworks.broker.appengine");
PersistenceManagerFactory pmfInstance;
@Override
public void init(ServletConfig config) throws Exception {
super.init(config);
pmfInstance = JDOHelper.getPersistenceManagerFactory("transactional");
}
@Override
public void destroy() throws Exception {
}
// ---------------------------------------------------------------------------------
protected HttpClient getHttpClient() {
ClientConnectionManager cm = new AppEngineClientConnectionManager();
return new DefaultHttpClient(cm, null);
}
// ---------------------------------------------------------------------------------
protected void expire(HttpServletResponse response) throws Exception {
// TODO: implement
}
protected void startProject(HttpServletResponse response, String pid, String uid, String lock, byte[] data, String metadata, List<String> transformations) throws Exception {
// TODO: implement
}
protected void expireLocks(HttpServletResponse response) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
Extent<Lock> extent = pm.getExtent(Lock.class, false);
try {
for (Lock lock : extent) {
if (lock.timestamp + LOCK_DURATION < System.currentTimeMillis()) {
Transaction tx = pm.currentTransaction();
try {
tx.begin();
pm.deletePersistent(lock);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
}
}
} finally {
extent.closeAll();
}
respond(response, OK);
} finally {
pm.close();
}
}
protected void getState(HttpServletResponse response, String pid, String uid, int rev) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
// TODO: implement
respond(response, lockToJSON(getLock(pm,pid)));
} finally {
pm.close();
}
}
protected void obtainLock(HttpServletResponse response, String pid, String uid, int locktype, String lockvalue) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
// TODO: implement
try {
Lock lock = getLock(pm, pid);
if (lock == null) {
Transaction tx = pm.currentTransaction();
try {
tx.begin();
lock = new Lock(Long.toHexString(tx.hashCode()), pid, uid);
pm.makePersistent(lock);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
}
respond(response, lockToJSON(lock));
} finally {
pm.close();
}
}
protected void releaseLock(HttpServletResponse response, String pid, String uid, String lid) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
Lock lock = getLock(pm, pid);
if (lock != null) {
if (!lock.id.equals(lid)) {
throw new RuntimeException("Lock id doesn't match, can't release the lock");
}
if (!lock.uid.equals(uid)) {
throw new RuntimeException("User id doesn't match the lock owner, can't release the lock");
}
Transaction tx = pm.currentTransaction();
try {
tx.begin();
pm.deletePersistent(lock);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
}
respond(response, OK);
} finally {
pm.close();
}
}
// ----------------------------------------------------------------------------------------------------
protected void startProject(HttpServletResponse response, String pid, String uid, String lid, String data) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
checkLock(pm, pid, uid, lid);
Project project = getProject(pm, pid);
if (project != null) {
throw new RuntimeException("Project '" + pid + "' already exists");
}
Transaction tx = pm.currentTransaction();
try {
tx.begin();
project = new Project(pid, data);
pm.makePersistent(project);
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
respond(response, OK);
} finally {
pm.close();
}
}
protected void addTransformations(HttpServletResponse response, String pid, String uid, String lid, List<String> transformations) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
checkLock(pm, pid, uid, lid);
Project project = getProject(pm, pid);
if (project == null) {
throw new RuntimeException("Project '" + pid + "' not found");
}
Transaction tx = pm.currentTransaction();
try {
for (String s : transformations) {
project.transformations.add(new Text(s));
}
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
respond(response, OK);
} finally {
pm.close();
}
}
// ---------------------------------------------------------------------------------
protected void openProject(HttpServletResponse response, String pid) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
Project project = getProject(pm, pid);
Writer w = response.getWriter();
JSONWriter writer = new JSONWriter(w);
writer.object();
writer.key("data"); writer.value(project.data.toString());
writer.key("transformations");
writer.array();
for (Text s : project.transformations) {
writer.value(s.toString());
}
writer.endArray();
writer.endObject();
w.flush();
w.close();
} finally {
pm.close();
}
}
protected void getHistory(HttpServletResponse response, String pid, int tindex) throws Exception {
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
Project project = getProject(pm, pid);
Writer w = response.getWriter();
JSONWriter writer = new JSONWriter(w);
writer.object();
writer.key("transformations");
writer.array();
int size = project.transformations.size();
for (int i = tindex; i < size; i++) {
writer.value(project.transformations.get(i).toString());
}
writer.endArray();
writer.endObject();
w.flush();
w.close();
} finally {
pm.close();
}
}
// ---------------------------------------------------------------------------------
Project getProject(PersistenceManager pm, String pid) {
Project project = pm.getObjectById(Project.class, pid);
if (project == null) {
throw new RuntimeException("Project '" + pid + "' is not managed by this broker");
}
return project;
}
@PersistenceCapable
static class Project {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
String pid;
@Persistent
List<Text> transformations = new ArrayList<Text>();
@Persistent
Text data;
Project(String pid, String data) {
this.pid = pid;
this.data = new Text(data);
}
}
// ---------------------------------------------------------------------------------
Lock getLock(PersistenceManager pm, String pid) {
return pm.getObjectById(Lock.class, pid);
}
void checkLock(PersistenceManager pm, String pid, String uid, String lid) {
Lock lock = getLock(pm, pid);
if (lock == null) {
throw new RuntimeException("No lock was found with the given Lock id '" + lid + "', you have to have a valid lock on a project in order to start it");
}
if (!lock.pid.equals(pid)) {
throw new RuntimeException("Lock '" + lid + "' is for another project: " + pid);
}
if (!lock.uid.equals(uid)) {
throw new RuntimeException("Lock '" + lid + "' is owned by another user: " + uid);
}
}
JSONObject lockToJSON(Lock lock) throws JSONException {
JSONObject o = new JSONObject();
if (lock != null) {
o.put("lock_id", lock.id);
o.put("project_id", lock.pid);
o.put("user_id", lock.uid);
o.put("timestamp", lock.timestamp);
}
return o;
}
@PersistenceCapable
static class Lock {
@Persistent
String id;
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
String pid;
@Persistent
String uid;
@Persistent
long timestamp;
Lock(String id, String pid, String uid) {
this.id = id;
this.pid = pid;
this.uid = uid;
this.timestamp = System.currentTimeMillis();
}
}
}

View File

@ -1,311 +0,0 @@
package com.google.gridworks.broker;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.mit.simile.butterfly.ButterflyModuleImpl;
/**
* This class contains all the code shared by various implementations of a Gridworks Broker.
*
* A broker is a server used by multiple Gridworks installations to enable collaborative
* development over the same project.
*
* Broker implementations differ in how they store their state but all of them are required
* to extend this abstract class and implement the services that are called via HTTP.
*
*/
public abstract class GridworksBroker extends ButterflyModuleImpl {
static final public String GET_STATE = "get_state";
static final public String EXPIRE = "expire";
static final public String OBTAIN_LOCK = "obtain_lock";
static final public String RELEASE_LOCK = "release_lock";
static final public String TRANSFORM = "transform";
static final public String START = "start";
static final public String OPEN = "open";
static final public int ALL = 0;
static final public int COL = 1;
static final public int CELL = 2;
static final protected Logger logger = LoggerFactory.getLogger("gridworks.broker");
static final protected String USER_INFO_URL = "http://www.freebase.com/api/service/user_info";
static final protected String DELEGATED_OAUTH_HEADER = "X-Freebase-Credentials";
static final protected String OAUTH_HEADER = "Authorization";
static protected String OK;
static {
try {
JSONObject o = new JSONObject();
o.put("status","ok");
OK = o.toString();
} catch (JSONException e) {
// not going to happen;
}
}
static public final long LOCK_DURATION = 60 * 1000; // 1 minute
static public final long USER_DURATION = 5 * 60 * 1000; // 1 minute
static public final long LOCK_EXPIRATION_CHECK_DELAY = 5 * 1000; // 5 seconds
protected HttpClient httpclient;
protected boolean developmentMode;
@Override
public void init(ServletConfig config) throws Exception {
super.init(config);
httpclient = getHttpClient();
developmentMode = Boolean.parseBoolean(config.getInitParameter("gridworks.development"));
if (developmentMode) logger.warn("Running in development mode");
}
@Override
public void destroy() throws Exception {
httpclient.getConnectionManager().shutdown();
}
@Override
public boolean process(String path, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("> process '{}'", path);
} else {
logger.info("process '{}'", path);
}
try {
if (GET_STATE.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
getState(response, getParameter(request, "pid"), getUserId(request), getInteger(request, "rev"));
} else if (EXPIRE.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
expire(response);
} else if (OBTAIN_LOCK.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
obtainLock(response, getParameter(request, "pid"), getUserId(request), getInteger(request, "locktype"), getParameter(request, "lockvalue"));
} else if (RELEASE_LOCK.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
releaseLock(response, getParameter(request, "pid"), getUserId(request), getParameter(request, "lock"));
} else if (TRANSFORM.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
addTransformations(response, getParameter(request, "pid"), getUserId(request), getParameter(request, "lock"), getList(request, "transformations"));
} else if (START.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
startProject(response, getParameter(request, "pid"), getUserId(request), getParameter(request, "lock"), getData(request), getParameter(request, "metadata"), getList(request, "transformations"));
} else if (OPEN.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
openProject(response, getParameter(request, "pid"));
} else {
boolean value = super.process(path, request, response);
if (logger.isDebugEnabled()) logger.debug("< process '{}'", path);
return value;
}
} catch (RuntimeException e) {
logger.error("runtime error", e.getMessage());
respondError(response, e.getMessage());
} catch (Exception e) {
logger.error("internal error", e);
respondException(response, e);
}
if (logger.isDebugEnabled()) logger.debug("< process '{}'", path);
return true;
}
// ----------------------------------------------------------------------------------------
protected abstract HttpClient getHttpClient();
protected abstract void expire(HttpServletResponse response) throws Exception;
protected abstract void getState(HttpServletResponse response, String pid, String uid, int rev) throws Exception;
protected abstract void obtainLock(HttpServletResponse response, String pid, String uid, int locktype, String lockvalue) throws Exception;
protected abstract void releaseLock(HttpServletResponse response, String pid, String uid, String lock) throws Exception;
protected abstract void startProject(HttpServletResponse response, String pid, String uid, String lock, byte[] data, String metadata, List<String> transformations) throws Exception;
protected abstract void addTransformations(HttpServletResponse response, String pid, String uid, String lock, List<String> transformations) throws Exception;
protected abstract void openProject(HttpServletResponse response, String pid) throws Exception;
// ----------------------------------------------------------------------------------------
@SuppressWarnings("unchecked")
protected String getUserId(HttpServletRequest request) throws Exception {
// This is useful for testing
if (developmentMode) {
return getParameter(request, "uid");
}
String oauth = request.getHeader(DELEGATED_OAUTH_HEADER);
if (oauth == null) {
throw new RuntimeException("The request needs to contain the '" + DELEGATED_OAUTH_HEADER + "' header set to obtain user identity via Freebase.");
}
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
Map<String,String> params = (Map<String,String>) request.getParameterMap();
for (Entry<String,String> e : params.entrySet()) {
formparams.add(new BasicNameValuePair((String) e.getKey(), (String) e.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8");
HttpPost httpRequest = new HttpPost(USER_INFO_URL);
httpRequest.setHeader(OAUTH_HEADER, oauth);
httpRequest.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "Gridworks Broker");
httpRequest.setEntity(entity);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String responseBody = httpclient.execute(httpRequest, responseHandler);
JSONObject o = new JSONObject(responseBody);
return o.getString("username");
}
// ----------------------------------------------------------------------------------------
static protected String getParameter(HttpServletRequest request, String name) throws ServletException {
String param = request.getParameter(name);
if (param == null) {
throw new RuntimeException("request must come with a '" + name + "' parameter");
}
return param;
}
static protected List<String> getList(HttpServletRequest request, String name) throws ServletException, JSONException {
String param = getParameter(request, name);
JSONArray a = new JSONArray(param);
List<String> result = new ArrayList<String>(a.length());
for (int i = 0; i < a.length(); i++) {
result.add(a.getString(i));
}
return result;
}
static protected int getInteger(HttpServletRequest request, String name) throws ServletException, JSONException {
return Integer.parseInt(getParameter(request, name));
}
static protected byte[] getData(HttpServletRequest request) throws ServletException, IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
InputStream input = request.getInputStream();
byte[] buffer = new byte[4096];
int count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return output.toByteArray();
}
static protected void respondError(HttpServletResponse response, String error) throws IOException, ServletException {
if (response == null) {
throw new ServletException("Response object can't be null");
}
try {
JSONObject o = new JSONObject();
o.put("status", "error");
o.put("message", error);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
respond(response, o.toString());
} catch (JSONException e) {
e.printStackTrace(response.getWriter());
}
}
static protected void respondException(HttpServletResponse response, Exception e) throws IOException, ServletException {
if (response == null) {
throw new ServletException("Response object can't be null");
}
try {
JSONObject o = new JSONObject();
o.put("status", "error");
o.put("message", e.getMessage());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
sw.flush();
o.put("stack", sw.toString());
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
respond(response, o.toString());
} catch (JSONException e1) {
e.printStackTrace(response.getWriter());
}
}
static protected void respond(HttpServletResponse response, JSONObject content) throws IOException, ServletException {
if (content == null) {
throw new ServletException("Content object can't be null");
}
respond(response, content.toString());
}
static protected void respond(HttpServletResponse response, String content) throws IOException, ServletException {
if (response == null) {
throw new ServletException("Response object can't be null");
}
Writer w = response.getWriter();
if (w != null) {
w.write(content);
w.flush();
w.close();
} else {
throw new ServletException("response returned a null writer");
}
}
}

View File

@ -1,592 +0,0 @@
package com.google.gridworks.broker;
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
import java.io.File;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.Transaction;
import com.sleepycat.persist.EntityCursor;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.PrimaryIndex;
import com.sleepycat.persist.SecondaryIndex;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.SecondaryKey;
public class GridworksBrokerImpl extends GridworksBroker {
protected static final Logger logger = LoggerFactory.getLogger("gridworks.broker.local");
Environment env;
EntityStore projectStore;
EntityStore lockStore;
EntityStore userStore;
PrimaryIndex<String,Project> projectById;
PrimaryIndex<String,Lock> lockById;
SecondaryIndex<String,String,Lock> locksByProject;
Timer timer;
Expirer expirer;
@Override
public void init(ServletConfig config) throws Exception {
logger.trace("> init");
super.init(config);
timer = new Timer();
expirer = new Expirer();
timer.schedule(expirer, 0, LOCK_EXPIRATION_CHECK_DELAY);
String dataDir = config.getInitParameter("gridworks.data");
if (dataDir == null) dataDir = "data";
File dataPath = new File(dataDir);
if (!dataPath.exists()) dataPath.mkdirs();
EnvironmentConfig envConfig = new EnvironmentConfig();
envConfig.setAllowCreate(true);
envConfig.setTransactional(true);
env = new Environment(dataPath, envConfig);
StoreConfig storeConfig = new StoreConfig();
storeConfig.setAllowCreate(true);
storeConfig.setTransactional(true);
projectStore = new EntityStore(env, "ProjectsStore", storeConfig);
lockStore = new EntityStore(env, "LockStore", storeConfig);
projectById = projectStore.getPrimaryIndex(String.class, Project.class);
lockById = lockStore.getPrimaryIndex(String.class, Lock.class);
locksByProject = lockStore.getSecondaryIndex(lockById, String.class, "pid");
logger.trace("< init");
}
@Override
public void destroy() throws Exception {
logger.trace("> destroy");
super.destroy();
if (projectStore != null) {
projectStore.close();
projectById = null;
}
if (lockStore != null) {
lockStore.close();
lockById = null;
}
if (timer != null) {
timer.cancel();
timer.purge();
timer = null;
}
if (env != null) {
env.close();
env = null;
}
logger.trace("< destroy");
}
class Expirer extends TimerTask {
public void run() {
if (lockById != null) {
logger.trace("> expire");
Transaction txn = env.beginTransaction(null, null);
try {
EntityCursor<Lock> cursor = lockById.entities();
try {
for (Lock lock : cursor) {
if (lock.timestamp + LOCK_DURATION < System.currentTimeMillis()) {
logger.trace("Found expired lock {}", lock.id);
try {
releaseLock(null, lock.pid, lock.uid, lock.id);
} catch (Exception e) {
logger.error("Exception while expiring lock for project '" + lock.pid + "'", e);
}
}
}
} finally {
cursor.close();
}
} finally {
if (txn != null) {
txn.abort();
txn = null;
}
}
logger.trace("< expire");
}
}
}
// ---------------------------------------------------------------------------------
@Override
protected HttpClient getHttpClient() {
return new DefaultHttpClient();
}
// ---------------------------------------------------------------------------------
@Override
protected void expire(HttpServletResponse response) throws Exception {
expirer.run();
respond(response, OK);
}
@Override
protected void obtainLock(HttpServletResponse response, String pid, String uid, int locktype, String lockvalue) throws Exception {
logger.trace("> obtain lock");
Lock lock = null;
Lock blocker = null;
Transaction txn = env.beginTransaction(null, null);
try {
EntityCursor<Lock> cursor = locksByProject.subIndex(pid).entities();
/*
* ALL
* blocked -> somebody else's lock
* reuse -> you already have an ALL lock
* new -> else
*
* COL
* blocked -> somebody else's all lock || a lock on the same col
* reuse -> you have an ALL lock || a lock on the same col
* new -> else
*
* CELL
* blocked -> somebody else's all lock || a lock on the same col || a lock on the same cell
* reuse -> you have a lock on the same cell
* yes -> (you have a lock on the same cell) && (nobody else has a lock on the same cell || the same col || all)
* new -> else
*
*/
try {
if (locktype == ALL) {
if (lockvalue.length() > 0) {
throw new RuntimeException("Hmm, seems like you're calling an ALL with a specific value, are you sure you didn't want another type of lock?");
}
for (Lock l : cursor) {
if (!l.uid.equals(uid)) {
blocker = l;
break;
} else {
if (l.type == ALL) {
lock = l;
break;
}
}
}
} else if (locktype == COL) {
if (lockvalue.indexOf(',') > -1) {
throw new RuntimeException("Hmm, seems like you're calling a COL lock with a CELL value");
}
for (Lock l : cursor) {
if (!l.uid.equals(uid)) {
if (l.type == ALL ||
(l.type == COL && l.value.equals(lockvalue)) ||
(l.type == CELL && l.value.split(",")[0].equals(lockvalue))) {
blocker = l;
break;
}
} else {
if (l.type == ALL ||
(l.type == COL && l.value.equals(lockvalue))) {
lock = l;
break;
}
}
}
} else if (locktype == CELL) {
if (lockvalue.indexOf(',') == -1) {
throw new RuntimeException("Hmm, seems like you're calling a CELL lock without specifying row and column: format must be 'row,column'");
}
for (Lock l : cursor) {
if (!l.uid.equals(uid)) {
if (l.type == ALL ||
(l.type == COL && l.value.equals(lockvalue.split(",")[0])) ||
(l.type == CELL && l.value.equals(lockvalue))) {
blocker = l;
break;
}
} else {
if (l.type == ALL ||
(l.type == COL && l.value.equals(lockvalue.split(",")[0])) ||
(l.type == CELL && l.value.equals(lockvalue))) {
lock = l;
break;
}
}
}
}
} finally {
cursor.close();
}
if (blocker != null) {
logger.info("found a blocking lock {}", lockToString(blocker));
throw new RuntimeException("Can't obtain lock, it is blocked by a type '" + blocker.type + "' lock owned by '" + blocker.uid + "'");
}
if (lock == null) {
logger.info("no comparable lock already exists, creating a new one");
lock = new Lock(Long.toHexString(txn.getId()), pid, uid, locktype, lockvalue);
lockById.put(txn, lock);
txn.commit();
}
} finally {
if (txn != null) {
txn.abort();
txn = null;
}
}
JSONObject o = lockToJSON(lock, uid);
o.put("status", "ok");
respond(response, o);
logger.trace("< obtain lock");
}
@Override
protected void releaseLock(HttpServletResponse response, String pid, String uid, String lid) throws Exception {
Transaction txn = env.beginTransaction(null, null);
try {
Lock lock = getLock(lid, pid, uid);
if (lock != null) {
if (!lock.uid.equals(uid)) {
throw new RuntimeException("User id doesn't match the lock owner, can't release the lock");
}
lockById.delete(lid);
txn.commit();
}
} finally {
if (txn != null) {
txn.abort();
txn = null;
}
}
if (response != null) { // this because the expiration thread can call this method without a real response
respond(response, OK);
}
}
// ----------------------------------------------------------------------------------------------------
@Override
protected void startProject(HttpServletResponse response, String pid, String uid, String lid, byte[] data, String metadata, List<String> transformations) throws Exception {
Transaction txn = env.beginTransaction(null, null);
try {
if (projectById.contains(pid)) {
throw new RuntimeException("Project '" + pid + "' already exists");
}
Lock lock = getLock(lid, pid, uid);
if (lock.type != ALL) {
throw new RuntimeException("The lock you have is not enough to start a project");
}
projectById.put(txn, new Project(pid, data, metadata, transformations));
txn.commit();
} finally {
if (txn != null) {
txn.abort();
txn = null;
}
}
respond(response, OK);
}
@Override
protected void addTransformations(HttpServletResponse response, String pid, String uid, String lid, List<String> transformations) throws Exception {
Transaction txn = env.beginTransaction(null, null);
try {
Project project = getProject(pid);
if (project == null) {
throw new RuntimeException("Project '" + pid + "' not found");
}
Lock lock = getLock(lid, pid, uid);
logger.info("obtained lock: {}", lockToString(lock));
if (lock.type == ALL) {
project.transformations.addAll(transformations);
} else {
for (String s : transformations) {
JSONObject o = new JSONObject(s);
int type = o.getInt("op_type");
String value = o.getString("op_value");
if (lock.type == COL) {
if (type == COL) {
if (value != null && value.equals(lock.value)) {
project.transformations.add(s);
} else {
throw new RuntimeException("Can't apply '" + s + "': you have a lock for column '" + lock.value + "' and you're attempting to modify column '" + value + "'.");
}
} else if (type == CELL) {
String column = value.split(",")[0];
if (column != null && column.equals(lock.value)) {
project.transformations.add(s);
} else {
throw new RuntimeException("Can't apply '" + s + "': you have a lock for column '" + lock.value + "' and you're attempting to modify cell '" + value + "' in another column.");
}
}
} else if (lock.type == CELL) {
if (type == COL) {
throw new RuntimeException("Can't apply '" + s + "': you offered a lock for a single cell and you're attempting an operation for the entire column.");
} else if (type == CELL) {
if (value != null && value.equals(lock.value)) {
project.transformations.add(s);
} else {
throw new RuntimeException("Can't apply '" + s + "': you have a lock for cell '" + lock.value + "' and you're attempting to modify cell '" + value + "'.");
}
}
}
}
}
projectById.put(txn, project);
txn.commit();
} finally {
if (txn != null) {
txn.abort();
txn = null;
}
}
respond(response, OK);
}
// ---------------------------------------------------------------------------------
@Override
protected void openProject(HttpServletResponse response, String pid) throws Exception {
Project project = getProject(pid);
Writer w = response.getWriter();
JSONWriter writer = new JSONWriter(w);
writer.object();
writer.key("status"); writer.value("ok");
writer.key("data"); writer.value(project.data);
writer.key("metadata"); writer.value(new JSONObject(project.metadata));
writer.key("transformations");
writer.array();
for (String s : project.transformations) {
writer.value(new JSONObject(s));
}
writer.endArray();
writer.endObject();
w.flush();
w.close();
}
// ---------------------------------------------------------------------------------
@Override
protected void getState(HttpServletResponse response, String pid, String uid, int rev) throws Exception {
Project project = getProject(pid);
Writer w = response.getWriter();
JSONWriter writer = new JSONWriter(w);
writer.object();
writer.key("status"); writer.value("ok");
writer.key("transformations");
writer.array();
int size = project.transformations.size();
for (int i = rev; i < size; i++) {
writer.value(new JSONObject(project.transformations.get(i)));
}
writer.endArray();
EntityCursor<Lock> cursor = locksByProject.subIndex(pid).entities();
try {
writer.key("locks");
writer.array();
for (Lock lock : cursor) {
writer.value(lockToJSON(lock, uid));
}
writer.endArray();
writer.endObject();
w.flush();
w.close();
} finally {
cursor.close();
}
}
// ---------------------------------------------------------------------------------
Project getProject(String pid) {
Project project = projectById.get(pid);
if (project == null) {
throw new RuntimeException("Project '" + pid + "' could not be found: are you sure is not managed by another broker?");
}
return project;
}
@Entity
static class Project {
@PrimaryKey
String pid;
List<String> transformations;
byte[] data;
String metadata;
int rev;
Project(String pid, byte[] data, String metadata, List<String> transformations) {
this.pid = pid;
this.data = data;
this.metadata = metadata;
this.transformations = (transformations != null) ? transformations : new ArrayList<String>();
this.rev = this.transformations.size();
}
@SuppressWarnings("unused")
private Project() {}
}
// ---------------------------------------------------------------------------------
Lock getLock(String lid, String pid, String uid) {
Lock lock = lockById.get(lid);
checkLock(lock, lid, pid, uid);
return lock;
}
void checkLock(Lock lock, String lid, String pid, String uid) {
if (lock == null) {
throw new RuntimeException("No lock was found with the given Lock id '" + lid + "', you have to have a valid lock on a project in order to start it");
}
if (!lock.pid.equals(pid)) {
throw new RuntimeException("Lock '" + lock.id + "' is for another project: " + lock.pid);
}
if (!lock.uid.equals(uid)) {
throw new RuntimeException("Lock '" + lock.id + "' is owned by another user: " + lock.uid);
}
}
Lock getLock(String pid, String uid, int locktype) {
Lock lock = null;
EntityCursor<Lock> cursor = locksByProject.subIndex(pid).entities();
try {
for (Lock l : cursor) {
if (uid.equals(l.uid) && (locktype == l.type)) {
lock = l;
break;
}
}
} finally {
cursor.close();
}
return lock;
}
JSONObject lockToJSON(Lock lock, String uid) throws JSONException {
JSONObject o = new JSONObject();
if (lock != null) {
// NOTE: only the owner of the lock should get the ID,
// otherwise others can just fake ownership of other people's locks
if (lock.uid.equals(uid)) {
o.put("lock", lock.id);
}
o.put("pid", lock.pid);
o.put("uid", lock.uid);
o.put("type", lock.type);
o.put("value", lock.value);
o.put("timestamp", lock.timestamp);
}
return o;
}
String lockToString(Lock lock) {
return lock.id + "," + lock.pid + "," + lock.uid + "," + lock.type + "," + lock.value;
}
@Entity
static class Lock {
@PrimaryKey
String id;
@SecondaryKey(relate=MANY_TO_ONE)
String pid;
String uid;
int type;
String value;
long timestamp;
Lock(String id, String pid, String uid, int type, String value) {
this.id = id;
this.pid = pid;
this.uid = uid;
this.type = type;
this.value = value;
this.timestamp = System.currentTimeMillis();
}
@SuppressWarnings("unused")
private Lock() {}
}
}

View File

@ -0,0 +1,311 @@
package com.google.refine.broker;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.mit.simile.butterfly.ButterflyModuleImpl;
/**
* This class contains all the code shared by various implementations of a Gridworks Broker.
*
* A broker is a server used by multiple Gridworks installations to enable collaborative
* development over the same project.
*
* Broker implementations differ in how they store their state but all of them are required
* to extend this abstract class and implement the services that are called via HTTP.
*
*/
public abstract class GridworksBroker extends ButterflyModuleImpl {
static final public String GET_STATE = "get_state";
static final public String EXPIRE = "expire";
static final public String OBTAIN_LOCK = "obtain_lock";
static final public String RELEASE_LOCK = "release_lock";
static final public String TRANSFORM = "transform";
static final public String START = "start";
static final public String OPEN = "open";
static final public int ALL = 0;
static final public int COL = 1;
static final public int CELL = 2;
static final protected Logger logger = LoggerFactory.getLogger("gridworks.broker");
static final protected String USER_INFO_URL = "http://www.freebase.com/api/service/user_info";
static final protected String DELEGATED_OAUTH_HEADER = "X-Freebase-Credentials";
static final protected String OAUTH_HEADER = "Authorization";
static protected String OK;
static {
try {
JSONObject o = new JSONObject();
o.put("status","ok");
OK = o.toString();
} catch (JSONException e) {
// not going to happen;
}
}
static public final long LOCK_DURATION = 60 * 1000; // 1 minute
static public final long USER_DURATION = 5 * 60 * 1000; // 1 minute
static public final long LOCK_EXPIRATION_CHECK_DELAY = 5 * 1000; // 5 seconds
protected HttpClient httpclient;
protected boolean developmentMode;
@Override
public void init(ServletConfig config) throws Exception {
super.init(config);
httpclient = getHttpClient();
developmentMode = Boolean.parseBoolean(config.getInitParameter("gridworks.development"));
if (developmentMode) logger.warn("Running in development mode");
}
@Override
public void destroy() throws Exception {
httpclient.getConnectionManager().shutdown();
}
@Override
public boolean process(String path, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("> process '{}'", path);
} else {
logger.info("process '{}'", path);
}
try {
if (GET_STATE.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
getState(response, getParameter(request, "pid"), getUserId(request), getInteger(request, "rev"));
} else if (EXPIRE.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
expire(response);
} else if (OBTAIN_LOCK.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
obtainLock(response, getParameter(request, "pid"), getUserId(request), getInteger(request, "locktype"), getParameter(request, "lockvalue"));
} else if (RELEASE_LOCK.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
releaseLock(response, getParameter(request, "pid"), getUserId(request), getParameter(request, "lock"));
} else if (TRANSFORM.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
addTransformations(response, getParameter(request, "pid"), getUserId(request), getParameter(request, "lock"), getList(request, "transformations"));
} else if (START.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
startProject(response, getParameter(request, "pid"), getUserId(request), getParameter(request, "lock"), getData(request), getParameter(request, "metadata"), getList(request, "transformations"));
} else if (OPEN.equals(path)) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
openProject(response, getParameter(request, "pid"));
} else {
boolean value = super.process(path, request, response);
if (logger.isDebugEnabled()) logger.debug("< process '{}'", path);
return value;
}
} catch (RuntimeException e) {
logger.error("runtime error", e.getMessage());
respondError(response, e.getMessage());
} catch (Exception e) {
logger.error("internal error", e);
respondException(response, e);
}
if (logger.isDebugEnabled()) logger.debug("< process '{}'", path);
return true;
}
// ----------------------------------------------------------------------------------------
protected abstract HttpClient getHttpClient();
protected abstract void expire(HttpServletResponse response) throws Exception;
protected abstract void getState(HttpServletResponse response, String pid, String uid, int rev) throws Exception;
protected abstract void obtainLock(HttpServletResponse response, String pid, String uid, int locktype, String lockvalue) throws Exception;
protected abstract void releaseLock(HttpServletResponse response, String pid, String uid, String lock) throws Exception;
protected abstract void startProject(HttpServletResponse response, String pid, String uid, String lock, byte[] data, String metadata, List<String> transformations) throws Exception;
protected abstract void addTransformations(HttpServletResponse response, String pid, String uid, String lock, List<String> transformations) throws Exception;
protected abstract void openProject(HttpServletResponse response, String pid) throws Exception;
// ----------------------------------------------------------------------------------------
@SuppressWarnings("unchecked")
protected String getUserId(HttpServletRequest request) throws Exception {
// This is useful for testing
if (developmentMode) {
return getParameter(request, "uid");
}
String oauth = request.getHeader(DELEGATED_OAUTH_HEADER);
if (oauth == null) {
throw new RuntimeException("The request needs to contain the '" + DELEGATED_OAUTH_HEADER + "' header set to obtain user identity via Freebase.");
}
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
Map<String,String> params = (Map<String,String>) request.getParameterMap();
for (Entry<String,String> e : params.entrySet()) {
formparams.add(new BasicNameValuePair((String) e.getKey(), (String) e.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8");
HttpPost httpRequest = new HttpPost(USER_INFO_URL);
httpRequest.setHeader(OAUTH_HEADER, oauth);
httpRequest.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "Gridworks Broker");
httpRequest.setEntity(entity);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String responseBody = httpclient.execute(httpRequest, responseHandler);
JSONObject o = new JSONObject(responseBody);
return o.getString("username");
}
// ----------------------------------------------------------------------------------------
static protected String getParameter(HttpServletRequest request, String name) throws ServletException {
String param = request.getParameter(name);
if (param == null) {
throw new RuntimeException("request must come with a '" + name + "' parameter");
}
return param;
}
static protected List<String> getList(HttpServletRequest request, String name) throws ServletException, JSONException {
String param = getParameter(request, name);
JSONArray a = new JSONArray(param);
List<String> result = new ArrayList<String>(a.length());
for (int i = 0; i < a.length(); i++) {
result.add(a.getString(i));
}
return result;
}
static protected int getInteger(HttpServletRequest request, String name) throws ServletException, JSONException {
return Integer.parseInt(getParameter(request, name));
}
static protected byte[] getData(HttpServletRequest request) throws ServletException, IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
InputStream input = request.getInputStream();
byte[] buffer = new byte[4096];
int count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return output.toByteArray();
}
static protected void respondError(HttpServletResponse response, String error) throws IOException, ServletException {
if (response == null) {
throw new ServletException("Response object can't be null");
}
try {
JSONObject o = new JSONObject();
o.put("status", "error");
o.put("message", error);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
respond(response, o.toString());
} catch (JSONException e) {
e.printStackTrace(response.getWriter());
}
}
static protected void respondException(HttpServletResponse response, Exception e) throws IOException, ServletException {
if (response == null) {
throw new ServletException("Response object can't be null");
}
try {
JSONObject o = new JSONObject();
o.put("status", "error");
o.put("message", e.getMessage());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
sw.flush();
o.put("stack", sw.toString());
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
respond(response, o.toString());
} catch (JSONException e1) {
e.printStackTrace(response.getWriter());
}
}
static protected void respond(HttpServletResponse response, JSONObject content) throws IOException, ServletException {
if (content == null) {
throw new ServletException("Content object can't be null");
}
respond(response, content.toString());
}
static protected void respond(HttpServletResponse response, String content) throws IOException, ServletException {
if (response == null) {
throw new ServletException("Response object can't be null");
}
Writer w = response.getWriter();
if (w != null) {
w.write(content);
w.flush();
w.close();
} else {
throw new ServletException("response returned a null writer");
}
}
}

View File

@ -0,0 +1,592 @@
package com.google.refine.broker;
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
import java.io.File;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.Transaction;
import com.sleepycat.persist.EntityCursor;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.PrimaryIndex;
import com.sleepycat.persist.SecondaryIndex;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.SecondaryKey;
public class GridworksBrokerImpl extends GridworksBroker {
protected static final Logger logger = LoggerFactory.getLogger("gridworks.broker.local");
Environment env;
EntityStore projectStore;
EntityStore lockStore;
EntityStore userStore;
PrimaryIndex<String,Project> projectById;
PrimaryIndex<String,Lock> lockById;
SecondaryIndex<String,String,Lock> locksByProject;
Timer timer;
Expirer expirer;
@Override
public void init(ServletConfig config) throws Exception {
logger.trace("> init");
super.init(config);
timer = new Timer();
expirer = new Expirer();
timer.schedule(expirer, 0, LOCK_EXPIRATION_CHECK_DELAY);
String dataDir = config.getInitParameter("gridworks.data");
if (dataDir == null) dataDir = "data";
File dataPath = new File(dataDir);
if (!dataPath.exists()) dataPath.mkdirs();
EnvironmentConfig envConfig = new EnvironmentConfig();
envConfig.setAllowCreate(true);
envConfig.setTransactional(true);
env = new Environment(dataPath, envConfig);
StoreConfig storeConfig = new StoreConfig();
storeConfig.setAllowCreate(true);
storeConfig.setTransactional(true);
projectStore = new EntityStore(env, "ProjectsStore", storeConfig);
lockStore = new EntityStore(env, "LockStore", storeConfig);
projectById = projectStore.getPrimaryIndex(String.class, Project.class);
lockById = lockStore.getPrimaryIndex(String.class, Lock.class);
locksByProject = lockStore.getSecondaryIndex(lockById, String.class, "pid");
logger.trace("< init");
}
@Override
public void destroy() throws Exception {
logger.trace("> destroy");
super.destroy();
if (projectStore != null) {
projectStore.close();
projectById = null;
}
if (lockStore != null) {
lockStore.close();
lockById = null;
}
if (timer != null) {
timer.cancel();
timer.purge();
timer = null;
}
if (env != null) {
env.close();
env = null;
}
logger.trace("< destroy");
}
class Expirer extends TimerTask {
public void run() {
if (lockById != null) {
logger.trace("> expire");
Transaction txn = env.beginTransaction(null, null);
try {
EntityCursor<Lock> cursor = lockById.entities();
try {
for (Lock lock : cursor) {
if (lock.timestamp + LOCK_DURATION < System.currentTimeMillis()) {
logger.trace("Found expired lock {}", lock.id);
try {
releaseLock(null, lock.pid, lock.uid, lock.id);
} catch (Exception e) {
logger.error("Exception while expiring lock for project '" + lock.pid + "'", e);
}
}
}
} finally {
cursor.close();
}
} finally {
if (txn != null) {
txn.abort();
txn = null;
}
}
logger.trace("< expire");
}
}
}
// ---------------------------------------------------------------------------------
@Override
protected HttpClient getHttpClient() {
return new DefaultHttpClient();
}
// ---------------------------------------------------------------------------------
@Override
protected void expire(HttpServletResponse response) throws Exception {
expirer.run();
respond(response, OK);
}
@Override
protected void obtainLock(HttpServletResponse response, String pid, String uid, int locktype, String lockvalue) throws Exception {
logger.trace("> obtain lock");
Lock lock = null;
Lock blocker = null;
Transaction txn = env.beginTransaction(null, null);
try {
EntityCursor<Lock> cursor = locksByProject.subIndex(pid).entities();
/*
* ALL
* blocked -> somebody else's lock
* reuse -> you already have an ALL lock
* new -> else
*
* COL
* blocked -> somebody else's all lock || a lock on the same col
* reuse -> you have an ALL lock || a lock on the same col
* new -> else
*
* CELL
* blocked -> somebody else's all lock || a lock on the same col || a lock on the same cell
* reuse -> you have a lock on the same cell
* yes -> (you have a lock on the same cell) && (nobody else has a lock on the same cell || the same col || all)
* new -> else
*
*/
try {
if (locktype == ALL) {
if (lockvalue.length() > 0) {
throw new RuntimeException("Hmm, seems like you're calling an ALL with a specific value, are you sure you didn't want another type of lock?");
}
for (Lock l : cursor) {
if (!l.uid.equals(uid)) {
blocker = l;
break;
} else {
if (l.type == ALL) {
lock = l;
break;
}
}
}
} else if (locktype == COL) {
if (lockvalue.indexOf(',') > -1) {
throw new RuntimeException("Hmm, seems like you're calling a COL lock with a CELL value");
}
for (Lock l : cursor) {
if (!l.uid.equals(uid)) {
if (l.type == ALL ||
(l.type == COL && l.value.equals(lockvalue)) ||
(l.type == CELL && l.value.split(",")[0].equals(lockvalue))) {
blocker = l;
break;
}
} else {
if (l.type == ALL ||
(l.type == COL && l.value.equals(lockvalue))) {
lock = l;
break;
}
}
}
} else if (locktype == CELL) {
if (lockvalue.indexOf(',') == -1) {
throw new RuntimeException("Hmm, seems like you're calling a CELL lock without specifying row and column: format must be 'row,column'");
}
for (Lock l : cursor) {
if (!l.uid.equals(uid)) {
if (l.type == ALL ||
(l.type == COL && l.value.equals(lockvalue.split(",")[0])) ||
(l.type == CELL && l.value.equals(lockvalue))) {
blocker = l;
break;
}
} else {
if (l.type == ALL ||
(l.type == COL && l.value.equals(lockvalue.split(",")[0])) ||
(l.type == CELL && l.value.equals(lockvalue))) {
lock = l;
break;
}
}
}
}
} finally {
cursor.close();
}
if (blocker != null) {
logger.info("found a blocking lock {}", lockToString(blocker));
throw new RuntimeException("Can't obtain lock, it is blocked by a type '" + blocker.type + "' lock owned by '" + blocker.uid + "'");
}
if (lock == null) {
logger.info("no comparable lock already exists, creating a new one");
lock = new Lock(Long.toHexString(txn.getId()), pid, uid, locktype, lockvalue);
lockById.put(txn, lock);
txn.commit();
}
} finally {
if (txn != null) {
txn.abort();
txn = null;
}
}
JSONObject o = lockToJSON(lock, uid);
o.put("status", "ok");
respond(response, o);
logger.trace("< obtain lock");
}
@Override
protected void releaseLock(HttpServletResponse response, String pid, String uid, String lid) throws Exception {
Transaction txn = env.beginTransaction(null, null);
try {
Lock lock = getLock(lid, pid, uid);
if (lock != null) {
if (!lock.uid.equals(uid)) {
throw new RuntimeException("User id doesn't match the lock owner, can't release the lock");
}
lockById.delete(lid);
txn.commit();
}
} finally {
if (txn != null) {
txn.abort();
txn = null;
}
}
if (response != null) { // this because the expiration thread can call this method without a real response
respond(response, OK);
}
}
// ----------------------------------------------------------------------------------------------------
@Override
protected void startProject(HttpServletResponse response, String pid, String uid, String lid, byte[] data, String metadata, List<String> transformations) throws Exception {
Transaction txn = env.beginTransaction(null, null);
try {
if (projectById.contains(pid)) {
throw new RuntimeException("Project '" + pid + "' already exists");
}
Lock lock = getLock(lid, pid, uid);
if (lock.type != ALL) {
throw new RuntimeException("The lock you have is not enough to start a project");
}
projectById.put(txn, new Project(pid, data, metadata, transformations));
txn.commit();
} finally {
if (txn != null) {
txn.abort();
txn = null;
}
}
respond(response, OK);
}
@Override
protected void addTransformations(HttpServletResponse response, String pid, String uid, String lid, List<String> transformations) throws Exception {
Transaction txn = env.beginTransaction(null, null);
try {
Project project = getProject(pid);
if (project == null) {
throw new RuntimeException("Project '" + pid + "' not found");
}
Lock lock = getLock(lid, pid, uid);
logger.info("obtained lock: {}", lockToString(lock));
if (lock.type == ALL) {
project.transformations.addAll(transformations);
} else {
for (String s : transformations) {
JSONObject o = new JSONObject(s);
int type = o.getInt("op_type");
String value = o.getString("op_value");
if (lock.type == COL) {
if (type == COL) {
if (value != null && value.equals(lock.value)) {
project.transformations.add(s);
} else {
throw new RuntimeException("Can't apply '" + s + "': you have a lock for column '" + lock.value + "' and you're attempting to modify column '" + value + "'.");
}
} else if (type == CELL) {
String column = value.split(",")[0];
if (column != null && column.equals(lock.value)) {
project.transformations.add(s);
} else {
throw new RuntimeException("Can't apply '" + s + "': you have a lock for column '" + lock.value + "' and you're attempting to modify cell '" + value + "' in another column.");
}
}
} else if (lock.type == CELL) {
if (type == COL) {
throw new RuntimeException("Can't apply '" + s + "': you offered a lock for a single cell and you're attempting an operation for the entire column.");
} else if (type == CELL) {
if (value != null && value.equals(lock.value)) {
project.transformations.add(s);
} else {
throw new RuntimeException("Can't apply '" + s + "': you have a lock for cell '" + lock.value + "' and you're attempting to modify cell '" + value + "'.");
}
}
}
}
}
projectById.put(txn, project);
txn.commit();
} finally {
if (txn != null) {
txn.abort();
txn = null;
}
}
respond(response, OK);
}
// ---------------------------------------------------------------------------------
@Override
protected void openProject(HttpServletResponse response, String pid) throws Exception {
Project project = getProject(pid);
Writer w = response.getWriter();
JSONWriter writer = new JSONWriter(w);
writer.object();
writer.key("status"); writer.value("ok");
writer.key("data"); writer.value(project.data);
writer.key("metadata"); writer.value(new JSONObject(project.metadata));
writer.key("transformations");
writer.array();
for (String s : project.transformations) {
writer.value(new JSONObject(s));
}
writer.endArray();
writer.endObject();
w.flush();
w.close();
}
// ---------------------------------------------------------------------------------
@Override
protected void getState(HttpServletResponse response, String pid, String uid, int rev) throws Exception {
Project project = getProject(pid);
Writer w = response.getWriter();
JSONWriter writer = new JSONWriter(w);
writer.object();
writer.key("status"); writer.value("ok");
writer.key("transformations");
writer.array();
int size = project.transformations.size();
for (int i = rev; i < size; i++) {
writer.value(new JSONObject(project.transformations.get(i)));
}
writer.endArray();
EntityCursor<Lock> cursor = locksByProject.subIndex(pid).entities();
try {
writer.key("locks");
writer.array();
for (Lock lock : cursor) {
writer.value(lockToJSON(lock, uid));
}
writer.endArray();
writer.endObject();
w.flush();
w.close();
} finally {
cursor.close();
}
}
// ---------------------------------------------------------------------------------
Project getProject(String pid) {
Project project = projectById.get(pid);
if (project == null) {
throw new RuntimeException("Project '" + pid + "' could not be found: are you sure is not managed by another broker?");
}
return project;
}
@Entity
static class Project {
@PrimaryKey
String pid;
List<String> transformations;
byte[] data;
String metadata;
int rev;
Project(String pid, byte[] data, String metadata, List<String> transformations) {
this.pid = pid;
this.data = data;
this.metadata = metadata;
this.transformations = (transformations != null) ? transformations : new ArrayList<String>();
this.rev = this.transformations.size();
}
@SuppressWarnings("unused")
private Project() {}
}
// ---------------------------------------------------------------------------------
Lock getLock(String lid, String pid, String uid) {
Lock lock = lockById.get(lid);
checkLock(lock, lid, pid, uid);
return lock;
}
void checkLock(Lock lock, String lid, String pid, String uid) {
if (lock == null) {
throw new RuntimeException("No lock was found with the given Lock id '" + lid + "', you have to have a valid lock on a project in order to start it");
}
if (!lock.pid.equals(pid)) {
throw new RuntimeException("Lock '" + lock.id + "' is for another project: " + lock.pid);
}
if (!lock.uid.equals(uid)) {
throw new RuntimeException("Lock '" + lock.id + "' is owned by another user: " + lock.uid);
}
}
Lock getLock(String pid, String uid, int locktype) {
Lock lock = null;
EntityCursor<Lock> cursor = locksByProject.subIndex(pid).entities();
try {
for (Lock l : cursor) {
if (uid.equals(l.uid) && (locktype == l.type)) {
lock = l;
break;
}
}
} finally {
cursor.close();
}
return lock;
}
JSONObject lockToJSON(Lock lock, String uid) throws JSONException {
JSONObject o = new JSONObject();
if (lock != null) {
// NOTE: only the owner of the lock should get the ID,
// otherwise others can just fake ownership of other people's locks
if (lock.uid.equals(uid)) {
o.put("lock", lock.id);
}
o.put("pid", lock.pid);
o.put("uid", lock.uid);
o.put("type", lock.type);
o.put("value", lock.value);
o.put("timestamp", lock.timestamp);
}
return o;
}
String lockToString(Lock lock) {
return lock.id + "," + lock.pid + "," + lock.uid + "," + lock.type + "," + lock.value;
}
@Entity
static class Lock {
@PrimaryKey
String id;
@SecondaryKey(relate=MANY_TO_ONE)
String pid;
String uid;
int type;
String value;
long timestamp;
Lock(String id, String pid, String uid, int type, String value) {
this.id = id;
this.pid = pid;
this.uid = uid;
this.type = type;
this.value = value;
this.timestamp = System.currentTimeMillis();
}
@SuppressWarnings("unused")
private Lock() {}
}
}

View File

@ -1,452 +0,0 @@
package com.google.gridworks.broker.tests;
import static com.google.gridworks.broker.GridworksBroker.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.gridworks.broker.GridworksBroker;
import com.google.gridworks.broker.GridworksBrokerImpl;
public class GridworksBrokerTests {
Logger logger;
File data;
@BeforeSuite public void suite_init() {
System.setProperty("log4j.configuration", "tests.log4j.properties");
data = new File("data");
if (!data.exists()) data.mkdirs();
}
@AfterSuite public void suite_destroy() {
for (File f : data.listFiles()) {
f.delete();
}
data.delete();
}
// ------------------------------------------------------------------------------------
ServletConfig config = null;
GridworksBroker broker = null;
@BeforeTest public void test_init() throws Exception {
logger = LoggerFactory.getLogger(this.getClass());
config = mock(ServletConfig.class);
when(config.getInitParameter("gridworks.data")).thenReturn(data.getAbsolutePath());
when(config.getInitParameter("gridworks.development")).thenReturn("true");
broker = new GridworksBrokerImpl();
broker.init(config);
}
@AfterTest public void test_destroy() throws Exception {
broker.destroy();
broker = null;
config = null;
}
// ------------------------------------------------------------------------------------
HttpServletRequest request = null;
HttpServletResponse response = null;
StringWriter writer = null;
@BeforeMethod public void setup() throws Exception {
request = mock(HttpServletRequest.class);
response = mock(HttpServletResponse.class);
}
@AfterMethod public void teardown() throws Exception {
response = null;
request = null;
}
// ------------------------------------------------------------------------------------
@Test public void testLifeCycle() {
Assert.assertTrue(true);
}
@Test public void testService() {
try {
success(broker, request, response, EXPIRE);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testObtainLockFailure() {
try {
failure(broker, request, response, OBTAIN_LOCK);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testReleaseLockFailure() {
try {
failure(broker, request, response, RELEASE_LOCK);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testGetStateFailure() {
try {
failure(broker, request, response, GET_STATE, "pid", "project1934983948", "uid", "testuser", "rev", "0");
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testBrokenAllLockFailure() {
try {
failure(broker, request, response, OBTAIN_LOCK, "pid", "project", "uid", "testuser", "locktype", Integer.toString(ALL), "lockvalue", "1");
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testBrokenColLockFailure() {
try {
failure(broker, request, response, OBTAIN_LOCK, "pid", "project", "uid", "testuser", "locktype", Integer.toString(COL), "lockvalue", "1,1");
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testBrokenCellLockFailure() {
try {
failure(broker, request, response, OBTAIN_LOCK, "pid", "project", "uid", "testuser", "locktype", Integer.toString(CELL), "lockvalue", "1");
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testLockSimple() {
String project = "proj0";
String user = "testuser";
try {
logger.info("--- obtain ALL lock on project ---");
JSONObject result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
assertJSON(result, "uid", "testuser");
String lock = result.getString("lock");
logger.info("--- obtain ALL lock on project ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
logger.info("--- obtain COL lock on project ---");
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", "1");
assertJSON(result, "uid", "testuser");
lock = result.getString("lock");
logger.info("--- release COL lock on project ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
logger.info("--- obtain CELL lock on project ---");
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
assertJSON(result, "uid", "testuser");
lock = result.getString("lock");
logger.info("--- release CELL lock on project ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testLocksAllBlocks() {
String project = "proj1";
String user = "testuser";
String user2 = "testuser2";
try {
logger.info("--- obtain ALL lock on project ---");
JSONObject result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
assertJSON(result, "uid", user);
String lock = result.getString("lock");
logger.info("--- another using asking for any lock will fail ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(ALL), "lockvalue", "");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", "1");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
logger.info("--- same user asking for lower capable locks will return the ALL one ---");
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", "1");
String lock2 = result.getString("lock");
Assert.assertEquals(lock, lock2);
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
lock2 = result.getString("lock");
Assert.assertEquals(lock, lock2);
logger.info("--- release the ALL lock ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testLocksColBlocks() {
String project = "proj2";
String user = "testuser";
String user2 = "testuser2";
try {
logger.info("--- obtain COL lock on project ---");
JSONObject result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", "1");
String lock = result.getString("lock");
logger.info("--- other user must fail to obtain lock on the same COL or ALL ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(ALL), "lockvalue", "");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", "1");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
logger.info("--- but succeed in getting a COL lock on another column or cell ---");
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", "2");
String lock2 = result.getString("lock");
logger.info("--- now it's our first user's turn to fail to get lock ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", "2");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(CELL), "lockvalue", "2,1");
logger.info("--- release the locks ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user2, "lock", lock2);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testLocksCellBlocks() {
String project = "proj3";
String user = "testuser";
String user2 = "testuser2";
try {
logger.info("--- obtain CELL lock on project ---");
JSONObject result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
String lock = result.getString("lock");
logger.info("--- other user must fail to obtain lock on the same CELL, COL or ALL ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(ALL), "lockvalue", "");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", "1");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
logger.info("--- but succeed in getting a CELL lock on a cell in another column ---");
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(CELL), "lockvalue", "2,1");
String lock2 = result.getString("lock");
logger.info("--- now it's our first user's turn to fail to get lock ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", "2");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(CELL), "lockvalue", "2,1");
logger.info("--- release the locks ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user2, "lock", lock2);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testCompleteProjectLifeCycle() {
try {
String project = "proj4";
String user = "testuser";
String user2 = "testuser2";
String data = "blah";
String metadata = "{}";
String transformations = "[]";
String rev = "0";
logger.info("--- obtain ALL lock on project ---");
JSONObject result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
assertJSON(result, "uid", user);
String lock = result.getString("lock");
logger.info("--- start project ---");
success(broker, request, response, START, "pid", project, "uid", user, "lock", lock, "data", data, "metadata", metadata, "transformations", transformations);
logger.info("--- verify project state contains lock ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", rev);
JSONArray locks = result.getJSONArray("locks");
Assert.assertEquals(locks.length(), 1);
JSONObject l = locks.getJSONObject(0);
assertJSON(l, "uid", "testuser");
Assert.assertEquals(l.getInt("type"), ALL);
logger.info("--- release ALL lock on project ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
logger.info("--- verify no locks are present ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", rev);
locks = result.getJSONArray("locks");
Assert.assertEquals(locks.length(), 0);
logger.info("--- open project and verify data was loaded correctly ---");
result = success(broker, request, response, OPEN, "pid", project, "uid", user, "rev", rev);
JSONArray result_data = result.getJSONArray("data");
Assert.assertEquals(result_data.length(),data.getBytes("UTF-8").length);
JSONArray tt;
JSONObject t;
logger.info("--- obtain column lock ---");
String column = "1";
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", column);
String col_lock = result.getString("lock");
logger.info("--- perform column transformation ---");
t = new JSONObject();
t.put("op_type", COL);
t.put("op_value", column); // operate on col 1
t.put("value", new JSONObject());
tt = new JSONArray();
tt.put(t);
result = success(broker, request, response, TRANSFORM, "pid", project, "uid", user, "lock", col_lock, "transformations", tt.toString());
logger.info("--- make sure transformation was recorded properly ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "0");
tt = result.getJSONArray("transformations");
Assert.assertEquals(tt.length(), 1);
t = tt.getJSONObject(0);
assertJSON(t, "op_value", column);
logger.info("--- make sure revision numbers in state management work as expected ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "1");
tt = result.getJSONArray("transformations");
Assert.assertEquals(tt.length(), 0);
logger.info("--- perform cell transformation ---");
String cell = "1";
t = new JSONObject();
t.put("op_type", CELL);
t.put("op_value", column + "," + cell); // operate on cell at row 1 column 1
t.put("value", new JSONObject());
tt = new JSONArray();
tt.put(t);
result = success(broker, request, response, TRANSFORM, "pid", project, "uid", user, "lock", col_lock, "transformations", tt.toString());
logger.info("--- make sure transformation was recorded properly ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "0");
tt = result.getJSONArray("transformations");
Assert.assertEquals(tt.length(), 2);
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "1");
tt = result.getJSONArray("transformations");
Assert.assertEquals(tt.length(), 1);
t = tt.getJSONObject(0);
assertJSON(t, "op_value", column + "," + cell);
logger.info("--- make sure another user fails to acquire ALL lock ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(ALL), "lockvalue", "");
logger.info("--- make sure another user fails to acquire COL lock on the same column ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", column);
logger.info("--- make sure another user manages to acquire COL lock on another column ---");
String column2 = "2";
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", column2);
String col_lock2 = result.getString("lock");
logger.info("--- make sure that both locks are present ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "2");
locks = result.getJSONArray("locks");
Assert.assertEquals(locks.length(), 2);
logger.info("--- make sure we can't escalate our current COL lock to an ALL lock ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
logger.info("--- release column locks ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", col_lock);
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user2, "lock", col_lock2);
logger.info("--- make sure the project has no locks ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "2");
locks = result.getJSONArray("locks");
Assert.assertEquals(locks.length(), 0);
} catch (Exception e) {
Assert.fail();
}
}
// ------------------------------------------------------------------------------------
private void assertJSON(JSONObject o, String name, String value) throws JSONException {
Assert.assertEquals(o.get(name), value);
}
private JSONObject success(GridworksBroker broker, HttpServletRequest request, HttpServletResponse response, String service, String... params) throws Exception {
return call(true, broker, request, response, service, params);
}
private JSONObject failure(GridworksBroker broker, HttpServletRequest request, HttpServletResponse response, String service, String... params) throws Exception {
return call(false, broker, request, response, service, params);
}
private JSONObject call(boolean successful, GridworksBroker broker, HttpServletRequest request, HttpServletResponse response, String service, String... params) throws Exception {
if (params != null) {
for (int i = 0; i < params.length; ) {
String name = params[i++];
String value = params[i++];
if ("data".equals(name)) {
final ByteArrayInputStream inputStream = new ByteArrayInputStream(value.getBytes("UTF-8"));
when(request.getInputStream()).thenReturn(new ServletInputStream() {
public int read() throws IOException {
return inputStream.read();
}
});
} else {
when(request.getParameter(name)).thenReturn(value);
}
}
}
StringWriter writer = new StringWriter();
when(response.getWriter()).thenReturn(new PrintWriter(writer));
broker.process(service, request, response);
JSONObject result = new JSONObject(writer.toString());
if (successful) {
assertJSON(result, "status", "ok");
} else {
assertJSON(result, "status", "error");
}
logger.info(result.toString());
return result;
}
}

View File

@ -0,0 +1,452 @@
package com.google.refine.broker.tests;
import static com.google.refine.broker.GridworksBroker.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.refine.broker.GridworksBroker;
import com.google.refine.broker.GridworksBrokerImpl;
public class GridworksBrokerTests {
Logger logger;
File data;
@BeforeSuite public void suite_init() {
System.setProperty("log4j.configuration", "tests.log4j.properties");
data = new File("data");
if (!data.exists()) data.mkdirs();
}
@AfterSuite public void suite_destroy() {
for (File f : data.listFiles()) {
f.delete();
}
data.delete();
}
// ------------------------------------------------------------------------------------
ServletConfig config = null;
GridworksBroker broker = null;
@BeforeTest public void test_init() throws Exception {
logger = LoggerFactory.getLogger(this.getClass());
config = mock(ServletConfig.class);
when(config.getInitParameter("gridworks.data")).thenReturn(data.getAbsolutePath());
when(config.getInitParameter("gridworks.development")).thenReturn("true");
broker = new GridworksBrokerImpl();
broker.init(config);
}
@AfterTest public void test_destroy() throws Exception {
broker.destroy();
broker = null;
config = null;
}
// ------------------------------------------------------------------------------------
HttpServletRequest request = null;
HttpServletResponse response = null;
StringWriter writer = null;
@BeforeMethod public void setup() throws Exception {
request = mock(HttpServletRequest.class);
response = mock(HttpServletResponse.class);
}
@AfterMethod public void teardown() throws Exception {
response = null;
request = null;
}
// ------------------------------------------------------------------------------------
@Test public void testLifeCycle() {
Assert.assertTrue(true);
}
@Test public void testService() {
try {
success(broker, request, response, EXPIRE);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testObtainLockFailure() {
try {
failure(broker, request, response, OBTAIN_LOCK);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testReleaseLockFailure() {
try {
failure(broker, request, response, RELEASE_LOCK);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testGetStateFailure() {
try {
failure(broker, request, response, GET_STATE, "pid", "project1934983948", "uid", "testuser", "rev", "0");
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testBrokenAllLockFailure() {
try {
failure(broker, request, response, OBTAIN_LOCK, "pid", "project", "uid", "testuser", "locktype", Integer.toString(ALL), "lockvalue", "1");
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testBrokenColLockFailure() {
try {
failure(broker, request, response, OBTAIN_LOCK, "pid", "project", "uid", "testuser", "locktype", Integer.toString(COL), "lockvalue", "1,1");
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testBrokenCellLockFailure() {
try {
failure(broker, request, response, OBTAIN_LOCK, "pid", "project", "uid", "testuser", "locktype", Integer.toString(CELL), "lockvalue", "1");
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testLockSimple() {
String project = "proj0";
String user = "testuser";
try {
logger.info("--- obtain ALL lock on project ---");
JSONObject result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
assertJSON(result, "uid", "testuser");
String lock = result.getString("lock");
logger.info("--- obtain ALL lock on project ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
logger.info("--- obtain COL lock on project ---");
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", "1");
assertJSON(result, "uid", "testuser");
lock = result.getString("lock");
logger.info("--- release COL lock on project ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
logger.info("--- obtain CELL lock on project ---");
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
assertJSON(result, "uid", "testuser");
lock = result.getString("lock");
logger.info("--- release CELL lock on project ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testLocksAllBlocks() {
String project = "proj1";
String user = "testuser";
String user2 = "testuser2";
try {
logger.info("--- obtain ALL lock on project ---");
JSONObject result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
assertJSON(result, "uid", user);
String lock = result.getString("lock");
logger.info("--- another using asking for any lock will fail ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(ALL), "lockvalue", "");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", "1");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
logger.info("--- same user asking for lower capable locks will return the ALL one ---");
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", "1");
String lock2 = result.getString("lock");
Assert.assertEquals(lock, lock2);
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
lock2 = result.getString("lock");
Assert.assertEquals(lock, lock2);
logger.info("--- release the ALL lock ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testLocksColBlocks() {
String project = "proj2";
String user = "testuser";
String user2 = "testuser2";
try {
logger.info("--- obtain COL lock on project ---");
JSONObject result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", "1");
String lock = result.getString("lock");
logger.info("--- other user must fail to obtain lock on the same COL or ALL ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(ALL), "lockvalue", "");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", "1");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
logger.info("--- but succeed in getting a COL lock on another column or cell ---");
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", "2");
String lock2 = result.getString("lock");
logger.info("--- now it's our first user's turn to fail to get lock ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", "2");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(CELL), "lockvalue", "2,1");
logger.info("--- release the locks ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user2, "lock", lock2);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testLocksCellBlocks() {
String project = "proj3";
String user = "testuser";
String user2 = "testuser2";
try {
logger.info("--- obtain CELL lock on project ---");
JSONObject result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
String lock = result.getString("lock");
logger.info("--- other user must fail to obtain lock on the same CELL, COL or ALL ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(ALL), "lockvalue", "");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", "1");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(CELL), "lockvalue", "1,1");
logger.info("--- but succeed in getting a CELL lock on a cell in another column ---");
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(CELL), "lockvalue", "2,1");
String lock2 = result.getString("lock");
logger.info("--- now it's our first user's turn to fail to get lock ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", "2");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(CELL), "lockvalue", "2,1");
logger.info("--- release the locks ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user2, "lock", lock2);
} catch (Exception e) {
Assert.fail();
}
}
@Test public void testCompleteProjectLifeCycle() {
try {
String project = "proj4";
String user = "testuser";
String user2 = "testuser2";
String data = "blah";
String metadata = "{}";
String transformations = "[]";
String rev = "0";
logger.info("--- obtain ALL lock on project ---");
JSONObject result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
assertJSON(result, "uid", user);
String lock = result.getString("lock");
logger.info("--- start project ---");
success(broker, request, response, START, "pid", project, "uid", user, "lock", lock, "data", data, "metadata", metadata, "transformations", transformations);
logger.info("--- verify project state contains lock ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", rev);
JSONArray locks = result.getJSONArray("locks");
Assert.assertEquals(locks.length(), 1);
JSONObject l = locks.getJSONObject(0);
assertJSON(l, "uid", "testuser");
Assert.assertEquals(l.getInt("type"), ALL);
logger.info("--- release ALL lock on project ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", lock);
logger.info("--- verify no locks are present ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", rev);
locks = result.getJSONArray("locks");
Assert.assertEquals(locks.length(), 0);
logger.info("--- open project and verify data was loaded correctly ---");
result = success(broker, request, response, OPEN, "pid", project, "uid", user, "rev", rev);
JSONArray result_data = result.getJSONArray("data");
Assert.assertEquals(result_data.length(),data.getBytes("UTF-8").length);
JSONArray tt;
JSONObject t;
logger.info("--- obtain column lock ---");
String column = "1";
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(COL), "lockvalue", column);
String col_lock = result.getString("lock");
logger.info("--- perform column transformation ---");
t = new JSONObject();
t.put("op_type", COL);
t.put("op_value", column); // operate on col 1
t.put("value", new JSONObject());
tt = new JSONArray();
tt.put(t);
result = success(broker, request, response, TRANSFORM, "pid", project, "uid", user, "lock", col_lock, "transformations", tt.toString());
logger.info("--- make sure transformation was recorded properly ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "0");
tt = result.getJSONArray("transformations");
Assert.assertEquals(tt.length(), 1);
t = tt.getJSONObject(0);
assertJSON(t, "op_value", column);
logger.info("--- make sure revision numbers in state management work as expected ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "1");
tt = result.getJSONArray("transformations");
Assert.assertEquals(tt.length(), 0);
logger.info("--- perform cell transformation ---");
String cell = "1";
t = new JSONObject();
t.put("op_type", CELL);
t.put("op_value", column + "," + cell); // operate on cell at row 1 column 1
t.put("value", new JSONObject());
tt = new JSONArray();
tt.put(t);
result = success(broker, request, response, TRANSFORM, "pid", project, "uid", user, "lock", col_lock, "transformations", tt.toString());
logger.info("--- make sure transformation was recorded properly ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "0");
tt = result.getJSONArray("transformations");
Assert.assertEquals(tt.length(), 2);
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "1");
tt = result.getJSONArray("transformations");
Assert.assertEquals(tt.length(), 1);
t = tt.getJSONObject(0);
assertJSON(t, "op_value", column + "," + cell);
logger.info("--- make sure another user fails to acquire ALL lock ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(ALL), "lockvalue", "");
logger.info("--- make sure another user fails to acquire COL lock on the same column ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", column);
logger.info("--- make sure another user manages to acquire COL lock on another column ---");
String column2 = "2";
result = success(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user2, "locktype", Integer.toString(COL), "lockvalue", column2);
String col_lock2 = result.getString("lock");
logger.info("--- make sure that both locks are present ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "2");
locks = result.getJSONArray("locks");
Assert.assertEquals(locks.length(), 2);
logger.info("--- make sure we can't escalate our current COL lock to an ALL lock ---");
failure(broker, request, response, OBTAIN_LOCK, "pid", project, "uid", user, "locktype", Integer.toString(ALL), "lockvalue", "");
logger.info("--- release column locks ---");
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user, "lock", col_lock);
success(broker, request, response, RELEASE_LOCK, "pid", project, "uid", user2, "lock", col_lock2);
logger.info("--- make sure the project has no locks ---");
result = success(broker, request, response, GET_STATE, "pid", project, "uid", user, "rev", "2");
locks = result.getJSONArray("locks");
Assert.assertEquals(locks.length(), 0);
} catch (Exception e) {
Assert.fail();
}
}
// ------------------------------------------------------------------------------------
private void assertJSON(JSONObject o, String name, String value) throws JSONException {
Assert.assertEquals(o.get(name), value);
}
private JSONObject success(GridworksBroker broker, HttpServletRequest request, HttpServletResponse response, String service, String... params) throws Exception {
return call(true, broker, request, response, service, params);
}
private JSONObject failure(GridworksBroker broker, HttpServletRequest request, HttpServletResponse response, String service, String... params) throws Exception {
return call(false, broker, request, response, service, params);
}
private JSONObject call(boolean successful, GridworksBroker broker, HttpServletRequest request, HttpServletResponse response, String service, String... params) throws Exception {
if (params != null) {
for (int i = 0; i < params.length; ) {
String name = params[i++];
String value = params[i++];
if ("data".equals(name)) {
final ByteArrayInputStream inputStream = new ByteArrayInputStream(value.getBytes("UTF-8"));
when(request.getInputStream()).thenReturn(new ServletInputStream() {
public int read() throws IOException {
return inputStream.read();
}
});
} else {
when(request.getParameter(name)).thenReturn(value);
}
}
}
StringWriter writer = new StringWriter();
when(response.getWriter()).thenReturn(new PrintWriter(writer));
broker.process(service, request, response);
JSONObject result = new JSONObject(writer.toString());
if (successful) {
assertJSON(result, "status", "ok");
} else {
assertJSON(result, "status", "error");
}
logger.info(result.toString());
return result;
}
}

View File

@ -11,13 +11,11 @@
<echo message="Building extensions" />
<ant dir="sample-extension/" target="build" />
<ant dir="jython/" target="build" />
<ant dir="rdf-exporter/" target="build" />
</target>
<target name="clean">
<echo message="cleaning extensions" />
<ant dir="sample-extension/" target="clean" />
<ant dir="jython/" target="clean" />
<ant dir="rdf-exporter/" target="clean" />
</target>
</project>

View File

@ -1,10 +1,10 @@
function init() {
// Packages.java.lang.System.err.println("Initializing jython extension");
Packages.com.google.gridworks.expr.MetaParser.registerLanguageParser(
Packages.com.google.refine.expr.MetaParser.registerLanguageParser(
"jython",
"Jython",
Packages.com.google.gridworks.jython.JythonEvaluable.createParser(),
Packages.com.google.refine.jython.JythonEvaluable.createParser(),
"return value"
);
}

View File

@ -1,131 +0,0 @@
package com.google.gridworks.jython;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import org.python.core.Py;
import org.python.core.PyException;
import org.python.core.PyFunction;
import org.python.core.PyNone;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.util.PythonInterpreter;
import com.google.gridworks.expr.EvalError;
import com.google.gridworks.expr.Evaluable;
import com.google.gridworks.expr.HasFields;
import com.google.gridworks.expr.LanguageSpecificParser;
import com.google.gridworks.expr.ParsingException;
public class JythonEvaluable implements Evaluable {
static public LanguageSpecificParser createParser() {
return new LanguageSpecificParser() {
public Evaluable parse(String s) throws ParsingException {
return new JythonEvaluable(s);
}
};
}
private static final String s_functionName = "___temp___";
private static PythonInterpreter _engine;
// FIXME(SM): this initialization logic depends on the fact that the JVM's
// current working directory is the root of the Gridworks distributions
// or the development checkouts. While this works in practice, it would
// be preferable to have a more reliable address space, but since we
// don't have access to the servlet context from this class this is
// the best we can do for now.
static {
File libPath = new File("webapp/WEB-INF/lib/jython");
if (!libPath.exists() && !libPath.canRead()) {
libPath = new File("main/webapp/WEB-INF/lib/jython");
if (!libPath.exists() && !libPath.canRead()) {
libPath = null;
}
}
if (libPath != null) {
Properties props = new Properties();
props.setProperty("python.path", libPath.getAbsolutePath());
PythonInterpreter.initialize(System.getProperties(), props, new String[] { "" });
}
_engine = new PythonInterpreter();
}
public JythonEvaluable(String s) {
// indent and create a function out of the code
String[] lines = s.split("\r\n|\r|\n");
StringBuffer sb = new StringBuffer(1024);
sb.append("def ");
sb.append(s_functionName);
sb.append("(value, cell, cells, row, rowIndex):");
for (int i = 0; i < lines.length; i++) {
sb.append("\n ");
sb.append(lines[i]);
}
_engine.exec(sb.toString());
}
public Object evaluate(Properties bindings) {
try {
// call the temporary PyFunction directly
Object result = ((PyFunction)_engine.get(s_functionName)).__call__(
new PyObject[] {
Py.java2py( bindings.get("value") ),
new JythonHasFieldsWrapper((HasFields) bindings.get("cell"), bindings),
new JythonHasFieldsWrapper((HasFields) bindings.get("cells"), bindings),
new JythonHasFieldsWrapper((HasFields) bindings.get("row"), bindings),
Py.java2py( bindings.get("rowIndex") )
}
);
return unwrap(result);
} catch (PyException e) {
return new EvalError(e.getMessage());
}
}
protected Object unwrap(Object result) {
if (result != null) {
if (result instanceof JythonObjectWrapper) {
return ((JythonObjectWrapper) result)._obj;
} else if (result instanceof JythonHasFieldsWrapper) {
return ((JythonHasFieldsWrapper) result)._obj;
} else if (result instanceof PyString) {
return ((PyString) result).asString();
} else if (result instanceof PyObject) {
return unwrap((PyObject) result);
}
}
return result;
}
protected Object unwrap(PyObject po) {
if (po instanceof PyNone) {
return null;
} else if (po.isNumberType()) {
return po.asDouble();
} else if (po.isSequenceType()) {
Iterator<PyObject> i = po.asIterable().iterator();
List<Object> list = new ArrayList<Object>();
while (i.hasNext()) {
list.add(unwrap((Object) i.next()));
}
return list.toArray();
} else {
return po;
}
}
}

View File

@ -1,40 +0,0 @@
package com.google.gridworks.jython;
import java.util.Properties;
import org.python.core.Py;
import org.python.core.PyObject;
import com.google.gridworks.expr.HasFields;
public class JythonHasFieldsWrapper extends PyObject {
private static final long serialVersionUID = -1275353513262385099L;
public HasFields _obj;
private Properties _bindings;
public JythonHasFieldsWrapper(HasFields obj, Properties bindings) {
_obj = obj;
_bindings = bindings;
}
public PyObject __finditem__(PyObject key) {
String k = (String) key.__tojava__(String.class);
Object v = _obj.getField(k, _bindings);
if (v != null) {
if (v instanceof PyObject) {
return (PyObject) v;
} else if (v instanceof HasFields) {
return new JythonHasFieldsWrapper((HasFields) v, _bindings);
} else if (Py.getAdapter().canAdapt(v)) {
return Py.java2py(v);
} else {
return new JythonObjectWrapper(v);
}
} else {
return null;
}
}
}

View File

@ -1,17 +0,0 @@
package com.google.gridworks.jython;
import org.python.core.PyObject;
public class JythonObjectWrapper extends PyObject {
private static final long serialVersionUID = -6608115027151667441L;
public Object _obj;
public JythonObjectWrapper(Object obj) {
_obj = obj;
}
public String toString() {
return _obj.getClass().getSimpleName();
}
}

View File

@ -0,0 +1,131 @@
package com.google.refine.jython;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import org.python.core.Py;
import org.python.core.PyException;
import org.python.core.PyFunction;
import org.python.core.PyNone;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.util.PythonInterpreter;
import com.google.refine.expr.EvalError;
import com.google.refine.expr.Evaluable;
import com.google.refine.expr.HasFields;
import com.google.refine.expr.LanguageSpecificParser;
import com.google.refine.expr.ParsingException;
public class JythonEvaluable implements Evaluable {
static public LanguageSpecificParser createParser() {
return new LanguageSpecificParser() {
public Evaluable parse(String s) throws ParsingException {
return new JythonEvaluable(s);
}
};
}
private static final String s_functionName = "___temp___";
private static PythonInterpreter _engine;
// FIXME(SM): this initialization logic depends on the fact that the JVM's
// current working directory is the root of the Gridworks distributions
// or the development checkouts. While this works in practice, it would
// be preferable to have a more reliable address space, but since we
// don't have access to the servlet context from this class this is
// the best we can do for now.
static {
File libPath = new File("webapp/WEB-INF/lib/jython");
if (!libPath.exists() && !libPath.canRead()) {
libPath = new File("main/webapp/WEB-INF/lib/jython");
if (!libPath.exists() && !libPath.canRead()) {
libPath = null;
}
}
if (libPath != null) {
Properties props = new Properties();
props.setProperty("python.path", libPath.getAbsolutePath());
PythonInterpreter.initialize(System.getProperties(), props, new String[] { "" });
}
_engine = new PythonInterpreter();
}
public JythonEvaluable(String s) {
// indent and create a function out of the code
String[] lines = s.split("\r\n|\r|\n");
StringBuffer sb = new StringBuffer(1024);
sb.append("def ");
sb.append(s_functionName);
sb.append("(value, cell, cells, row, rowIndex):");
for (int i = 0; i < lines.length; i++) {
sb.append("\n ");
sb.append(lines[i]);
}
_engine.exec(sb.toString());
}
public Object evaluate(Properties bindings) {
try {
// call the temporary PyFunction directly
Object result = ((PyFunction)_engine.get(s_functionName)).__call__(
new PyObject[] {
Py.java2py( bindings.get("value") ),
new JythonHasFieldsWrapper((HasFields) bindings.get("cell"), bindings),
new JythonHasFieldsWrapper((HasFields) bindings.get("cells"), bindings),
new JythonHasFieldsWrapper((HasFields) bindings.get("row"), bindings),
Py.java2py( bindings.get("rowIndex") )
}
);
return unwrap(result);
} catch (PyException e) {
return new EvalError(e.getMessage());
}
}
protected Object unwrap(Object result) {
if (result != null) {
if (result instanceof JythonObjectWrapper) {
return ((JythonObjectWrapper) result)._obj;
} else if (result instanceof JythonHasFieldsWrapper) {
return ((JythonHasFieldsWrapper) result)._obj;
} else if (result instanceof PyString) {
return ((PyString) result).asString();
} else if (result instanceof PyObject) {
return unwrap((PyObject) result);
}
}
return result;
}
protected Object unwrap(PyObject po) {
if (po instanceof PyNone) {
return null;
} else if (po.isNumberType()) {
return po.asDouble();
} else if (po.isSequenceType()) {
Iterator<PyObject> i = po.asIterable().iterator();
List<Object> list = new ArrayList<Object>();
while (i.hasNext()) {
list.add(unwrap((Object) i.next()));
}
return list.toArray();
} else {
return po;
}
}
}

View File

@ -0,0 +1,40 @@
package com.google.refine.jython;
import java.util.Properties;
import org.python.core.Py;
import org.python.core.PyObject;
import com.google.refine.expr.HasFields;
public class JythonHasFieldsWrapper extends PyObject {
private static final long serialVersionUID = -1275353513262385099L;
public HasFields _obj;
private Properties _bindings;
public JythonHasFieldsWrapper(HasFields obj, Properties bindings) {
_obj = obj;
_bindings = bindings;
}
public PyObject __finditem__(PyObject key) {
String k = (String) key.__tojava__(String.class);
Object v = _obj.getField(k, _bindings);
if (v != null) {
if (v instanceof PyObject) {
return (PyObject) v;
} else if (v instanceof HasFields) {
return new JythonHasFieldsWrapper((HasFields) v, _bindings);
} else if (Py.getAdapter().canAdapt(v)) {
return Py.java2py(v);
} else {
return new JythonObjectWrapper(v);
}
} else {
return null;
}
}
}

View File

@ -0,0 +1,17 @@
package com.google.refine.jython;
import org.python.core.PyObject;
public class JythonObjectWrapper extends PyObject {
private static final long serialVersionUID = -6608115027151667441L;
public Object _obj;
public JythonObjectWrapper(Object obj) {
_obj = obj;
}
public String toString() {
return _obj.getClass().getSimpleName();
}
}

View File

@ -1,6 +1,6 @@
var html = "text/html";
var encoding = "UTF-8";
var ClientSideResourceManager = Packages.com.google.gridworks.ClientSideResourceManager;
var ClientSideResourceManager = Packages.com.google.refine.ClientSideResourceManager;
/*
* Function invoked to initialize the extension.
@ -39,7 +39,7 @@ function process(path, request, response) {
// here's how to pass things into the .vt templates
context.someList = ["Superior","Michigan","Huron","Erie","Ontario"];
context.someString = "foo";
context.someInt = Packages.com.google.gridworks.sampleExtension.SampleUtil.stringArrayLength(context.someList);
context.someInt = Packages.com.google.refine.sampleExtension.SampleUtil.stringArrayLength(context.someList);
send(request, response, "index.vt", context);
}

View File

@ -1,8 +0,0 @@
package com.google.gridworks.sampleExtension;
public class SampleUtil {
static public int stringArrayLength(String[] a) {
return a.length;
}
}

View File

@ -0,0 +1,8 @@
package com.google.refine.sampleExtension;
public class SampleUtil {
static public int stringArrayLength(String[] a) {
return a.length;
}
}

View File

@ -622,7 +622,7 @@ run() {
CLASSPATH="$GRIDWORKS_CLASSES_DIR${SEP}$GRIDWORKS_LIB_DIR/*"
RUN_CMD="$JAVA -cp $CLASSPATH $OPTS com.google.gridworks.Gridworks"
RUN_CMD="$JAVA -cp $CLASSPATH $OPTS com.google.refine.Gridworks"
#echo "$RUN_CMD"
#echo ""
@ -674,7 +674,7 @@ broker_run() {
CLASSPATH="$GRIDWORKS_CLASSES_DIR${SEP}$GRIDWORKS_LIB_DIR/*"
RUN_CMD="$JAVA -cp $CLASSPATH $OPTS com.google.gridworks.Gridworks"
RUN_CMD="$JAVA -cp $CLASSPATH $OPTS com.google.refine.Gridworks"
#echo "$RUN_CMD"
#echo ""

View File

@ -159,7 +159,7 @@ if ""%ACTION%"" == ""run"" goto doRun
:doRun
set CLASSPATH="%GRIDWORKS_CLASSES_DIR%;%GRIDWORKS_LIB_DIR%\*"
"%JAVA_HOME%\bin\java.exe" -cp %CLASSPATH% %OPTS% -Djava.library.path=%GRIDWORKS_LIB_DIR%/native/windows com.google.gridworks.Gridworks
"%JAVA_HOME%\bin\java.exe" -cp %CLASSPATH% %OPTS% -Djava.library.path=%GRIDWORKS_LIB_DIR%/native/windows com.google.refine.Gridworks
goto end
:doAnt

View File

@ -1,91 +0,0 @@
package com.google.gridworks;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.mit.simile.butterfly.ButterflyModule;
import edu.mit.simile.butterfly.MountPoint;
public class ClientSideResourceManager {
final static Logger logger = LoggerFactory.getLogger("gridworks_clientSideResourceManager");
static public class QualifiedPath {
public ButterflyModule module;
public String path;
public String fullPath;
}
static public class ClientSideResourceBundle {
final protected Set<String> _pathSet = new HashSet<String>();
final protected List<QualifiedPath> _pathList = new ArrayList<QualifiedPath>();
}
final static protected Map<String, ClientSideResourceBundle> s_bundles
= new HashMap<String, ClientSideResourceBundle>();
static public void addPaths(
String bundleName,
ButterflyModule module,
String[] paths) {
ClientSideResourceBundle bundle = s_bundles.get(bundleName);
if (bundle == null) {
bundle = new ClientSideResourceBundle();
s_bundles.put(bundleName, bundle);
}
for (String path : paths) {
String fullPath = resolve(module, path);
if (fullPath == null) {
logger.error("Failed to add paths to unmounted module " + module.getName());
break;
}
if (!bundle._pathSet.contains(fullPath)) {
QualifiedPath qualifiedPath = new QualifiedPath();
qualifiedPath.module = module;
qualifiedPath.path = path;
qualifiedPath.fullPath = fullPath;
bundle._pathSet.add(fullPath);
bundle._pathList.add(qualifiedPath);
}
}
}
static public QualifiedPath[] getPaths(String bundleName) {
ClientSideResourceBundle bundle = s_bundles.get(bundleName);
if (bundle == null) {
return new QualifiedPath[] {};
} else {
QualifiedPath[] paths = new QualifiedPath[bundle._pathList.size()];
bundle._pathList.toArray(paths);
return paths;
}
}
static protected String resolve(ButterflyModule module, String path) {
MountPoint mountPoint = module.getMountPoint();
if (mountPoint != null) {
String mountPointPath = mountPoint.getMountPoint();
if (mountPointPath != null) {
StringBuffer sb = new StringBuffer();
boolean slashed = path.startsWith("/");
char[] mountPointChars = mountPointPath.toCharArray();
sb.append(mountPointChars, 0, slashed ? mountPointChars.length - 1 : mountPointChars.length);
sb.append(path);
return sb.toString();
}
}
return null;
}
}

View File

@ -1,230 +0,0 @@
package com.google.gridworks;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gridworks.commands.Command;
import com.google.gridworks.io.FileProjectManager;
import edu.mit.simile.butterfly.Butterfly;
import edu.mit.simile.butterfly.ButterflyModule;
public class GridworksServlet extends Butterfly {
static private final String VERSION = "1.5";
private static final long serialVersionUID = 2386057901503517403L;
private static final String JAVAX_SERVLET_CONTEXT_TEMPDIR = "javax.servlet.context.tempdir";
static private GridworksServlet s_singleton;
static private File s_dataDir;
static final private Map<String, Command> commands = new HashMap<String, Command>();
// timer for periodically saving projects
static private Timer _timer;
final static Logger logger = LoggerFactory.getLogger("gridworks");
public static String getVersion() {
return VERSION;
}
final static protected long s_autoSavePeriod = 1000 * 60 * 5; // 5 minutes
static protected class AutoSaveTimerTask extends TimerTask {
public void run() {
try {
ProjectManager.singleton.save(false); // quick, potentially incomplete save
} finally {
_timer.schedule(new AutoSaveTimerTask(), s_autoSavePeriod);
// we don't use scheduleAtFixedRate because that might result in
// bunched up events when the computer is put in sleep mode
}
}
}
protected ServletConfig config;
@Override
public void init() throws ServletException {
super.init();
s_singleton = this;
logger.trace("> initialize");
String data = getInitParameter("gridworks.data");
if (data == null) {
throw new ServletException("can't find servlet init config 'gridworks.data', I have to give up initializing");
}
s_dataDir = new File(data);
FileProjectManager.initialize(s_dataDir);
if (_timer == null) {
_timer = new Timer("autosave");
_timer.schedule(new AutoSaveTimerTask(), s_autoSavePeriod);
}
logger.trace("< initialize");
}
@Override
public void destroy() {
logger.trace("> destroy");
// cancel automatic periodic saving and force a complete save.
if (_timer != null) {
_timer.cancel();
_timer = null;
}
if (ProjectManager.singleton != null) {
ProjectManager.singleton.dispose();
ProjectManager.singleton = null;
}
this.config = null;
logger.trace("< destroy");
super.destroy();
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (request.getPathInfo().startsWith("/command/")) {
String commandKey = getCommandKey(request);
Command command = commands.get(commandKey);
if (command != null) {
if (request.getMethod().equals("GET")) {
logger.trace("> GET {}", commandKey);
command.doGet(request, response);
logger.trace("< GET {}", commandKey);
} else if (request.getMethod().equals("POST")) {
logger.trace("> POST {}", commandKey);
command.doPost(request, response);
logger.trace("< POST {}", commandKey);
} else {
response.sendError(405);
}
} else {
response.sendError(404);
}
} else {
super.service(request, response);
}
}
protected String getCommandKey(HttpServletRequest request) {
// A command path has this format: /command/module-name/command-name/...
String path = request.getPathInfo().substring("/command/".length());
int slash1 = path.indexOf('/');
if (slash1 >= 0) {
int slash2 = path.indexOf('/', slash1 + 1);
if (slash2 > 0) {
path = path.substring(0, slash2);
}
}
return path;
}
private File tempDir = null;
public File getTempDir() {
if (tempDir == null) {
File tempDir = (File) this.config.getServletContext().getAttribute(JAVAX_SERVLET_CONTEXT_TEMPDIR);
if (tempDir == null) {
throw new RuntimeException("This app server doesn't support temp directories");
}
}
return tempDir;
}
public File getTempFile(String name) {
return new File(getTempDir(), name);
}
public File getCacheDir(String name) {
File dir = new File(new File(s_dataDir, "cache"), name);
dir.mkdirs();
return dir;
}
public String getConfiguration(String name, String def) {
return null;
}
/**
* Register a single command.
*
* @param module the module the command belongs to
* @param name command verb for command
* @param commandObject object implementing the command
* @return true if command was loaded and registered successfully
*/
protected boolean registerOneCommand(ButterflyModule module, String name, Command commandObject) {
return registerOneCommand(module.getName() + "/" + name, commandObject);
}
/**
* Register a single command.
*
* @param path path for command
* @param commandObject object implementing the command
* @return true if command was loaded and registered successfully
*/
protected boolean registerOneCommand(String path, Command commandObject) {
if (commands.containsKey(path)) {
return false;
}
commandObject.init(this);
commands.put(path, commandObject);
return true;
}
// Currently only for test purposes
protected boolean unregisterCommand(String verb) {
return commands.remove(verb) != null;
}
/**
* Register a single command. Used by extensions.
*
* @param module the module the command belongs to
* @param name command verb for command
* @param commandObject object implementing the command
*
* @return true if command was loaded and registered successfully
*/
static public boolean registerCommand(ButterflyModule module, String commandName, Command commandObject) {
return s_singleton.registerOneCommand(module, commandName, commandObject);
}
static public Class<?> getClass(String className) throws ClassNotFoundException {
if (className.startsWith("com.metaweb.")) {
className = "com.google." + className.substring("com.metaweb.".length());
}
return Class.forName(className);
}
}

View File

@ -1,128 +0,0 @@
package com.google.gridworks;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.expr.HasFieldsListImpl;
import com.google.gridworks.expr.WrappedRow;
import com.google.gridworks.model.Column;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
public class InterProjectModel {
static public class ProjectJoin {
final public long fromProjectID;
final public String fromProjectColumnName;
final public long toProjectID;
final public String toProjectColumnName;
final public Map<Object, List<Integer>> valueToRowIndices =
new HashMap<Object, List<Integer>>();
ProjectJoin(
long fromProjectID,
String fromProjectColumnName,
long toProjectID,
String toProjectColumnName
) {
this.fromProjectID = fromProjectID;
this.fromProjectColumnName = fromProjectColumnName;
this.toProjectID = toProjectID;
this.toProjectColumnName = toProjectColumnName;
}
public HasFieldsListImpl getRows(Object value) {
if (ExpressionUtils.isNonBlankData(value) && valueToRowIndices.containsKey(value)) {
Project toProject = ProjectManager.singleton.getProject(toProjectID);
if (toProject != null) {
HasFieldsListImpl rows = new HasFieldsListImpl();
for (Integer r : valueToRowIndices.get(value)) {
Row row = toProject.rows.get(r);
rows.add(new WrappedRow(toProject, r, row));
}
return rows;
}
}
return null;
}
}
protected Map<String, ProjectJoin> _joins = new HashMap<String, ProjectJoin>();
public ProjectJoin getJoin(String fromProject, String fromColumn, String toProject, String toColumn) {
String key = fromProject + ";" + fromColumn + ";" + toProject + ";" + toColumn;
if (!_joins.containsKey(key)) {
ProjectJoin join = new ProjectJoin(
ProjectManager.singleton.getProjectID(fromProject),
fromColumn,
ProjectManager.singleton.getProjectID(toProject),
toColumn
);
computeJoin(join);
_joins.put(key, join);
}
return _joins.get(key);
}
public void flushJoinsInvolvingProject(long projectID) {
for (Entry<String, ProjectJoin> entry : _joins.entrySet()) {
ProjectJoin join = entry.getValue();
if (join.fromProjectID == projectID || join.toProjectID == projectID) {
_joins.remove(entry.getKey());
}
}
}
public void flushJoinsInvolvingProjectColumn(long projectID, String columnName) {
for (Entry<String, ProjectJoin> entry : _joins.entrySet()) {
ProjectJoin join = entry.getValue();
if (join.fromProjectID == projectID && join.fromProjectColumnName.equals(columnName) ||
join.toProjectID == projectID && join.toProjectColumnName.equals(columnName)) {
_joins.remove(entry.getKey());
}
}
}
protected void computeJoin(ProjectJoin join) {
if (join.fromProjectID < 0 || join.toProjectID < 0) {
return;
}
Project fromProject = ProjectManager.singleton.getProject(join.fromProjectID);
Project toProject = ProjectManager.singleton.getProject(join.toProjectID);
if (fromProject == null || toProject == null) {
return;
}
Column fromColumn = fromProject.columnModel.getColumnByName(join.fromProjectColumnName);
Column toColumn = toProject.columnModel.getColumnByName(join.toProjectColumnName);
if (fromColumn == null || toColumn == null) {
return;
}
for (Row fromRow : fromProject.rows) {
Object value = fromRow.getCellValue(fromColumn.getCellIndex());
if (ExpressionUtils.isNonBlankData(value) && !join.valueToRowIndices.containsKey(value)) {
join.valueToRowIndices.put(value, new ArrayList<Integer>());
}
}
int count = toProject.rows.size();
for (int r = 0; r < count; r++) {
Row toRow = toProject.rows.get(r);
Object value = toRow.getCellValue(toColumn.getCellIndex());
if (ExpressionUtils.isNonBlankData(value) && join.valueToRowIndices.containsKey(value)) {
join.valueToRowIndices.get(value).add(r);
}
}
}
}

View File

@ -1,16 +0,0 @@
package com.google.gridworks;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
/**
* Interface for streaming out JSON, either into HTTP responses or
* serialization files.
*
* @author dfhuynh
*/
public interface Jsonizable {
public void write(JSONWriter writer, Properties options) throws JSONException;
}

View File

@ -1,434 +0,0 @@
package com.google.gridworks;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.tools.tar.TarOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gridworks.history.HistoryEntryManager;
import com.google.gridworks.model.Project;
import com.google.gridworks.preference.PreferenceStore;
import com.google.gridworks.preference.TopList;
/**
* ProjectManager is responsible for loading and saving the workspace and projects.
*
*
*/
public abstract class ProjectManager {
// last n expressions used across all projects
static protected final int s_expressionHistoryMax = 100;
protected Map<Long, ProjectMetadata> _projectsMetadata;
protected PreferenceStore _preferenceStore;
final static Logger logger = LoggerFactory.getLogger("project_manager");
/**
* What caches the joins between projects.
*/
transient protected InterProjectModel _interProjectModel = new InterProjectModel();
/**
* Flags
*/
transient protected int _busy = 0; // heavy operations like creating or importing projects are going on
/**
* While each project's metadata is loaded completely at start-up, each project's raw data
* is loaded only when the project is accessed by the user. This is because project
* metadata is tiny compared to raw project data. This hash map from project ID to project
* is more like a last accessed-last out cache.
*/
transient protected Map<Long, Project> _projects;
static public ProjectManager singleton;
protected ProjectManager(){
_projectsMetadata = new HashMap<Long, ProjectMetadata>();
_preferenceStore = new PreferenceStore();
_projects = new HashMap<Long, Project>();
preparePreferenceStore(_preferenceStore);
}
public void dispose() {
save(true); // complete save
for (Project project : _projects.values()) {
if (project != null) {
project.dispose();
}
}
_projects.clear();
_projectsMetadata.clear();
}
/**
* Registers the project in the memory of the current session
* @param project
* @param projectMetadata
*/
public void registerProject(Project project, ProjectMetadata projectMetadata) {
synchronized (this) {
_projects.put(project.id, project);
_projectsMetadata.put(project.id, projectMetadata);
}
}
//----------Load from data store to memory----------------
/**
* Load project metadata from data storage
* @param projectID
* @return
*/
public abstract boolean loadProjectMetadata(long projectID);
/**
* Loads a project from the data store into memory
* @param id
* @return
*/
protected abstract Project loadProject(long id);
//------------Import and Export from Gridworks archive-----------------
/**
* Import project from a Gridworks archive
* @param projectID
* @param inputStream
* @param gziped
* @throws IOException
*/
public abstract void importProject(long projectID, InputStream inputStream, boolean gziped) throws IOException;
/**
* Export project to a Gridworks archive
* @param projectId
* @param tos
* @throws IOException
*/
public abstract void exportProject(long projectId, TarOutputStream tos) throws IOException;
//------------Save to record store------------
/**
* Saves a project and its metadata to the data store
* @param id
*/
public void ensureProjectSaved(long id) {
synchronized(this){
ProjectMetadata metadata = this.getProjectMetadata(id);
if (metadata != null) {
try {
saveMetadata(metadata, id);
} catch (Exception e) {
e.printStackTrace();
}
}//FIXME what should be the behaviour if metadata is null? i.e. not found
Project project = getProject(id);
if (project != null && metadata != null && metadata.getModified().after(project.getLastSave())) {
try {
saveProject(project);
} catch (Exception e) {
e.printStackTrace();
}
}//FIXME what should be the behaviour if project is null? i.e. not found or loaded.
//FIXME what should happen if the metadata is found, but not the project? or vice versa?
}
}
/**
* Save project metadata to the data store
* @param metadata
* @param projectId
* @throws Exception
*/
protected abstract void saveMetadata(ProjectMetadata metadata, long projectId) throws Exception;
/**
* Save project to the data store
* @param project
*/
protected abstract void saveProject(Project project);
/**
* Save workspace and all projects to data store
* @param allModified
*/
public void save(boolean allModified) {
if (allModified || _busy == 0) {
saveProjects(allModified);
saveWorkspace();
}
}
/**
* Saves the workspace to the data store
*/
protected abstract void saveWorkspace();
/**
* A utility class to prioritize projects for saving, depending on how long ago
* they have been changed but have not been saved.
*/
static protected class SaveRecord {
final Project project;
final long overdue;
SaveRecord(Project project, long overdue) {
this.project = project;
this.overdue = overdue;
}
}
static protected final int s_projectFlushDelay = 1000 * 60 * 60; // 1 hour
static protected final int s_quickSaveTimeout = 1000 * 30; // 30 secs
/**
* Saves all projects to the data store
* @param allModified
*/
protected void saveProjects(boolean allModified) {
List<SaveRecord> records = new ArrayList<SaveRecord>();
Date startTimeOfSave = new Date();
synchronized (this) {
for (long id : _projectsMetadata.keySet()) {
ProjectMetadata metadata = getProjectMetadata(id);
Project project = _projects.get(id); // don't call getProject() as that will load the project.
if (project != null) {
boolean hasUnsavedChanges =
metadata.getModified().getTime() > project.getLastSave().getTime();
if (hasUnsavedChanges) {
long msecsOverdue = startTimeOfSave.getTime() - project.getLastSave().getTime();
records.add(new SaveRecord(project, msecsOverdue));
} else if (startTimeOfSave.getTime() - project.getLastSave().getTime() > s_projectFlushDelay) {
/*
* It's been a while since the project was last saved and it hasn't been
* modified. We can safely remove it from the cache to save some memory.
*/
_projects.remove(id).dispose();
}
}
}
}
if (records.size() > 0) {
Collections.sort(records, new Comparator<SaveRecord>() {
public int compare(SaveRecord o1, SaveRecord o2) {
if (o1.overdue < o2.overdue) {
return 1;
} else if (o1.overdue > o2.overdue) {
return -1;
} else {
return 0;
}
}
});
logger.info(allModified ?
"Saving all modified projects ..." :
"Saving some modified projects ..."
);
for (int i = 0;
i < records.size() &&
(allModified || (new Date().getTime() - startTimeOfSave.getTime() < s_quickSaveTimeout));
i++) {
try {
saveProject(records.get(i).project);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//--------------Get from memory--------------
/**
* Gets the InterProjectModel from memory
*/
public InterProjectModel getInterProjectModel() {
return _interProjectModel;
}
/**
* Gets the project metadata from memory
* Requires that the metadata has already been loaded from the data store
* @param id
* @return
*/
public ProjectMetadata getProjectMetadata(long id) {
return _projectsMetadata.get(id);
}
/**
* Gets the project metadata from memory
* Requires that the metadata has already been loaded from the data store
* @param name
* @return
*/
public ProjectMetadata getProjectMetadata(String name) {
for (ProjectMetadata pm : _projectsMetadata.values()) {
if (pm.getName().equals(name)) {
return pm;
}
}
return null;
}
/**
* Tries to find the project id when given a project name
* Requires that all project metadata exists has been loaded to memory from the data store
* @param name
* The name of the project
* @return
* The id of the project, or -1 if it cannot be found
*/
public long getProjectID(String name) {
for (Entry<Long, ProjectMetadata> entry : _projectsMetadata.entrySet()) {
if (entry.getValue().getName().equals(name)) {
return entry.getKey();
}
}
return -1;
}
/**
* Gets all the project Metadata currently held in memory
* @return
*/
public Map<Long, ProjectMetadata> getAllProjectMetadata() {
return _projectsMetadata;
}
/**
* Gets the required project from the data store
* If project does not already exist in memory, it is loaded from the data store
* @param id
* the id of the project
* @return
* the project with the matching id, or null if it can't be found
*/
public Project getProject(long id) {
synchronized (this) {
if (_projects.containsKey(id)) {
return _projects.get(id);
} else {
Project project = loadProject(id);
_projects.put(id, project);
return project;
}
}
}
/**
* Gets the preference store
* @return
*/
public PreferenceStore getPreferenceStore() {
return _preferenceStore;
}
/**
* Gets all expressions from the preference store
* @return
*/
public List<String> getExpressions() {
return ((TopList) _preferenceStore.get("scripting.expressions")).getList();
}
/**
* The history entry manager deals with changes
* @return manager for handling history
*/
public abstract HistoryEntryManager getHistoryEntryManager();
//-------------remove project-----------
/**
* Remove the project from the data store
* @param project
*/
public void deleteProject(Project project) {
deleteProject(project.id);
}
/**
* Remove project from data store
* @param projectID
*/
public abstract void deleteProject(long projectID);
/**
* Removes project from memory
* @param projectID
*/
protected void removeProject(long projectID){
if (_projects.containsKey(projectID)) {
_projects.remove(projectID).dispose();
}
if (_projectsMetadata.containsKey(projectID)) {
_projectsMetadata.remove(projectID);
}
}
//--------------Miscellaneous-----------
/**
* Sets the flag for long running operations
* @param busy
*/
public void setBusy(boolean busy) {
synchronized (this) {
if (busy) {
_busy++;
} else {
_busy--;
}
}
}
/**
* Add the latest expression to the preference store
* @param s
*/
public void addLatestExpression(String s) {
synchronized (this) {
((TopList) _preferenceStore.get("scripting.expressions")).add(s);
}
}
/**
*
* @param ps
*/
static protected void preparePreferenceStore(PreferenceStore ps) {
ps.put("scripting.expressions", new TopList(s_expressionHistoryMax));
}
}

View File

@ -1,198 +0,0 @@
package com.google.gridworks;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gridworks.preference.PreferenceStore;
import com.google.gridworks.preference.TopList;
import com.google.gridworks.util.JSONUtilities;
import com.google.gridworks.util.ParsingUtilities;
public class ProjectMetadata implements Jsonizable {
private final Date _created;
private Date _modified;
private String _name;
private String _password;
private String _encoding;
private int _encodingConfidence;
private Map<String, Serializable> _customMetadata = new HashMap<String, Serializable>();
private PreferenceStore _preferenceStore = new PreferenceStore();
final Logger logger = LoggerFactory.getLogger("project_metadata");
protected ProjectMetadata(Date date) {
_created = date;
preparePreferenceStore(_preferenceStore);
}
public ProjectMetadata() {
_created = new Date();
_modified = _created;
preparePreferenceStore(_preferenceStore);
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("name"); writer.value(_name);
writer.key("created"); writer.value(ParsingUtilities.dateToString(_created));
writer.key("modified"); writer.value(ParsingUtilities.dateToString(_modified));
if ("save".equals(options.getProperty("mode"))) {
writer.key("password"); writer.value(_password);
writer.key("encoding"); writer.value(_encoding);
writer.key("encodingConfidence"); writer.value(_encodingConfidence);
writer.key("customMetadata"); writer.object();
for (String key : _customMetadata.keySet()) {
Serializable value = _customMetadata.get(key);
writer.key(key);
writer.value(value);
}
writer.endObject();
writer.key("preferences"); _preferenceStore.write(writer, options);
}
writer.endObject();
}
public void write(JSONWriter jsonWriter) throws Exception {
Properties options = new Properties();
options.setProperty("mode", "save");
write(jsonWriter, options);
}
static public ProjectMetadata loadFromJSON(JSONObject obj) {
ProjectMetadata pm = new ProjectMetadata(JSONUtilities.getDate(obj, "modified", new Date()));
pm._modified = JSONUtilities.getDate(obj, "modified", new Date());
pm._name = JSONUtilities.getString(obj, "name", "<Error recovering project name>");
pm._password = JSONUtilities.getString(obj, "password", "");
pm._encoding = JSONUtilities.getString(obj, "encoding", "");
pm._encodingConfidence = JSONUtilities.getInt(obj, "encodingConfidence", 0);
if (obj.has("preferences") && !obj.isNull("preferences")) {
try {
pm._preferenceStore.load(obj.getJSONObject("preferences"));
} catch (JSONException e) {
// ignore
}
}
if (obj.has("expressions") && !obj.isNull("expressions")) { // backward compatibility
try {
((TopList) pm._preferenceStore.get("scripting.expressions"))
.load(obj.getJSONArray("expressions"));
} catch (JSONException e) {
// ignore
}
}
if (obj.has("customMetadata") && !obj.isNull("customMetadata")) {
try {
JSONObject obj2 = obj.getJSONObject("customMetadata");
@SuppressWarnings("unchecked")
Iterator<String> keys = obj2.keys();
while (keys.hasNext()) {
String key = keys.next();
Object value = obj2.get(key);
if (value != null && value instanceof Serializable) {
pm._customMetadata.put(key, (Serializable) value);
}
}
} catch (JSONException e) {
// ignore
}
}
return pm;
}
static protected void preparePreferenceStore(PreferenceStore ps) {
ProjectManager.preparePreferenceStore(ps);
// Any project specific preferences?
}
public Date getCreated() {
return _created;
}
public void setName(String name) {
this._name = name;
}
public String getName() {
return _name;
}
public void setEncoding(String encoding) {
this._encoding = encoding;
}
public String getEncoding() {
return _encoding;
}
public void setEncodingConfidence(int confidence) {
this._encodingConfidence = confidence;
}
public void setEncodingConfidence(String confidence) {
if (confidence != null) {
this.setEncodingConfidence(Integer.parseInt(confidence));
}
}
public int getEncodingConfidence() {
return _encodingConfidence;
}
public void setPassword(String password) {
this._password = password;
}
public String getPassword() {
return _password;
}
public Date getModified() {
return _modified;
}
public void updateModified() {
_modified = new Date();
}
public PreferenceStore getPreferenceStore() {
return _preferenceStore;
}
public Serializable getCustomMetadata(String key) {
return _customMetadata.get(key);
}
public void setCustomMetadata(String key, Serializable value) {
if (value == null) {
_customMetadata.remove(key);
} else {
_customMetadata.put(key, value);
}
}
}

View File

@ -1,33 +0,0 @@
package com.google.gridworks.browsing;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.gridworks.Jsonizable;
/**
* Store a value and its text label, in case the value is not a string itself.
* For instance, if a value is a date, then its label can be one particular
* rendering of that date.
*
* Facet choices that are presented to the user as text are stored as decorated values.
*/
public class DecoratedValue implements Jsonizable {
final public Object value;
final public String label;
public DecoratedValue(Object value, String label) {
this.value = value;
this.label = label;
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("v"); writer.value(value);
writer.key("l"); writer.value(label);
writer.endObject();
}
}

View File

@ -1,214 +0,0 @@
package com.google.gridworks.browsing;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import com.google.gridworks.Jsonizable;
import com.google.gridworks.browsing.facets.Facet;
import com.google.gridworks.browsing.facets.ListFacet;
import com.google.gridworks.browsing.facets.RangeFacet;
import com.google.gridworks.browsing.facets.ScatterplotFacet;
import com.google.gridworks.browsing.facets.TextSearchFacet;
import com.google.gridworks.browsing.facets.TimeRangeFacet;
import com.google.gridworks.browsing.util.ConjunctiveFilteredRecords;
import com.google.gridworks.browsing.util.ConjunctiveFilteredRows;
import com.google.gridworks.browsing.util.FilteredRecordsAsFilteredRows;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
/**
* Faceted browsing engine.
*/
public class Engine implements Jsonizable {
static public enum Mode {
RowBased,
RecordBased
}
public final static String INCLUDE_DEPENDENT = "includeDependent";
public final static String MODE = "mode";
public final static String MODE_ROW_BASED = "row-based";
public final static String MODE_RECORD_BASED = "record-based";
protected Project _project;
protected List<Facet> _facets = new LinkedList<Facet>();
protected Mode _mode = Mode.RowBased;
static public String modeToString(Mode mode) {
return mode == Mode.RowBased ? MODE_ROW_BASED : MODE_RECORD_BASED;
}
static public Mode stringToMode(String s) {
return MODE_ROW_BASED.equals(s) ? Mode.RowBased : Mode.RecordBased;
}
public Engine(Project project) {
_project = project;
}
public Mode getMode() {
return _mode;
}
public void setMode(Mode mode) {
_mode = mode;
}
public FilteredRows getAllRows() {
return new FilteredRows() {
@Override
public void accept(Project project, RowVisitor visitor) {
try {
visitor.start(project);
int c = project.rows.size();
for (int rowIndex = 0; rowIndex < c; rowIndex++) {
Row row = project.rows.get(rowIndex);
visitor.visit(project, rowIndex, row);
}
} finally {
visitor.end(project);
}
}
};
}
public FilteredRows getAllFilteredRows() {
return getFilteredRows(null);
}
public FilteredRows getFilteredRows(Facet except) {
if (_mode == Mode.RecordBased) {
return new FilteredRecordsAsFilteredRows(getFilteredRecords(except));
} else if (_mode == Mode.RowBased) {
ConjunctiveFilteredRows cfr = new ConjunctiveFilteredRows();
for (Facet facet : _facets) {
if (facet != except) {
RowFilter rowFilter = facet.getRowFilter(_project);
if (rowFilter != null) {
cfr.add(rowFilter);
}
}
}
return cfr;
}
throw new InternalError("Unknown mode.");
}
public FilteredRecords getAllRecords() {
return new FilteredRecords() {
@Override
public void accept(Project project, RecordVisitor visitor) {
try {
visitor.start(project);
int c = project.recordModel.getRecordCount();
for (int r = 0; r < c; r++) {
visitor.visit(project, project.recordModel.getRecord(r));
}
} finally {
visitor.end(project);
}
}
};
}
public FilteredRecords getFilteredRecords() {
return getFilteredRecords(null);
}
public FilteredRecords getFilteredRecords(Facet except) {
if (_mode == Mode.RecordBased) {
ConjunctiveFilteredRecords cfr = new ConjunctiveFilteredRecords();
for (Facet facet : _facets) {
if (facet != except) {
RecordFilter recordFilter = facet.getRecordFilter(_project);
if (recordFilter != null) {
cfr.add(recordFilter);
}
}
}
return cfr;
}
throw new InternalError("This method should not be called when the engine is not in record mode.");
}
public void initializeFromJSON(JSONObject o) throws Exception {
if (o == null) {
return;
}
if (o.has("facets") && !o.isNull("facets")) {
JSONArray a = o.getJSONArray("facets");
int length = a.length();
for (int i = 0; i < length; i++) {
JSONObject fo = a.getJSONObject(i);
String type = fo.has("type") ? fo.getString("type") : "list";
Facet facet = null;
if ("list".equals(type)) {
facet = new ListFacet();
} else if ("range".equals(type)) {
facet = new RangeFacet();
} else if ("timerange".equals(type)) {
facet = new TimeRangeFacet();
} else if ("scatterplot".equals(type)) {
facet = new ScatterplotFacet();
} else if ("text".equals(type)) {
facet = new TextSearchFacet();
}
if (facet != null) {
facet.initializeFromJSON(_project, fo);
_facets.add(facet);
}
}
}
// for backward compatibility
if (o.has(INCLUDE_DEPENDENT) && !o.isNull(INCLUDE_DEPENDENT)) {
_mode = o.getBoolean(INCLUDE_DEPENDENT) ? Mode.RecordBased : Mode.RowBased;
}
if (o.has(MODE) && !o.isNull(MODE)) {
_mode = MODE_ROW_BASED.equals(o.getString(MODE)) ? Mode.RowBased : Mode.RecordBased;
}
}
public void computeFacets() throws JSONException {
if (_mode == Mode.RowBased) {
for (Facet facet : _facets) {
FilteredRows filteredRows = getFilteredRows(facet);
facet.computeChoices(_project, filteredRows);
}
} else if (_mode == Mode.RecordBased) {
for (Facet facet : _facets) {
FilteredRecords filteredRecords = getFilteredRecords(facet);
facet.computeChoices(_project, filteredRecords);
}
} else {
throw new InternalError("Unknown mode.");
}
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("facets");
writer.array();
for (Facet facet : _facets) {
facet.write(writer, options);
}
writer.endArray();
writer.key(MODE); writer.value(_mode == Mode.RowBased ? MODE_ROW_BASED : MODE_RECORD_BASED);
writer.endObject();
}
}

View File

@ -1,18 +0,0 @@
package com.google.gridworks.browsing;
import com.google.gridworks.model.Project;
/**
* Interface for anything that can decide which records match and which don't
* based on some particular criteria.
*/
public interface FilteredRecords {
/**
* Go through the records of the given project, determine which match and which don't,
* and call visitor.visit() on those that match
*
* @param project
* @param visitor
*/
public void accept(Project project, RecordVisitor visitor);
}

View File

@ -1,19 +0,0 @@
package com.google.gridworks.browsing;
import com.google.gridworks.model.Project;
/**
* Interface for anything that can decide which rows match and which rows don't match
* based on some particular criteria.
*/
public interface FilteredRows {
/**
* Go through the rows of the given project, determine which match and which don't,
* and call visitor.visit() on those that match, and possibly their context and
* dependent rows.
*
* @param project
* @param visitor
*/
public void accept(Project project, RowVisitor visitor);
}

View File

@ -1,12 +0,0 @@
package com.google.gridworks.browsing;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
/**
* Interface for judging if a particular record matches or doesn't match some
* particular criterion, such as a facet constraint.
*/
public interface RecordFilter {
public boolean filterRecord(Project project, Record record);
}

View File

@ -1,19 +0,0 @@
package com.google.gridworks.browsing;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
/**
* Interface for visiting records one by one. The records visited are only those that match some
* particular criteria, such as facets' constraints.
*/
public interface RecordVisitor {
public void start(Project project); // called before any visit() call
public boolean visit(
Project project,
Record record
);
public void end(Project project); // called after all visit() calls
}

View File

@ -1,12 +0,0 @@
package com.google.gridworks.browsing;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
/**
* Interface for judging if a particular row matches or doesn't match some
* particular criterion, such as a facet constraint.
*/
public interface RowFilter {
public boolean filterRow(Project project, int rowIndex, Row row);
}

View File

@ -1,20 +0,0 @@
package com.google.gridworks.browsing;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
/**
* Interface for visiting rows one by one. The rows visited are only those that match some
* particular criteria, such as facets' constraints.
*/
public interface RowVisitor {
public void start(Project project); // called before any visit() call
public boolean visit(
Project project,
int rowIndex, // zero-based row index
Row row
);
public void end(Project project); // called after all visit() calls
}

View File

@ -1,25 +0,0 @@
package com.google.gridworks.browsing.facets;
import org.json.JSONObject;
import com.google.gridworks.Jsonizable;
import com.google.gridworks.browsing.FilteredRecords;
import com.google.gridworks.browsing.FilteredRows;
import com.google.gridworks.browsing.RecordFilter;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.model.Project;
/**
* Interface of facets.
*/
public interface Facet extends Jsonizable {
public RowFilter getRowFilter(Project project);
public RecordFilter getRecordFilter(Project project);
public void computeChoices(Project project, FilteredRows filteredRows);
public void computeChoices(Project project, FilteredRecords filteredRecords);
public void initializeFromJSON(Project project, JSONObject o) throws Exception;
}

View File

@ -1,255 +0,0 @@
package com.google.gridworks.browsing.facets;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import com.google.gridworks.ProjectManager;
import com.google.gridworks.browsing.DecoratedValue;
import com.google.gridworks.browsing.FilteredRecords;
import com.google.gridworks.browsing.FilteredRows;
import com.google.gridworks.browsing.RecordFilter;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.browsing.filters.AllRowsRecordFilter;
import com.google.gridworks.browsing.filters.AnyRowRecordFilter;
import com.google.gridworks.browsing.filters.ExpressionEqualRowFilter;
import com.google.gridworks.browsing.util.ExpressionNominalValueGrouper;
import com.google.gridworks.expr.Evaluable;
import com.google.gridworks.expr.MetaParser;
import com.google.gridworks.expr.ParsingException;
import com.google.gridworks.model.Column;
import com.google.gridworks.model.Project;
import com.google.gridworks.util.JSONUtilities;
public class ListFacet implements Facet {
/*
* Configuration
*/
protected String _name;
protected String _expression;
protected String _columnName;
protected boolean _invert;
// If true, then facet won't show the blank and error choices
protected boolean _omitBlank;
protected boolean _omitError;
protected List<NominalFacetChoice> _selection = new LinkedList<NominalFacetChoice>();
protected boolean _selectBlank;
protected boolean _selectError;
/*
* Derived configuration
*/
protected int _cellIndex;
protected Evaluable _eval;
protected String _errorMessage;
/*
* Computed results
*/
protected List<NominalFacetChoice> _choices = new LinkedList<NominalFacetChoice>();
protected int _blankCount;
protected int _errorCount;
public ListFacet() {
}
@Override
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("name"); writer.value(_name);
writer.key("expression"); writer.value(_expression);
writer.key("columnName"); writer.value(_columnName);
writer.key("invert"); writer.value(_invert);
if (_errorMessage != null) {
writer.key("error"); writer.value(_errorMessage);
} else if (_choices.size() > getLimit()) {
writer.key("error"); writer.value("Too many choices");
} else {
writer.key("choices"); writer.array();
for (NominalFacetChoice choice : _choices) {
choice.write(writer, options);
}
writer.endArray();
if (!_omitBlank && (_selectBlank || _blankCount > 0)) {
writer.key("blankChoice");
writer.object();
writer.key("s"); writer.value(_selectBlank);
writer.key("c"); writer.value(_blankCount);
writer.endObject();
}
if (!_omitError && (_selectError || _errorCount > 0)) {
writer.key("errorChoice");
writer.object();
writer.key("s"); writer.value(_selectError);
writer.key("c"); writer.value(_errorCount);
writer.endObject();
}
}
writer.endObject();
}
protected int getLimit() {
Object v = ProjectManager.singleton.getPreferenceStore().get("ui.browsing.listFacet.limit");
if (v != null) {
if (v instanceof Number) {
return ((Number) v).intValue();
} else {
try {
int n = Integer.parseInt(v.toString());
return n;
} catch (NumberFormatException e) {
// ignore
}
}
}
return 2000;
}
@Override
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
_name = o.getString("name");
_expression = o.getString("expression");
_columnName = o.getString("columnName");
_invert = o.has("invert") && o.getBoolean("invert");
if (_columnName.length() > 0) {
Column column = project.columnModel.getColumnByName(_columnName);
if (column != null) {
_cellIndex = column.getCellIndex();
} else {
_errorMessage = "No column named " + _columnName;
}
} else {
_cellIndex = -1;
}
try {
_eval = MetaParser.parse(_expression);
} catch (ParsingException e) {
_errorMessage = e.getMessage();
}
_selection.clear();
JSONArray a = o.getJSONArray("selection");
int length = a.length();
for (int i = 0; i < length; i++) {
JSONObject oc = a.getJSONObject(i);
JSONObject ocv = oc.getJSONObject("v");
DecoratedValue decoratedValue = new DecoratedValue(
ocv.get("v"), ocv.getString("l"));
NominalFacetChoice nominalFacetChoice = new NominalFacetChoice(decoratedValue);
nominalFacetChoice.selected = true;
_selection.add(nominalFacetChoice);
}
_omitBlank = JSONUtilities.getBoolean(o, "omitBlank", false);
_omitError = JSONUtilities.getBoolean(o, "omitError", false);
_selectBlank = JSONUtilities.getBoolean(o, "selectBlank", false);
_selectError = JSONUtilities.getBoolean(o, "selectError", false);
}
@Override
public RowFilter getRowFilter(Project project) {
return
_eval == null ||
_errorMessage != null ||
(_selection.size() == 0 && !_selectBlank && !_selectError) ?
null :
new ExpressionEqualRowFilter(
_eval,
_columnName,
_cellIndex,
createMatches(),
_selectBlank,
_selectError,
_invert);
}
@Override
public RecordFilter getRecordFilter(Project project) {
RowFilter rowFilter = getRowFilter(project);
return rowFilter == null ? null :
(_invert ?
new AllRowsRecordFilter(rowFilter) :
new AnyRowRecordFilter(rowFilter));
}
@Override
public void computeChoices(Project project, FilteredRows filteredRows) {
if (_eval != null && _errorMessage == null) {
ExpressionNominalValueGrouper grouper =
new ExpressionNominalValueGrouper(_eval, _columnName, _cellIndex);
filteredRows.accept(project, grouper);
postProcessGrouper(grouper);
}
}
@Override
public void computeChoices(Project project, FilteredRecords filteredRecords) {
if (_eval != null && _errorMessage == null) {
ExpressionNominalValueGrouper grouper =
new ExpressionNominalValueGrouper(_eval, _columnName, _cellIndex);
filteredRecords.accept(project, grouper);
postProcessGrouper(grouper);
}
}
protected void postProcessGrouper(ExpressionNominalValueGrouper grouper) {
_choices.clear();
_choices.addAll(grouper.choices.values());
for (NominalFacetChoice choice : _selection) {
String valueString = choice.decoratedValue.value.toString();
if (grouper.choices.containsKey(valueString)) {
grouper.choices.get(valueString).selected = true;
} else {
/*
* A selected choice can have zero count if it is selected together
* with other choices, and some other facets' constraints eliminate
* all rows projected to this choice altogether. For example, if you
* select both "car" and "bicycle" in the "type of vehicle" facet, and
* then constrain the "wheels" facet to more than 2, then the "bicycle"
* choice now has zero count even if it's still selected. The grouper
* won't be able to detect the "bicycle" choice, so we need to inject
* that choice into the choice list ourselves.
*/
choice.count = 0;
_choices.add(choice);
}
}
_blankCount = grouper.blankCount;
_errorCount = grouper.errorCount;
}
protected Object[] createMatches() {
Object[] a = new Object[_selection.size()];
for (int i = 0; i < a.length; i++) {
a[i] = _selection.get(i).decoratedValue.value;
}
return a;
}
}

View File

@ -1,32 +0,0 @@
package com.google.gridworks.browsing.facets;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.gridworks.Jsonizable;
import com.google.gridworks.browsing.DecoratedValue;
/**
* Store a facet choice that has a decorated value, a count of matched rows,
* and a flag of whether it has been selected.
*/
public class NominalFacetChoice implements Jsonizable {
final public DecoratedValue decoratedValue;
public int count;
public boolean selected;
public NominalFacetChoice(DecoratedValue decoratedValue) {
this.decoratedValue = decoratedValue;
}
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("v"); decoratedValue.write(writer, options);
writer.key("c"); writer.value(count);
writer.key("s"); writer.value(selected);
writer.endObject();
}
}

View File

@ -1,259 +0,0 @@
package com.google.gridworks.browsing.facets;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import com.google.gridworks.browsing.FilteredRecords;
import com.google.gridworks.browsing.FilteredRows;
import com.google.gridworks.browsing.RecordFilter;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.browsing.filters.AnyRowRecordFilter;
import com.google.gridworks.browsing.filters.ExpressionNumberComparisonRowFilter;
import com.google.gridworks.browsing.util.ExpressionBasedRowEvaluable;
import com.google.gridworks.browsing.util.ExpressionNumericValueBinner;
import com.google.gridworks.browsing.util.NumericBinIndex;
import com.google.gridworks.browsing.util.NumericBinRecordIndex;
import com.google.gridworks.browsing.util.NumericBinRowIndex;
import com.google.gridworks.browsing.util.RowEvaluable;
import com.google.gridworks.expr.Evaluable;
import com.google.gridworks.expr.MetaParser;
import com.google.gridworks.expr.ParsingException;
import com.google.gridworks.model.Column;
import com.google.gridworks.model.Project;
import com.google.gridworks.util.JSONUtilities;
public class RangeFacet implements Facet {
/*
* Configuration, from the client side
*/
protected String _name; // name of facet
protected String _expression; // expression to compute numeric value(s) per row
protected String _columnName; // column to base expression on, if any
protected double _from; // the numeric selection
protected double _to;
protected boolean _selectNumeric; // whether the numeric selection applies, default true
protected boolean _selectNonNumeric;
protected boolean _selectBlank;
protected boolean _selectError;
/*
* Derived configuration data
*/
protected int _cellIndex;
protected Evaluable _eval;
protected String _errorMessage;
protected boolean _selected; // false if we're certain that all rows will match
// and there isn't any filtering to do
/*
* Computed data, to return to the client side
*/
protected double _min;
protected double _max;
protected double _step;
protected int[] _baseBins;
protected int[] _bins;
protected int _baseNumericCount;
protected int _baseNonNumericCount;
protected int _baseBlankCount;
protected int _baseErrorCount;
protected int _numericCount;
protected int _nonNumericCount;
protected int _blankCount;
protected int _errorCount;
public RangeFacet() {
}
protected static final String MIN = "min";
protected static final String MAX = "max";
protected static final String TO = "to";
protected static final String FROM = "from";
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("name"); writer.value(_name);
writer.key("expression"); writer.value(_expression);
writer.key("columnName"); writer.value(_columnName);
if (_errorMessage != null) {
writer.key("error"); writer.value(_errorMessage);
} else {
if (!Double.isInfinite(_min) && !Double.isInfinite(_max)) {
writer.key(MIN); writer.value(_min);
writer.key(MAX); writer.value(_max);
writer.key("step"); writer.value(_step);
writer.key("bins"); writer.array();
for (int b : _bins) {
writer.value(b);
}
writer.endArray();
writer.key("baseBins"); writer.array();
for (int b : _baseBins) {
writer.value(b);
}
writer.endArray();
writer.key(FROM); writer.value(_from);
writer.key(TO); writer.value(_to);
}
writer.key("baseNumericCount"); writer.value(_baseNumericCount);
writer.key("baseNonNumericCount"); writer.value(_baseNonNumericCount);
writer.key("baseBlankCount"); writer.value(_baseBlankCount);
writer.key("baseErrorCount"); writer.value(_baseErrorCount);
writer.key("numericCount"); writer.value(_numericCount);
writer.key("nonNumericCount"); writer.value(_nonNumericCount);
writer.key("blankCount"); writer.value(_blankCount);
writer.key("errorCount"); writer.value(_errorCount);
}
writer.endObject();
}
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
_name = o.getString("name");
_expression = o.getString("expression");
_columnName = o.getString("columnName");
if (_columnName.length() > 0) {
Column column = project.columnModel.getColumnByName(_columnName);
if (column != null) {
_cellIndex = column.getCellIndex();
} else {
_errorMessage = "No column named " + _columnName;
}
} else {
_cellIndex = -1;
}
try {
_eval = MetaParser.parse(_expression);
} catch (ParsingException e) {
_errorMessage = e.getMessage();
}
if (o.has(FROM) || o.has(TO)) {
_from = o.has(FROM) ? o.getDouble(FROM) : _min;
_to = o.has(TO) ? o.getDouble(TO) : _max;
_selected = true;
}
_selectNumeric = JSONUtilities.getBoolean(o, "selectNumeric", true);
_selectNonNumeric = JSONUtilities.getBoolean(o, "selectNonNumeric", true);
_selectBlank = JSONUtilities.getBoolean(o, "selectBlank", true);
_selectError = JSONUtilities.getBoolean(o, "selectError", true);
if (!_selectNumeric || !_selectNonNumeric || !_selectBlank || !_selectError) {
_selected = true;
}
}
public RowFilter getRowFilter(Project project) {
if (_eval != null && _errorMessage == null && _selected) {
return new ExpressionNumberComparisonRowFilter(
getRowEvaluable(project), _selectNumeric, _selectNonNumeric, _selectBlank, _selectError) {
protected boolean checkValue(double d) {
return d >= _from && d < _to;
};
};
} else {
return null;
}
}
@Override
public RecordFilter getRecordFilter(Project project) {
RowFilter rowFilter = getRowFilter(project);
return rowFilter == null ? null : new AnyRowRecordFilter(rowFilter);
}
public void computeChoices(Project project, FilteredRows filteredRows) {
if (_eval != null && _errorMessage == null) {
RowEvaluable rowEvaluable = getRowEvaluable(project);
Column column = project.columnModel.getColumnByCellIndex(_cellIndex);
String key = "numeric-bin:row-based:" + _expression;
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
if (index == null) {
index = new NumericBinRowIndex(project, rowEvaluable);
column.setPrecompute(key, index);
}
retrieveDataFromBaseBinIndex(index);
ExpressionNumericValueBinner binner =
new ExpressionNumericValueBinner(rowEvaluable, index);
filteredRows.accept(project, binner);
retrieveDataFromBinner(binner);
}
}
public void computeChoices(Project project, FilteredRecords filteredRecords) {
if (_eval != null && _errorMessage == null) {
RowEvaluable rowEvaluable = getRowEvaluable(project);
Column column = project.columnModel.getColumnByCellIndex(_cellIndex);
String key = "numeric-bin:record-based:" + _expression;
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
if (index == null) {
index = new NumericBinRecordIndex(project, rowEvaluable);
column.setPrecompute(key, index);
}
retrieveDataFromBaseBinIndex(index);
ExpressionNumericValueBinner binner =
new ExpressionNumericValueBinner(rowEvaluable, index);
filteredRecords.accept(project, binner);
retrieveDataFromBinner(binner);
}
}
protected RowEvaluable getRowEvaluable(Project project) {
return new ExpressionBasedRowEvaluable(_columnName, _cellIndex, _eval);
}
protected void retrieveDataFromBaseBinIndex(NumericBinIndex index) {
_min = index.getMin();
_max = index.getMax();
_step = index.getStep();
_baseBins = index.getBins();
_baseNumericCount = index.getNumericRowCount();
_baseNonNumericCount = index.getNonNumericRowCount();
_baseBlankCount = index.getBlankRowCount();
_baseErrorCount = index.getErrorRowCount();
if (_selected) {
_from = Math.max(_from, _min);
_to = Math.min(_to, _max);
} else {
_from = _min;
_to = _max;
}
}
protected void retrieveDataFromBinner(ExpressionNumericValueBinner binner) {
_bins = binner.bins;
_numericCount = binner.numericCount;
_nonNumericCount = binner.nonNumericCount;
_blankCount = binner.blankCount;
_errorCount = binner.errorCount;
}
}

View File

@ -1,133 +0,0 @@
package com.google.gridworks.browsing.facets;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import com.google.gridworks.browsing.RecordVisitor;
import com.google.gridworks.browsing.RowVisitor;
import com.google.gridworks.model.Cell;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
import com.google.gridworks.model.Row;
public class ScatterplotDrawingRowVisitor implements RowVisitor, RecordVisitor {
int col_x;
int col_y;
int dim_x;
int dim_y;
int rotation;
double l;
double dot;
double min_x;
double max_x;
double min_y;
double max_y;
BufferedImage image;
Graphics2D g2;
AffineTransform r;
public ScatterplotDrawingRowVisitor(
int col_x, int col_y, double min_x, double max_x, double min_y, double max_y,
int size, int dim_x, int dim_y, int rotation, double dot, Color color)
{
this.col_x = col_x;
this.col_y = col_y;
this.min_x = min_x;
this.min_y = min_y;
this.max_x = max_x;
this.max_y = max_y;
this.dot = dot;
this.dim_x = dim_x;
this.dim_y = dim_y;
this.rotation = rotation;
l = (double) size;
r = ScatterplotFacet.createRotationMatrix(rotation, l);
image = new BufferedImage(size, size, BufferedImage.TYPE_4BYTE_ABGR);
g2 = (Graphics2D) image.getGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(1.0f));
AffineTransform t = AffineTransform.getTranslateInstance(0, l);
t.scale(1, -1);
g2.setTransform(t);
g2.setColor(color);
g2.setPaint(color);
if (r != null) {
/*
* Fill in the negative quadrants to give a hint of how the plot has been rotated.
*/
Graphics2D g2r = (Graphics2D) g2.create();
g2r.transform(r);
g2r.setPaint(Color.lightGray);
g2r.fillRect(-size, 0, size, size);
g2r.fillRect(0, -size, size, size);
g2r.dispose();
}
}
public void setColor(Color color) {
g2.setColor(color);
g2.setPaint(color);
}
@Override
public void start(Project project) {
// nothing to do
}
@Override
public void end(Project project) {
// nothing to do
}
@Override
public boolean visit(Project project, int rowIndex, Row row) {
Cell cellx = row.getCell(col_x);
Cell celly = row.getCell(col_y);
if ((cellx != null && cellx.value != null && cellx.value instanceof Number) &&
(celly != null && celly.value != null && celly.value instanceof Number))
{
double xv = ((Number) cellx.value).doubleValue();
double yv = ((Number) celly.value).doubleValue();
Point2D.Double p = new Point2D.Double(xv,yv);
p = ScatterplotFacet.translateCoordinates(
p, min_x, max_x, min_y, max_y, dim_x, dim_y, l, r);
g2.fill(new Rectangle2D.Double(p.x - dot / 2, p.y - dot / 2, dot, dot));
}
return false;
}
@Override
public boolean visit(Project project, Record record) {
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
visit(project, r, project.rows.get(r));
}
return false;
}
public RenderedImage getImage() {
return image;
}
}

View File

@ -1,452 +0,0 @@
package com.google.gridworks.browsing.facets;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Properties;
import javax.imageio.ImageIO;
import org.apache.commons.codec.binary.Base64;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gridworks.browsing.FilteredRecords;
import com.google.gridworks.browsing.FilteredRows;
import com.google.gridworks.browsing.RecordFilter;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.browsing.filters.AnyRowRecordFilter;
import com.google.gridworks.browsing.filters.DualExpressionsNumberComparisonRowFilter;
import com.google.gridworks.browsing.util.ExpressionBasedRowEvaluable;
import com.google.gridworks.browsing.util.NumericBinIndex;
import com.google.gridworks.browsing.util.NumericBinRecordIndex;
import com.google.gridworks.browsing.util.NumericBinRowIndex;
import com.google.gridworks.expr.Evaluable;
import com.google.gridworks.expr.MetaParser;
import com.google.gridworks.expr.ParsingException;
import com.google.gridworks.model.Column;
import com.google.gridworks.model.Project;
public class ScatterplotFacet implements Facet {
public static final int LIN = 0;
public static final int LOG = 1;
public static final int NO_ROTATION = 0;
public static final int ROTATE_CW = 1;
public static final int ROTATE_CCW = 2;
/*
* Configuration, from the client side
*/
protected String name; // name of facet
protected String expression_x; // expression to compute the x numeric value(s) per row
protected String expression_y; // expression to compute the y numeric value(s) per row
protected String columnName_x; // column to base the x expression on, if any
protected String columnName_y; // column to base the y expression on, if any
protected int size;
protected int dim_x;
protected int dim_y;
protected int rotation;
protected double l;
protected double dot;
protected String image;
protected String color_str;
protected Color color;
protected double from_x; // the numeric selection for the x axis, from 0 to 1
protected double to_x;
protected double from_y; // the numeric selection for the y axis, from 0 to 1
protected double to_y;
/*
* Derived configuration data
*/
protected int columnIndex_x;
protected int columnIndex_y;
protected Evaluable eval_x;
protected Evaluable eval_y;
protected String errorMessage_x;
protected String errorMessage_y;
protected double min_x;
protected double max_x;
protected double min_y;
protected double max_y;
protected AffineTransform t;
protected boolean selected; // false if we're certain that all rows will match
// and there isn't any filtering to do
public static final String NAME = "name";
public static final String IMAGE = "image";
public static final String COLOR = "color";
public static final String BASE_COLOR = "base_color";
public static final String SIZE = "l";
public static final String ROTATION = "r";
public static final String DOT = "dot";
public static final String DIM_X = "dim_x";
public static final String DIM_Y = "dim_y";
public static final String X_COLUMN_NAME = "cx";
public static final String X_EXPRESSION = "ex";
public static final String MIN_X = "min_x";
public static final String MAX_X = "max_x";
public static final String TO_X = "to_x";
public static final String FROM_X = "from_x";
public static final String ERROR_X = "error_x";
public static final String Y_COLUMN_NAME = "cy";
public static final String Y_EXPRESSION = "ey";
public static final String MIN_Y = "min_y";
public static final String MAX_Y = "max_y";
public static final String TO_Y = "to_y";
public static final String FROM_Y = "from_y";
public static final String ERROR_Y = "error_y";
private static final boolean IMAGE_URI = false;
public static String EMPTY_IMAGE;
final static Logger logger = LoggerFactory.getLogger("scatterplot_facet");
static {
try {
EMPTY_IMAGE = serializeImage(new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR));
} catch (IOException e) {
EMPTY_IMAGE = "";
}
}
public void write(JSONWriter writer, Properties options) throws JSONException {
writer.object();
writer.key(NAME); writer.value(name);
writer.key(X_COLUMN_NAME); writer.value(columnName_x);
writer.key(X_EXPRESSION); writer.value(expression_x);
writer.key(Y_COLUMN_NAME); writer.value(columnName_y);
writer.key(Y_EXPRESSION); writer.value(expression_y);
writer.key(SIZE); writer.value(size);
writer.key(DOT); writer.value(dot);
writer.key(ROTATION); writer.value(rotation);
writer.key(DIM_X); writer.value(dim_x);
writer.key(DIM_Y); writer.value(dim_y);
writer.key(COLOR); writer.value(color_str);
if (IMAGE_URI) {
writer.key(IMAGE); writer.value(image);
}
if (errorMessage_x != null) {
writer.key(ERROR_X); writer.value(errorMessage_x);
} else {
if (!Double.isInfinite(min_x) && !Double.isInfinite(max_x)) {
writer.key(FROM_X); writer.value(from_x);
writer.key(TO_X); writer.value(to_x);
}
}
if (errorMessage_y != null) {
writer.key(ERROR_Y); writer.value(errorMessage_y);
} else {
if (!Double.isInfinite(min_y) && !Double.isInfinite(max_y)) {
writer.key(FROM_Y); writer.value(from_y);
writer.key(TO_Y); writer.value(to_y);
}
}
writer.endObject();
}
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
name = o.getString(NAME);
l = size = (o.has(SIZE)) ? o.getInt(SIZE) : 100;
dot = (o.has(DOT)) ? o.getInt(DOT) : 0.5d;
dim_x = (o.has(DIM_X)) ? getAxisDim(o.getString(DIM_X)) : LIN;
if (o.has(FROM_X) && o.has(TO_X)) {
from_x = o.getDouble(FROM_X);
to_x = o.getDouble(TO_X);
selected = true;
} else {
from_x = 0;
to_x = 1;
}
dim_y = (o.has(DIM_Y)) ? getAxisDim(o.getString(DIM_Y)) : LIN;
if (o.has(FROM_Y) && o.has(TO_Y)) {
from_y = o.getDouble(FROM_Y);
to_y = o.getDouble(TO_Y);
selected = true;
} else {
from_y = 0;
to_y = 1;
}
rotation = (o.has(ROTATION)) ? getRotation(o.getString(ROTATION)) : NO_ROTATION;
t = createRotationMatrix(rotation, l);
color_str = (o.has(COLOR)) ? o.getString(COLOR) : "000000";
color = new Color(Integer.parseInt(color_str,16));
columnName_x = o.getString(X_COLUMN_NAME);
expression_x = o.getString(X_EXPRESSION);
if (columnName_x.length() > 0) {
Column x_column = project.columnModel.getColumnByName(columnName_x);
if (x_column != null) {
columnIndex_x = x_column.getCellIndex();
NumericBinIndex index_x = ScatterplotFacet.getBinIndex(project, x_column, eval_x, expression_x);
min_x = index_x.getMin();
max_x = index_x.getMax();
} else {
errorMessage_x = "No column named " + columnName_x;
}
} else {
columnIndex_x = -1;
}
try {
eval_x = MetaParser.parse(expression_x);
} catch (ParsingException e) {
errorMessage_x = e.getMessage();
}
columnName_y = o.getString(Y_COLUMN_NAME);
expression_y = o.getString(Y_EXPRESSION);
if (columnName_y.length() > 0) {
Column y_column = project.columnModel.getColumnByName(columnName_y);
if (y_column != null) {
columnIndex_y = y_column.getCellIndex();
NumericBinIndex index_y = ScatterplotFacet.getBinIndex(project, y_column, eval_y, expression_y);
min_y = index_y.getMin();
max_y = index_y.getMax();
} else {
errorMessage_y = "No column named " + columnName_y;
}
} else {
columnIndex_y = -1;
}
try {
eval_y = MetaParser.parse(expression_y);
} catch (ParsingException e) {
errorMessage_y = e.getMessage();
}
}
public RowFilter getRowFilter(Project project) {
if (selected &&
eval_x != null && errorMessage_x == null &&
eval_y != null && errorMessage_y == null)
{
return new DualExpressionsNumberComparisonRowFilter(
eval_x, columnName_x, columnIndex_x, eval_y, columnName_y, columnIndex_y) {
double from_x_pixels = from_x * l;
double to_x_pixels = to_x * l;
double from_y_pixels = from_y * l;
double to_y_pixels = to_y * l;
protected boolean checkValues(double x, double y) {
Point2D.Double p = new Point2D.Double(x,y);
p = translateCoordinates(p, min_x, max_x, min_y, max_y, dim_x, dim_y, l, t);
return p.x >= from_x_pixels && p.x <= to_x_pixels && p.y >= from_y_pixels && p.y <= to_y_pixels;
};
};
} else {
return null;
}
}
@Override
public RecordFilter getRecordFilter(Project project) {
RowFilter rowFilter = getRowFilter(project);
return rowFilter == null ? null : new AnyRowRecordFilter(rowFilter);
}
public void computeChoices(Project project, FilteredRows filteredRows) {
if (eval_x != null && eval_y != null && errorMessage_x == null && errorMessage_y == null) {
Column column_x = project.columnModel.getColumnByCellIndex(columnIndex_x);
NumericBinIndex index_x = getBinIndex(project, column_x, eval_x, expression_x, "row-based");
Column column_y = project.columnModel.getColumnByCellIndex(columnIndex_y);
NumericBinIndex index_y = getBinIndex(project, column_y, eval_y, expression_y, "row-based");
retrieveDataFromBinIndices(index_x, index_y);
if (IMAGE_URI) {
if (index_x.isNumeric() && index_y.isNumeric()) {
ScatterplotDrawingRowVisitor drawer = new ScatterplotDrawingRowVisitor(
columnIndex_x, columnIndex_y, min_x, max_x, min_y, max_y,
size, dim_x, dim_y, rotation, dot, color
);
filteredRows.accept(project, drawer);
try {
image = serializeImage(drawer.getImage());
} catch (IOException e) {
logger.warn("Exception caught while generating the image", e);
}
} else {
image = EMPTY_IMAGE;
}
}
}
}
public void computeChoices(Project project, FilteredRecords filteredRecords) {
if (eval_x != null && eval_y != null && errorMessage_x == null && errorMessage_y == null) {
Column column_x = project.columnModel.getColumnByCellIndex(columnIndex_x);
NumericBinIndex index_x = getBinIndex(project, column_x, eval_x, expression_x, "record-based");
Column column_y = project.columnModel.getColumnByCellIndex(columnIndex_y);
NumericBinIndex index_y = getBinIndex(project, column_y, eval_y, expression_y, "record-based");
retrieveDataFromBinIndices(index_x, index_y);
if (IMAGE_URI) {
if (index_x.isNumeric() && index_y.isNumeric()) {
ScatterplotDrawingRowVisitor drawer = new ScatterplotDrawingRowVisitor(
columnIndex_x, columnIndex_y, min_x, max_x, min_y, max_y,
size, dim_x, dim_y, rotation, dot, color
);
filteredRecords.accept(project, drawer);
try {
image = serializeImage(drawer.getImage());
} catch (IOException e) {
logger.warn("Exception caught while generating the image", e);
}
} else {
image = EMPTY_IMAGE;
}
}
}
}
protected void retrieveDataFromBinIndices(NumericBinIndex index_x, NumericBinIndex index_y) {
min_x = index_x.getMin();
max_x = index_x.getMax();
min_y = index_y.getMin();
max_y = index_y.getMax();
}
public static String serializeImage(RenderedImage image) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream(4096);
ImageIO.write(image, "png", output);
output.close();
String encoded = Base64.encodeBase64String(output.toByteArray());
String url = "data:image/png;base64," + encoded;
return url;
}
public static int getAxisDim(String type) {
return ("log".equals(type.toLowerCase())) ? LOG : LIN;
}
public static int getRotation(String rotation) {
rotation = rotation.toLowerCase();
if ("cw".equals(rotation) || "right".equals(rotation)) {
return ScatterplotFacet.ROTATE_CW;
} else if ("ccw".equals(rotation) || "left".equals(rotation)) {
return ScatterplotFacet.ROTATE_CCW;
} else {
return NO_ROTATION;
}
}
public static NumericBinIndex getBinIndex(Project project, Column column, Evaluable eval, String expression) {
return getBinIndex(project, column, eval, expression, "row-based");
}
public static NumericBinIndex getBinIndex(Project project, Column column, Evaluable eval, String expression, String mode) {
String key = "numeric-bin:" + mode + ":" + expression;
if (eval == null) {
try {
eval = MetaParser.parse(expression);
} catch (ParsingException e) {
logger.warn("Error parsing expression",e);
}
}
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
if (index == null) {
index = "row-based".equals(mode) ?
new NumericBinRowIndex(project, new ExpressionBasedRowEvaluable(column.getName(), column.getCellIndex(), eval)) :
new NumericBinRecordIndex(project, new ExpressionBasedRowEvaluable(column.getName(), column.getCellIndex(), eval));
column.setPrecompute(key, index);
}
return index;
}
private static double s_rotateScale = 1 / Math.sqrt(2.0);
public static AffineTransform createRotationMatrix(int rotation, double l) {
if (rotation == ScatterplotFacet.ROTATE_CW) {
AffineTransform t = AffineTransform.getTranslateInstance(0, l / 2);
t.scale(s_rotateScale, s_rotateScale);
t.rotate(-Math.PI / 4);
return t;
} else if (rotation == ScatterplotFacet.ROTATE_CCW) {
AffineTransform t = AffineTransform.getTranslateInstance(l / 2, 0);
t.scale(s_rotateScale, s_rotateScale);
t.rotate(Math.PI / 4);
return t;
} else {
return null;
}
}
public static Point2D.Double translateCoordinates(
Point2D.Double p,
double min_x, double max_x, double min_y, double max_y,
int dim_x, int dim_y, double l, AffineTransform t) {
double x = p.x;
double y = p.y;
double relative_x = x - min_x;
double range_x = max_x - min_x;
if (dim_x == ScatterplotFacet.LOG) {
x = Math.log10(relative_x + 1) * l / Math.log10(range_x + 1);
} else {
x = relative_x * l / range_x;
}
double relative_y = y - min_y;
double range_y = max_y - min_y;
if (dim_y == ScatterplotFacet.LOG) {
y = Math.log10(relative_y + 1) * l / Math.log10(range_y + 1);
} else {
y = relative_y * l / range_y;
}
p.x = x;
p.y = y;
if (t != null) {
t.transform(p, p);
}
return p;
}
}

View File

@ -1,120 +0,0 @@
package com.google.gridworks.browsing.facets;
import java.util.Properties;
import java.util.regex.Pattern;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import com.google.gridworks.browsing.FilteredRecords;
import com.google.gridworks.browsing.FilteredRows;
import com.google.gridworks.browsing.RecordFilter;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.browsing.filters.AnyRowRecordFilter;
import com.google.gridworks.browsing.filters.ExpressionStringComparisonRowFilter;
import com.google.gridworks.expr.Evaluable;
import com.google.gridworks.gel.ast.VariableExpr;
import com.google.gridworks.model.Project;
public class TextSearchFacet implements Facet {
/*
* Configuration
*/
protected String _name;
protected String _columnName;
protected String _query;
protected String _mode;
protected boolean _caseSensitive;
/*
* Derived configuration
*/
protected int _cellIndex;
protected Pattern _pattern;
public TextSearchFacet() {
}
@Override
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("name"); writer.value(_name);
writer.key("columnName"); writer.value(_columnName);
writer.key("query"); writer.value(_query);
writer.key("mode"); writer.value(_mode);
writer.key("caseSensitive"); writer.value(_caseSensitive);
writer.endObject();
}
@Override
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
_name = o.getString("name");
_columnName = o.getString("columnName");
_cellIndex = project.columnModel.getColumnByName(_columnName).getCellIndex();
if (!o.isNull("query")) {
_query = o.getString("query");
}
_mode = o.getString("mode");
_caseSensitive = o.getBoolean("caseSensitive");
if (_query != null) {
if ("regex".equals(_mode)) {
try {
_pattern = Pattern.compile(
_query,
_caseSensitive ? 0 : Pattern.CASE_INSENSITIVE);
} catch (java.util.regex.PatternSyntaxException e) {
e.printStackTrace();
}
} else if (!_caseSensitive) {
_query = _query.toLowerCase();
}
}
}
@Override
public RowFilter getRowFilter(Project project) {
if (_query == null || _query.length() == 0) {
return null;
} else if ("regex".equals(_mode) && _pattern == null) {
return null;
}
Evaluable eval = new VariableExpr("value");
if ("regex".equals(_mode)) {
return new ExpressionStringComparisonRowFilter(eval, _columnName, _cellIndex) {
protected boolean checkValue(String s) {
return _pattern.matcher(s).find();
};
};
} else {
return new ExpressionStringComparisonRowFilter(eval, _columnName, _cellIndex) {
protected boolean checkValue(String s) {
return (_caseSensitive ? s : s.toLowerCase()).contains(_query);
};
};
}
}
@Override
public RecordFilter getRecordFilter(Project project) {
RowFilter rowFilter = getRowFilter(project);
return rowFilter == null ? null : new AnyRowRecordFilter(rowFilter);
}
@Override
public void computeChoices(Project project, FilteredRows filteredRows) {
// nothing to do
}
@Override
public void computeChoices(Project project, FilteredRecords filteredRecords) {
// nothing to do
}
}

View File

@ -1,201 +0,0 @@
package com.google.gridworks.browsing.facets;
import java.util.Properties;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import com.google.gridworks.browsing.FilteredRecords;
import com.google.gridworks.browsing.FilteredRows;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.browsing.filters.ExpressionTimeComparisonRowFilter;
import com.google.gridworks.browsing.util.ExpressionTimeValueBinner;
import com.google.gridworks.browsing.util.RowEvaluable;
import com.google.gridworks.browsing.util.TimeBinIndex;
import com.google.gridworks.browsing.util.TimeBinRecordIndex;
import com.google.gridworks.browsing.util.TimeBinRowIndex;
import com.google.gridworks.expr.MetaParser;
import com.google.gridworks.expr.ParsingException;
import com.google.gridworks.model.Column;
import com.google.gridworks.model.Project;
import com.google.gridworks.util.JSONUtilities;
public class TimeRangeFacet extends RangeFacet {
protected boolean _selectTime; // whether the time selection applies, default true
protected boolean _selectNonTime;
protected int _baseTimeCount;
protected int _baseNonTimeCount;
protected int _timeCount;
protected int _nonTimeCount;
public void write(JSONWriter writer, Properties options) throws JSONException {
writer.object();
writer.key("name"); writer.value(_name);
writer.key("expression"); writer.value(_expression);
writer.key("columnName"); writer.value(_columnName);
if (_errorMessage != null) {
writer.key("error"); writer.value(_errorMessage);
} else {
if (!Double.isInfinite(_min) && !Double.isInfinite(_max)) {
writer.key(MIN); writer.value(_min);
writer.key(MAX); writer.value(_max);
writer.key("step"); writer.value(_step);
writer.key("bins"); writer.array();
for (int b : _bins) {
writer.value(b);
}
writer.endArray();
writer.key("baseBins"); writer.array();
for (int b : _baseBins) {
writer.value(b);
}
writer.endArray();
writer.key(FROM); writer.value(_from);
writer.key(TO); writer.value(_to);
}
writer.key("baseTimeCount"); writer.value(_baseTimeCount);
writer.key("baseNonTimeCount"); writer.value(_baseNonTimeCount);
writer.key("baseBlankCount"); writer.value(_baseBlankCount);
writer.key("baseErrorCount"); writer.value(_baseErrorCount);
writer.key("timeCount"); writer.value(_timeCount);
writer.key("nonTimeCount"); writer.value(_nonTimeCount);
writer.key("blankCount"); writer.value(_blankCount);
writer.key("errorCount"); writer.value(_errorCount);
}
writer.endObject();
}
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
_name = o.getString("name");
_expression = o.getString("expression");
_columnName = o.getString("columnName");
if (_columnName.length() > 0) {
Column column = project.columnModel.getColumnByName(_columnName);
if (column != null) {
_cellIndex = column.getCellIndex();
} else {
_errorMessage = "No column named " + _columnName;
}
} else {
_cellIndex = -1;
}
try {
_eval = MetaParser.parse(_expression);
} catch (ParsingException e) {
_errorMessage = e.getMessage();
}
if (o.has(FROM) || o.has(TO)) {
_from = o.has(FROM) ? o.getDouble(FROM) : _min;
_to = o.has(TO) ? o.getDouble(TO) : _max;
_selected = true;
}
_selectTime = JSONUtilities.getBoolean(o, "selectTime", true);
_selectNonTime = JSONUtilities.getBoolean(o, "selectNonTime", true);
_selectBlank = JSONUtilities.getBoolean(o, "selectBlank", true);
_selectError = JSONUtilities.getBoolean(o, "selectError", true);
if (!_selectTime || !_selectNonTime || !_selectBlank || !_selectError) {
_selected = true;
}
}
public RowFilter getRowFilter(Project project) {
if (_eval != null && _errorMessage == null && _selected) {
return new ExpressionTimeComparisonRowFilter(
getRowEvaluable(project), _selectTime, _selectNonTime, _selectBlank, _selectError) {
protected boolean checkValue(long t) {
return t >= _from && t < _to;
};
};
} else {
return null;
}
}
public void computeChoices(Project project, FilteredRows filteredRows) {
if (_eval != null && _errorMessage == null) {
RowEvaluable rowEvaluable = getRowEvaluable(project);
Column column = project.columnModel.getColumnByCellIndex(_cellIndex);
String key = "time-bin:row-based:" + _expression;
TimeBinIndex index = (TimeBinIndex) column.getPrecompute(key);
if (index == null) {
index = new TimeBinRowIndex(project, rowEvaluable);
column.setPrecompute(key, index);
}
retrieveDataFromBaseBinIndex(index);
ExpressionTimeValueBinner binner = new ExpressionTimeValueBinner(rowEvaluable, index);
filteredRows.accept(project, binner);
retrieveDataFromBinner(binner);
}
}
public void computeChoices(Project project, FilteredRecords filteredRecords) {
if (_eval != null && _errorMessage == null) {
RowEvaluable rowEvaluable = getRowEvaluable(project);
Column column = project.columnModel.getColumnByCellIndex(_cellIndex);
String key = "time-bin:record-based:" + _expression;
TimeBinIndex index = (TimeBinIndex) column.getPrecompute(key);
if (index == null) {
index = new TimeBinRecordIndex(project, rowEvaluable);
column.setPrecompute(key, index);
}
retrieveDataFromBaseBinIndex(index);
ExpressionTimeValueBinner binner = new ExpressionTimeValueBinner(rowEvaluable, index);
filteredRecords.accept(project, binner);
retrieveDataFromBinner(binner);
}
}
protected void retrieveDataFromBaseBinIndex(TimeBinIndex index) {
_min = index.getMin();
_max = index.getMax();
_step = index.getStep();
_baseBins = index.getBins();
_baseTimeCount = index.getTimeRowCount();
_baseNonTimeCount = index.getNonTimeRowCount();
_baseBlankCount = index.getBlankRowCount();
_baseErrorCount = index.getErrorRowCount();
if (_selected) {
_from = Math.max(_from, _min);
_to = Math.min(_to, _max);
} else {
_from = _min;
_to = _max;
}
}
protected void retrieveDataFromBinner(ExpressionTimeValueBinner binner) {
_bins = binner.bins;
_timeCount = binner.timeCount;
_nonTimeCount = binner.nonTimeCount;
_blankCount = binner.blankCount;
_errorCount = binner.errorCount;
}
}

View File

@ -1,24 +0,0 @@
package com.google.gridworks.browsing.filters;
import com.google.gridworks.browsing.RecordFilter;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
public class AllRowsRecordFilter implements RecordFilter {
final protected RowFilter _rowFilter;
public AllRowsRecordFilter(RowFilter rowFilter) {
_rowFilter = rowFilter;
}
@Override
public boolean filterRecord(Project project, Record record) {
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
if (!_rowFilter.filterRow(project, r, project.rows.get(r))) {
return false;
}
}
return true;
}
}

View File

@ -1,24 +0,0 @@
package com.google.gridworks.browsing.filters;
import com.google.gridworks.browsing.RecordFilter;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
public class AnyRowRecordFilter implements RecordFilter {
final protected RowFilter _rowFilter;
public AnyRowRecordFilter(RowFilter rowFilter) {
_rowFilter = rowFilter;
}
@Override
public boolean filterRecord(Project project, Record record) {
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
if (_rowFilter.filterRow(project, r, project.rows.get(r))) {
return true;
}
}
return false;
}
}

View File

@ -1,85 +0,0 @@
package com.google.gridworks.browsing.filters;
import java.util.Collection;
import java.util.Properties;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.expr.Evaluable;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Cell;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
/**
* Judge if a row matches by evaluating two given expressions on the row, based on two different columns
* and checking the results. It's a match if the result satisfies some numeric comparisons.
*/
abstract public class DualExpressionsNumberComparisonRowFilter implements RowFilter {
final protected Evaluable _x_evaluable;
final protected String _x_columnName;
final protected int _x_cellIndex;
final protected Evaluable _y_evaluable;
final protected String _y_columnName;
final protected int _y_cellIndex;
public DualExpressionsNumberComparisonRowFilter (
Evaluable x_evaluable,
String x_columnName,
int x_cellIndex,
Evaluable y_evaluable,
String y_columnName,
int y_cellIndex
) {
_x_evaluable = x_evaluable;
_x_columnName = x_columnName;
_x_cellIndex = x_cellIndex;
_y_evaluable = y_evaluable;
_y_columnName = y_columnName;
_y_cellIndex = y_cellIndex;
}
public boolean filterRow(Project project, int rowIndex, Row row) {
Cell x_cell = _x_cellIndex < 0 ? null : row.getCell(_x_cellIndex);
Properties x_bindings = ExpressionUtils.createBindings(project);
ExpressionUtils.bind(x_bindings, row, rowIndex, _x_columnName, x_cell);
Object x_value = _x_evaluable.evaluate(x_bindings);
Cell y_cell = _y_cellIndex < 0 ? null : row.getCell(_y_cellIndex);
Properties y_bindings = ExpressionUtils.createBindings(project);
ExpressionUtils.bind(y_bindings, row, rowIndex, _y_columnName, y_cell);
Object y_value = _y_evaluable.evaluate(y_bindings);
if (x_value != null && y_value != null) {
if (x_value.getClass().isArray() || y_value.getClass().isArray()) {
return false;
} else if (x_value instanceof Collection<?> || y_value instanceof Collection<?>) {
return false;
} // else, fall through
}
return checkValue(x_value,y_value);
}
protected boolean checkValue(Object vx, Object vy) {
if (ExpressionUtils.isError(vx) || ExpressionUtils.isError(vy)) {
return false;
} else if (ExpressionUtils.isNonBlankData(vx) && ExpressionUtils.isNonBlankData(vy)) {
if (vx instanceof Number && vy instanceof Number) {
double dx = ((Number) vx).doubleValue();
double dy = ((Number) vy).doubleValue();
return (!Double.isInfinite(dx) &&
!Double.isNaN(dx) &&
!Double.isInfinite(dy) &&
!Double.isNaN(dy) &&
checkValues(dx,dy));
} else {
return false;
}
} else {
return false;
}
}
abstract protected boolean checkValues(double dx, double dy);
}

View File

@ -1,164 +0,0 @@
package com.google.gridworks.browsing.filters;
import java.util.Collection;
import java.util.Properties;
import org.json.JSONArray;
import org.json.JSONException;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.expr.Evaluable;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Cell;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
/**
* Judge if a row matches by evaluating a given expression on the row, based on a particular
* column, and checking the result. It's a match if the result is any one of a given list of
* values, or if the result is blank or error and we want blank or error values.
*/
public class ExpressionEqualRowFilter implements RowFilter {
final protected Evaluable _evaluable; // the expression to evaluate
final protected String _columnName;
final protected int _cellIndex; // the expression is based on this column;
// -1 if based on no column in particular,
// for expression such as "row.starred".
final protected Object[] _matches;
final protected boolean _selectBlank;
final protected boolean _selectError;
final protected boolean _invert;
public ExpressionEqualRowFilter(
Evaluable evaluable,
String columnName,
int cellIndex,
Object[] matches,
boolean selectBlank,
boolean selectError,
boolean invert
) {
_evaluable = evaluable;
_columnName = columnName;
_cellIndex = cellIndex;
_matches = matches;
_selectBlank = selectBlank;
_selectError = selectError;
_invert = invert;
}
public boolean filterRow(Project project, int rowIndex, Row row) {
return _invert ?
internalInvertedFilterRow(project, rowIndex, row) :
internalFilterRow(project, rowIndex, row);
}
public boolean internalFilterRow(Project project, int rowIndex, Row row) {
Cell cell = _cellIndex < 0 ? null : row.getCell(_cellIndex);
Properties bindings = ExpressionUtils.createBindings(project);
ExpressionUtils.bind(bindings, row, rowIndex, _columnName, cell);
Object value = _evaluable.evaluate(bindings);
if (value != null) {
if (value.getClass().isArray()) {
Object[] a = (Object[]) value;
for (Object v : a) {
if (testValue(v)) {
return true;
}
}
return false;
} else if (value instanceof Collection<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) {
if (testValue(v)) {
return true;
}
}
return false;
} else if (value instanceof JSONArray) {
JSONArray a = (JSONArray) value;
int l = a.length();
for (int i = 0; i < l; i++) {
try {
if (testValue(a.get(i))) {
return true;
}
} catch (JSONException e) {
// ignore
}
}
return false;
} // else, fall through
}
return testValue(value);
}
public boolean internalInvertedFilterRow(Project project, int rowIndex, Row row) {
Cell cell = _cellIndex < 0 ? null : row.getCell(_cellIndex);
Properties bindings = ExpressionUtils.createBindings(project);
ExpressionUtils.bind(bindings, row, rowIndex, _columnName, cell);
Object value = _evaluable.evaluate(bindings);
if (value != null) {
if (value.getClass().isArray()) {
Object[] a = (Object[]) value;
for (Object v : a) {
if (testValue(v)) {
return false;
}
}
return true;
} else if (value instanceof Collection<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) {
if (testValue(v)) {
return false;
}
}
return true;
} else if (value instanceof JSONArray) {
JSONArray a = (JSONArray) value;
int l = a.length();
for (int i = 0; i < l; i++) {
try {
if (testValue(a.get(i))) {
return false;
}
} catch (JSONException e) {
// ignore
}
}
return true;
} // else, fall through
}
return !testValue(value);
}
protected boolean testValue(Object v) {
if (ExpressionUtils.isError(v)) {
return _selectError;
} else if (ExpressionUtils.isNonBlankData(v)) {
for (Object match : _matches) {
if (testValue(v, match)) {
return true;
}
}
return false;
} else {
return _selectBlank;
}
}
protected boolean testValue(Object v, Object match) {
return (v instanceof Number && match instanceof Number) ?
((Number) match).doubleValue() == ((Number) v).doubleValue() :
match.equals(v);
}
}

View File

@ -1,102 +0,0 @@
package com.google.gridworks.browsing.filters;
import java.util.Collection;
import java.util.Properties;
import org.json.JSONArray;
import org.json.JSONException;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.browsing.util.RowEvaluable;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
/**
* Judge if a row matches by evaluating a given expression on the row, based on a particular
* column, and checking the result. It's a match if the result satisfies some numeric comparisons,
* or if the result is non-numeric or blank or error and we want non-numeric or blank or error
* values.
*/
abstract public class ExpressionNumberComparisonRowFilter implements RowFilter {
final protected RowEvaluable _rowEvaluable;
final protected boolean _selectNumeric;
final protected boolean _selectNonNumeric;
final protected boolean _selectBlank;
final protected boolean _selectError;
public ExpressionNumberComparisonRowFilter(
RowEvaluable rowEvaluable,
boolean selectNumeric,
boolean selectNonNumeric,
boolean selectBlank,
boolean selectError
) {
_rowEvaluable = rowEvaluable;
_selectNumeric = selectNumeric;
_selectNonNumeric = selectNonNumeric;
_selectBlank = selectBlank;
_selectError = selectError;
}
public boolean filterRow(Project project, int rowIndex, Row row) {
Properties bindings = ExpressionUtils.createBindings(project);
Object value = _rowEvaluable.eval(project, rowIndex, row, bindings);
if (value != null) {
if (value.getClass().isArray()) {
Object[] a = (Object[]) value;
for (Object v : a) {
if (checkValue(v)) {
return true;
}
}
return false;
} else if (value instanceof Collection<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) {
if (checkValue(v)) {
return true;
}
}
return false;
} else if (value instanceof JSONArray) {
JSONArray a = (JSONArray) value;
int l = a.length();
for (int i = 0; i < l; i++) {
try {
if (checkValue(a.get(i))) {
return true;
}
} catch (JSONException e) {
// ignore
}
}
return false;
} // else, fall through
}
return checkValue(value);
}
protected boolean checkValue(Object v) {
if (ExpressionUtils.isError(v)) {
return _selectError;
} else if (ExpressionUtils.isNonBlankData(v)) {
if (v instanceof Number) {
double d = ((Number) v).doubleValue();
if (Double.isInfinite(d) || Double.isNaN(d)) {
return _selectError;
} else {
return _selectNumeric && checkValue(d);
}
} else {
return _selectNonNumeric;
}
} else {
return _selectBlank;
}
}
abstract protected boolean checkValue(double d);
}

View File

@ -1,77 +0,0 @@
package com.google.gridworks.browsing.filters;
import java.util.Collection;
import java.util.Properties;
import org.json.JSONArray;
import org.json.JSONException;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.expr.Evaluable;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Cell;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
/**
* Judge if a row matches by evaluating a given expression on the row, based on a particular
* column, and checking the result. It's a match if the result satisfies some string comparisons.
*/
abstract public class ExpressionStringComparisonRowFilter implements RowFilter {
final protected Evaluable _evaluable;
final protected String _columnName;
final protected int _cellIndex;
public ExpressionStringComparisonRowFilter(Evaluable evaluable, String columnName, int cellIndex) {
_evaluable = evaluable;
_columnName = columnName;
_cellIndex = cellIndex;
}
public boolean filterRow(Project project, int rowIndex, Row row) {
Cell cell = _cellIndex < 0 ? null : row.getCell(_cellIndex);
Properties bindings = ExpressionUtils.createBindings(project);
ExpressionUtils.bind(bindings, row, rowIndex, _columnName, cell);
Object value = _evaluable.evaluate(bindings);
if (value != null) {
if (value.getClass().isArray()) {
Object[] a = (Object[]) value;
for (Object v : a) {
if (checkValue(v instanceof String ? ((String) v) : v.toString())) {
return true;
}
}
} else if (value instanceof Collection<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) {
if (checkValue(v.toString())) {
return true;
}
}
return false;
} else if (value instanceof JSONArray) {
JSONArray a = (JSONArray) value;
int l = a.length();
for (int i = 0; i < l; i++) {
try {
if (checkValue(a.get(i).toString())) {
return true;
}
} catch (JSONException e) {
// ignore
}
}
return false;
} else {
if (checkValue(value instanceof String ? ((String) value) : value.toString())) {
return true;
}
}
}
return false;
}
abstract protected boolean checkValue(String s);
}

View File

@ -1,52 +0,0 @@
package com.google.gridworks.browsing.filters;
import java.util.Date;
import com.google.gridworks.browsing.util.RowEvaluable;
import com.google.gridworks.expr.ExpressionUtils;
/**
* Judge if a row matches by evaluating a given expression on the row, based on a particular
* column, and checking the result. It's a match if the result satisfies some time comparisons,
* or if the result is not a time or blank or error and we want non-time or blank or error
* values.
*/
abstract public class ExpressionTimeComparisonRowFilter extends ExpressionNumberComparisonRowFilter {
final protected boolean _selectTime;
final protected boolean _selectNonTime;
public ExpressionTimeComparisonRowFilter(
RowEvaluable rowEvaluable,
boolean selectTime,
boolean selectNonTime,
boolean selectBlank,
boolean selectError
) {
super(rowEvaluable, selectTime, selectNonTime, selectBlank, selectError);
_selectTime = selectTime;
_selectNonTime = selectNonTime;
}
protected boolean checkValue(Object v) {
if (ExpressionUtils.isError(v)) {
return _selectError;
} else if (ExpressionUtils.isNonBlankData(v)) {
if (v instanceof Date) {
long time = ((Date) v).getTime();
return _selectTime && checkValue(time);
} else {
return _selectNonTime;
}
} else {
return _selectBlank;
}
}
// not really needed for operation, just to make extending the abstract class possible
protected boolean checkValue(double d) {
return false;
}
abstract protected boolean checkValue(long d);
}

View File

@ -1,49 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.LinkedList;
import java.util.List;
import com.google.gridworks.browsing.FilteredRecords;
import com.google.gridworks.browsing.RecordFilter;
import com.google.gridworks.browsing.RecordVisitor;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
/**
* Encapsulate logic for visiting records that match all given record filters.
*/
public class ConjunctiveFilteredRecords implements FilteredRecords {
final protected List<RecordFilter> _recordFilters = new LinkedList<RecordFilter>();
public void add(RecordFilter recordFilter) {
_recordFilters.add(recordFilter);
}
@Override
public void accept(Project project, RecordVisitor visitor) {
try {
visitor.start(project);
int c = project.recordModel.getRecordCount();
for (int r = 0; r < c; r++) {
Record record = project.recordModel.getRecord(r);
if (matchRecord(project, record)) {
if (visitor.visit(project, record)) {
return;
}
}
}
} finally {
visitor.end(project);
}
}
protected boolean matchRecord(Project project, Record record) {
for (RecordFilter recordFilter : _recordFilters) {
if (!recordFilter.filterRecord(project, record)) {
return false;
}
}
return true;
}
}

View File

@ -1,51 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.LinkedList;
import java.util.List;
import com.google.gridworks.browsing.FilteredRows;
import com.google.gridworks.browsing.RowFilter;
import com.google.gridworks.browsing.RowVisitor;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
/**
* Encapsulate logic for visiting rows that match all give row filters. Also visit
* context rows and dependent rows if configured so.
*/
public class ConjunctiveFilteredRows implements FilteredRows {
final protected List<RowFilter> _rowFilters = new LinkedList<RowFilter>();
public void add(RowFilter rowFilter) {
_rowFilters.add(rowFilter);
}
public void accept(Project project, RowVisitor visitor) {
try {
visitor.start(project);
int c = project.rows.size();
for (int rowIndex = 0; rowIndex < c; rowIndex++) {
Row row = project.rows.get(rowIndex);
if (matchRow(project, rowIndex, row)) {
visitRow(project, visitor, rowIndex, row);
}
}
} finally {
visitor.end(project);
}
}
protected void visitRow(Project project, RowVisitor visitor, int rowIndex, Row row) {
visitor.visit(project, rowIndex, row);
}
protected boolean matchRow(Project project, int rowIndex, Row row) {
for (RowFilter rowFilter : _rowFilters) {
if (!rowFilter.filterRow(project, rowIndex, row)) {
return false;
}
}
return true;
}
}

View File

@ -1,34 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.Properties;
import com.google.gridworks.expr.Evaluable;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Cell;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
public class ExpressionBasedRowEvaluable implements RowEvaluable {
final protected String _columnName;
final protected int _cellIndex;
final protected Evaluable _eval;
public ExpressionBasedRowEvaluable(
String columnName, int cellIndex, Evaluable eval) {
_columnName = columnName;
_cellIndex = cellIndex;
_eval = eval;
}
@Override
public Object eval(
Project project, int rowIndex, Row row, Properties bindings) {
Cell cell = row.getCell(_cellIndex);
ExpressionUtils.bind(bindings, row, rowIndex, _columnName, cell);
return _eval.evaluate(bindings);
}
}

View File

@ -1,211 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import com.google.gridworks.browsing.DecoratedValue;
import com.google.gridworks.browsing.RecordVisitor;
import com.google.gridworks.browsing.RowVisitor;
import com.google.gridworks.browsing.facets.NominalFacetChoice;
import com.google.gridworks.expr.Evaluable;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Cell;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
import com.google.gridworks.model.Row;
/**
* Visit matched rows or records and group them into facet choices based on the values computed
* from a given expression.
*/
public class ExpressionNominalValueGrouper implements RowVisitor, RecordVisitor {
static public class IndexedNominalFacetChoice extends NominalFacetChoice {
int _latestIndex;
public IndexedNominalFacetChoice(DecoratedValue decoratedValue, int latestIndex) {
super(decoratedValue);
_latestIndex = latestIndex;
}
}
/*
* Configuration
*/
final protected Evaluable _evaluable;
final protected String _columnName;
final protected int _cellIndex;
/*
* Computed results
*/
final public Map<Object, IndexedNominalFacetChoice> choices = new HashMap<Object, IndexedNominalFacetChoice>();
public int blankCount = 0;
public int errorCount = 0;
/*
* Scratch pad variables
*/
protected boolean hasBlank;
protected boolean hasError;
public ExpressionNominalValueGrouper(Evaluable evaluable, String columnName, int cellIndex) {
_evaluable = evaluable;
_columnName = columnName;
_cellIndex = cellIndex;
}
@Override
public void start(Project project) {
// nothing to do
}
@Override
public void end(Project project) {
// nothing to do
}
public boolean visit(Project project, int rowIndex, Row row) {
hasError = false;
hasBlank = false;
Properties bindings = ExpressionUtils.createBindings(project);
visitRow(project, rowIndex, row, bindings, rowIndex);
if (hasError) {
errorCount++;
}
if (hasBlank) {
blankCount++;
}
return false;
}
@Override
public boolean visit(Project project, Record record) {
hasError = false;
hasBlank = false;
Properties bindings = ExpressionUtils.createBindings(project);
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
Row row = project.rows.get(r);
visitRow(project, r, row, bindings, record.recordIndex);
}
if (hasError) {
errorCount++;
}
if (hasBlank) {
blankCount++;
}
return false;
}
protected void visitRow(Project project, int rowIndex, Row row, Properties bindings, int index) {
Object value = evalRow(project, rowIndex, row, bindings);
if (value != null) {
if (value.getClass().isArray()) {
Object[] a = (Object[]) value;
for (Object v : a) {
processValue(v, rowIndex);
}
} else if (value instanceof Collection<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) {
processValue(v, rowIndex);
}
} else {
processValue(value, rowIndex);
}
} else {
processValue(value, rowIndex);
}
}
protected Object evalRow(Project project, int rowIndex, Row row, Properties bindings) {
Cell cell = _cellIndex < 0 ? null : row.getCell(_cellIndex);
ExpressionUtils.bind(bindings, row, rowIndex, _columnName, cell);
return _evaluable.evaluate(bindings);
}
protected void processValue(Object value, int index) {
if (ExpressionUtils.isError(value)) {
hasError = true;
} else if (ExpressionUtils.isNonBlankData(value)) {
String valueString = value.toString();
IndexedNominalFacetChoice facetChoice = choices.get(valueString);
if (facetChoice != null) {
if (facetChoice._latestIndex < index) {
facetChoice._latestIndex = index;
facetChoice.count++;
}
} else {
String label = value.toString();
DecoratedValue dValue = new DecoratedValue(value, label);
IndexedNominalFacetChoice choice =
new IndexedNominalFacetChoice(dValue, index);
choice.count = 1;
choices.put(valueString, choice);
}
} else {
hasBlank = true;
}
}
public RowEvaluable getChoiceCountRowEvaluable() {
return new RowEvaluable() {
@Override
public Object eval(Project project, int rowIndex, Row row, Properties bindings) {
Object value = evalRow(project, rowIndex, row, bindings);
return getChoiceValueCountMultiple(value);
}
};
}
public Object getChoiceValueCountMultiple(Object value) {
if (value != null) {
if (value.getClass().isArray()) {
Object[] choiceValues = (Object[]) value;
List<Integer> counts = new ArrayList<Integer>(choiceValues.length);
for (int i = 0; i < choiceValues.length; i++) {
counts.add(getChoiceValueCount(choiceValues[i]));
}
return counts;
} else if (value instanceof Collection<?>) {
List<Object> choiceValues = ExpressionUtils.toObjectList(value);
List<Integer> counts = new ArrayList<Integer>(choiceValues.size());
int count = choiceValues.size();
for (int i = 0; i < count; i++) {
counts.add(getChoiceValueCount(choiceValues.get(i)));
}
return counts;
}
}
return getChoiceValueCount(value);
}
public Integer getChoiceValueCount(Object choiceValue) {
if (ExpressionUtils.isError(choiceValue)) {
return errorCount;
} else if (ExpressionUtils.isNonBlankData(choiceValue)) {
IndexedNominalFacetChoice choice = choices.get(choiceValue);
return choice != null ? choice.count : 0;
} else {
return blankCount;
}
}
}

View File

@ -1,148 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.Collection;
import java.util.Properties;
import com.google.gridworks.browsing.RecordVisitor;
import com.google.gridworks.browsing.RowVisitor;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
import com.google.gridworks.model.Row;
/**
* Visit matched rows or records and slot them into bins based on the numbers computed
* from a given expression.
*/
public class ExpressionNumericValueBinner implements RowVisitor, RecordVisitor {
/*
* Configuration
*/
final protected RowEvaluable _rowEvaluable;
final protected NumericBinIndex _index; // base bins
/*
* Computed results
*/
final public int[] bins;
public int numericCount;
public int nonNumericCount;
public int blankCount;
public int errorCount;
/*
* Scratchpad variables
*/
protected boolean hasError;
protected boolean hasBlank;
protected boolean hasNumeric;
protected boolean hasNonNumeric;
public ExpressionNumericValueBinner(RowEvaluable rowEvaluable, NumericBinIndex index) {
_rowEvaluable = rowEvaluable;
_index = index;
bins = new int[_index.getBins().length];
}
@Override
public void start(Project project) {
// nothing to do
}
@Override
public void end(Project project) {
// nothing to do
}
@Override
public boolean visit(Project project, int rowIndex, Row row) {
resetFlags();
Properties bindings = ExpressionUtils.createBindings(project);
processRow(project, rowIndex, row, bindings);
updateCounts();
return false;
}
@Override
public boolean visit(Project project, Record record) {
resetFlags();
Properties bindings = ExpressionUtils.createBindings(project);
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
processRow(project, r, project.rows.get(r), bindings);
}
updateCounts();
return false;
}
protected void resetFlags() {
hasError = false;
hasBlank = false;
hasNumeric = false;
hasNonNumeric = false;
}
protected void updateCounts() {
if (hasError) {
errorCount++;
}
if (hasBlank) {
blankCount++;
}
if (hasNumeric) {
numericCount++;
}
if (hasNonNumeric) {
nonNumericCount++;
}
}
protected void processRow(Project project, int rowIndex, Row row, Properties bindings) {
Object value = _rowEvaluable.eval(project, rowIndex, row, bindings);
if (value != null) {
if (value.getClass().isArray()) {
Object[] a = (Object[]) value;
for (Object v : a) {
processValue(v);
}
return;
} else if (value instanceof Collection<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) {
processValue(v);
}
return;
} // else, fall through
}
processValue(value);
}
protected void processValue(Object value) {
if (ExpressionUtils.isError(value)) {
hasError = true;
} else if (ExpressionUtils.isNonBlankData(value)) {
if (value instanceof Number) {
double d = ((Number) value).doubleValue();
if (!Double.isInfinite(d) && !Double.isNaN(d)) {
hasNumeric = true;
int bin = (int) Math.floor((d - _index.getMin()) / _index.getStep());
if (bin >= 0 && bin < bins.length) { // as a precaution
bins[bin]++;
}
} else {
hasError = true;
}
} else {
hasNonNumeric = true;
}
} else {
hasBlank = true;
}
}
}

View File

@ -1,146 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.Collection;
import java.util.Date;
import java.util.Properties;
import com.google.gridworks.browsing.RecordVisitor;
import com.google.gridworks.browsing.RowVisitor;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
import com.google.gridworks.model.Row;
/**
* Visit matched rows or records and slot them into bins based on the date computed
* from a given expression.
*/
public class ExpressionTimeValueBinner implements RowVisitor, RecordVisitor {
/*
* Configuration
*/
final protected RowEvaluable _rowEvaluable;
final protected TimeBinIndex _index; // base bins
/*
* Computed results
*/
final public int[] bins;
public int timeCount;
public int nonTimeCount;
public int blankCount;
public int errorCount;
/*
* Scratchpad variables
*/
protected boolean hasError;
protected boolean hasBlank;
protected boolean hasTime;
protected boolean hasNonTime;
public ExpressionTimeValueBinner(RowEvaluable rowEvaluable, TimeBinIndex index) {
_rowEvaluable = rowEvaluable;
_index = index;
bins = new int[_index.getBins().length];
}
@Override
public void start(Project project) {
// nothing to do
}
@Override
public void end(Project project) {
// nothing to do
}
@Override
public boolean visit(Project project, int rowIndex, Row row) {
resetFlags();
Properties bindings = ExpressionUtils.createBindings(project);
processRow(project, rowIndex, row, bindings);
updateCounts();
return false;
}
@Override
public boolean visit(Project project, Record record) {
resetFlags();
Properties bindings = ExpressionUtils.createBindings(project);
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
processRow(project, r, project.rows.get(r), bindings);
}
updateCounts();
return false;
}
protected void resetFlags() {
hasError = false;
hasBlank = false;
hasTime = false;
hasNonTime = false;
}
protected void updateCounts() {
if (hasError) {
errorCount++;
}
if (hasBlank) {
blankCount++;
}
if (hasTime) {
timeCount++;
}
if (hasNonTime) {
nonTimeCount++;
}
}
protected void processRow(Project project, int rowIndex, Row row, Properties bindings) {
Object value = _rowEvaluable.eval(project, rowIndex, row, bindings);
if (value != null) {
if (value.getClass().isArray()) {
Object[] a = (Object[]) value;
for (Object v : a) {
processValue(v);
}
return;
} else if (value instanceof Collection<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) {
processValue(v);
}
return;
} // else, fall through
}
processValue(value);
}
protected void processValue(Object value) {
if (ExpressionUtils.isError(value)) {
hasError = true;
} else if (ExpressionUtils.isNonBlankData(value)) {
if (value instanceof Date) {
long t = ((Date) value).getTime();
hasTime = true;
int bin = (int) Math.floor((t - _index.getMin()) / _index.getStep());
if (bin >= 0 && bin < bins.length) { // as a precaution
bins[bin]++;
}
} else {
hasNonTime = true;
}
} else {
hasBlank = true;
}
}
}

View File

@ -1,20 +0,0 @@
package com.google.gridworks.browsing.util;
import com.google.gridworks.browsing.FilteredRecords;
import com.google.gridworks.browsing.FilteredRows;
import com.google.gridworks.browsing.RowVisitor;
import com.google.gridworks.model.Project;
public class FilteredRecordsAsFilteredRows implements FilteredRows {
final protected FilteredRecords _filteredRecords;
public FilteredRecordsAsFilteredRows(FilteredRecords filteredRecords) {
_filteredRecords = filteredRecords;
}
@Override
public void accept(Project project, RowVisitor visitor) {
_filteredRecords.accept(project, new RowVisitorAsRecordVisitor(visitor));
}
}

View File

@ -1,226 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
/**
* A utility class for computing the base bins that form the base histograms of
* numeric range facets. It evaluates an expression on all the rows of a project to
* get numeric values, determines how many bins to distribute those values in, and
* bins the rows accordingly.
*
* This class processes all rows rather than just the filtered rows because it
* needs to compute the base bins of a numeric range facet, which remain unchanged
* as the user interacts with the facet.
*/
abstract public class NumericBinIndex {
protected int _totalValueCount;
protected int _numbericValueCount;
protected double _min;
protected double _max;
protected double _step;
protected int[] _bins;
protected int _numericRowCount;
protected int _nonNumericRowCount;
protected int _blankRowCount;
protected int _errorRowCount;
protected boolean _hasError = false;
protected boolean _hasNonNumeric = false;
protected boolean _hasNumeric = false;
protected boolean _hasBlank = false;
abstract protected void iterate(Project project, RowEvaluable rowEvaluable, List<Double> allValues);
public NumericBinIndex(Project project, RowEvaluable rowEvaluable) {
_min = Double.POSITIVE_INFINITY;
_max = Double.NEGATIVE_INFINITY;
List<Double> allValues = new ArrayList<Double>();
iterate(project, rowEvaluable, allValues);
_numbericValueCount = allValues.size();
if (_min >= _max) {
_step = 1;
_min = Math.min(_min, _max);
_max = _step;
_bins = new int[1];
return;
}
double diff = _max - _min;
_step = 1;
if (diff > 10) {
while (_step * 100 < diff) {
_step *= 10;
}
} else {
while (_step * 100 > diff) {
_step /= 10;
}
}
double originalMax = _max;
_min = (Math.floor(_min / _step) * _step);
_max = (Math.ceil(_max / _step) * _step);
double binCount = (_max - _min) / _step;
if (binCount > 100) {
_step *= 2;
binCount = (binCount + 1) / 2;
}
if (_max <= originalMax) {
_max += _step;
binCount++;
}
_bins = new int[(int) Math.round(binCount)];
for (double d : allValues) {
int bin = Math.max((int) Math.floor((d - _min) / _step),0);
_bins[bin]++;
}
}
public boolean isNumeric() {
return _numbericValueCount > _totalValueCount / 2;
}
public double getMin() {
return _min;
}
public double getMax() {
return _max;
}
public double getStep() {
return _step;
}
public int[] getBins() {
return _bins;
}
public int getNumericRowCount() {
return _numericRowCount;
}
public int getNonNumericRowCount() {
return _nonNumericRowCount;
}
public int getBlankRowCount() {
return _blankRowCount;
}
public int getErrorRowCount() {
return _errorRowCount;
}
protected void processRow(
Project project,
RowEvaluable rowEvaluable,
List<Double> allValues,
int rowIndex,
Row row,
Properties bindings
) {
Object value = rowEvaluable.eval(project, rowIndex, row, bindings);
if (ExpressionUtils.isError(value)) {
_hasError = true;
} else if (ExpressionUtils.isNonBlankData(value)) {
if (value.getClass().isArray()) {
Object[] a = (Object[]) value;
for (Object v : a) {
_totalValueCount++;
if (ExpressionUtils.isError(v)) {
_hasError = true;
} else if (ExpressionUtils.isNonBlankData(v)) {
if (v instanceof Number) {
_hasNumeric = true;
processValue(((Number) v).doubleValue(), allValues);
} else {
_hasNonNumeric = true;
}
} else {
_hasBlank = true;
}
}
} else if (value instanceof Collection<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) {
_totalValueCount++;
if (ExpressionUtils.isError(v)) {
_hasError = true;
} else if (ExpressionUtils.isNonBlankData(v)) {
if (v instanceof Number) {
_hasNumeric = true;
processValue(((Number) v).doubleValue(), allValues);
} else {
_hasNonNumeric = true;
}
} else {
_hasBlank = true;
}
}
} else {
_totalValueCount++;
if (value instanceof Number) {
_hasNumeric = true;
processValue(((Number) value).doubleValue(), allValues);
} else {
_hasNonNumeric = true;
}
}
} else {
_hasBlank = true;
}
}
protected void preprocessing() {
_hasBlank = false;
_hasError = false;
_hasNonNumeric = false;
_hasNumeric = false;
}
protected void postprocessing() {
if (_hasError) {
_errorRowCount++;
}
if (_hasBlank) {
_blankRowCount++;
}
if (_hasNumeric) {
_numericRowCount++;
}
if (_hasNonNumeric) {
_nonNumericRowCount++;
}
}
protected void processValue(double v, List<Double> allValues) {
if (!Double.isInfinite(v) && !Double.isNaN(v)) {
_min = Math.min(_min, v);
_max = Math.max(_max, v);
allValues.add(v);
}
}
}

View File

@ -1,38 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.List;
import java.util.Properties;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
import com.google.gridworks.model.Row;
public class NumericBinRecordIndex extends NumericBinIndex {
public NumericBinRecordIndex(Project project, RowEvaluable rowEvaluable) {
super(project, rowEvaluable);
}
@Override
protected void iterate(
Project project, RowEvaluable rowEvaluable, List<Double> allValues) {
Properties bindings = ExpressionUtils.createBindings(project);
int count = project.recordModel.getRecordCount();
for (int r = 0; r < count; r++) {
Record record = project.recordModel.getRecord(r);
preprocessing();
for (int i = record.fromRowIndex; i < record.toRowIndex; i++) {
Row row = project.rows.get(i);
processRow(project, rowEvaluable, allValues, i, row, bindings);
}
postprocessing();
}
}
}

View File

@ -1,33 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.List;
import java.util.Properties;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
public class NumericBinRowIndex extends NumericBinIndex {
public NumericBinRowIndex(Project project, RowEvaluable rowEvaluable) {
super(project, rowEvaluable);
}
@Override
protected void iterate(
Project project, RowEvaluable rowEvaluable, List<Double> allValues) {
Properties bindings = ExpressionUtils.createBindings(project);
for (int i = 0; i < project.rows.size(); i++) {
Row row = project.rows.get(i);
preprocessing();
processRow(project, rowEvaluable, allValues, i, row, bindings);
postprocessing();
}
}
}

View File

@ -1,10 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.Properties;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
public interface RowEvaluable {
public Object eval(Project project, int rowIndex, Row row, Properties bindings);
}

View File

@ -1,34 +0,0 @@
package com.google.gridworks.browsing.util;
import com.google.gridworks.browsing.RecordVisitor;
import com.google.gridworks.browsing.RowVisitor;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
public class RowVisitorAsRecordVisitor implements RecordVisitor {
final protected RowVisitor _rowVisitor;
public RowVisitorAsRecordVisitor(RowVisitor rowVisitor) {
_rowVisitor = rowVisitor;
}
@Override
public void start(Project project) {
_rowVisitor.start(project);
}
@Override
public void end(Project project) {
_rowVisitor.end(project);
}
@Override
public boolean visit(Project project, Record record) {
for (int r = record.fromRowIndex; r < record.toRowIndex; r++) {
if (_rowVisitor.visit(project, r, project.rows.get(r))) {
return true;
}
}
return false;
}
}

View File

@ -1,218 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
/**
* A utility class for computing the base bins that form the base histograms of
* temporal range facets. It evaluates an expression on all the rows of a project to
* get temporal values, determines how many bins to distribute those values in, and
* bins the rows accordingly.
*
* This class processes all rows rather than just the filtered rows because it
* needs to compute the base bins of a temporal range facet, which remain unchanged
* as the user interacts with the facet.
*/
abstract public class TimeBinIndex {
protected int _totalValueCount;
protected int _timeValueCount;
protected long _min;
protected long _max;
protected long _step;
protected int[] _bins;
protected int _timeRowCount;
protected int _nonTimeRowCount;
protected int _blankRowCount;
protected int _errorRowCount;
protected boolean _hasError = false;
protected boolean _hasNonTime = false;
protected boolean _hasTime = false;
protected boolean _hasBlank = false;
protected long[] steps = {
1, // msec
1000, // sec
1000*60, // min
1000*60*60, // hour
1000*60*60*24, // day
1000*60*60*24*7, // week
1000*2629746, // month (average Gregorian year / 12)
1000*31556952, // year (average Gregorian year)
1000*31556952*10, // decade
1000*31556952*100, // century
1000*31556952*1000, // millennium
};
abstract protected void iterate(Project project, RowEvaluable rowEvaluable, List<Long> allValues);
public TimeBinIndex(Project project, RowEvaluable rowEvaluable) {
_min = Long.MAX_VALUE;
_max = Long.MIN_VALUE;
List<Long> allValues = new ArrayList<Long>();
iterate(project, rowEvaluable, allValues);
_timeValueCount = allValues.size();
if (_min >= _max) {
_step = 1;
_min = Math.min(_min, _max);
_max = _step;
_bins = new int[1];
return;
}
long diff = _max - _min;
for (int i = 0; i < steps.length; i++) {
_step = steps[i];
if (diff / _step <= 100) break;
}
_bins = new int[(int) (diff / _step) + 1];
for (long d : allValues) {
int bin = (int) Math.max((d - _min) / _step,0);
_bins[bin]++;
}
}
public boolean isTemporal() {
return _timeValueCount > _totalValueCount / 2;
}
public long getMin() {
return _min;
}
public long getMax() {
return _max;
}
public long getStep() {
return _step;
}
public int[] getBins() {
return _bins;
}
public int getTimeRowCount() {
return _timeRowCount;
}
public int getNonTimeRowCount() {
return _nonTimeRowCount;
}
public int getBlankRowCount() {
return _blankRowCount;
}
public int getErrorRowCount() {
return _errorRowCount;
}
protected void processRow(
Project project,
RowEvaluable rowEvaluable,
List<Long> allValues,
int rowIndex,
Row row,
Properties bindings
) {
Object value = rowEvaluable.eval(project, rowIndex, row, bindings);
if (ExpressionUtils.isError(value)) {
_hasError = true;
} else if (ExpressionUtils.isNonBlankData(value)) {
if (value.getClass().isArray()) {
Object[] a = (Object[]) value;
for (Object v : a) {
_totalValueCount++;
if (ExpressionUtils.isError(v)) {
_hasError = true;
} else if (ExpressionUtils.isNonBlankData(v)) {
if (v instanceof Date) {
_hasTime = true;
processValue(((Date) v).getTime(), allValues);
} else {
_hasNonTime = true;
}
} else {
_hasBlank = true;
}
}
} else if (value instanceof Collection<?>) {
for (Object v : ExpressionUtils.toObjectCollection(value)) {
_totalValueCount++;
if (ExpressionUtils.isError(v)) {
_hasError = true;
} else if (ExpressionUtils.isNonBlankData(v)) {
if (v instanceof Date) {
_hasTime = true;
processValue(((Date) v).getTime(), allValues);
} else {
_hasNonTime = true;
}
} else {
_hasBlank = true;
}
}
} else {
_totalValueCount++;
if (value instanceof Date) {
_hasTime = true;
processValue(((Date) value).getTime(), allValues);
} else {
_hasNonTime = true;
}
}
} else {
_hasBlank = true;
}
}
protected void preprocessing() {
_hasBlank = false;
_hasError = false;
_hasNonTime = false;
_hasTime = false;
}
protected void postprocessing() {
if (_hasError) {
_errorRowCount++;
}
if (_hasBlank) {
_blankRowCount++;
}
if (_hasTime) {
_timeRowCount++;
}
if (_hasNonTime) {
_nonTimeRowCount++;
}
}
protected void processValue(long v, List<Long> allValues) {
_min = Math.min(_min, v);
_max = Math.max(_max, v);
allValues.add(v);
}
}

View File

@ -1,38 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.List;
import java.util.Properties;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Record;
import com.google.gridworks.model.Row;
public class TimeBinRecordIndex extends TimeBinIndex {
public TimeBinRecordIndex(Project project, RowEvaluable rowEvaluable) {
super(project, rowEvaluable);
}
@Override
protected void iterate(Project project, RowEvaluable rowEvaluable, List<Long> allValues) {
Properties bindings = ExpressionUtils.createBindings(project);
int count = project.recordModel.getRecordCount();
for (int r = 0; r < count; r++) {
Record record = project.recordModel.getRecord(r);
preprocessing();
for (int i = record.fromRowIndex; i < record.toRowIndex; i++) {
Row row = project.rows.get(i);
processRow(project, rowEvaluable, allValues, i, row, bindings);
}
postprocessing();
}
}
}

View File

@ -1,32 +0,0 @@
package com.google.gridworks.browsing.util;
import java.util.List;
import java.util.Properties;
import com.google.gridworks.expr.ExpressionUtils;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
public class TimeBinRowIndex extends TimeBinIndex {
public TimeBinRowIndex(Project project, RowEvaluable rowEvaluable) {
super(project, rowEvaluable);
}
@Override
protected void iterate(Project project, RowEvaluable rowEvaluable, List<Long> allValues) {
Properties bindings = ExpressionUtils.createBindings(project);
for (int i = 0; i < project.rows.size(); i++) {
Row row = project.rows.get(i);
preprocessing();
processRow(project, rowEvaluable, allValues, i, row, bindings);
postprocessing();
}
}
}

View File

@ -1,29 +0,0 @@
package com.google.gridworks.clustering;
import org.json.JSONObject;
import com.google.gridworks.Jsonizable;
import com.google.gridworks.browsing.Engine;
import com.google.gridworks.model.Column;
import com.google.gridworks.model.Project;
public abstract class Clusterer implements Jsonizable {
protected Project _project;
protected int _colindex;
protected JSONObject _config;
public abstract void computeClusters(Engine engine);
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
_project = project;
_config = o;
String colname = o.getString("column");
for (Column column : project.columnModel.columns) {
if (column.getName().equals(colname)) {
_colindex = column.getCellIndex();
}
}
}
}

View File

@ -1,169 +0,0 @@
package com.google.gridworks.clustering.binning;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.Map.Entry;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gridworks.browsing.Engine;
import com.google.gridworks.browsing.FilteredRows;
import com.google.gridworks.browsing.RowVisitor;
import com.google.gridworks.clustering.Clusterer;
import com.google.gridworks.model.Cell;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
public class BinningClusterer extends Clusterer {
private Keyer _keyer;
static final protected Map<String, Keyer> _keyers = new HashMap<String, Keyer>();
final static Logger logger = LoggerFactory.getLogger("binning_clusterer");
List<Map<String,Integer>> _clusters;
static {
_keyers.put("fingerprint", new FingerprintKeyer());
_keyers.put("ngram-fingerprint", new NGramFingerprintKeyer());
_keyers.put("metaphone", new MetaphoneKeyer());
_keyers.put("double-metaphone", new DoubleMetaphoneKeyer());
_keyers.put("soundex", new SoundexKeyer());
}
class BinningRowVisitor implements RowVisitor {
Keyer _keyer;
Object[] _params;
JSONObject _config;
Map<String,Map<String,Integer>> _map = new HashMap<String,Map<String,Integer>>();
public BinningRowVisitor(Keyer k, JSONObject o) {
_keyer = k;
_config = o;
if (k instanceof NGramFingerprintKeyer) {
try {
int size = _config.getJSONObject("params").getInt("ngram-size");
logger.debug("Using ngram size: {}", size);
_params = new Object[1];
_params[0] = size;
} catch (JSONException e) {
//Gridworks.warn("No params specified, using default");
}
}
}
@Override
public void start(Project project) {
// nothing to do
}
@Override
public void end(Project project) {
// nothing to do
}
public boolean visit(Project project, int rowIndex, Row row) {
Cell cell = row.getCell(_colindex);
if (cell != null && cell.value != null) {
Object v = cell.value;
String s = (v instanceof String) ? ((String) v) : v.toString();
String key = _keyer.key(s,_params);
if (_map.containsKey(key)) {
Map<String,Integer> m = _map.get(key);
if (m.containsKey(s)) {
m.put(s, m.get(s) + 1);
} else {
m.put(s,1);
}
} else {
Map<String,Integer> m = new TreeMap<String,Integer>();
m.put(s,1);
_map.put(key, m);
}
}
return false;
}
public Map<String,Map<String,Integer>> getMap() {
return _map;
}
}
public static class SizeComparator implements Comparator<Map<String,Integer>>, Serializable {
private static final long serialVersionUID = -1390696157208674054L;
public int compare(Map<String,Integer> o1, Map<String,Integer> o2) {
int s1 = o1.size();
int s2 = o2.size();
if (o1 == o2) {
int total1 = 0;
for (int i : o1.values()) {
total1 += i;
}
int total2 = 0;
for (int i : o2.values()) {
total2 += i;
}
return total2 - total1;
} else {
return s2 - s1;
}
}
}
public static class EntriesComparator implements Comparator<Entry<String,Integer>>, Serializable {
private static final long serialVersionUID = 2763378036791777964L;
public int compare(Entry<String,Integer> o1, Entry<String,Integer> o2) {
return o2.getValue() - o1.getValue();
}
}
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
super.initializeFromJSON(project, o);
_keyer = _keyers.get(o.getString("function").toLowerCase());
}
public void computeClusters(Engine engine) {
BinningRowVisitor visitor = new BinningRowVisitor(_keyer,_config);
FilteredRows filteredRows = engine.getAllFilteredRows();
filteredRows.accept(_project, visitor);
Map<String,Map<String,Integer>> map = visitor.getMap();
_clusters = new ArrayList<Map<String,Integer>>(map.values());
Collections.sort(_clusters, new SizeComparator());
}
public void write(JSONWriter writer, Properties options) throws JSONException {
EntriesComparator c = new EntriesComparator();
writer.array();
for (Map<String,Integer> m : _clusters) {
if (m.size() > 1) {
writer.array();
List<Entry<String,Integer>> entries = new ArrayList<Entry<String,Integer>>(m.entrySet());
Collections.sort(entries,c);
for (Entry<String,Integer> e : entries) {
writer.object();
writer.key("v"); writer.value(e.getKey());
writer.key("c"); writer.value(e.getValue());
writer.endObject();
}
writer.endArray();
}
}
writer.endArray();
}
}

View File

@ -1,18 +0,0 @@
package com.google.gridworks.clustering.binning;
import org.apache.commons.codec.language.DoubleMetaphone;
public class DoubleMetaphoneKeyer extends Keyer {
private DoubleMetaphone _metaphone2;
public DoubleMetaphoneKeyer() {
_metaphone2 = new DoubleMetaphone();
_metaphone2.setMaxCodeLen(2000);
}
public String key(String s, Object... o) {
return _metaphone2.doubleMetaphone(s);
}
}

View File

@ -1,249 +0,0 @@
package com.google.gridworks.clustering.binning;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
public class FingerprintKeyer extends Keyer {
static final Pattern alphanum = Pattern.compile("\\p{Punct}|\\p{Cntrl}");
public String key(String s, Object... o) {
s = s.trim(); // first off, remove whitespace around the string
s = s.toLowerCase(); // then lowercase it
s = alphanum.matcher(s).replaceAll(""); // then remove all punctuation and control chars
String[] frags = StringUtils.split(s); // split by whitespace
TreeSet<String> set = new TreeSet<String>();
for (String ss : frags) {
set.add(ss); // order fragments and dedupe
}
StringBuffer b = new StringBuffer();
Iterator<String> i = set.iterator();
while (i.hasNext()) { // join ordered fragments back together
b.append(i.next());
b.append(' ');
}
return asciify(b.toString()); // find ASCII equivalent to characters
}
protected String asciify(String s) {
char[] c = s.toCharArray();
StringBuffer b = new StringBuffer();
for (int i = 0; i < c.length; i++) {
b.append(translate(c[i]));
}
return b.toString();
}
/**
* Translate the given unicode char in the closest ASCII representation
* NOTE: this function deals only with latin-1 supplement and latin-1 extended code charts
*/
private char translate(char c) {
switch(c) {
case '\u00C0':
case '\u00C1':
case '\u00C2':
case '\u00C3':
case '\u00C4':
case '\u00C5':
case '\u00E0':
case '\u00E1':
case '\u00E2':
case '\u00E3':
case '\u00E4':
case '\u00E5':
case '\u0100':
case '\u0101':
case '\u0102':
case '\u0103':
case '\u0104':
case '\u0105':
return 'a';
case '\u00C7':
case '\u00E7':
case '\u0106':
case '\u0107':
case '\u0108':
case '\u0109':
case '\u010A':
case '\u010B':
case '\u010C':
case '\u010D':
return 'c';
case '\u00D0':
case '\u00F0':
case '\u010E':
case '\u010F':
case '\u0110':
case '\u0111':
return 'd';
case '\u00C8':
case '\u00C9':
case '\u00CA':
case '\u00CB':
case '\u00E8':
case '\u00E9':
case '\u00EA':
case '\u00EB':
case '\u0112':
case '\u0113':
case '\u0114':
case '\u0115':
case '\u0116':
case '\u0117':
case '\u0118':
case '\u0119':
case '\u011A':
case '\u011B':
return 'e';
case '\u011C':
case '\u011D':
case '\u011E':
case '\u011F':
case '\u0120':
case '\u0121':
case '\u0122':
case '\u0123':
return 'g';
case '\u0124':
case '\u0125':
case '\u0126':
case '\u0127':
return 'h';
case '\u00CC':
case '\u00CD':
case '\u00CE':
case '\u00CF':
case '\u00EC':
case '\u00ED':
case '\u00EE':
case '\u00EF':
case '\u0128':
case '\u0129':
case '\u012A':
case '\u012B':
case '\u012C':
case '\u012D':
case '\u012E':
case '\u012F':
case '\u0130':
case '\u0131':
return 'i';
case '\u0134':
case '\u0135':
return 'j';
case '\u0136':
case '\u0137':
case '\u0138':
return 'k';
case '\u0139':
case '\u013A':
case '\u013B':
case '\u013C':
case '\u013D':
case '\u013E':
case '\u013F':
case '\u0140':
case '\u0141':
case '\u0142':
return 'l';
case '\u00D1':
case '\u00F1':
case '\u0143':
case '\u0144':
case '\u0145':
case '\u0146':
case '\u0147':
case '\u0148':
case '\u0149':
case '\u014A':
case '\u014B':
return 'n';
case '\u00D2':
case '\u00D3':
case '\u00D4':
case '\u00D5':
case '\u00D6':
case '\u00D8':
case '\u00F2':
case '\u00F3':
case '\u00F4':
case '\u00F5':
case '\u00F6':
case '\u00F8':
case '\u014C':
case '\u014D':
case '\u014E':
case '\u014F':
case '\u0150':
case '\u0151':
return 'o';
case '\u0154':
case '\u0155':
case '\u0156':
case '\u0157':
case '\u0158':
case '\u0159':
return 'r';
case '\u015A':
case '\u015B':
case '\u015C':
case '\u015D':
case '\u015E':
case '\u015F':
case '\u0160':
case '\u0161':
case '\u017F':
return 's';
case '\u0162':
case '\u0163':
case '\u0164':
case '\u0165':
case '\u0166':
case '\u0167':
return 't';
case '\u00D9':
case '\u00DA':
case '\u00DB':
case '\u00DC':
case '\u00F9':
case '\u00FA':
case '\u00FB':
case '\u00FC':
case '\u0168':
case '\u0169':
case '\u016A':
case '\u016B':
case '\u016C':
case '\u016D':
case '\u016E':
case '\u016F':
case '\u0170':
case '\u0171':
case '\u0172':
case '\u0173':
return 'u';
case '\u0174':
case '\u0175':
return 'w';
case '\u00DD':
case '\u00FD':
case '\u00FF':
case '\u0176':
case '\u0177':
case '\u0178':
return 'y';
case '\u0179':
case '\u017A':
case '\u017B':
case '\u017C':
case '\u017D':
case '\u017E':
return 'z';
}
return c;
}
}

View File

@ -1,12 +0,0 @@
package com.google.gridworks.clustering.binning;
public abstract class Keyer {
public String key(String s) {
return this.key(s, (Object[]) null);
}
public abstract String key(String string, Object... params);
}

View File

@ -1,18 +0,0 @@
package com.google.gridworks.clustering.binning;
import org.apache.commons.codec.language.Metaphone;
public class MetaphoneKeyer extends Keyer {
private Metaphone _metaphone;
public MetaphoneKeyer() {
_metaphone = new Metaphone();
_metaphone.setMaxCodeLen(2000);
}
public String key(String s, Object... o) {
return _metaphone.metaphone(s);
}
}

View File

@ -1,35 +0,0 @@
package com.google.gridworks.clustering.binning;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.regex.Pattern;
public class NGramFingerprintKeyer extends FingerprintKeyer {
static final Pattern alphanum = Pattern.compile("\\p{Punct}|\\p{Cntrl}|\\p{Space}");
public String key(String s, Object... o) {
int ngram_size = 2;
if (o != null && o.length > 0 && o[0] instanceof Number) {
ngram_size = (Integer) o[0];
}
s = s.toLowerCase(); // then lowercase it
s = alphanum.matcher(s).replaceAll(""); // then remove all punctuation and control chars
TreeSet<String> set = ngram_split(s,ngram_size);
StringBuffer b = new StringBuffer();
Iterator<String> i = set.iterator();
while (i.hasNext()) { // join ordered fragments back together
b.append(i.next());
}
return asciify(b.toString()); // find ASCII equivalent to characters
}
protected TreeSet<String> ngram_split(String s, int size) {
TreeSet<String> set = new TreeSet<String>();
char[] chars = s.toCharArray();
for (int i = 0; i + size <= chars.length; i++) {
set.add(new String(chars,i,size));
}
return set;
}
}

View File

@ -1,17 +0,0 @@
package com.google.gridworks.clustering.binning;
import org.apache.commons.codec.language.Soundex;
public class SoundexKeyer extends Keyer {
private Soundex _soundex;
public SoundexKeyer() {
_soundex = new Soundex();
}
public String key(String s, Object... o) {
return _soundex.soundex(s);
}
}

View File

@ -1,211 +0,0 @@
package com.google.gridworks.clustering.knn;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gridworks.browsing.Engine;
import com.google.gridworks.browsing.FilteredRows;
import com.google.gridworks.browsing.RowVisitor;
import com.google.gridworks.clustering.Clusterer;
import com.google.gridworks.model.Cell;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.Row;
import edu.mit.simile.vicino.clustering.NGramClusterer;
import edu.mit.simile.vicino.clustering.VPTreeClusterer;
import edu.mit.simile.vicino.distances.BZip2Distance;
import edu.mit.simile.vicino.distances.Distance;
import edu.mit.simile.vicino.distances.GZipDistance;
import edu.mit.simile.vicino.distances.JaccardDistance;
import edu.mit.simile.vicino.distances.JaroDistance;
import edu.mit.simile.vicino.distances.JaroWinklerDistance;
import edu.mit.simile.vicino.distances.JaroWinklerTFIDFDistance;
import edu.mit.simile.vicino.distances.LevenshteinDistance;
import edu.mit.simile.vicino.distances.PPMDistance;
public class kNNClusterer extends Clusterer {
private Distance _distance;
static final protected Map<String, Distance> _distances = new HashMap<String, Distance>();
List<Set<Serializable>> _clusters;
Map<Serializable, Integer> _counts = new HashMap<Serializable, Integer>();
final static Logger logger = LoggerFactory.getLogger("kNN_clusterer");
static {
_distances.put("levenshtein", new LevenshteinDistance());
_distances.put("jaccard", new JaccardDistance());
_distances.put("jaro", new JaroDistance());
_distances.put("jaro-winkler", new JaroWinklerDistance());
_distances.put("jaro-winkler-tfidf", new JaroWinklerTFIDFDistance());
_distances.put("gzip", new GZipDistance());
_distances.put("bzip2", new BZip2Distance());
_distances.put("ppm", new PPMDistance());
}
class VPTreeClusteringRowVisitor implements RowVisitor {
Distance _distance;
JSONObject _config;
VPTreeClusterer _clusterer;
double _radius = 1.0f;
public VPTreeClusteringRowVisitor(Distance d, JSONObject o) {
_distance = d;
_config = o;
_clusterer = new VPTreeClusterer(_distance);
try {
JSONObject params = o.getJSONObject("params");
_radius = params.getDouble("radius");
} catch (JSONException e) {
//Gridworks.warn("No parameters found, using defaults");
}
}
@Override
public void start(Project project) {
// nothing to do
}
@Override
public void end(Project project) {
// nothing to do
}
public boolean visit(Project project, int rowIndex, Row row) {
Cell cell = row.getCell(_colindex);
if (cell != null && cell.value != null) {
Object v = cell.value;
String s = (v instanceof String) ? ((String) v) : v.toString();
_clusterer.populate(s);
count(s);
}
return false;
}
public List<Set<Serializable>> getClusters() {
return _clusterer.getClusters(_radius);
}
}
class BlockingClusteringRowVisitor implements RowVisitor {
Distance _distance;
JSONObject _config;
double _radius = 1.0d;
int _blockingNgramSize = 6;
HashSet<String> _data;
NGramClusterer _clusterer;
public BlockingClusteringRowVisitor(Distance d, JSONObject o) {
_distance = d;
_config = o;
_data = new HashSet<String>();
try {
JSONObject params = o.getJSONObject("params");
_radius = params.getDouble("radius");
logger.debug("Use radius: {}", _radius);
_blockingNgramSize = params.getInt("blocking-ngram-size");
logger.debug("Use blocking ngram size: {}",_blockingNgramSize);
} catch (JSONException e) {
logger.debug("No parameters found, using defaults");
}
_clusterer = new NGramClusterer(_distance, _blockingNgramSize);
}
@Override
public void start(Project project) {
// nothing to do
}
@Override
public void end(Project project) {
// nothing to do
}
public boolean visit(Project project, int rowIndex, Row row) {
Cell cell = row.getCell(_colindex);
if (cell != null && cell.value != null) {
Object v = cell.value;
String s = (v instanceof String) ? ((String) v) : v.toString().intern();
_clusterer.populate(s);
count(s);
}
return false;
}
public List<Set<Serializable>> getClusters() {
return _clusterer.getClusters(_radius);
}
}
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
super.initializeFromJSON(project, o);
_distance = _distances.get(o.getString("function").toLowerCase());
}
public void computeClusters(Engine engine) {
//VPTreeClusteringRowVisitor visitor = new VPTreeClusteringRowVisitor(_distance,_config);
BlockingClusteringRowVisitor visitor = new BlockingClusteringRowVisitor(_distance,_config);
FilteredRows filteredRows = engine.getAllFilteredRows();
filteredRows.accept(_project, visitor);
_clusters = visitor.getClusters();
}
public static class ValuesComparator implements Comparator<Entry<Serializable,Integer>>, Serializable {
private static final long serialVersionUID = 204469656070583155L;
public int compare(Entry<Serializable,Integer> o1, Entry<Serializable,Integer> o2) {
return o2.getValue() - o1.getValue();
}
}
public void write(JSONWriter writer, Properties options) throws JSONException {
writer.array();
for (Set<Serializable> m : _clusters) {
if (m.size() > 1) {
Map<Serializable,Integer> internal_counts = new HashMap<Serializable,Integer>();
for (Serializable s : m) {
internal_counts.put(s,_counts.get(s));
}
List<Entry<Serializable,Integer>> values = new ArrayList<Entry<Serializable,Integer>>(internal_counts.entrySet());
Collections.sort(values, new ValuesComparator());
writer.array();
for (Entry<Serializable,Integer> e : values) {
writer.object();
writer.key("v"); writer.value(e.getKey());
writer.key("c"); writer.value(e.getValue());
writer.endObject();
}
writer.endArray();
}
}
writer.endArray();
}
private void count(Serializable s) {
if (_counts.containsKey(s)) {
_counts.put(s, _counts.get(s) + 1);
} else {
_counts.put(s, 1);
}
}
}

View File

@ -1,272 +0,0 @@
package com.google.gridworks.commands;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gridworks.GridworksServlet;
import com.google.gridworks.Jsonizable;
import com.google.gridworks.ProjectManager;
import com.google.gridworks.ProjectMetadata;
import com.google.gridworks.browsing.Engine;
import com.google.gridworks.history.HistoryEntry;
import com.google.gridworks.model.Project;
import com.google.gridworks.process.Process;
import com.google.gridworks.util.ParsingUtilities;
/**
* The super class of all calls that the client side can invoke, most of which
* are AJAX calls.
*/
public abstract class Command {
final static protected Logger logger = LoggerFactory.getLogger("command");
protected GridworksServlet servlet;
public void init(GridworksServlet servlet) {
this.servlet = servlet;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
throw new UnsupportedOperationException();
};
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
throw new UnsupportedOperationException();
};
/**
* Utility function to get the browsing engine's configuration as a JSON object
* from the "engine" request parameter, most often in the POST body.
*
* @param request
* @return
* @throws JSONException
*/
static protected JSONObject getEngineConfig(HttpServletRequest request)
throws JSONException {
if (request == null) throw new IllegalArgumentException("parameter 'request' should not be null");
String json = request.getParameter("engine");
try{
return (json == null) ? null : ParsingUtilities.evaluateJsonStringToObject(json);
} catch (JSONException e){
logger.debug( json + " could not be parsed to JSON");
return null;
}
}
/**
* Utility function to reconstruct the browsing engine from the "engine" request parameter,
* most often in the POST body.
*
* @param request
* @param project
* @return
* @throws Exception
*/
static protected Engine getEngine(HttpServletRequest request, Project project)
throws Exception {
if (request == null) throw new IllegalArgumentException("parameter 'request' should not be null");
if (project == null) throw new IllegalArgumentException("parameter 'project' should not be null");
Engine engine = new Engine(project);
JSONObject o = getEngineConfig(request);
if (o != null)
engine.initializeFromJSON(o);
return engine;
}
/**
* Utility method for retrieving the Project object having the ID specified
* in the "project" URL parameter.
*
* @param request
* @return
* @throws ServletException
*/
protected Project getProject(HttpServletRequest request) throws ServletException {
if (request == null) throw new IllegalArgumentException("parameter 'request' should not be null");
try {
Project p = ProjectManager.singleton.getProject(Long.parseLong(request.getParameter("project")));
if (p != null) {
return p;
}
} catch (Exception e) {
// ignore
}
throw new ServletException("Can't find project: missing or bad URL parameter");
}
/**
* Utility method for retrieving the ProjectMetadata object having the ID specified
* in the "project" URL parameter.
*
* @param request
* @return
* @throws ServletException
*/
protected ProjectMetadata getProjectMetadata(HttpServletRequest request) throws ServletException {
if (request == null) throw new IllegalArgumentException("parameter 'request' should not be null");
try {
ProjectMetadata pm = ProjectManager.singleton.getProjectMetadata(Long.parseLong(request.getParameter("project")));
if (pm != null) {
return pm;
}
} catch (Exception e) {
// ignore
}
throw new ServletException("Can't find project metadata: missing or bad URL parameter");
}
static protected int getIntegerParameter(HttpServletRequest request, String name, int def) {
if (request == null) throw new IllegalArgumentException("parameter 'request' should not be null");
try {
return Integer.parseInt(request.getParameter(name));
} catch (Exception e) {
// ignore
}
return def;
}
static protected JSONObject getJsonParameter(HttpServletRequest request, String name) {
if (request == null) throw new IllegalArgumentException("parameter 'request' should not be null");
String value = request.getParameter(name);
if (value != null) {
try {
return ParsingUtilities.evaluateJsonStringToObject(value);
} catch (JSONException e) {
logger.warn("error getting json parameter",e);
}
}
return null;
}
static protected void performProcessAndRespond(
HttpServletRequest request,
HttpServletResponse response,
Project project,
Process process
) throws Exception {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
HistoryEntry historyEntry = project.processManager.queueProcess(process);
if (historyEntry != null) {
Writer w = response.getWriter();
JSONWriter writer = new JSONWriter(w);
Properties options = new Properties();
writer.object();
writer.key("code"); writer.value("ok");
writer.key("historyEntry"); historyEntry.write(writer, options);
writer.endObject();
w.flush();
w.close();
} else {
respond(response, "{ \"code\" : \"pending\" }");
}
}
static protected void respond(HttpServletResponse response, String content)
throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
Writer w = response.getWriter();
if (w != null) {
w.write(content);
w.flush();
w.close();
} else {
throw new ServletException("response returned a null writer");
}
}
static protected void respond(HttpServletResponse response, String status, String message)
throws IOException, JSONException {
Writer w = response.getWriter();
JSONWriter writer = new JSONWriter(w);
writer.object();
writer.key("status"); writer.value(status);
writer.key("message"); writer.value(message);
writer.endObject();
w.flush();
w.close();
}
static protected void respondJSON(HttpServletResponse response, Jsonizable o)
throws IOException, JSONException {
respondJSON(response, o, new Properties());
}
static protected void respondJSON(
HttpServletResponse response, Jsonizable o, Properties options)
throws IOException, JSONException {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
Writer w = response.getWriter();
JSONWriter writer = new JSONWriter(w);
o.write(writer, options);
w.flush();
w.close();
}
static protected void respondException(HttpServletResponse response, Exception e)
throws IOException, ServletException {
logger.warn("Exception caught", e);
if (response == null) {
throw new ServletException("Response object can't be null");
}
try {
JSONObject o = new JSONObject();
o.put("code", "error");
o.put("message", e.getMessage());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
sw.flush();
o.put("stack", sw.toString());
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
respond(response, o.toString());
} catch (JSONException e1) {
e.printStackTrace(response.getWriter());
}
}
static protected void redirect(HttpServletResponse response, String url) throws IOException {
response.sendRedirect(url);
}
}

View File

@ -1,56 +0,0 @@
package com.google.gridworks.commands;
import java.io.IOException;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONObject;
import com.google.gridworks.model.AbstractOperation;
import com.google.gridworks.model.Project;
import com.google.gridworks.process.Process;
/**
* Convenient super class for commands that perform abstract operations on
* only the filtered rows based on the faceted browsing engine's configuration
* on the client side.
*
* The engine's configuration is passed over as a POST body parameter. It is
* retrieved, de-serialized, and used to construct the abstract operation.
* The operation is then used to construct a process. The process is then
* queued for execution. If the process is not long running and there is no
* other queued process, then it gets executed right away, resulting in some
* change to the history. Otherwise, it is pending. The client side can
* decide how to update its UI depending on whether the process is done or
* still pending.
*
* Note that there are interactions on the client side that change only
* individual cells or individual rows (such as starring one row or editing
* the text of one cell). These interactions do not depend on the faceted
* browsing engine's configuration, and so they don't invoke commands that
* subclass this class. See AnnotateOneRowCommand and EditOneCellCommand as
* examples.
*/
abstract public class EngineDependentCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Project project = getProject(request);
AbstractOperation op = createOperation(project, request, getEngineConfig(request));
Process process = op.createProcess(project, new Properties());
performProcessAndRespond(request, response, project, process);
} catch (Exception e) {
respondException(response, e);
}
}
abstract protected AbstractOperation createOperation(
Project project, HttpServletRequest request, JSONObject engineConfig) throws Exception;
}

View File

@ -1,48 +0,0 @@
package com.google.gridworks.commands;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.gridworks.ProjectManager;
import com.google.gridworks.model.Project;
import com.google.gridworks.preference.PreferenceStore;
public class GetAllPreferencesCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Project project = request.getParameter("project") != null ? getProject(request) : null;
PreferenceStore ps = project != null ?
project.getMetadata().getPreferenceStore() :
ProjectManager.singleton.getPreferenceStore();
try {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
JSONWriter writer = new JSONWriter(response.getWriter());
writer.object();
for (String key : ps.getKeys()) {
Object pref = ps.get(key);
if (pref == null || pref instanceof String || pref instanceof Number || pref instanceof Boolean) {
writer.key(key);
writer.value(pref);
}
}
writer.endObject();
} catch (JSONException e) {
respondException(response, e);
}
}
}

View File

@ -1,54 +0,0 @@
package com.google.gridworks.commands;
import java.io.IOException;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONWriter;
import com.google.gridworks.ProjectManager;
import com.google.gridworks.model.Project;
import com.google.gridworks.preference.PreferenceStore;
import com.google.gridworks.preference.TopList;
public class GetPreferenceCommand extends Command {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Project project = request.getParameter("project") != null ? getProject(request) : null;
PreferenceStore ps = project != null ?
project.getMetadata().getPreferenceStore() :
ProjectManager.singleton.getPreferenceStore();
String prefName = request.getParameter("name");
Object pref = ps.get(prefName);
try {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
JSONWriter writer = new JSONWriter(response.getWriter());
writer.object();
writer.key("value");
if (pref == null || pref instanceof String || pref instanceof Number || pref instanceof Boolean) {
writer.value(pref);
} else if (pref instanceof TopList) {
TopList tl = (TopList) pref;
tl.write(writer, new Properties());
} else {
writer.value(pref.toString());
}
writer.endObject();
} catch (JSONException e) {
respondException(response, e);
}
}
}

View File

@ -1,37 +0,0 @@
package com.google.gridworks.commands;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gridworks.ProjectManager;
import com.google.gridworks.io.FileProjectManager;
public class OpenWorkspaceDirCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String serverName = request.getServerName();
if (!"127.0.0.1".equals(serverName) && !"localhost".equals(serverName)) {
respond(response, "{ \"code\" : \"error\", \"message\" : \"Workspace directory can only be opened on the local machine where Gridworks is run.\" }");
} else if (ProjectManager.singleton instanceof FileProjectManager) {
File dir = ((FileProjectManager) ProjectManager.singleton).getWorkspaceDir();
Runtime.getRuntime().exec(
"open .",
new String[] {},
dir
);
respond(response, "{ \"code\" : \"ok\" }");
} else {
respond(response, "{ \"code\" : \"error\", \"message\" : \"Workspace is not stored on the file system.\" }");
}
}
}

View File

@ -1,40 +0,0 @@
package com.google.gridworks.commands;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONTokener;
import com.google.gridworks.ProjectManager;
import com.google.gridworks.model.Project;
import com.google.gridworks.preference.PreferenceStore;
public class SetPreferenceCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Project project = request.getParameter("project") != null ? getProject(request) : null;
PreferenceStore ps = project != null ?
project.getMetadata().getPreferenceStore() :
ProjectManager.singleton.getPreferenceStore();
String prefName = request.getParameter("name");
String valueString = request.getParameter("value");
try {
Object o = valueString == null ? null : new JSONTokener(valueString).nextValue();
ps.put(prefName, PreferenceStore.loadObject(o));
respond(response, "{ \"code\" : \"ok\" }");
} catch (JSONException e) {
respondException(response, e);
}
}
}

View File

@ -1,134 +0,0 @@
package com.google.gridworks.commands.auth;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.OAuthProvider;
import com.google.gridworks.commands.Command;
import com.google.gridworks.oauth.Credentials;
import com.google.gridworks.oauth.OAuthUtilities;
import com.google.gridworks.oauth.Provider;
public class AuthorizeCommand extends Command {
private static final String OAUTH_VERIFIER_PARAM = "oauth_verifier";
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// get the provider from the request
Provider provider = OAuthUtilities.getProvider(request);
try {
// see if the request comes with access credentials
Credentials access_credentials = Credentials.getCredentials(request, provider, Credentials.Type.ACCESS);
// prepare the continuation URL that the OAuth provider will redirect the user to
// (we need to make sure this URL points back to this code or the dance will never complete)
String callbackURL = getBaseURL(request,provider);
if (access_credentials == null) {
// access credentials are not available so we need to check
// to see at what stage of the OAuth dance we are
// get the request token credentials
Credentials request_credentials = Credentials.getCredentials(request, provider, Credentials.Type.REQUEST);
OAuthConsumer consumer = OAuthUtilities.getConsumer(request_credentials, provider);
OAuthProvider pp = OAuthUtilities.getOAuthProvider(provider);
if (request_credentials == null) {
// no credentials were found, so let's start the dance
// get the request token
String url = pp.retrieveRequestToken(consumer, callbackURL);
request_credentials = new Credentials(consumer.getToken(), consumer.getTokenSecret(), provider);
// and set them to that we can retrieve them later in the second part of the dance
Credentials.setCredentials(request, response, request_credentials, Credentials.Type.REQUEST, 3600);
// now redirect the user to the Authorize URL where she can authenticate against the
// service provider and authorize us.
// The provider will bounce the user back here for us to continue the dance.
response.sendRedirect(url);
} else {
// we are at the second stage of the dance, so we need need to obtain the access credentials now
// if we got here, it means that the user performed a valid authentication against the
// service provider and authorized us, so now we can request more permanent credentials
// to the service provider and save those as well for later use.
// this is set only for OAuth 1.0a
String verificationCode = request.getParameter(OAUTH_VERIFIER_PARAM);
pp.retrieveAccessToken(consumer, verificationCode);
access_credentials = new Credentials(consumer.getToken(), consumer.getTokenSecret(), provider);
// no matter the result, we need to remove the request token
Credentials.deleteCredentials(request, response, provider, Credentials.Type.REQUEST);
Credentials.setCredentials(request, response, access_credentials, Credentials.Type.ACCESS, 30 * 24 * 3600);
finish(response);
}
} else {
finish(response);
}
} catch (Exception e) {
Credentials.deleteCredentials(request, response, provider, Credentials.Type.REQUEST);
Credentials.deleteCredentials(request, response, provider, Credentials.Type.ACCESS);
respondException(response, e);
}
}
private void finish(HttpServletResponse response) throws IOException {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "text/html");
PrintWriter writer = response.getWriter();
writer.write(
"<html>" +
"<body></body>" +
"<script type='text/javascript'>" +
"if (top.opener && top.opener.onauthorization) {" +
" top.opener.onauthorization(window);" +
"}" +
"self.close();" +
"</script>" +
"</html>"
);
writer.flush();
}
private String getBaseURL(HttpServletRequest request, Provider provider) {
String host = request.getHeader("host");
if (host == null) {
String referrer = request.getHeader("referer");
if (referrer != null) {
URI url;
try {
url = new URI(referrer);
int port = url.getPort();
host = url.getHost() + ((port > -1) ? ":" + url.getPort() : "");
} catch (URISyntaxException e) {
throw new RuntimeException("referrer '" + referrer + "' can't be parsed as a URL");
}
} else {
throw new RuntimeException("neither the 'host' nor 'referer' headers were present in the HTTP response, I can't determine what URL gridworks is listening to.");
}
}
return "http://" + host + "/command/core/authorize/" + provider.getHost();
}
}

View File

@ -1,47 +0,0 @@
package com.google.gridworks.commands.auth;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gridworks.commands.Command;
import com.google.gridworks.oauth.Credentials;
import com.google.gridworks.oauth.OAuthUtilities;
import com.google.gridworks.oauth.Provider;
import com.google.gridworks.util.FreebaseUtils;
public class CheckAuthorizationCommand extends Command {
final static Logger logger = LoggerFactory.getLogger("check-authorization_command");
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Provider provider = OAuthUtilities.getProvider(request);
// this cookie should not be there, but this is good hygiene practice
Credentials.deleteCredentials(request, response, provider, Credentials.Type.REQUEST);
Credentials access_credentials = Credentials.getCredentials(request, provider, Credentials.Type.ACCESS);
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
if (access_credentials != null) {
String user_info = FreebaseUtils.getUserInfo(access_credentials, provider);
response.getWriter().write(user_info);
} else {
respond(response, "401 Unauthorized", "You don't have the right credentials");
}
} catch (Exception e) {
logger.info("error",e);
respondException(response, e);
}
}
}

View File

@ -1,31 +0,0 @@
package com.google.gridworks.commands.auth;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gridworks.commands.Command;
import com.google.gridworks.oauth.Credentials;
import com.google.gridworks.oauth.OAuthUtilities;
import com.google.gridworks.oauth.Provider;
public class DeAuthorizeCommand extends Command {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
Provider provider = OAuthUtilities.getProvider(request);
Credentials.deleteCredentials(request, response, provider, Credentials.Type.ACCESS);
respond(response, "200 OK", "");
} catch (Exception e) {
respondException(response, e);
}
}
}

View File

@ -1,36 +0,0 @@
package com.google.gridworks.commands.auth;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gridworks.commands.Command;
import com.google.gridworks.oauth.OAuthUtilities;
import com.google.gridworks.oauth.Provider;
import com.google.gridworks.util.FreebaseUtils;
public class GetUserBadgesCommand extends Command {
final static Logger logger = LoggerFactory.getLogger("check-authorization_command");
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Provider provider = OAuthUtilities.getProvider(request);
String user_id = request.getParameter("user_id");
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
String user_badges = FreebaseUtils.getUserBadges(provider, user_id);
response.getWriter().write(user_badges);
} catch (Exception e) {
logger.info("error",e);
respondException(response, e);
}
}
}

View File

@ -1,53 +0,0 @@
package com.google.gridworks.commands.browsing;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gridworks.browsing.Engine;
import com.google.gridworks.clustering.Clusterer;
import com.google.gridworks.clustering.binning.BinningClusterer;
import com.google.gridworks.clustering.knn.kNNClusterer;
import com.google.gridworks.commands.Command;
import com.google.gridworks.model.Project;
public class ComputeClustersCommand extends Command {
final static Logger logger = LoggerFactory.getLogger("compute-clusters_command");
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
long start = System.currentTimeMillis();
Project project = getProject(request);
Engine engine = getEngine(request, project);
JSONObject clusterer_conf = getJsonParameter(request,"clusterer");
Clusterer clusterer = null;
String type = clusterer_conf.has("type") ? clusterer_conf.getString("type") : "binning";
if ("knn".equals(type)) {
clusterer = new kNNClusterer();
} else {
clusterer = new BinningClusterer();
}
clusterer.initializeFromJSON(project, clusterer_conf);
clusterer.computeClusters(engine);
respondJSON(response, clusterer);
logger.info("computed clusters [{},{}] in {}ms", new Object[] { type, clusterer_conf.getString("function"), Long.toString(System.currentTimeMillis() - start) });
} catch (Exception e) {
respondException(response, e);
}
}
}

View File

@ -1,29 +0,0 @@
package com.google.gridworks.commands.browsing;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gridworks.browsing.Engine;
import com.google.gridworks.commands.Command;
import com.google.gridworks.model.Project;
public class ComputeFacetsCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Project project = getProject(request);
Engine engine = getEngine(request, project);
engine.computeFacets();
respondJSON(response, engine);
} catch (Exception e) {
respondException(response, e);
}
}
}

View File

@ -1,175 +0,0 @@
package com.google.gridworks.commands.browsing;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gridworks.browsing.Engine;
import com.google.gridworks.browsing.FilteredRows;
import com.google.gridworks.browsing.facets.ScatterplotDrawingRowVisitor;
import com.google.gridworks.browsing.facets.ScatterplotFacet;
import com.google.gridworks.browsing.util.NumericBinIndex;
import com.google.gridworks.commands.Command;
import com.google.gridworks.expr.Evaluable;
import com.google.gridworks.expr.MetaParser;
import com.google.gridworks.expr.ParsingException;
import com.google.gridworks.model.Column;
import com.google.gridworks.model.Project;
public class GetScatterplotCommand extends Command {
final static Logger logger = LoggerFactory.getLogger("get-scatterplot_command");
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
long start = System.currentTimeMillis();
Project project = getProject(request);
Engine engine = getEngine(request, project);
JSONObject conf = getJsonParameter(request,"plotter");
response.setHeader("Content-Type", "image/png");
ServletOutputStream sos = null;
try {
sos = response.getOutputStream();
draw(sos, project, engine, conf);
} finally {
sos.close();
}
logger.trace("Drawn scatterplot in {} ms", Long.toString(System.currentTimeMillis() - start));
} catch (Exception e) {
e.printStackTrace();
respondException(response, e);
}
}
public void draw(OutputStream output, Project project, Engine engine, JSONObject o) throws IOException, JSONException {
double min_x = 0;
double min_y = 0;
double max_x = 0;
double max_y = 0;
int columnIndex_x = 0;
int columnIndex_y = 0;
Evaluable eval_x = null;
Evaluable eval_y = null;
int size = (o.has(ScatterplotFacet.SIZE)) ? o.getInt(ScatterplotFacet.SIZE) : 100;
double dot = (o.has(ScatterplotFacet.DOT)) ? o.getDouble(ScatterplotFacet.DOT) : 100;
int dim_x = (o.has(ScatterplotFacet.DIM_X)) ? ScatterplotFacet.getAxisDim(o.getString(ScatterplotFacet.DIM_X)) : ScatterplotFacet.LIN;
int dim_y = (o.has(ScatterplotFacet.DIM_Y)) ? ScatterplotFacet.getAxisDim(o.getString(ScatterplotFacet.DIM_Y)) : ScatterplotFacet.LIN;
int rotation = (o.has(ScatterplotFacet.ROTATION)) ? ScatterplotFacet.getRotation(o.getString(ScatterplotFacet.ROTATION)) : ScatterplotFacet.NO_ROTATION;
String color_str = (o.has(ScatterplotFacet.COLOR)) ? o.getString(ScatterplotFacet.COLOR) : "000000";
Color color = new Color(Integer.parseInt(color_str,16));
String base_color_str = (o.has(ScatterplotFacet.BASE_COLOR)) ? o.getString(ScatterplotFacet.BASE_COLOR) : null;
Color base_color = base_color_str != null ? new Color(Integer.parseInt(base_color_str,16)) : null;
String columnName_x = o.getString(ScatterplotFacet.X_COLUMN_NAME);
String expression_x = (o.has(ScatterplotFacet.X_EXPRESSION)) ? o.getString(ScatterplotFacet.X_EXPRESSION) : "value";
if (columnName_x.length() > 0) {
Column x_column = project.columnModel.getColumnByName(columnName_x);
if (x_column != null) {
columnIndex_x = x_column.getCellIndex();
}
} else {
columnIndex_x = -1;
}
try {
eval_x = MetaParser.parse(expression_x);
} catch (ParsingException e) {
logger.warn("error parsing expression", e);
}
String columnName_y = o.getString(ScatterplotFacet.Y_COLUMN_NAME);
String expression_y = (o.has(ScatterplotFacet.Y_EXPRESSION)) ? o.getString(ScatterplotFacet.Y_EXPRESSION) : "value";
if (columnName_y.length() > 0) {
Column y_column = project.columnModel.getColumnByName(columnName_y);
if (y_column != null) {
columnIndex_y = y_column.getCellIndex();
}
} else {
columnIndex_y = -1;
}
try {
eval_y = MetaParser.parse(expression_y);
} catch (ParsingException e) {
logger.warn("error parsing expression", e);
}
NumericBinIndex index_x = null;
NumericBinIndex index_y = null;
String col_x_name = o.getString(ScatterplotFacet.X_COLUMN_NAME);
Column column_x = project.columnModel.getColumnByName(col_x_name);
if (column_x != null) {
columnIndex_x = column_x.getCellIndex();
index_x = ScatterplotFacet.getBinIndex(project, column_x, eval_x, expression_x);
min_x = index_x.getMin();
max_x = index_x.getMax();
}
String col_y_name = o.getString(ScatterplotFacet.Y_COLUMN_NAME);
Column column_y = project.columnModel.getColumnByName(col_y_name);
if (column_y != null) {
columnIndex_y = column_y.getCellIndex();
index_y = ScatterplotFacet.getBinIndex(project, column_y, eval_y, expression_y);
min_y = index_y.getMin();
max_y = index_y.getMax();
}
if (index_x != null && index_y != null && index_x.isNumeric() && index_y.isNumeric()) {
ScatterplotDrawingRowVisitor drawer = new ScatterplotDrawingRowVisitor(
columnIndex_x, columnIndex_y, min_x, max_x, min_y, max_y,
size, dim_x, dim_y, rotation, dot, color
);
if (base_color != null) {
drawer.setColor(base_color);
FilteredRows filteredRows = engine.getAllRows();
filteredRows.accept(project, drawer);
drawer.setColor(color);
}
{
FilteredRows filteredRows = engine.getAllFilteredRows();
filteredRows.accept(project, drawer);
}
ImageIO.write(drawer.getImage(), "png", output);
} else {
ImageIO.write(new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR), "png", output);
}
}
}

View File

@ -1,24 +0,0 @@
package com.google.gridworks.commands.cell;
import javax.servlet.http.HttpServletRequest;
import org.json.JSONObject;
import com.google.gridworks.commands.EngineDependentCommand;
import com.google.gridworks.model.AbstractOperation;
import com.google.gridworks.model.Project;
import com.google.gridworks.operations.cell.BlankDownOperation;
public class BlankDownCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");
return new BlankDownOperation(
engineConfig,
columnName
);
}
}

View File

@ -1,128 +0,0 @@
package com.google.gridworks.commands.cell;
import java.io.IOException;
import java.io.Serializable;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONWriter;
import com.google.gridworks.commands.Command;
import com.google.gridworks.history.Change;
import com.google.gridworks.history.HistoryEntry;
import com.google.gridworks.model.Cell;
import com.google.gridworks.model.Column;
import com.google.gridworks.model.Project;
import com.google.gridworks.model.changes.CellChange;
import com.google.gridworks.process.QuickHistoryEntryProcess;
import com.google.gridworks.util.ParsingUtilities;
import com.google.gridworks.util.Pool;
public class EditOneCellCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
Project project = getProject(request);
int rowIndex = Integer.parseInt(request.getParameter("row"));
int cellIndex = Integer.parseInt(request.getParameter("cell"));
String type = request.getParameter("type");
String valueString = request.getParameter("value");
Serializable value = null;
if ("number".equals(type)) {
value = Double.parseDouble(valueString);
} else if ("boolean".equals(type)) {
value = "true".equalsIgnoreCase(valueString);
} else if ("date".equals(type)) {
value = ParsingUtilities.stringToDate(valueString);
} else {
value = valueString;
}
EditOneCellProcess process = new EditOneCellProcess(
project,
"Edit single cell",
rowIndex,
cellIndex,
value
);
HistoryEntry historyEntry = project.processManager.queueProcess(process);
if (historyEntry != null) {
/*
* If the operation has been done, return the new cell's data
* so the client side can update the cell's rendering right away.
*/
JSONWriter writer = new JSONWriter(response.getWriter());
Pool pool = new Pool();
Properties options = new Properties();
options.put("pool", pool);
writer.object();
writer.key("code"); writer.value("ok");
writer.key("historyEntry"); historyEntry.write(writer, options);
writer.key("cell"); process.newCell.write(writer, options);
writer.key("pool"); pool.write(writer, options);
writer.endObject();
} else {
respond(response, "{ \"code\" : \"pending\" }");
}
} catch (Exception e) {
respondException(response, e);
}
}
protected static class EditOneCellProcess extends QuickHistoryEntryProcess {
final int rowIndex;
final int cellIndex;
final Serializable value;
Cell newCell;
EditOneCellProcess(
Project project,
String briefDescription,
int rowIndex,
int cellIndex,
Serializable value
) {
super(project, briefDescription);
this.rowIndex = rowIndex;
this.cellIndex = cellIndex;
this.value = value;
}
protected HistoryEntry createHistoryEntry(long historyEntryID) throws Exception {
Cell cell = _project.rows.get(rowIndex).getCell(cellIndex);
Column column = _project.columnModel.getColumnByCellIndex(cellIndex);
if (column == null) {
throw new Exception("No such column");
}
newCell = new Cell(
value,
cell != null ? cell.recon : null
);
String description =
"Edit single cell on row " + (rowIndex + 1) +
", column " + column.getName();
Change change = new CellChange(rowIndex, cellIndex, cell, newCell);
return new HistoryEntry(
historyEntryID, _project, description, null, change);
}
}
}

View File

@ -1,24 +0,0 @@
package com.google.gridworks.commands.cell;
import javax.servlet.http.HttpServletRequest;
import org.json.JSONObject;
import com.google.gridworks.commands.EngineDependentCommand;
import com.google.gridworks.model.AbstractOperation;
import com.google.gridworks.model.Project;
import com.google.gridworks.operations.cell.FillDownOperation;
public class FillDownCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");
return new FillDownOperation(
engineConfig,
columnName
);
}
}

View File

@ -1,36 +0,0 @@
package com.google.gridworks.commands.cell;
import java.io.IOException;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gridworks.commands.Command;
import com.google.gridworks.model.AbstractOperation;
import com.google.gridworks.model.Project;
import com.google.gridworks.operations.cell.MultiValuedCellJoinOperation;
import com.google.gridworks.process.Process;
public class JoinMultiValueCellsCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Project project = getProject(request);
String columnName = request.getParameter("columnName");
String keyColumnName = request.getParameter("keyColumnName");
String separator = request.getParameter("separator");
AbstractOperation op = new MultiValuedCellJoinOperation(columnName, keyColumnName, separator);
Process process = op.createProcess(project, new Properties());
performProcessAndRespond(request, response, project, process);
} catch (Exception e) {
respondException(response, e);
}
}
}

View File

@ -1,29 +0,0 @@
package com.google.gridworks.commands.cell;
import javax.servlet.http.HttpServletRequest;
import org.json.JSONObject;
import com.google.gridworks.commands.EngineDependentCommand;
import com.google.gridworks.model.AbstractOperation;
import com.google.gridworks.model.Project;
import com.google.gridworks.operations.cell.MassEditOperation;
import com.google.gridworks.util.ParsingUtilities;
public class MassEditCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");
String expression = request.getParameter("expression");
String editsString = request.getParameter("edits");
return new MassEditOperation(
engineConfig,
columnName,
expression,
MassEditOperation.reconstructEdits(ParsingUtilities.evaluateJsonStringToArray(editsString))
);
}
}

View File

@ -1,37 +0,0 @@
package com.google.gridworks.commands.cell;
import java.io.IOException;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gridworks.commands.Command;
import com.google.gridworks.model.AbstractOperation;
import com.google.gridworks.model.Project;
import com.google.gridworks.operations.cell.MultiValuedCellSplitOperation;
import com.google.gridworks.process.Process;
public class SplitMultiValueCellsCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Project project = getProject(request);
String columnName = request.getParameter("columnName");
String keyColumnName = request.getParameter("keyColumnName");
String separator = request.getParameter("separator");
String mode = request.getParameter("mode");
AbstractOperation op = new MultiValuedCellSplitOperation(columnName, keyColumnName, separator, mode);
Process process = op.createProcess(project, new Properties());
performProcessAndRespond(request, response, project, process);
} catch (Exception e) {
respondException(response, e);
}
}
}

View File

@ -1,38 +0,0 @@
package com.google.gridworks.commands.cell;
import javax.servlet.http.HttpServletRequest;
import org.json.JSONObject;
import com.google.gridworks.commands.EngineDependentCommand;
import com.google.gridworks.model.AbstractOperation;
import com.google.gridworks.model.Project;
import com.google.gridworks.operations.cell.TextTransformOperation;
public class TextTransformCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");
String expression = request.getParameter("expression");
String onError = request.getParameter("onError");
boolean repeat = "true".equals(request.getParameter("repeat"));
int repeatCount = 10;
String repeatCountString = request.getParameter("repeatCount");
try {
repeatCount = Math.max(Math.min(Integer.parseInt(repeatCountString), 10), 0);
} catch (Exception e) {
}
return new TextTransformOperation(
engineConfig,
columnName,
expression,
TextTransformOperation.stringToOnError(onError),
repeat,
repeatCount
);
}
}

View File

@ -1,42 +0,0 @@
package com.google.gridworks.commands.cell;
import java.io.IOException;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gridworks.commands.Command;
import com.google.gridworks.model.AbstractOperation;
import com.google.gridworks.model.Project;
import com.google.gridworks.operations.cell.TransposeColumnsIntoRowsOperation;
import com.google.gridworks.process.Process;
public class TransposeColumnsIntoRowsCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Project project = getProject(request);
String startColumnName = request.getParameter("startColumnName");
int columnCount = Integer.parseInt(request.getParameter("columnCount"));
String combinedColumnName = request.getParameter("combinedColumnName");
boolean prependColumnName = Boolean.parseBoolean(request.getParameter("prependColumnName"));
String separator = request.getParameter("separator");
boolean ignoreBlankCells = Boolean.parseBoolean(request.getParameter("ignoreBlankCells"));
AbstractOperation op = new TransposeColumnsIntoRowsOperation(
startColumnName, columnCount, combinedColumnName, prependColumnName, separator, ignoreBlankCells);
Process process = op.createProcess(project, new Properties());
performProcessAndRespond(request, response, project, process);
} catch (Exception e) {
respondException(response, e);
}
}
}

View File

@ -1,37 +0,0 @@
package com.google.gridworks.commands.cell;
import java.io.IOException;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gridworks.commands.Command;
import com.google.gridworks.model.AbstractOperation;
import com.google.gridworks.model.Project;
import com.google.gridworks.operations.cell.TransposeRowsIntoColumnsOperation;
import com.google.gridworks.process.Process;
public class TransposeRowsIntoColumnsCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Project project = getProject(request);
String columnName = request.getParameter("columnName");
int rowCount = Integer.parseInt(request.getParameter("rowCount"));
AbstractOperation op = new TransposeRowsIntoColumnsOperation(
columnName, rowCount);
Process process = op.createProcess(project, new Properties());
performProcessAndRespond(request, response, project, process);
} catch (Exception e) {
respondException(response, e);
}
}
}

Some files were not shown because too many files have changed in this diff Show More