mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-27 19:11:56 +02:00
Converted build tool to Maven.
This commit is contained in:
3
services/git-bridge/src/main/java/META-INF/MANIFEST.MF
Normal file
3
services/git-bridge/src/main/java/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: uk.ac.ic.wlgitbridge.Main
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package uk.ac.ic.wlgitbridge;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.application.WLGitBridgeApplication;
|
||||
|
||||
/**
|
||||
* Created by Winston on 01/11/14.
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new WLGitBridgeApplication(args).run();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package uk.ac.ic.wlgitbridge.application;
|
||||
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.ResourceHandler;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.WriteLatexAPI;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.InvalidPostbackKeyException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 04/12/14.
|
||||
*/
|
||||
public class AttsResourceHandler extends ResourceHandler {
|
||||
|
||||
private final WriteLatexAPI writeLatexDataSource;
|
||||
|
||||
public AttsResourceHandler(WriteLatexAPI writeLatexDataSource) {
|
||||
this.writeLatexDataSource = writeLatexDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
HttpURI uri = baseRequest.getUri();
|
||||
System.out.println(baseRequest.getMethod() + " " + uri);
|
||||
MultiMap<String> multimap = new MultiMap<String>();
|
||||
uri.decodeQueryTo(multimap);
|
||||
String[] pathSections = uri.getPath().split("/");
|
||||
String key = multimap.getString("key");
|
||||
if (key == null || pathSections.length < 2) {
|
||||
throw new ServletException();
|
||||
}
|
||||
try {
|
||||
writeLatexDataSource.checkPostbackKey(pathSections[1], key);
|
||||
} catch (InvalidPostbackKeyException e) {
|
||||
throw new ServletException();
|
||||
}
|
||||
|
||||
if (false) {
|
||||
throw new ServletException();
|
||||
}
|
||||
super.handle(target, baseRequest, request, response);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package uk.ac.ic.wlgitbridge.application;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import uk.ac.ic.wlgitbridge.application.exception.InvalidConfigFileException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.JSONSource;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 05/12/14.
|
||||
*/
|
||||
public class Config implements JSONSource {
|
||||
|
||||
private int port;
|
||||
private String rootGitDirectory;
|
||||
private String username;
|
||||
private String password;
|
||||
private String apiBaseURL;
|
||||
private String postbackURL;
|
||||
private String serviceName;
|
||||
|
||||
public Config(String configFilePath) throws InvalidConfigFileException, IOException {
|
||||
try {
|
||||
fromJSON(new Gson().fromJson(new FileReader(configFilePath), JsonElement.class));
|
||||
} catch (JsonParseException e) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
JsonObject configObject = json.getAsJsonObject();
|
||||
port = getElement(configObject, "port").getAsInt();
|
||||
rootGitDirectory = getElement(configObject, "rootGitDirectory").getAsString();
|
||||
username = getOptionalString(configObject, "username");
|
||||
password = getOptionalString(configObject, "password");
|
||||
String apiBaseURL = getElement(configObject, "apiBaseUrl").getAsString();
|
||||
if (!apiBaseURL.endsWith("/")) {
|
||||
apiBaseURL += "/";
|
||||
}
|
||||
this.apiBaseURL = apiBaseURL;
|
||||
serviceName = getElement(configObject, "serviceName").getAsString();
|
||||
postbackURL = getElement(configObject, "postbackBaseUrl").getAsString();
|
||||
if (!postbackURL.endsWith("/")) {
|
||||
postbackURL += "/";
|
||||
}
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getRootGitDirectory() {
|
||||
return rootGitDirectory;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public String getAPIBaseURL() {
|
||||
return apiBaseURL;
|
||||
}
|
||||
|
||||
private JsonElement getElement(JsonObject configObject, String name) {
|
||||
JsonElement element = configObject.get(name);
|
||||
if (element == null) {
|
||||
throw new RuntimeException(new InvalidConfigFileException(name));
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
private String getOptionalString(JsonObject configObject, String name) {
|
||||
JsonElement element = configObject.get(name);
|
||||
if (element == null || !element.isJsonPrimitive()) {
|
||||
return "";
|
||||
}
|
||||
return element.getAsString();
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
public String getPostbackURL() {
|
||||
return postbackURL;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package uk.ac.ic.wlgitbridge.application;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.JSONSource;
|
||||
|
||||
/**
|
||||
* Created by Winston on 05/01/15.
|
||||
*/
|
||||
public class SSLConfig implements JSONSource {
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
public SSLConfig(JsonObject ssl) {
|
||||
fromJSON(ssl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
JsonObject obj = json.getAsJsonObject();
|
||||
enabled = obj.get("enabled").getAsJsonPrimitive().getAsBoolean();
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package uk.ac.ic.wlgitbridge.application;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WriteLatexDataSource;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.JSONSource;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.UnexpectedPostbackException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostExceptionBuilder;
|
||||
|
||||
/**
|
||||
* Created by Winston on 17/11/14.
|
||||
*/
|
||||
public class SnapshotPushPostbackContents implements JSONSource {
|
||||
|
||||
private static final String CODE_SUCCESS = "upToDate";
|
||||
|
||||
private final WriteLatexDataSource writeLatexDataSource;
|
||||
private final String projectName;
|
||||
private final String postbackKey;
|
||||
|
||||
private final SnapshotPostExceptionBuilder snapshotPostExceptionBuilder;
|
||||
|
||||
private int versionID;
|
||||
private SnapshotPostException exception;
|
||||
|
||||
public SnapshotPushPostbackContents(WriteLatexDataSource writeLatexDataSource, String projectName, String postbackKey, String contents) {
|
||||
this.writeLatexDataSource = writeLatexDataSource;
|
||||
this.projectName = projectName;
|
||||
this.postbackKey = postbackKey;
|
||||
snapshotPostExceptionBuilder = new SnapshotPostExceptionBuilder();
|
||||
fromJSON(new Gson().fromJson(contents, JsonElement.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
System.out.println(json);
|
||||
JsonObject responseObject = json.getAsJsonObject();
|
||||
String code = responseObject.get("code").getAsString();
|
||||
setResult(responseObject, code);
|
||||
}
|
||||
|
||||
public void processPostback() throws UnexpectedPostbackException {
|
||||
if (exception == null) {
|
||||
writeLatexDataSource.postbackReceivedSuccessfully(projectName, postbackKey, versionID);
|
||||
} else {
|
||||
writeLatexDataSource.postbackReceivedWithException(projectName, postbackKey, exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void setResult(JsonObject responseObject, String code) {
|
||||
if (code.equals(CODE_SUCCESS)) {
|
||||
setVersionID(responseObject);
|
||||
} else {
|
||||
setException(responseObject, code);
|
||||
}
|
||||
}
|
||||
|
||||
private void setVersionID(JsonObject responseObject) {
|
||||
versionID = responseObject.get("latestVerId").getAsInt();
|
||||
}
|
||||
|
||||
private void setException(JsonObject responseObject, String code) {
|
||||
try {
|
||||
exception = snapshotPostExceptionBuilder.build(code, responseObject);
|
||||
} catch (UnexpectedPostbackException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package uk.ac.ic.wlgitbridge.application;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WriteLatexDataSource;
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.UnexpectedPostbackException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class SnapshotPushPostbackHandler extends AbstractHandler {
|
||||
|
||||
private final WriteLatexDataSource writeLatexDataSource;
|
||||
|
||||
public SnapshotPushPostbackHandler(WriteLatexDataSource writeLatexDataSource) {
|
||||
this.writeLatexDataSource = writeLatexDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
if (request.getMethod().equals("POST") && request.getPathInfo().endsWith("postback")) {
|
||||
String contents = Util.getContentsOfReader(request.getReader());
|
||||
String[] parts = request.getRequestURI().split("/");
|
||||
if (parts.length < 4) {
|
||||
throw new ServletException();
|
||||
}
|
||||
String projectName = parts[1];
|
||||
String postbackKey = parts[2];
|
||||
System.out.println("Postback received for project: " + projectName);
|
||||
SnapshotPushPostbackContents postbackContents = new SnapshotPushPostbackContents(writeLatexDataSource, projectName, postbackKey, contents);
|
||||
try {
|
||||
postbackContents.processPostback();
|
||||
} catch (UnexpectedPostbackException e) {
|
||||
throw new ServletException();
|
||||
}
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package uk.ac.ic.wlgitbridge.application;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.application.exception.InvalidConfigFileException;
|
||||
import uk.ac.ic.wlgitbridge.application.exception.InvalidProgramArgumentsException;
|
||||
import uk.ac.ic.wlgitbridge.git.exception.InvalidRootDirectoryPathException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 02/11/14.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class that represents the application. Parses arguments and gives them to the server, or dies with a usage message.
|
||||
*/
|
||||
public class WLGitBridgeApplication {
|
||||
|
||||
public static final int EXIT_CODE_FAILED = 1;
|
||||
private static final String USAGE_MESSAGE = "usage: writelatex-git-bridge config_file";
|
||||
|
||||
private String configFilePath;
|
||||
private Config config;
|
||||
private WLGitBridgeServer server;
|
||||
|
||||
/**
|
||||
* Constructs an instance of the WriteLatex-Git Bridge application.
|
||||
* @param args args from main, which should be in the format [port, root_git_directory_path]
|
||||
*/
|
||||
public WLGitBridgeApplication(String[] args) {
|
||||
try {
|
||||
parseArguments(args);
|
||||
loadConfigFile();
|
||||
} catch (InvalidProgramArgumentsException e) {
|
||||
printUsage();
|
||||
System.exit(EXIT_CODE_FAILED);
|
||||
} catch (InvalidConfigFileException e) {
|
||||
System.out.println("The property for " + e.getMissingMember() + " is invalid. Check your config file.");
|
||||
System.exit(EXIT_CODE_FAILED);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Invalid config file. Check the file path.");
|
||||
System.exit(EXIT_CODE_FAILED);
|
||||
}
|
||||
try {
|
||||
server = new WLGitBridgeServer(config);
|
||||
} catch (ServletException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidRootDirectoryPathException e) {
|
||||
System.out.println("Invalid root git directory path. Check your config file.");
|
||||
System.exit(EXIT_CODE_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the server with the port number and root directory path given in the command-line arguments.
|
||||
*/
|
||||
public void run() {
|
||||
server.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
/* Helper methods */
|
||||
|
||||
private void parseArguments(String[] args) throws InvalidProgramArgumentsException {
|
||||
checkArgumentsLength(args);
|
||||
parseConfigFilePath(args);
|
||||
}
|
||||
|
||||
private void checkArgumentsLength(String[] args) throws InvalidProgramArgumentsException {
|
||||
if (args.length < 1) {
|
||||
throw new InvalidProgramArgumentsException();
|
||||
}
|
||||
}
|
||||
|
||||
private void parseConfigFilePath(String[] args) throws InvalidProgramArgumentsException {
|
||||
configFilePath = args[0];
|
||||
}
|
||||
|
||||
private void loadConfigFile() throws InvalidConfigFileException, IOException {
|
||||
config = new Config(configFilePath);
|
||||
}
|
||||
|
||||
private void printUsage() {
|
||||
System.out.println(USAGE_MESSAGE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package uk.ac.ic.wlgitbridge.application;
|
||||
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.ResourceHandler;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import uk.ac.ic.wlgitbridge.application.jetty.NullLogger;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WriteLatexDataSource;
|
||||
import uk.ac.ic.wlgitbridge.git.exception.InvalidRootDirectoryPathException;
|
||||
import uk.ac.ic.wlgitbridge.git.servlet.WLGitServlet;
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.WriteLatexAPI;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.SnapshotAPIRequest;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.WLDataModel;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import java.io.File;
|
||||
import java.net.BindException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 02/11/14.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class for the actual server.
|
||||
*/
|
||||
public class WLGitBridgeServer {
|
||||
|
||||
private final Server jettyServer;
|
||||
private final int port;
|
||||
private String rootGitDirectoryPath;
|
||||
private String writeLatexHostname;
|
||||
|
||||
/**
|
||||
* Constructs an instance of the server.
|
||||
* @param port the port number to listen on
|
||||
* @param rootGitDirectoryPath the root directory path containing the git repositories
|
||||
* @throws ServletException if the servlet throws an exception
|
||||
*/
|
||||
private WLGitBridgeServer(final int port, String rootGitDirectoryPath) throws ServletException, InvalidRootDirectoryPathException {
|
||||
this.port = port;
|
||||
this.rootGitDirectoryPath = rootGitDirectoryPath;
|
||||
Log.setLog(new NullLogger());
|
||||
jettyServer = new Server(port);
|
||||
configureJettyServer();
|
||||
}
|
||||
|
||||
public WLGitBridgeServer(Config config) throws ServletException, InvalidRootDirectoryPathException {
|
||||
this(config.getPort(), config.getRootGitDirectory());
|
||||
SnapshotAPIRequest.setBasicAuth(config.getUsername(), config.getPassword());
|
||||
writeLatexHostname = config.getAPIBaseURL();
|
||||
SnapshotAPIRequest.setBaseURL(writeLatexHostname);
|
||||
Util.setServiceName(config.getServiceName());
|
||||
Util.setPostbackURL(config.getPostbackURL());
|
||||
Util.setPort(config.getPort());
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the server on the port given on construction.
|
||||
*/
|
||||
public void start() {
|
||||
try {
|
||||
jettyServer.start();
|
||||
System.out.println();
|
||||
System.out.println(Util.getServiceName() + "-Git Bridge server started");
|
||||
System.out.println("Listening on port: " + port);
|
||||
System.out.println("Bridged to: " + writeLatexHostname);
|
||||
System.out.println("Postback base URL: " + Util.getPostbackURL());
|
||||
System.out.println("Root git directory path: " + rootGitDirectoryPath);
|
||||
} catch (BindException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
try {
|
||||
jettyServer.stop();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void configureJettyServer() throws ServletException, InvalidRootDirectoryPathException {
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
WriteLatexAPI writeLatexDataSource = new WriteLatexAPI(new WLDataModel(rootGitDirectoryPath));
|
||||
handlers.setHandlers(new Handler[] {
|
||||
initResourceHandler(writeLatexDataSource),
|
||||
new SnapshotPushPostbackHandler(writeLatexDataSource),
|
||||
initGitHandler(writeLatexDataSource)
|
||||
});
|
||||
jettyServer.setHandler(handlers);
|
||||
}
|
||||
|
||||
private Handler initGitHandler(WriteLatexDataSource writeLatexDataSource) throws ServletException, InvalidRootDirectoryPathException {
|
||||
final ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
servletContextHandler.setContextPath("/");
|
||||
servletContextHandler.addServlet(
|
||||
new ServletHolder(
|
||||
new WLGitServlet(servletContextHandler, writeLatexDataSource, rootGitDirectoryPath)),
|
||||
"/*"
|
||||
);
|
||||
return servletContextHandler;
|
||||
}
|
||||
|
||||
private Handler initResourceHandler(WriteLatexAPI writeLatexDataSource) {
|
||||
ResourceHandler resourceHandler = new AttsResourceHandler(writeLatexDataSource);
|
||||
resourceHandler.setResourceBase(new File(rootGitDirectoryPath, ".wlgb/atts").getAbsolutePath());
|
||||
return resourceHandler;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package uk.ac.ic.wlgitbridge.application.exception;
|
||||
|
||||
/**
|
||||
* Created by Winston on 05/12/14.
|
||||
*/
|
||||
public class InvalidConfigFileException extends Exception {
|
||||
|
||||
private final String missingMember;
|
||||
|
||||
public InvalidConfigFileException(String missingMember) {
|
||||
|
||||
this.missingMember = missingMember;
|
||||
}
|
||||
|
||||
public String getMissingMember() {
|
||||
return missingMember;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package uk.ac.ic.wlgitbridge.application.exception;
|
||||
|
||||
/**
|
||||
* Created by Winston on 03/11/14.
|
||||
*/
|
||||
public class InvalidProgramArgumentsException extends Throwable {
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package uk.ac.ic.wlgitbridge.application.jetty;
|
||||
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* Created by Winston on 03/11/14.
|
||||
*/
|
||||
public class NullLogger implements Logger {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "null_logger";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Object... objects) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Throwable throwable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Throwable throwable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s, Object... objects) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Throwable throwable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s, Throwable throwable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDebugEnabled(boolean b) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, Object... objects) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, long l) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Throwable throwable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, Throwable throwable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger(String s) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignore(Throwable throwable) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package uk.ac.ic.wlgitbridge.bridge;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.WLDirectoryNode;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public interface CandidateSnapshot {
|
||||
|
||||
public JsonElement getJsonRepresentation();
|
||||
public int getPreviousVersionID();
|
||||
public String getProjectURL();
|
||||
public void approveWithVersionID(int versionID);
|
||||
public String getProjectName();
|
||||
public WLDirectoryNode getDirectoryNode();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package uk.ac.ic.wlgitbridge.bridge;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public interface CandidateSnapshotCallback {
|
||||
|
||||
public void approveSnapshot(int versionID, CandidateSnapshot candidateSnapshot);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package uk.ac.ic.wlgitbridge.bridge;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public interface RawDirectoryContents {
|
||||
|
||||
public Map<String, byte[]> getFileContentsTable();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package uk.ac.ic.wlgitbridge.bridge;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public interface RawFile {
|
||||
|
||||
public String getPath();
|
||||
public byte[] getContents();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package uk.ac.ic.wlgitbridge.bridge;
|
||||
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by Winston on 03/11/14.
|
||||
*/
|
||||
public interface RepositorySource {
|
||||
|
||||
public Repository getRepositoryWithNameAtRootDirectory(String name, File rootDirectory) throws RepositoryNotFoundException, ServiceNotEnabledException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package uk.ac.ic.wlgitbridge.bridge;
|
||||
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.WLFileStore;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Created by Winston on 05/11/14.
|
||||
*/
|
||||
public class WLBridgedProject {
|
||||
|
||||
private final Repository repository;
|
||||
private final String name;
|
||||
private final WriteLatexDataSource writeLatexDataSource;
|
||||
|
||||
public WLBridgedProject(Repository repository, String name, WriteLatexDataSource writeLatexDataSource) {
|
||||
this.repository = repository;
|
||||
this.name = name;
|
||||
this.writeLatexDataSource = writeLatexDataSource;
|
||||
}
|
||||
|
||||
public void buildRepository() throws RepositoryNotFoundException, ServiceNotEnabledException, FailedConnectionException {
|
||||
writeLatexDataSource.lockForProject(name);
|
||||
if (repository.getObjectDatabase().exists()) {
|
||||
updateRepositoryFromSnapshots(repository);
|
||||
} else {
|
||||
buildRepositoryFromScratch(repository);
|
||||
}
|
||||
writeLatexDataSource.unlockForProject(name);
|
||||
}
|
||||
|
||||
private void updateRepositoryFromSnapshots(Repository repository) throws ServiceNotEnabledException, RepositoryNotFoundException, FailedConnectionException {
|
||||
List<WritableRepositoryContents> writableRepositories;
|
||||
try {
|
||||
writableRepositories = writeLatexDataSource.getWritableRepositories(name);
|
||||
} catch (InvalidProjectException e) {
|
||||
throw new RepositoryNotFoundException(name);
|
||||
}
|
||||
try {
|
||||
for (WritableRepositoryContents contents : writableRepositories) {
|
||||
contents.write();
|
||||
Git git = new Git(repository);
|
||||
git.add().addFilepattern(".").call();
|
||||
git.commit().setAuthor(new PersonIdent(contents.getUserName(), contents.getUserEmail(), contents.getWhen(), TimeZone.getDefault()))
|
||||
.setMessage(contents.getCommitMessage())
|
||||
.call();
|
||||
System.out.println(repository.getDirectory());
|
||||
WLFileStore.deleteInDirectoryApartFrom(contents.getDirectory(), ".git");
|
||||
}
|
||||
} catch (GitAPIException e) {
|
||||
throw new ServiceNotEnabledException();
|
||||
} catch (IOException e) {
|
||||
throw new ServiceNotEnabledException();
|
||||
}
|
||||
}
|
||||
|
||||
private void buildRepositoryFromScratch(Repository repository) throws RepositoryNotFoundException, ServiceNotEnabledException, FailedConnectionException {
|
||||
if (!writeLatexDataSource.repositoryExists(name)) {
|
||||
throw new RepositoryNotFoundException(name);
|
||||
}
|
||||
try {
|
||||
repository.create();
|
||||
} catch (IOException e) {
|
||||
throw new ServiceNotEnabledException();
|
||||
}
|
||||
updateRepositoryFromSnapshots(repository);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package uk.ac.ic.wlgitbridge.bridge;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by Winston on 14/11/14.
|
||||
*/
|
||||
public interface WritableRepositoryContents {
|
||||
|
||||
public void write() throws IOException, FailedConnectionException;
|
||||
|
||||
public File getDirectory();
|
||||
|
||||
public String getUserName();
|
||||
public String getUserEmail();
|
||||
public String getCommitMessage();
|
||||
public Date getWhen();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package uk.ac.ic.wlgitbridge.bridge;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.InvalidPostbackKeyException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.UnexpectedPostbackException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 03/11/14.
|
||||
*/
|
||||
public interface WriteLatexDataSource {
|
||||
|
||||
void lockForProject(String projectName);
|
||||
|
||||
void unlockForProject(String projectName);
|
||||
|
||||
/* Called by request thread. */
|
||||
public boolean repositoryExists(String projectName) throws FailedConnectionException;
|
||||
public List<WritableRepositoryContents> getWritableRepositories(String projectName) throws FailedConnectionException, InvalidProjectException;
|
||||
public void putDirectoryContentsToProjectWithName(String projectName, RawDirectoryContents directoryContents, String hostname) throws SnapshotPostException, IOException, FailedConnectionException;
|
||||
|
||||
void checkPostbackKey(String projectName, String postbackKey) throws InvalidPostbackKeyException;
|
||||
|
||||
/* Called by postback thread. */
|
||||
public void postbackReceivedSuccessfully(String projectName, String postbackKey, int versionID) throws UnexpectedPostbackException;
|
||||
public void postbackReceivedWithException(String projectName, String postbackKey, SnapshotPostException exception) throws UnexpectedPostbackException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package uk.ac.ic.wlgitbridge.git.exception;
|
||||
|
||||
/**
|
||||
* Created by Winston on 03/11/14.
|
||||
*/
|
||||
public class InvalidRootDirectoryPathException extends Exception {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package uk.ac.ic.wlgitbridge.git.handler;
|
||||
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.ReceivePack;
|
||||
import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WriteLatexDataSource;
|
||||
import uk.ac.ic.wlgitbridge.git.handler.hook.WriteLatexPutHook;
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Created by Winston on 02/11/14.
|
||||
*/
|
||||
/* */
|
||||
public class WLReceivePackFactory implements ReceivePackFactory<HttpServletRequest> {
|
||||
|
||||
private final WriteLatexDataSource writeLatexDataSource;
|
||||
|
||||
public WLReceivePackFactory(WriteLatexDataSource writeLatexDataSource) {
|
||||
this.writeLatexDataSource = writeLatexDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReceivePack create(HttpServletRequest httpServletRequest, Repository repository) throws ServiceNotEnabledException, ServiceNotAuthorizedException {
|
||||
ReceivePack receivePack = new ReceivePack(repository);
|
||||
String hostname = Util.getPostbackURL();
|
||||
if (hostname == null) {
|
||||
hostname = httpServletRequest.getLocalName();
|
||||
}
|
||||
receivePack.setPreReceiveHook(new WriteLatexPutHook(writeLatexDataSource, hostname));
|
||||
return receivePack;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package uk.ac.ic.wlgitbridge.git.handler;
|
||||
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.ServiceMayNotContinueException;
|
||||
import org.eclipse.jgit.transport.resolver.RepositoryResolver;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
|
||||
import uk.ac.ic.wlgitbridge.bridge.RepositorySource;
|
||||
import uk.ac.ic.wlgitbridge.git.exception.InvalidRootDirectoryPathException;
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.SnapshotRepositoryBuilder;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by Winston on 02/11/14.
|
||||
*/
|
||||
public class WLRepositoryResolver implements RepositoryResolver<HttpServletRequest> {
|
||||
|
||||
private File rootGitDirectory;
|
||||
private RepositorySource repositorySource;
|
||||
|
||||
public WLRepositoryResolver(String rootGitDirectoryPath, SnapshotRepositoryBuilder repositorySource) throws InvalidRootDirectoryPathException {
|
||||
this.repositorySource = repositorySource;
|
||||
initRootGitDirectory(rootGitDirectoryPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Repository open(HttpServletRequest httpServletRequest, String name) throws RepositoryNotFoundException, ServiceNotAuthorizedException, ServiceNotEnabledException, ServiceMayNotContinueException {
|
||||
try {
|
||||
return repositorySource.getRepositoryWithNameAtRootDirectory(Util.removeAllSuffixes(name, "/", ".git"), rootGitDirectory);
|
||||
} catch (RepositoryNotFoundException e) {
|
||||
throw e;
|
||||
} catch (ServiceNotEnabledException e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("An exception occurred");
|
||||
throw new ServiceNotEnabledException();
|
||||
}
|
||||
}
|
||||
|
||||
private void initRootGitDirectory(String rootGitDirectoryPath) throws InvalidRootDirectoryPathException {
|
||||
rootGitDirectory = new File(rootGitDirectoryPath);
|
||||
/* throws SecurityException */
|
||||
rootGitDirectory.mkdirs();
|
||||
rootGitDirectory.getAbsolutePath();
|
||||
if (!rootGitDirectory.isDirectory()) {
|
||||
throw new InvalidRootDirectoryPathException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package uk.ac.ic.wlgitbridge.git.handler;
|
||||
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.UploadPack;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
|
||||
import org.eclipse.jgit.transport.resolver.UploadPackFactory;
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Created by Winston on 02/11/14.
|
||||
*/
|
||||
public class WLUploadPackFactory implements UploadPackFactory<HttpServletRequest> {
|
||||
@Override
|
||||
public UploadPack create(HttpServletRequest httpServletRequest, Repository repository) throws ServiceNotEnabledException, ServiceNotAuthorizedException {
|
||||
UploadPack uploadPack = new UploadPack(repository);
|
||||
uploadPack.sendMessage("Downloading files from " + Util.getServiceName());
|
||||
return uploadPack;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package uk.ac.ic.wlgitbridge.git.handler.hook;
|
||||
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.PreReceiveHook;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand.Result;
|
||||
import org.eclipse.jgit.transport.ReceivePack;
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WriteLatexDataSource;
|
||||
import uk.ac.ic.wlgitbridge.git.handler.hook.exception.ForcedPushException;
|
||||
import uk.ac.ic.wlgitbridge.git.handler.hook.exception.WrongBranchException;
|
||||
import uk.ac.ic.wlgitbridge.git.util.RepositoryObjectTreeWalker;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.OutOfDateException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Created by Winston on 03/11/14.
|
||||
*/
|
||||
public class WriteLatexPutHook implements PreReceiveHook {
|
||||
|
||||
private final WriteLatexDataSource writeLatexDataSource;
|
||||
private final String hostname;
|
||||
|
||||
public WriteLatexPutHook(WriteLatexDataSource writeLatexDataSource, String hostname) {
|
||||
this.writeLatexDataSource = writeLatexDataSource;
|
||||
this.hostname = hostname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreReceive(ReceivePack receivePack, Collection<ReceiveCommand> receiveCommands) {
|
||||
for (ReceiveCommand receiveCommand : receiveCommands) {
|
||||
try {
|
||||
handleReceiveCommand(receivePack.getRepository(), receiveCommand);
|
||||
} catch (IOException e) {
|
||||
receivePack.sendError("IOException");
|
||||
receiveCommand.setResult(Result.REJECTED_OTHER_REASON, "I/O Exception");
|
||||
} catch (FailedConnectionException e) {
|
||||
receivePack.sendError("failed connection");
|
||||
receiveCommand.setResult(Result.REJECTED_OTHER_REASON, "failed connection");
|
||||
} catch (OutOfDateException e) {
|
||||
receiveCommand.setResult(Result.REJECTED_NONFASTFORWARD);
|
||||
} catch (SnapshotPostException e) {
|
||||
String message = e.getMessage();
|
||||
receivePack.sendError(message);
|
||||
for (String line : e.getDescriptionLines()) {
|
||||
receivePack.sendMessage("hint: " + line);
|
||||
}
|
||||
receiveCommand.setResult(Result.REJECTED_OTHER_REASON, message);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleReceiveCommand(Repository repository, ReceiveCommand receiveCommand) throws IOException, SnapshotPostException, FailedConnectionException {
|
||||
checkBranch(receiveCommand);
|
||||
checkForcedPush(receiveCommand);
|
||||
writeLatexDataSource.putDirectoryContentsToProjectWithName(repository.getWorkTree().getName(),
|
||||
getPushedDirectoryContents(repository,
|
||||
receiveCommand),
|
||||
hostname);
|
||||
}
|
||||
|
||||
private void checkBranch(ReceiveCommand receiveCommand) throws WrongBranchException {
|
||||
if (!receiveCommand.getRefName().equals("refs/heads/master")) {
|
||||
throw new WrongBranchException();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForcedPush(ReceiveCommand receiveCommand) throws ForcedPushException {
|
||||
if (receiveCommand.getType() == ReceiveCommand.Type.UPDATE_NONFASTFORWARD) {
|
||||
throw new ForcedPushException();
|
||||
}
|
||||
}
|
||||
|
||||
private RawDirectoryContents getPushedDirectoryContents(Repository repository, ReceiveCommand receiveCommand) throws IOException {
|
||||
return new RepositoryObjectTreeWalker(repository,
|
||||
receiveCommand.getNewId())
|
||||
.getDirectoryContents();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package uk.ac.ic.wlgitbridge.git.handler.hook.exception;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class ForcedPushException extends SnapshotPostException {
|
||||
|
||||
private static final String[] DESCRIPTION_LINES = {
|
||||
"You can't git push --force to a " + Util.getServiceName() + " project.",
|
||||
"Try to put your changes on top of the current head.",
|
||||
"If everything else fails, delete and reclone your repository, make your changes, then push again."
|
||||
};
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "forced push prohibited";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDescriptionLines() {
|
||||
return Arrays.asList(DESCRIPTION_LINES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package uk.ac.ic.wlgitbridge.git.handler.hook.exception;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 19/12/14.
|
||||
*/
|
||||
public class WrongBranchException extends SnapshotPostException {
|
||||
|
||||
private static final String[] DESCRIPTION_LINES = {
|
||||
"You can't push any new branches.",
|
||||
"Please use the master branch."
|
||||
};
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "wrong branch";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDescriptionLines() {
|
||||
return Arrays.asList(DESCRIPTION_LINES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package uk.ac.ic.wlgitbridge.git.servlet;
|
||||
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jgit.http.server.GitServlet;
|
||||
import uk.ac.ic.wlgitbridge.git.exception.InvalidRootDirectoryPathException;
|
||||
import uk.ac.ic.wlgitbridge.git.handler.WLReceivePackFactory;
|
||||
import uk.ac.ic.wlgitbridge.git.handler.WLRepositoryResolver;
|
||||
import uk.ac.ic.wlgitbridge.git.handler.WLUploadPackFactory;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.SnapshotRepositoryBuilder;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WriteLatexDataSource;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 02/11/14.
|
||||
*/
|
||||
public class WLGitServlet extends GitServlet {
|
||||
|
||||
public WLGitServlet(ServletContextHandler servletContextHandler, WriteLatexDataSource writeLatexDataSource, String rootGitDirectoryPath) throws ServletException, InvalidRootDirectoryPathException {
|
||||
setRepositoryResolver(new WLRepositoryResolver(rootGitDirectoryPath, new SnapshotRepositoryBuilder(writeLatexDataSource)));
|
||||
setReceivePackFactory(new WLReceivePackFactory(writeLatexDataSource));
|
||||
setUploadPackFactory(new WLUploadPackFactory());
|
||||
init(new WLGitServletConfig(servletContextHandler));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package uk.ac.ic.wlgitbridge.git.servlet;
|
||||
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* Created by Winston on 02/11/14.
|
||||
*/
|
||||
public class WLGitServletConfig implements ServletConfig {
|
||||
|
||||
private static final String SERVLET_NAME = "git-servlet";
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
public WLGitServletConfig(ServletContextHandler servletContextHandler) {
|
||||
servletContext = servletContextHandler.getServletContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServletName() {
|
||||
return SERVLET_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitParameter(String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getInitParameterNames() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package uk.ac.ic.wlgitbridge.git.util;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class FileDirectoryContents implements RawDirectoryContents {
|
||||
|
||||
private final Map<String, byte[]> fileContentsTable;
|
||||
|
||||
public FileDirectoryContents(Map<String, byte[]> fileContentsTable) {
|
||||
this.fileContentsTable = fileContentsTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, byte[]> getFileContentsTable() {
|
||||
return fileContentsTable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package uk.ac.ic.wlgitbridge.git.util;
|
||||
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class RepositoryObjectTreeWalker {
|
||||
|
||||
private final TreeWalk treeWalk;
|
||||
private final Repository repository;
|
||||
|
||||
public RepositoryObjectTreeWalker(Repository repository, ObjectId objectId) throws IOException {
|
||||
treeWalk = initTreeWalk(repository, objectId);
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public RawDirectoryContents getDirectoryContents() throws IOException {
|
||||
return new FileDirectoryContents(walkGitObjectTree());
|
||||
}
|
||||
|
||||
private TreeWalk initTreeWalk(Repository repository, ObjectId objectId) throws IOException {
|
||||
RevWalk walk = new RevWalk(repository);
|
||||
TreeWalk treeWalk = new TreeWalk(repository);
|
||||
treeWalk.addTree(walk.parseCommit(objectId).getTree());
|
||||
treeWalk.setRecursive(true);
|
||||
return treeWalk;
|
||||
}
|
||||
|
||||
private Map<String, byte[]> walkGitObjectTree() throws IOException {
|
||||
Map<String, byte[]> fileContentsTable = new HashMap<String, byte[]>();
|
||||
while (treeWalk.next()) {
|
||||
fileContentsTable.put(treeWalk.getPathString(), repository.open(treeWalk.getObjectId(0)).getBytes());
|
||||
}
|
||||
return fileContentsTable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package uk.ac.ic.wlgitbridge.test;
|
||||
|
||||
import org.eclipse.jetty.server.NetworkConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 09/01/15.
|
||||
*/
|
||||
public class SnapshotDummyServer {
|
||||
|
||||
private final Server server;
|
||||
private int port;
|
||||
|
||||
public SnapshotDummyServer() {
|
||||
server = new Server(0);
|
||||
server.setHandler(new AbstractHandler() {
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
response.getWriter().println(target);
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void start() {
|
||||
try {
|
||||
server.start();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
port = ((NetworkConnector) server.getConnectors()[0]).getLocalPort();
|
||||
System.out.println(port);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SnapshotDummyServer().start();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package uk.ac.ic.wlgitbridge.util;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.application.SSLConfig;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 19/11/14.
|
||||
*/
|
||||
public class Util {
|
||||
|
||||
private static String SERVICE_NAME;
|
||||
private static String HOSTNAME;
|
||||
private static SSLConfig SSL_CONFIG;
|
||||
private static int PORT;
|
||||
private static String POSTBACK_URL;
|
||||
|
||||
public static String entries(int entries) {
|
||||
if (entries == 1) {
|
||||
return "entry";
|
||||
} else {
|
||||
return "entries";
|
||||
}
|
||||
}
|
||||
|
||||
public static int booleanToInt(boolean b) {
|
||||
if (b) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean intToBoolean(int i) {
|
||||
return i != 0;
|
||||
}
|
||||
|
||||
private static String removeAllSuffix(String str, String suffix) {
|
||||
int lastIndexOfSuffix;
|
||||
String result = str;
|
||||
while ((lastIndexOfSuffix = result.lastIndexOf(suffix)) > -1) {
|
||||
result = result.substring(0, lastIndexOfSuffix);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* removeAllSuffixes("something.git///", "/", ".git") => "something" */
|
||||
public static String removeAllSuffixes(String str, String... suffixes) {
|
||||
String result = str;
|
||||
for (String suffix : suffixes) {
|
||||
result = removeAllSuffix(result, suffix);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getContentsOfReader(BufferedReader reader) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String line; (line = reader.readLine()) != null; ) {
|
||||
sb.append(line);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void setServiceName(String serviceName) {
|
||||
SERVICE_NAME = serviceName;
|
||||
}
|
||||
|
||||
public static String getServiceName() {
|
||||
return SERVICE_NAME;
|
||||
}
|
||||
|
||||
public static int getPort() {
|
||||
return PORT;
|
||||
}
|
||||
|
||||
public static void setPort(int port) {
|
||||
PORT = port;
|
||||
}
|
||||
|
||||
public static void setPostbackURL(String postbackURL) {
|
||||
POSTBACK_URL = postbackURL;
|
||||
}
|
||||
|
||||
public static String getPostbackURL() {
|
||||
return POSTBACK_URL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Created by Winston on 20/11/14.
|
||||
*/
|
||||
public class ProjectLock {
|
||||
|
||||
private final Map<String, Lock> projectLocks;
|
||||
|
||||
public ProjectLock() {
|
||||
projectLocks = new HashMap<String, Lock>();
|
||||
}
|
||||
|
||||
public void lockForProject(String projectName) {
|
||||
getLockForProjectName(projectName).lock();
|
||||
}
|
||||
|
||||
public void unlockForProject(String projectName) {
|
||||
getLockForProjectName(projectName).unlock();
|
||||
}
|
||||
|
||||
private synchronized Lock getLockForProjectName(String projectName) {
|
||||
Lock lock = projectLocks.get(projectName);
|
||||
if (lock == null) {
|
||||
lock = new ReentrantLock();
|
||||
projectLocks.put(projectName, lock);
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.SnapshotGetDocRequest;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.SnapshotGetDocResult;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotData;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotGetForVersionRequest;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotGetForVersionResult;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers.SnapshotGetSavedVersRequest;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers.SnapshotInfo;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.Snapshot;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreSource;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by Winston on 07/11/14.
|
||||
*/
|
||||
public class SnapshotFetcher implements PersistentStoreSource {
|
||||
|
||||
private PersistentStoreAPI persistentStore;
|
||||
|
||||
private final String projectName;
|
||||
private final Map<Integer, Snapshot> snapshots;
|
||||
private final SortedSet<Integer> versions;
|
||||
|
||||
public SnapshotFetcher(String projectName, Map<Integer, Snapshot> snapshots) {
|
||||
this.projectName = projectName;
|
||||
this.snapshots = snapshots;
|
||||
versions = new TreeSet<Integer>();
|
||||
}
|
||||
|
||||
public SortedSet<Snapshot> fetchNewSnapshots() throws FailedConnectionException, InvalidProjectException {
|
||||
SortedSet<Snapshot> newSnapshots = new TreeSet<Snapshot>();
|
||||
while (getNew(newSnapshots));
|
||||
for (Snapshot snapshot : newSnapshots) {
|
||||
persistentStore.addSnapshot(projectName, snapshot.getVersionID());
|
||||
}
|
||||
System.out.println("Fetched snapshots: " + newSnapshots);
|
||||
return newSnapshots;
|
||||
}
|
||||
|
||||
public Snapshot getLatestSnapshot() {
|
||||
if (versions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return snapshots.get(versions.last());
|
||||
}
|
||||
|
||||
public void putLatestVersion(int versionID) {
|
||||
versions.add(versionID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initFromPersistentStore(PersistentStoreAPI persistentStore) {
|
||||
this.persistentStore = persistentStore;
|
||||
for (Integer savedVersionID : persistentStore.getVersionIDsForProjectName(projectName)) {
|
||||
snapshots.put(savedVersionID, new Snapshot(savedVersionID));
|
||||
versions.add(savedVersionID);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getNew(SortedSet<Snapshot> newSnapshots) throws FailedConnectionException, InvalidProjectException {
|
||||
SnapshotGetDocRequest getDoc = new SnapshotGetDocRequest(projectName);
|
||||
SnapshotGetSavedVersRequest getSavedVers = new SnapshotGetSavedVersRequest(projectName);
|
||||
|
||||
getDoc.request();
|
||||
getSavedVers.request();
|
||||
|
||||
Set<Integer> fetchedIDs = new HashSet<Integer>();
|
||||
Map<Integer, SnapshotInfo> fetchedSnapshotInfos = new HashMap<Integer, SnapshotInfo>();
|
||||
|
||||
int latestVersionID = putLatestDoc(getDoc, fetchedIDs, fetchedSnapshotInfos);
|
||||
|
||||
putSavedVers(getSavedVers, fetchedIDs, fetchedSnapshotInfos);
|
||||
|
||||
List<Integer> idsToUpdate = getIDsToUpdate(fetchedIDs);
|
||||
|
||||
versions.addAll(fetchedIDs);
|
||||
versions.add(latestVersionID);
|
||||
|
||||
return updateIDs(idsToUpdate, fetchedSnapshotInfos, newSnapshots);
|
||||
}
|
||||
|
||||
private void putFetchedResult(SnapshotInfo snapshotInfo, Set<Integer> ids, Map<Integer, SnapshotInfo> snapshotInfos) {
|
||||
int versionID = snapshotInfo.getVersionId();
|
||||
snapshotInfos.put(versionID, snapshotInfo);
|
||||
ids.add(versionID);
|
||||
}
|
||||
|
||||
private int putLatestDoc(SnapshotGetDocRequest getDoc, Set<Integer> fetchedIDs, Map<Integer, SnapshotInfo> fetchedSnapshotInfos) throws FailedConnectionException, InvalidProjectException {
|
||||
SnapshotGetDocResult result = getDoc.getResult();
|
||||
int latestVersionID = result.getVersionID();
|
||||
putFetchedResult(new SnapshotInfo(latestVersionID, result.getCreatedAt(), result.getName(), result.getEmail()), fetchedIDs, fetchedSnapshotInfos);
|
||||
return latestVersionID;
|
||||
}
|
||||
|
||||
private void putSavedVers(SnapshotGetSavedVersRequest getSavedVers, Set<Integer> fetchedIDs, Map<Integer, SnapshotInfo> fetchedSnapshotInfos) throws FailedConnectionException {
|
||||
for (SnapshotInfo snapshotInfo : getSavedVers.getResult().getSavedVers()) {
|
||||
putFetchedResult(snapshotInfo, fetchedIDs, fetchedSnapshotInfos);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Integer> getIDsToUpdate(Set<Integer> fetchedIDs) {
|
||||
List<Integer> idsToUpdate = new LinkedList<Integer>();
|
||||
for (Integer id : fetchedIDs) {
|
||||
if (!versions.contains(id)) {
|
||||
idsToUpdate.add(id);
|
||||
}
|
||||
}
|
||||
return idsToUpdate;
|
||||
}
|
||||
|
||||
private boolean updateIDs(List<Integer> idsToUpdate, Map<Integer, SnapshotInfo> fetchedSnapshotInfos, SortedSet<Snapshot> newSnapshots) throws FailedConnectionException {
|
||||
if (idsToUpdate.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
fetchVersions(idsToUpdate, fetchedSnapshotInfos, newSnapshots);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void fetchVersions(List<Integer> idsToUpdate, Map<Integer, SnapshotInfo> fetchedSnapshotInfos, SortedSet<Snapshot> newSnapshots) throws FailedConnectionException {
|
||||
List<SnapshotGetForVersionRequest> requests = createFiredRequests(idsToUpdate);
|
||||
processResults(fetchedSnapshotInfos, newSnapshots, requests);
|
||||
}
|
||||
|
||||
private List<SnapshotGetForVersionRequest> createFiredRequests(List<Integer> idsToUpdate) {
|
||||
List<SnapshotGetForVersionRequest> requests = new LinkedList<SnapshotGetForVersionRequest>();
|
||||
for (int id : idsToUpdate) {
|
||||
SnapshotGetForVersionRequest request = new SnapshotGetForVersionRequest(projectName, id);
|
||||
requests.add(request);
|
||||
request.request();
|
||||
}
|
||||
return requests;
|
||||
}
|
||||
|
||||
private void processResults(Map<Integer, SnapshotInfo> fetchedSnapshotInfos, SortedSet<Snapshot> newSnapshots, List<SnapshotGetForVersionRequest> requests) throws FailedConnectionException {
|
||||
for (SnapshotGetForVersionRequest request : requests) {
|
||||
processResult(fetchedSnapshotInfos, newSnapshots, request);
|
||||
}
|
||||
}
|
||||
|
||||
private void processResult(Map<Integer, SnapshotInfo> fetchedSnapshotInfos, SortedSet<Snapshot> newSnapshots, SnapshotGetForVersionRequest request) throws FailedConnectionException {
|
||||
SnapshotGetForVersionResult result = request.getResult();
|
||||
SnapshotData data = result.getSnapshotData();
|
||||
Snapshot snapshot = new Snapshot(fetchedSnapshotInfos.get(request.getVersionID()), data);
|
||||
snapshots.put(request.getVersionID(), snapshot);
|
||||
newSnapshots.add(snapshot);
|
||||
}
|
||||
|
||||
public SortedSet<Integer> getVersions() {
|
||||
return versions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex;
|
||||
|
||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
|
||||
import uk.ac.ic.wlgitbridge.bridge.RepositorySource;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WLBridgedProject;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WriteLatexDataSource;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 03/11/14.
|
||||
*/
|
||||
public class SnapshotRepositoryBuilder implements RepositorySource {
|
||||
|
||||
private final WriteLatexDataSource writeLatexDataSource;
|
||||
|
||||
public SnapshotRepositoryBuilder(WriteLatexDataSource writeLatexDataSource) {
|
||||
this.writeLatexDataSource = writeLatexDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Repository getRepositoryWithNameAtRootDirectory(String name, File rootDirectory) throws RepositoryNotFoundException, ServiceNotEnabledException {
|
||||
try {
|
||||
if (!writeLatexDataSource.repositoryExists(name)) {
|
||||
throw new RepositoryNotFoundException(name);
|
||||
}
|
||||
} catch (FailedConnectionException e) {
|
||||
throw new ServiceNotEnabledException();
|
||||
}
|
||||
File repositoryDirectory = new File(rootDirectory, name);
|
||||
|
||||
Repository repository = null;
|
||||
try {
|
||||
repository = new FileRepositoryBuilder().setWorkTree(repositoryDirectory).build();
|
||||
new WLBridgedProject(repository, name, writeLatexDataSource).buildRepository();
|
||||
} catch (FailedConnectionException e) {
|
||||
e.printStackTrace();
|
||||
throw new ServiceNotEnabledException();
|
||||
} catch (IOException e) {
|
||||
throw new ServiceNotEnabledException();
|
||||
}
|
||||
return repository;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.bridge.CandidateSnapshot;
|
||||
import uk.ac.ic.wlgitbridge.bridge.CandidateSnapshotCallback;
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.FileNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.WLDirectoryNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.WLProject;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class WLDirectoryNodeSnapshot implements CandidateSnapshot {
|
||||
|
||||
private final int previousVersionID;
|
||||
private final String projectName;
|
||||
private final String projectURL;
|
||||
private final WLDirectoryNode directoryNode;
|
||||
private final String postbackKey;
|
||||
private final CandidateSnapshotCallback callback;
|
||||
|
||||
public WLDirectoryNodeSnapshot(WLProject project, WLDirectoryNode directoryNode, String hostname, String postbackKey, CandidateSnapshotCallback callback) {
|
||||
previousVersionID = project.getLatestSnapshotID();
|
||||
projectName = project.getName();
|
||||
projectURL = Util.getPostbackURL() + projectName;
|
||||
|
||||
this.directoryNode = directoryNode;
|
||||
this.postbackKey = postbackKey;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement getJsonRepresentation() {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("latestVerId", previousVersionID);
|
||||
jsonObject.add("files", getFilesAsJson());
|
||||
jsonObject.addProperty("postbackUrl", projectURL + "/" + postbackKey + "/postback");
|
||||
System.out.println(jsonObject);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
private JsonArray getFilesAsJson() {
|
||||
JsonArray filesArray = new JsonArray();
|
||||
for (FileNode fileNode : directoryNode.getFileNodes()) {
|
||||
filesArray.add(getFileAsJson(fileNode));
|
||||
}
|
||||
return filesArray;
|
||||
}
|
||||
|
||||
private JsonObject getFileAsJson(FileNode fileNode) {
|
||||
JsonObject file = new JsonObject();
|
||||
file.addProperty("name", fileNode.getFilePath());
|
||||
if (fileNode.isChanged()) {
|
||||
file.addProperty("url", projectURL + "/" + fileNode.getFilePath() + "?key=" + postbackKey);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousVersionID() {
|
||||
return previousVersionID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProjectURL() {
|
||||
return projectURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void approveWithVersionID(int versionID) {
|
||||
callback.approveSnapshot(versionID, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProjectName() {
|
||||
return projectName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WLDirectoryNode getDirectoryNode() {
|
||||
return directoryNode;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.bridge.CandidateSnapshot;
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WritableRepositoryContents;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WriteLatexDataSource;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.SnapshotGetDocRequest;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.InvalidPostbackKeyException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.PostbackManager;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.SnapshotPushRequest;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.SnapshotPushRequestResult;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.UnexpectedPostbackException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.OutOfDateException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.WLDataModel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class WriteLatexAPI implements WriteLatexDataSource {
|
||||
|
||||
private final WLDataModel dataModel;
|
||||
private final PostbackManager postbackManager;
|
||||
private final ProjectLock mainProjectLock;
|
||||
|
||||
public WriteLatexAPI(WLDataModel dataModel) {
|
||||
this.dataModel = dataModel;
|
||||
postbackManager = new PostbackManager();
|
||||
mainProjectLock = new ProjectLock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lockForProject(String projectName) {
|
||||
mainProjectLock.lockForProject(projectName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockForProject(String projectName) {
|
||||
mainProjectLock.unlockForProject(projectName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean repositoryExists(String projectName) throws FailedConnectionException {
|
||||
lockForProject(projectName);
|
||||
SnapshotGetDocRequest snapshotGetDocRequest = new SnapshotGetDocRequest(projectName);
|
||||
snapshotGetDocRequest.request();
|
||||
try {
|
||||
snapshotGetDocRequest.getResult().getVersionID();
|
||||
} catch (InvalidProjectException e) {
|
||||
return false;
|
||||
} catch (FailedConnectionException e) {
|
||||
throw e;
|
||||
} finally {
|
||||
unlockForProject(projectName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WritableRepositoryContents> getWritableRepositories(String projectName) throws FailedConnectionException, InvalidProjectException {
|
||||
System.out.println("Fetching project: " + projectName);
|
||||
List<WritableRepositoryContents> writableRepositoryContents = dataModel.updateProjectWithName(projectName);
|
||||
return writableRepositoryContents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putDirectoryContentsToProjectWithName(String projectName, RawDirectoryContents directoryContents, String hostname) throws SnapshotPostException, IOException, FailedConnectionException {
|
||||
mainProjectLock.lockForProject(projectName);
|
||||
try {
|
||||
System.out.println("Pushing project: " + projectName);
|
||||
String postbackKey = postbackManager.makeKeyForProject(projectName);
|
||||
CandidateSnapshot candidate = dataModel.createCandidateSnapshotFromProjectWithContents(projectName, directoryContents, hostname, postbackKey);
|
||||
SnapshotPushRequest snapshotPushRequest = new SnapshotPushRequest(candidate);
|
||||
snapshotPushRequest.request();
|
||||
SnapshotPushRequestResult result = snapshotPushRequest.getResult();
|
||||
if (result.wasSuccessful()) {
|
||||
candidate.approveWithVersionID(postbackManager.getVersionID(projectName));
|
||||
} else {
|
||||
throw new OutOfDateException();
|
||||
}
|
||||
} catch (SnapshotPostException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (FailedConnectionException e) {
|
||||
throw e;
|
||||
} finally {
|
||||
mainProjectLock.unlockForProject(projectName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkPostbackKey(String projectName, String postbackKey) throws InvalidPostbackKeyException {
|
||||
postbackManager.checkPostbackKey(projectName, postbackKey);
|
||||
}
|
||||
|
||||
/* Called by postback thread. */
|
||||
@Override
|
||||
public void postbackReceivedSuccessfully(String projectName, String postbackKey, int versionID) throws UnexpectedPostbackException {
|
||||
postbackManager.postVersionIDForProject(projectName, versionID, postbackKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postbackReceivedWithException(String projectName, String postbackKey, SnapshotPostException exception) throws UnexpectedPostbackException {
|
||||
postbackManager.postExceptionForProject(projectName, exception, postbackKey);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.base;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public enum HTTPMethod {
|
||||
|
||||
POST,
|
||||
GET
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.base;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public interface JSONSource {
|
||||
|
||||
public abstract void fromJSON(JsonElement json);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.base;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.ning.http.client.AsyncCompletionHandler;
|
||||
import com.ning.http.client.AsyncHttpClient;
|
||||
import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder;
|
||||
import com.ning.http.client.Realm;
|
||||
import com.ning.http.client.Response;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public abstract class Request<T extends Result> {
|
||||
|
||||
private final String url;
|
||||
|
||||
private Future<T> future;
|
||||
private boolean error;
|
||||
|
||||
public Request(String url) {
|
||||
this.url = url;
|
||||
error = false;
|
||||
}
|
||||
|
||||
public void request() {
|
||||
switch (httpMethod()) {
|
||||
case GET:
|
||||
performGetRequest();
|
||||
break;
|
||||
case POST:
|
||||
performPostRequest();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public T getResult() throws FailedConnectionException {
|
||||
if (error) {
|
||||
throw new FailedConnectionException();
|
||||
}
|
||||
try {
|
||||
return future.get();
|
||||
} catch (InterruptedException e) {
|
||||
throw new FailedConnectionException();
|
||||
} catch (ExecutionException e) {
|
||||
throw new FailedConnectionException();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract HTTPMethod httpMethod();
|
||||
protected abstract Realm buildRequestRealm();
|
||||
protected abstract T parseResponse(JsonElement json) throws FailedConnectionException;
|
||||
|
||||
protected String getPostBody() {
|
||||
return "";
|
||||
}
|
||||
|
||||
private void performGetRequest() {
|
||||
request(new AsyncHttpClient().prepareGet(url));
|
||||
}
|
||||
|
||||
private void performPostRequest() {
|
||||
request(new AsyncHttpClient().preparePost(url).setBody(getPostBody()).setHeader("Content-Type", "application/json"));
|
||||
}
|
||||
|
||||
private void request(BoundRequestBuilder boundRequestBuilder) {
|
||||
future = boundRequestBuilder.setRealm(buildRequestRealm()).execute(new AsyncCompletionHandler<T>() {
|
||||
|
||||
@Override
|
||||
public T onCompleted(Response response) throws Exception {
|
||||
System.out.println("Response: " + response.getResponseBody());
|
||||
return parseResponse(new Gson().fromJson(response.getResponseBody(), JsonElement.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onThrowable(Throwable t) {
|
||||
t.printStackTrace();
|
||||
error = true;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.base;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public abstract class Result implements JSONSource {
|
||||
|
||||
private JsonElement json;
|
||||
private final Request request;
|
||||
|
||||
public Result(Request request, JsonElement json) {
|
||||
this.request = request;
|
||||
this.json = json;
|
||||
fromJSON(json);
|
||||
}
|
||||
|
||||
public Request getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return json.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.base;
|
||||
|
||||
import com.ning.http.client.Realm;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public abstract class SnapshotAPIRequest<T extends Result> extends Request<T> {
|
||||
|
||||
private static String USERNAME;
|
||||
private static String PASSWORD;
|
||||
|
||||
private static String BASE_URL;
|
||||
|
||||
public SnapshotAPIRequest(String projectName, String apiCall) {
|
||||
super(BASE_URL + projectName + apiCall);
|
||||
}
|
||||
|
||||
protected Realm buildRequestRealm() {
|
||||
return new Realm.RealmBuilder()
|
||||
.setPrincipal(USERNAME)
|
||||
.setPassword(PASSWORD)
|
||||
.setUsePreemptiveAuth(true)
|
||||
.setScheme(Realm.AuthScheme.BASIC)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static void setBasicAuth(String username, String password) {
|
||||
USERNAME = username;
|
||||
PASSWORD = password;
|
||||
}
|
||||
|
||||
/* baseURL ends with / */
|
||||
public static void setBaseURL(String baseURL) {
|
||||
BASE_URL = baseURL + "/docs/";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.exception;
|
||||
|
||||
/**
|
||||
* Created by Winston on 08/11/14.
|
||||
*/
|
||||
public class FailedConnectionException extends Exception {
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.HTTPMethod;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.SnapshotAPIRequest;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class SnapshotGetDocRequest extends SnapshotAPIRequest<SnapshotGetDocResult> {
|
||||
|
||||
public static final String API_CALL = "";
|
||||
|
||||
public SnapshotGetDocRequest(String projectName) {
|
||||
super(projectName, API_CALL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HTTPMethod httpMethod() {
|
||||
return HTTPMethod.GET;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SnapshotGetDocResult parseResponse(JsonElement json) throws FailedConnectionException {
|
||||
return new SnapshotGetDocResult(this, json);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.Request;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.Result;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class SnapshotGetDocResult extends Result {
|
||||
|
||||
private int versionID;
|
||||
private String createdAt;
|
||||
private String name;
|
||||
private String email;
|
||||
|
||||
private InvalidProjectException invalidProjectException;
|
||||
|
||||
public SnapshotGetDocResult(Request request, JsonElement json) throws FailedConnectionException {
|
||||
super(request, json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
JsonObject jsonObject = json.getAsJsonObject();
|
||||
if (jsonObject.has("status") && jsonObject.get("status").getAsInt() == 404) {
|
||||
invalidProjectException = new InvalidProjectException();
|
||||
} else {
|
||||
versionID = jsonObject.get("latestVerId").getAsInt();
|
||||
createdAt = jsonObject.get("latestVerAt").getAsString();
|
||||
JsonElement latestVerBy = jsonObject.get("latestVerBy");
|
||||
if (latestVerBy.isJsonObject()) {
|
||||
JsonObject userObject = latestVerBy.getAsJsonObject();
|
||||
name = userObject.get("name").getAsString();
|
||||
email = userObject.get("email").getAsString();
|
||||
} else {
|
||||
name = "Anonymous";
|
||||
email = "anonymous@writelatex.com";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getVersionID() throws InvalidProjectException {
|
||||
if (invalidProjectException != null) {
|
||||
throw invalidProjectException;
|
||||
}
|
||||
return versionID;
|
||||
}
|
||||
|
||||
public String getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 08/11/14.
|
||||
*/
|
||||
public class InvalidProjectException extends SnapshotPostException {
|
||||
|
||||
public InvalidProjectException(JsonObject json) {
|
||||
super(json);
|
||||
}
|
||||
|
||||
public InvalidProjectException() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDescriptionLines() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class SnapshotAttachment extends SnapshotFile {
|
||||
|
||||
private String url;
|
||||
|
||||
public SnapshotAttachment(JsonElement json) {
|
||||
super(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getContents() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getContentsFromJSON(JsonArray jsonArray) {
|
||||
url = jsonArray.get(0).getAsString();
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.JSONSource;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class SnapshotData implements JSONSource {
|
||||
|
||||
public static final String JSON_KEY_SRCS = "srcs";
|
||||
public static final String JSON_KEY_ATTS = "atts";
|
||||
|
||||
private List<SnapshotFile> srcs;
|
||||
private List<SnapshotAttachment> atts;
|
||||
|
||||
public SnapshotData(JsonElement json) {
|
||||
srcs = new LinkedList<SnapshotFile>();
|
||||
atts = new LinkedList<SnapshotAttachment>();
|
||||
fromJSON(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
populateSrcs(json.getAsJsonObject().get(JSON_KEY_SRCS).getAsJsonArray());
|
||||
populateAtts(json.getAsJsonObject().get(JSON_KEY_ATTS).getAsJsonArray());
|
||||
}
|
||||
|
||||
private void populateSrcs(JsonArray jsonArray) {
|
||||
for (JsonElement json : jsonArray) {
|
||||
srcs.add(new SnapshotFile(json));
|
||||
}
|
||||
}
|
||||
|
||||
private void populateAtts(JsonArray jsonArray) {
|
||||
for (JsonElement json : jsonArray) {
|
||||
atts.add(new SnapshotAttachment(json));
|
||||
}
|
||||
}
|
||||
|
||||
public List<SnapshotFile> getSrcs() {
|
||||
return srcs;
|
||||
}
|
||||
|
||||
public List<SnapshotAttachment> getAtts() {
|
||||
return atts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawFile;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.JSONSource;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class SnapshotFile implements JSONSource, RawFile {
|
||||
|
||||
protected byte[] contents;
|
||||
private String path;
|
||||
|
||||
public SnapshotFile(JsonElement json) {
|
||||
fromJSON(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getContents() {
|
||||
return contents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
JsonArray jsonArray = json.getAsJsonArray();
|
||||
getContentsFromJSON(jsonArray);
|
||||
getPathFromJSON(jsonArray);
|
||||
}
|
||||
|
||||
protected void getContentsFromJSON(JsonArray jsonArray) {
|
||||
contents = jsonArray.get(0).getAsString().getBytes();
|
||||
}
|
||||
|
||||
protected void getPathFromJSON(JsonArray jsonArray) {
|
||||
path = jsonArray.get(1).getAsString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.HTTPMethod;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.SnapshotAPIRequest;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class SnapshotGetForVersionRequest extends SnapshotAPIRequest<SnapshotGetForVersionResult> {
|
||||
|
||||
public static final String API_CALL = "/snapshots";
|
||||
|
||||
private int versionID;
|
||||
|
||||
public SnapshotGetForVersionRequest(String projectName, int versionID) {
|
||||
super(projectName, API_CALL + "/" + versionID);
|
||||
this.versionID = versionID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HTTPMethod httpMethod() {
|
||||
return HTTPMethod.GET;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SnapshotGetForVersionResult parseResponse(JsonElement json) throws FailedConnectionException {
|
||||
return new SnapshotGetForVersionResult(this, json);
|
||||
}
|
||||
|
||||
public int getVersionID() {
|
||||
return versionID;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.Request;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.Result;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class SnapshotGetForVersionResult extends Result {
|
||||
|
||||
private SnapshotData snapshotData;
|
||||
|
||||
public SnapshotGetForVersionResult(Request request, JsonElement json) {
|
||||
super(request, json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
snapshotData = new SnapshotData(json);
|
||||
}
|
||||
|
||||
public SnapshotData getSnapshotData() {
|
||||
return snapshotData;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.HTTPMethod;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.SnapshotAPIRequest;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class SnapshotGetSavedVersRequest extends SnapshotAPIRequest<SnapshotGetSavedVersResult> {
|
||||
|
||||
public static final String API_CALL = "/saved_vers";
|
||||
|
||||
public SnapshotGetSavedVersRequest(String projectName) {
|
||||
super(projectName, API_CALL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HTTPMethod httpMethod() {
|
||||
return HTTPMethod.GET;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SnapshotGetSavedVersResult parseResponse(JsonElement json) throws FailedConnectionException {
|
||||
return new SnapshotGetSavedVersResult(this, json);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.Request;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.Result;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class SnapshotGetSavedVersResult extends Result {
|
||||
|
||||
private List<SnapshotInfo> savedVers;
|
||||
|
||||
public SnapshotGetSavedVersResult(Request request, JsonElement json) throws FailedConnectionException {
|
||||
super(request, json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
savedVers = new LinkedList<SnapshotInfo>();
|
||||
for (JsonElement elem : json.getAsJsonArray()) {
|
||||
savedVers.add(new Gson().fromJson(elem.getAsJsonObject(), SnapshotInfo.class));
|
||||
}
|
||||
}
|
||||
|
||||
public List<SnapshotInfo> getSavedVers() {
|
||||
return savedVers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class SnapshotInfo {
|
||||
|
||||
private int versionId;
|
||||
private String comment;
|
||||
private WLUser user;
|
||||
private String createdAt;
|
||||
|
||||
public SnapshotInfo(int versionID, String createdAt, String name, String email) {
|
||||
this.versionId = versionID;
|
||||
comment = "Update on " + Util.getServiceName() + ".";
|
||||
user = new WLUser(name, email);
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public int getVersionId() {
|
||||
return versionId;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public WLUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public String getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class WLUser {
|
||||
|
||||
private final String name;
|
||||
private final String email;
|
||||
|
||||
public WLUser() {
|
||||
this("Anonymous", "anonymous@writelatex.com");
|
||||
}
|
||||
|
||||
public WLUser(String name, String email) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.InvalidPostbackKeyException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 17/11/14.
|
||||
*/
|
||||
public class PostbackContents {
|
||||
|
||||
private final String postbackKey;
|
||||
|
||||
private boolean received;
|
||||
private int versionID;
|
||||
private SnapshotPostException exception;
|
||||
|
||||
public PostbackContents(String postbackKey) {
|
||||
this.postbackKey = postbackKey;
|
||||
received = false;
|
||||
exception = null;
|
||||
}
|
||||
|
||||
public synchronized int waitForPostback() throws SnapshotPostException {
|
||||
while (!received) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
return versionID;
|
||||
}
|
||||
|
||||
public synchronized void receivedVersionID(int versionID, String postbackKey) {
|
||||
if (postbackKey.equals(this.postbackKey)) {
|
||||
this.versionID = versionID;
|
||||
received = true;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void receivedException(SnapshotPostException exception, String postbackKey) {
|
||||
if (postbackKey.equals(this.postbackKey)) {
|
||||
this.exception = exception;
|
||||
received = true;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void checkPostbackKey(String postbackKey) throws InvalidPostbackKeyException {
|
||||
if (!postbackKey.equals(this.postbackKey)) {
|
||||
throw new InvalidPostbackKeyException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.InvalidPostbackKeyException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.UnexpectedPostbackException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 17/11/14.
|
||||
*/
|
||||
public class PostbackManager {
|
||||
|
||||
private final SecureRandom random;
|
||||
private final Map<String, PostbackContents> postbackContentsTable;
|
||||
|
||||
public PostbackManager() {
|
||||
random = new SecureRandom();
|
||||
postbackContentsTable = new HashMap<String, PostbackContents>();
|
||||
}
|
||||
|
||||
public int getVersionID(String projectName) throws SnapshotPostException {
|
||||
int versionID = postbackContentsTable.get(projectName).waitForPostback();
|
||||
postbackContentsTable.remove(projectName);
|
||||
return versionID;
|
||||
}
|
||||
|
||||
public void postVersionIDForProject(String projectName, int versionID, String postbackKey) throws UnexpectedPostbackException {
|
||||
getPostbackForProject(projectName).receivedVersionID(versionID, postbackKey);
|
||||
}
|
||||
|
||||
public void postExceptionForProject(String projectName, SnapshotPostException exception, String postbackKey) throws UnexpectedPostbackException {
|
||||
getPostbackForProject(projectName).receivedException(exception, postbackKey);
|
||||
}
|
||||
|
||||
private PostbackContents getPostbackForProject(String projectName) throws UnexpectedPostbackException {
|
||||
PostbackContents contents = postbackContentsTable.remove(projectName);
|
||||
if (contents == null) {
|
||||
throw new UnexpectedPostbackException();
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
|
||||
public String makeKeyForProject(String projectName) {
|
||||
String key = System.currentTimeMillis() + randomString();
|
||||
PostbackContents contents = new PostbackContents(key);
|
||||
postbackContentsTable.put(projectName, contents);
|
||||
return key;
|
||||
}
|
||||
|
||||
public void checkPostbackKey(String projectName, String postbackKey) throws InvalidPostbackKeyException {
|
||||
postbackContentsTable.get(projectName).checkPostbackKey(postbackKey);
|
||||
}
|
||||
|
||||
private String randomString() {
|
||||
return new BigInteger(130, random).toString(32);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.bridge.CandidateSnapshot;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.HTTPMethod;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.SnapshotAPIRequest;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class SnapshotPushRequest extends SnapshotAPIRequest<SnapshotPushRequestResult> {
|
||||
|
||||
private static final String API_CALL = "/snapshots";
|
||||
|
||||
private final CandidateSnapshot candidateSnapshot;
|
||||
|
||||
public SnapshotPushRequest(CandidateSnapshot candidateSnapshot) {
|
||||
super(candidateSnapshot.getProjectName(), API_CALL);
|
||||
this.candidateSnapshot = candidateSnapshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HTTPMethod httpMethod() {
|
||||
return HTTPMethod.POST;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPostBody() {
|
||||
return candidateSnapshot.getJsonRepresentation().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SnapshotPushRequestResult parseResponse(JsonElement json) throws FailedConnectionException {
|
||||
return new SnapshotPushRequestResult(this, json);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.Request;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.Result;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class SnapshotPushRequestResult extends Result {
|
||||
|
||||
private boolean success;
|
||||
|
||||
public SnapshotPushRequestResult(Request request, JsonElement json) throws FailedConnectionException {
|
||||
super(request, json);
|
||||
}
|
||||
|
||||
public boolean wasSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
JsonObject responseObject = json.getAsJsonObject();
|
||||
String code = responseObject.get("code").getAsString();
|
||||
if (code.equals("accepted")) {
|
||||
success = true;
|
||||
} else if (code.equals("outOfDate")) {
|
||||
success = false;
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class InvalidFilesException extends SnapshotPostException {
|
||||
|
||||
private List<String> descriptionLines;
|
||||
|
||||
public InvalidFilesException(JsonObject json) {
|
||||
super(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "invalid files";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDescriptionLines() {
|
||||
return descriptionLines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
descriptionLines = new LinkedList<String>();
|
||||
JsonArray errors = json.getAsJsonObject().get("errors").getAsJsonArray();
|
||||
descriptionLines.add("You have " + errors.size() + " invalid files in your " + Util.getServiceName() + " project:");
|
||||
for (JsonElement error : errors) {
|
||||
descriptionLines.add(describeError(error.getAsJsonObject()));
|
||||
}
|
||||
}
|
||||
|
||||
private String describeError(JsonObject jsonObject) {
|
||||
return jsonObject.get("file").getAsString() + " (" + describeFile(jsonObject) + ")";
|
||||
}
|
||||
|
||||
private String describeFile(JsonObject file) {
|
||||
if (file.has("cleanFile")) {
|
||||
return describeCleanFile(file.get("cleanFile").getAsString());
|
||||
} else {
|
||||
return describeErrorState(file.get("state").getAsString());
|
||||
}
|
||||
}
|
||||
|
||||
private String describeCleanFile(String cleanFile) {
|
||||
return "rename to: " + cleanFile;
|
||||
}
|
||||
|
||||
private String describeErrorState(String state) {
|
||||
if (state.equals("disallowed")) {
|
||||
return "invalid file extension";
|
||||
} else {
|
||||
return "error";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception;
|
||||
|
||||
/**
|
||||
* Created by Winston on 04/12/14.
|
||||
*/
|
||||
public class InvalidPostbackKeyException extends Exception {
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class InvalidProjectException extends SnapshotPostException {
|
||||
|
||||
private LinkedList<String> descriptionLines;
|
||||
|
||||
public InvalidProjectException(JsonElement jsonElement) {
|
||||
super(jsonElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "invalid project";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDescriptionLines() {
|
||||
return descriptionLines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
descriptionLines = new LinkedList<String>();
|
||||
JsonArray errors = json.getAsJsonObject().get("errors").getAsJsonArray();
|
||||
for (JsonElement error : errors) {
|
||||
descriptionLines.add(error.getAsString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class OutOfDateException extends SnapshotPostException {
|
||||
|
||||
public OutOfDateException(JsonObject json) {
|
||||
super(json);
|
||||
}
|
||||
|
||||
public OutOfDateException() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "out of date";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDescriptionLines() {
|
||||
return Arrays.asList("out of date (shouldn't print this)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.JSONSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public abstract class SnapshotPostException extends Exception implements JSONSource {
|
||||
|
||||
public SnapshotPostException() {
|
||||
|
||||
}
|
||||
|
||||
public SnapshotPostException(JsonElement jsonElement) {
|
||||
fromJSON(jsonElement);
|
||||
}
|
||||
|
||||
public abstract String getMessage();
|
||||
public abstract List<String> getDescriptionLines();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 17/11/14.
|
||||
*/
|
||||
public class SnapshotPostExceptionBuilder {
|
||||
|
||||
private static final String CODE_ERROR_OUT_OF_DATE = "outOfDate";
|
||||
private static final String CODE_ERROR_INVALID_FILES = "invalidFiles";
|
||||
private static final String CODE_ERROR_INVALID_PROJECT = "invalidProject";
|
||||
private static final String CODE_ERROR_UNKNOWN = "error";
|
||||
|
||||
public SnapshotPostException build(String errorCode, JsonObject json) throws UnexpectedPostbackException {
|
||||
if (errorCode.equals(CODE_ERROR_OUT_OF_DATE)) {
|
||||
return new OutOfDateException(json);
|
||||
} else if (errorCode.equals(CODE_ERROR_INVALID_FILES)) {
|
||||
return new InvalidFilesException(json);
|
||||
} else if (errorCode.equals(CODE_ERROR_INVALID_PROJECT)) {
|
||||
return new InvalidProjectException(json);
|
||||
} else if (errorCode.equals(CODE_ERROR_UNKNOWN)) {
|
||||
return new UnexpectedErrorException(json);
|
||||
} else {
|
||||
throw new UnexpectedPostbackException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class UnexpectedErrorException extends SnapshotPostException {
|
||||
|
||||
private static final String[] DESCRIPTION_LINES = {
|
||||
"There was an internal error with the " + Util.getServiceName() + " server.",
|
||||
"Please contact " + Util.getServiceName() + "."
|
||||
};
|
||||
|
||||
public UnexpectedErrorException(JsonObject json) {
|
||||
super(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return Util.getServiceName() + " error";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDescriptionLines() {
|
||||
return Arrays.asList(DESCRIPTION_LINES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception;
|
||||
|
||||
/**
|
||||
* Created by Winston on 17/11/14.
|
||||
*/
|
||||
public class UnexpectedPostbackException extends Exception {
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.bridge.WritableRepositoryContents;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.FileNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.WLFileStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.Snapshot;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 14/11/14.
|
||||
*/
|
||||
public class GitDirectoryContents implements WritableRepositoryContents {
|
||||
|
||||
private final List<FileNode> fileNodes;
|
||||
private final File gitDirectory;
|
||||
private final String userName;
|
||||
private final String userEmail;
|
||||
private final String commitMessage;
|
||||
private final Date when;
|
||||
|
||||
public GitDirectoryContents(List<FileNode> fileNodes, File rootGitDirectory, String projectName, Snapshot snapshot) {
|
||||
this.fileNodes = fileNodes;
|
||||
gitDirectory = new File(rootGitDirectory, projectName);
|
||||
userName = snapshot.getUserName();
|
||||
userEmail = snapshot.getUserEmail();
|
||||
commitMessage = snapshot.getComment();
|
||||
when = snapshot.getCreatedAt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write() throws IOException, FailedConnectionException {
|
||||
WLFileStore.deleteInDirectoryApartFrom(gitDirectory, ".git");
|
||||
for (FileNode fileNode : fileNodes) {
|
||||
fileNode.writeToDisk(gitDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDirectory() {
|
||||
return gitDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserEmail() {
|
||||
return userEmail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommitMessage() {
|
||||
return commitMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getWhen() {
|
||||
return when;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawFile;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Created by Winston on 16/11/14.
|
||||
*/
|
||||
public class RepositoryFile implements RawFile {
|
||||
|
||||
private final Entry<String, byte[]> fileContents;
|
||||
|
||||
public RepositoryFile(Entry<String, byte[]> fileContents) {
|
||||
this.fileContents = fileContents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return fileContents.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getContents() {
|
||||
return fileContents.getValue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.blob;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.FileNode;
|
||||
|
||||
/**
|
||||
* Created by Winston on 14/11/14.
|
||||
*/
|
||||
public class AttachmentBlob extends ByteBlob {
|
||||
|
||||
public AttachmentBlob(FileNode fileNode) throws FailedConnectionException {
|
||||
super(fileNode.getContents());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.blob;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.AttachmentNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreUpdater;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by Winston on 14/11/14.
|
||||
*/
|
||||
public abstract class Blob implements PersistentStoreUpdater<AttachmentNode> {
|
||||
|
||||
public abstract byte[] getContents() throws FailedConnectionException;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Blob)) {
|
||||
return false;
|
||||
}
|
||||
Blob that = (Blob) obj;
|
||||
try {
|
||||
return Arrays.equals(getContents(), that.getContents());
|
||||
} catch (FailedConnectionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.blob;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.AttachmentNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
|
||||
|
||||
/**
|
||||
* Created by Winston on 14/11/14.
|
||||
*/
|
||||
public class ByteBlob extends Blob {
|
||||
|
||||
private final byte[] contents;
|
||||
|
||||
public ByteBlob(byte[] contents) {
|
||||
this.contents = contents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getContents() {
|
||||
return contents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePersistentStore(PersistentStoreAPI persistentStore, AttachmentNode node) {
|
||||
persistentStore.addFileNodeBlob(node.getProjectName(), node.getFilePath(), node.isChanged(), contents);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.blob;
|
||||
|
||||
import com.ning.http.client.AsyncCompletionHandler;
|
||||
import com.ning.http.client.AsyncHttpClient;
|
||||
import com.ning.http.client.HttpResponseBodyPart;
|
||||
import com.ning.http.client.Response;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.AttachmentNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Created by Winston on 14/11/14.
|
||||
*/
|
||||
public class ExternalBlob extends Blob {
|
||||
|
||||
private Future<byte[]> future;
|
||||
|
||||
public ExternalBlob(String url) throws FailedConnectionException {
|
||||
super();
|
||||
fetchContents(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getContents() throws FailedConnectionException {
|
||||
try {
|
||||
return future.get();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new FailedConnectionException();
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchContents(String url) throws FailedConnectionException {
|
||||
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
|
||||
future = asyncHttpClient.prepareGet(url).execute(new AsyncCompletionHandler<byte[]>() {
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
@Override
|
||||
public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
|
||||
bytes.write(bodyPart.getBodyPartBytes());
|
||||
return STATE.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] onCompleted(Response response) throws Exception {
|
||||
return bytes.toByteArray();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePersistentStore(PersistentStoreAPI persistentStore, AttachmentNode node) {
|
||||
persistentStore.addFileNodeExternal(node.getProjectName(), node.getFilePath(), node.isChanged(), node.getURL());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.blob;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawFile;
|
||||
|
||||
/**
|
||||
* Created by Winston on 14/11/14.
|
||||
*/
|
||||
public class RawFileBlob extends ByteBlob {
|
||||
|
||||
public RawFileBlob(RawFile rawFile) {
|
||||
super(rawFile.getContents());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.node;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotAttachment;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.blob.AttachmentBlob;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.blob.Blob;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.blob.ByteBlob;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.blob.ExternalBlob;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.FileIndexStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 12/11/14.
|
||||
*/
|
||||
public class AttachmentNode extends FileNode {
|
||||
|
||||
private String projectName;
|
||||
|
||||
private final String url;
|
||||
private Blob blob;
|
||||
|
||||
public AttachmentNode(SnapshotAttachment snapshotAttachment, Map<String, FileNode> context, FileIndexStore fileIndexes) throws FailedConnectionException {
|
||||
super(snapshotAttachment, context);
|
||||
url = snapshotAttachment.getUrl();
|
||||
initBlob(fileIndexes);
|
||||
}
|
||||
|
||||
public AttachmentNode(String filePath, boolean changed, String url, FileIndexStore fileIndexStore) {
|
||||
super(filePath, changed);
|
||||
this.url = url;
|
||||
try {
|
||||
initBlob(fileIndexStore);
|
||||
} catch (FailedConnectionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public AttachmentNode(String url, byte[] blob) {
|
||||
super();
|
||||
this.url = url;
|
||||
this.blob = new ByteBlob(blob);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void indexWith(FileNodeIndexer fileNodeIndexer) {
|
||||
fileNodeIndexer.index(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blob getBlob() {
|
||||
return blob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePersistentStore(PersistentStoreAPI persistentStore, String projectName) {
|
||||
this.projectName = projectName;
|
||||
getBlob().updatePersistentStore(persistentStore, this);
|
||||
}
|
||||
|
||||
public String getURL() {
|
||||
return url;
|
||||
}
|
||||
|
||||
private void initBlob(FileIndexStore fileIndexes) throws FailedConnectionException {
|
||||
if (fileIndexes.hasAttachmentWithURL(url)) {
|
||||
FileNode attachment = fileIndexes.getAttachment(url);
|
||||
blob = new AttachmentBlob(attachment);
|
||||
} else {
|
||||
blob = new ExternalBlob(url);
|
||||
}
|
||||
}
|
||||
|
||||
public String getProjectName() {
|
||||
return projectName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.node;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawFile;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.RepositoryFile;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.blob.Blob;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.blob.ByteBlob;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.blob.RawFileBlob;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 12/11/14.
|
||||
*/
|
||||
public class BlobNode extends FileNode {
|
||||
|
||||
private ByteBlob blob;
|
||||
|
||||
public BlobNode(RawFile rawFile, Map<String, FileNode> context) {
|
||||
super(rawFile, context);
|
||||
blob = new RawFileBlob(rawFile);
|
||||
}
|
||||
|
||||
public BlobNode(RepositoryFile repositoryFile, Map<String, FileNode> fileNodeTable, File projectAttDirectory) throws IOException, FailedConnectionException {
|
||||
this(repositoryFile, fileNodeTable);
|
||||
blob = new RawFileBlob(repositoryFile);
|
||||
writeChanged(projectAttDirectory);
|
||||
}
|
||||
|
||||
public BlobNode(String fileName, boolean changed, byte[] blob) {
|
||||
super(fileName, changed);
|
||||
this.blob = new ByteBlob(blob);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void indexWith(FileNodeIndexer fileNodeIndexer) {
|
||||
fileNodeIndexer.index(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Blob getBlob() {
|
||||
return blob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePersistentStore(PersistentStoreAPI persistentStore, String projectName) {
|
||||
try {
|
||||
persistentStore.addFileNodeBlob(projectName, getFilePath(), isChanged(), getBlob().getContents());
|
||||
} catch (FailedConnectionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeChanged(File projectAttDirectory) throws FailedConnectionException, IOException {
|
||||
if (isChanged()) {
|
||||
writeToDisk(projectAttDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.node;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawFile;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.blob.Blob;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreUpdater;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 12/11/14.
|
||||
*/
|
||||
public abstract class FileNode implements PersistentStoreUpdater<String> {
|
||||
|
||||
private final String filePath;
|
||||
private FileNode previous;
|
||||
private boolean changed;
|
||||
|
||||
public FileNode(RawFile file, Map<String, FileNode> context) {
|
||||
this(file.getPath(), context);
|
||||
}
|
||||
|
||||
public FileNode(String filePath, Map<String, FileNode> context) {
|
||||
previous = context.get(filePath);
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
protected FileNode(String filePath, boolean changed) {
|
||||
this.filePath = filePath;
|
||||
this.changed = changed;
|
||||
}
|
||||
|
||||
protected FileNode() {
|
||||
filePath = "";
|
||||
previous = null;
|
||||
changed = false;
|
||||
}
|
||||
|
||||
public byte[] getContents() throws FailedConnectionException {
|
||||
return getBlob().getContents();
|
||||
}
|
||||
|
||||
public void writeToDisk(File directory) throws FailedConnectionException, IOException {
|
||||
File file = new File(directory, filePath);
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
out.write(getContents());
|
||||
out.close();
|
||||
}
|
||||
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public boolean isChanged() {
|
||||
return changed || previous == null || !equals(previous);
|
||||
}
|
||||
|
||||
public abstract void indexWith(FileNodeIndexer indexer);
|
||||
protected abstract Blob getBlob();
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof FileNode)) {
|
||||
return false;
|
||||
}
|
||||
FileNode that = (FileNode) obj;
|
||||
return filePath.equals(that.filePath) && getBlob().equals(that.getBlob());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.node;
|
||||
|
||||
/**
|
||||
* Created by Winston on 14/11/14.
|
||||
*/
|
||||
public interface FileNodeIndexer {
|
||||
|
||||
public void index(BlobNode blobNode);
|
||||
public void index(AttachmentNode attachmentNode);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.node;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotAttachment;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotFile;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.RepositoryFile;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.FileIndexStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.WLFileStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.Snapshot;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreSource;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreUpdater;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Created by Winston on 08/11/14.
|
||||
*/
|
||||
public class WLDirectoryNode implements PersistentStoreSource, PersistentStoreUpdater<Void> {
|
||||
|
||||
private final String projectName;
|
||||
private Map<String, FileNode> fileNodeTable;
|
||||
private FileIndexStore fileIndexStore;
|
||||
|
||||
public WLDirectoryNode(String projectName, File attsDirectory, File rootGitDirectory, PersistentStoreAPI persistentStore) {
|
||||
this(projectName, attsDirectory, rootGitDirectory);
|
||||
initFromPersistentStore(persistentStore);
|
||||
}
|
||||
|
||||
private WLDirectoryNode(String projectName, File attsDirectory, File rootGitDirectory) {
|
||||
this.projectName = projectName;
|
||||
new File(attsDirectory, projectName).mkdirs();
|
||||
new File(rootGitDirectory, projectName).mkdirs();
|
||||
}
|
||||
|
||||
private WLDirectoryNode(String projectName, Map<String, FileNode> fileNodeTable, FileIndexStore fileIndexStore) {
|
||||
this.projectName = projectName;
|
||||
this.fileNodeTable = fileNodeTable;
|
||||
this.fileIndexStore = fileIndexStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initFromPersistentStore(PersistentStoreAPI persistentStore) {
|
||||
fileIndexStore = new FileIndexStore(projectName, persistentStore);
|
||||
fileNodeTable = new HashMap<String, FileNode>();
|
||||
for (FileNode fileNode : persistentStore.getFileNodesForProjectName(projectName, fileIndexStore)) {
|
||||
fileNodeTable.put(fileNode.getFilePath(), fileNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePersistentStore(PersistentStoreAPI persistentStore, Void info) {
|
||||
updateFileNodeTableInPersistentStore(persistentStore);
|
||||
fileIndexStore.updatePersistentStore(persistentStore, projectName);
|
||||
}
|
||||
|
||||
private void updateFileNodeTableInPersistentStore(PersistentStoreAPI persistentStore) {
|
||||
persistentStore.deleteFileNodesForProjectName(projectName);
|
||||
for (FileNode fileNode : fileNodeTable.values()) {
|
||||
fileNode.updatePersistentStore(persistentStore, projectName);
|
||||
}
|
||||
}
|
||||
|
||||
public List<FileNode> getFileNodes() {
|
||||
return new LinkedList<FileNode>(fileNodeTable.values());
|
||||
}
|
||||
|
||||
public List<FileNode> updateFromSnapshot(Snapshot snapshot) throws FailedConnectionException {
|
||||
Map<String, FileNode> updatedFileNodeTable = new HashMap<String, FileNode>();
|
||||
List<SnapshotFile> srcs = snapshot.getSrcs();
|
||||
List<SnapshotAttachment> atts = snapshot.getAtts();
|
||||
for (SnapshotFile src : srcs) {
|
||||
BlobNode blobNode = new BlobNode(src, fileNodeTable);
|
||||
updatedFileNodeTable.put(blobNode.getFilePath(), blobNode);
|
||||
}
|
||||
for (SnapshotAttachment att : atts) {
|
||||
AttachmentNode attachmentNode = new AttachmentNode(att, fileNodeTable, fileIndexStore);
|
||||
updatedFileNodeTable.put(attachmentNode.getFilePath(), attachmentNode);
|
||||
}
|
||||
LinkedList<FileNode> fileNodes = new LinkedList<FileNode>(updatedFileNodeTable.values());
|
||||
fileNodeTable = updatedFileNodeTable;
|
||||
fileIndexStore = new FileIndexStore(fileNodes);
|
||||
return fileNodes;
|
||||
}
|
||||
|
||||
public WLDirectoryNode createFromRawDirectoryContents(RawDirectoryContents rawDirectoryContents, File attachmentDirectory) throws IOException, FailedConnectionException {
|
||||
Map<String, FileNode> candidateFileNodeTable = new HashMap<String, FileNode>();
|
||||
File projectAttDirectory = new File(attachmentDirectory, projectName);
|
||||
projectAttDirectory.mkdirs();
|
||||
WLFileStore.deleteInDirectory(projectAttDirectory);
|
||||
for (Entry<String, byte[]> fileContents : rawDirectoryContents.getFileContentsTable().entrySet()) {
|
||||
BlobNode blobNode = new BlobNode(new RepositoryFile(fileContents), fileNodeTable, projectAttDirectory);
|
||||
candidateFileNodeTable.put(blobNode.getFilePath(), blobNode);
|
||||
}
|
||||
return new WLDirectoryNode(projectName, candidateFileNodeTable,
|
||||
new FileIndexStore(new LinkedList<FileNode>(candidateFileNodeTable.values())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return fileNodeTable.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.store;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Created by Winston on 08/11/14.
|
||||
*/
|
||||
public class BlobHash {
|
||||
|
||||
private byte[] hash;
|
||||
|
||||
public BlobHash(byte[] blob) {
|
||||
MessageDigest md = null;
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA-256");
|
||||
hash = md.digest(blob);
|
||||
System.out.println(Arrays.toString(hash));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof BlobHash && Arrays.equals(((BlobHash) obj).hash, hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(hash);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.store;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.AttachmentNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.BlobNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.FileNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.FileNodeIndexer;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreSource;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreUpdater;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Created by Winston on 08/11/14.
|
||||
*/
|
||||
public class FileIndexStore implements FileNodeIndexer, PersistentStoreSource, PersistentStoreUpdater<String> {
|
||||
|
||||
private final Map<BlobHash, FileNode> blobHashMappings;
|
||||
private Map<String, FileNode> urlMappings;
|
||||
|
||||
private String projectName;
|
||||
|
||||
public FileIndexStore(List<FileNode> fileNodes) {
|
||||
blobHashMappings = new HashMap<BlobHash, FileNode>();
|
||||
urlMappings = new HashMap<String, FileNode>();
|
||||
for (FileNode fileNode : fileNodes) {
|
||||
fileNode.indexWith(this);
|
||||
}
|
||||
}
|
||||
|
||||
public FileIndexStore(String projectName, PersistentStoreAPI persistentStore) {
|
||||
this.projectName = projectName;
|
||||
blobHashMappings = new HashMap<BlobHash, FileNode>();
|
||||
initFromPersistentStore(persistentStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void index(BlobNode blobNode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void index(AttachmentNode attachmentNode) {
|
||||
urlMappings.put(attachmentNode.getURL(), attachmentNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initFromPersistentStore(PersistentStoreAPI persistentStore) {
|
||||
urlMappings = persistentStore.getURLIndexTableForProjectName(projectName);
|
||||
}
|
||||
|
||||
public boolean hasAttachmentWithURL(String url) {
|
||||
return urlMappings.containsKey(url);
|
||||
}
|
||||
|
||||
public FileNode getAttachment(String url) {
|
||||
return urlMappings.get(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePersistentStore(PersistentStoreAPI persistentStore, String projectName) {
|
||||
persistentStore.deleteURLIndexesForProjectName(projectName);
|
||||
for (Entry<String, FileNode> urlMapping : urlMappings.entrySet()) {
|
||||
try {
|
||||
persistentStore.addURLIndex(projectName, urlMapping.getKey(), urlMapping.getValue().getContents());
|
||||
} catch (FailedConnectionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*Winston is really cool
|
||||
and he's a cat
|
||||
meow
|
||||
miaow
|
||||
meaaaoowww
|
||||
=^.^=
|
||||
*/
|
||||
@@ -0,0 +1,101 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.filestore.store;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.bridge.CandidateSnapshot;
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WritableRepositoryContents;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.GitDirectoryContents;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.WLDirectoryNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.Snapshot;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.WLProject;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreSource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by Winston on 08/11/14.
|
||||
*/
|
||||
public class WLFileStore implements PersistentStoreSource {
|
||||
|
||||
private final Map<String, WLDirectoryNode> fileStore;
|
||||
private final File rootGitDirectory;
|
||||
private final File attDirectory;
|
||||
|
||||
private PersistentStoreAPI persistentStore;
|
||||
|
||||
public WLFileStore(File rootGitDirectory) {
|
||||
fileStore = new HashMap<String, WLDirectoryNode>();
|
||||
this.rootGitDirectory = rootGitDirectory;
|
||||
attDirectory = new File(rootGitDirectory, ".wlgb/atts");
|
||||
attDirectory.mkdirs();
|
||||
}
|
||||
|
||||
public WLFileStore(File rootGitDirectory, PersistentStoreAPI persistentStoreAPI) {
|
||||
this(rootGitDirectory);
|
||||
initFromPersistentStore(persistentStoreAPI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initFromPersistentStore(PersistentStoreAPI persistentStore) {
|
||||
this.persistentStore = persistentStore;
|
||||
for (String projectName : persistentStore.getProjectNames()) {
|
||||
fileStore.put(projectName, new WLDirectoryNode(projectName, attDirectory, rootGitDirectory, persistentStore));
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteInDirectory(File directory) {
|
||||
deleteInDirectoryApartFrom(directory);
|
||||
}
|
||||
|
||||
public static void deleteInDirectoryApartFrom(File directory, String... apartFrom) {
|
||||
Set<String> excluded = new HashSet<String>(Arrays.asList(apartFrom));
|
||||
for (File file : directory.listFiles()) {
|
||||
if (!excluded.contains(file.getName())) {
|
||||
if (file.isDirectory()) {
|
||||
deleteInDirectory(file);
|
||||
}
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<WritableRepositoryContents> updateForProject(WLProject project) throws FailedConnectionException,
|
||||
InvalidProjectException {
|
||||
SortedSet<Snapshot> snapshots = project.fetchNewSnapshots();
|
||||
String projectName = project.getName();
|
||||
WLDirectoryNode directoryNode = getDirectoryNodeForProjectName(projectName);
|
||||
List<WritableRepositoryContents> writableRepositories = new LinkedList<WritableRepositoryContents>();
|
||||
for (Snapshot snapshot : snapshots) {
|
||||
writableRepositories.add(new GitDirectoryContents(directoryNode.updateFromSnapshot(snapshot),
|
||||
rootGitDirectory,
|
||||
projectName,
|
||||
snapshot));
|
||||
}
|
||||
directoryNode.updatePersistentStore(persistentStore, null);
|
||||
return writableRepositories;
|
||||
}
|
||||
|
||||
public WLDirectoryNode createNextDirectoryNodeInProjectFromContents(WLProject project, RawDirectoryContents directoryContents) throws IOException, FailedConnectionException {
|
||||
return getDirectoryNodeForProjectName(project.getName()).createFromRawDirectoryContents(directoryContents, attDirectory);
|
||||
}
|
||||
|
||||
public void approveCandidateSnapshot(CandidateSnapshot candidateSnapshot) {
|
||||
WLDirectoryNode directoryNode = candidateSnapshot.getDirectoryNode();
|
||||
fileStore.put(candidateSnapshot.getProjectName(), directoryNode);
|
||||
directoryNode.updatePersistentStore(persistentStore, null);
|
||||
}
|
||||
|
||||
private WLDirectoryNode getDirectoryNodeForProjectName(String projectName) {
|
||||
WLDirectoryNode directoryNode = fileStore.get(projectName);
|
||||
if (directoryNode == null) {
|
||||
directoryNode = new WLDirectoryNode(projectName, attDirectory, rootGitDirectory, persistentStore);
|
||||
fileStore.put(projectName, directoryNode);
|
||||
}
|
||||
return directoryNode;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public interface JSONModel {
|
||||
|
||||
public void updateFromJSON(JsonElement json);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotAttachment;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotData;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotFile;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers.SnapshotInfo;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers.WLUser;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by Winston on 03/11/14.
|
||||
*/
|
||||
public class Snapshot implements Comparable<Snapshot> {
|
||||
|
||||
private final int versionID;
|
||||
private final String comment;
|
||||
private final String userName;
|
||||
private final String userEmail;
|
||||
private final Date createdAt;
|
||||
|
||||
private final List<SnapshotFile> srcs;
|
||||
private final List<SnapshotAttachment> atts;
|
||||
|
||||
public Snapshot(SnapshotInfo info, SnapshotData data) {
|
||||
versionID = info.getVersionId();
|
||||
comment = info.getComment();
|
||||
WLUser user = info.getUser();
|
||||
userName = user.getName();
|
||||
userEmail = user.getEmail();
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
Calendar cal = Calendar.getInstance(tz);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
sdf.setCalendar(cal);
|
||||
try {
|
||||
cal.setTime(sdf.parse(info.getCreatedAt()));
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
createdAt = cal.getTime();
|
||||
|
||||
srcs = data.getSrcs();
|
||||
atts = data.getAtts();
|
||||
}
|
||||
|
||||
public Snapshot(int versionID) {
|
||||
this.versionID = versionID;
|
||||
comment = "Most recent update";
|
||||
userName = "Anonymous";
|
||||
userEmail = "anonymous@" + Util.getServiceName() + ".com";
|
||||
createdAt = new Date();
|
||||
|
||||
srcs = new LinkedList<SnapshotFile>();
|
||||
atts = new LinkedList<SnapshotAttachment>();
|
||||
}
|
||||
|
||||
public int getVersionID() {
|
||||
return versionID;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public String getUserEmail() {
|
||||
return userEmail;
|
||||
}
|
||||
|
||||
public List<SnapshotFile> getSrcs() {
|
||||
return srcs;
|
||||
}
|
||||
|
||||
public List<SnapshotAttachment> getAtts() {
|
||||
return atts;
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Snapshot snapshot) {
|
||||
return Integer.compare(versionID, snapshot.versionID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(versionID);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.bridge.CandidateSnapshot;
|
||||
import uk.ac.ic.wlgitbridge.bridge.CandidateSnapshotCallback;
|
||||
import uk.ac.ic.wlgitbridge.bridge.RawDirectoryContents;
|
||||
import uk.ac.ic.wlgitbridge.bridge.WritableRepositoryContents;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.WLDirectoryNodeSnapshot;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.WLFileStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.WLGBPersistentStore;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class WLDataModel implements CandidateSnapshotCallback {
|
||||
|
||||
private final PersistentStoreAPI persistentStore;
|
||||
private final WLProjectStore projectStore;
|
||||
private final WLFileStore fileStore;
|
||||
|
||||
public WLDataModel(String rootGitDirectoryPath) {
|
||||
File rootGitDirectory = initRootGitDirectory(rootGitDirectoryPath);
|
||||
persistentStore = new WLGBPersistentStore(rootGitDirectory);
|
||||
projectStore = persistentStore.loadProjectStore();
|
||||
System.out.println("Loaded projects: " + projectStore.getProjectNames().size() + ".");
|
||||
fileStore = persistentStore.loadFileStore();
|
||||
System.out.println("Loaded file store and index tables.");
|
||||
List<String> excludedFromDeletion = projectStore.getProjectNames();
|
||||
excludedFromDeletion.add(".wlgb");
|
||||
WLFileStore.deleteInDirectoryApartFrom(rootGitDirectory, excludedFromDeletion.toArray(new String[] {}));
|
||||
}
|
||||
|
||||
public List<WritableRepositoryContents> updateProjectWithName(String name) throws FailedConnectionException, InvalidProjectException {
|
||||
return fileStore.updateForProject(getProjectWithName(name));
|
||||
}
|
||||
|
||||
public WLProject getProjectWithName(String name) {
|
||||
return projectStore.getProjectWithName(name);
|
||||
}
|
||||
|
||||
public CandidateSnapshot createCandidateSnapshotFromProjectWithContents(String projectName, RawDirectoryContents directoryContents, String hostname, String postbackKey) throws SnapshotPostException, IOException, FailedConnectionException {
|
||||
return new WLDirectoryNodeSnapshot(getProjectWithName(projectName),
|
||||
fileStore.createNextDirectoryNodeInProjectFromContents(getProjectWithName(projectName),
|
||||
directoryContents),
|
||||
hostname,
|
||||
postbackKey,
|
||||
this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void approveSnapshot(int versionID, CandidateSnapshot candidateSnapshot) {
|
||||
getProjectWithName(candidateSnapshot.getProjectName()).putLatestSnapshot(versionID);
|
||||
fileStore.approveCandidateSnapshot(candidateSnapshot);
|
||||
}
|
||||
|
||||
private File initRootGitDirectory(String rootGitDirectoryPath) {
|
||||
File rootGitDirectory = new File(rootGitDirectoryPath);
|
||||
rootGitDirectory.mkdirs();
|
||||
return rootGitDirectory;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.SnapshotFetcher;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreSource;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
|
||||
/**
|
||||
* Created by Winston on 06/11/14.
|
||||
*/
|
||||
public class WLProject implements PersistentStoreSource {
|
||||
|
||||
public static final int INVALID_VERSION_ID = -1;
|
||||
private final String name;
|
||||
private final Map<Integer, Snapshot> snapshots;
|
||||
private final SnapshotFetcher snapshotFetcher;
|
||||
|
||||
private int latestSnapshotID;
|
||||
private PersistentStoreAPI persistentStore;
|
||||
|
||||
public WLProject(String name) {
|
||||
this.name = name;
|
||||
snapshots = new HashMap<Integer, Snapshot>();
|
||||
snapshotFetcher = new SnapshotFetcher(name, snapshots);
|
||||
}
|
||||
|
||||
public WLProject(String projectName, PersistentStoreAPI database) {
|
||||
this(projectName);
|
||||
initFromPersistentStore(database);
|
||||
}
|
||||
|
||||
public SortedSet<Snapshot> fetchNewSnapshots() throws FailedConnectionException, InvalidProjectException {
|
||||
SortedSet<Snapshot> newSnapshots = snapshotFetcher.fetchNewSnapshots();
|
||||
updateLatestSnapshot();
|
||||
return newSnapshots;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getLatestSnapshotID() {
|
||||
return latestSnapshotID;
|
||||
}
|
||||
|
||||
private void updateLatestSnapshot() {
|
||||
Snapshot latest = snapshotFetcher.getLatestSnapshot();
|
||||
if (latest == null) {
|
||||
latestSnapshotID = INVALID_VERSION_ID;
|
||||
} else {
|
||||
latestSnapshotID = latest.getVersionID();
|
||||
}
|
||||
}
|
||||
|
||||
public void putLatestSnapshot(int versionID) {
|
||||
snapshots.put(versionID, new Snapshot(versionID));
|
||||
snapshotFetcher.putLatestVersion(versionID);
|
||||
latestSnapshotID = versionID;
|
||||
persistentStore.addSnapshot(name, versionID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initFromPersistentStore(PersistentStoreAPI persistentStore) {
|
||||
this.persistentStore = persistentStore;
|
||||
snapshotFetcher.initFromPersistentStore(persistentStore);
|
||||
updateLatestSnapshot();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreAPI;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.PersistentStoreSource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 17/11/14.
|
||||
*/
|
||||
public class WLProjectStore implements PersistentStoreSource {
|
||||
|
||||
private PersistentStoreAPI persistentStore;
|
||||
private final Map<String, WLProject> projects;
|
||||
|
||||
public WLProjectStore() {
|
||||
projects = new HashMap<String, WLProject>();
|
||||
}
|
||||
|
||||
public WLProjectStore(PersistentStoreAPI persistentStore) {
|
||||
this();
|
||||
initFromPersistentStore(persistentStore);
|
||||
}
|
||||
|
||||
public WLProject getProjectWithName(String name) {
|
||||
WLProject project;
|
||||
if (projects.containsKey(name)) {
|
||||
project = projects.get(name);
|
||||
} else {
|
||||
project = new WLProject(name, persistentStore);
|
||||
projects.put(name, project);
|
||||
persistentStore.addProject(name);
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
public List<String> getProjectNames() {
|
||||
return new ArrayList<String>(projects.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initFromPersistentStore(PersistentStoreAPI persistentStore) {
|
||||
this.persistentStore = persistentStore;
|
||||
for (String projectName : persistentStore.getProjectNames()) {
|
||||
projects.put(projectName, new WLProject(projectName, persistentStore));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.FileNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.FileIndexStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.WLFileStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.WLProjectStore;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 17/11/14.
|
||||
*/
|
||||
public interface PersistentStoreAPI {
|
||||
|
||||
public WLProjectStore loadProjectStore();
|
||||
public WLFileStore loadFileStore();
|
||||
|
||||
public void addProject(String name);
|
||||
public void addSnapshot(String projectName, int versionID);
|
||||
public void addFileNodeBlob(String projectName, String fileName, boolean changed, byte[] blob);
|
||||
public void addFileNodeExternal(String projectName, String fileName, boolean changed, String url);
|
||||
public void addURLIndex(String projectName, String url, byte[] blob);
|
||||
|
||||
public List<String> getProjectNames();
|
||||
public List<Integer> getVersionIDsForProjectName(String projectName);
|
||||
public List<FileNode> getFileNodesForProjectName(String projectName, FileIndexStore fileIndexStore);
|
||||
public Map<String, FileNode> getURLIndexTableForProjectName(String projectName);
|
||||
|
||||
public void deleteFileNodesForProjectName(String projectName);
|
||||
public void deleteURLIndexesForProjectName(String projectName);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db;
|
||||
|
||||
/**
|
||||
* Created by Winston on 19/11/14.
|
||||
*/
|
||||
public interface PersistentStoreSource {
|
||||
|
||||
public void initFromPersistentStore(PersistentStoreAPI persistentStore);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db;
|
||||
|
||||
/**
|
||||
* Created by Winston on 19/11/14.
|
||||
*/
|
||||
public interface PersistentStoreUpdater<T> {
|
||||
|
||||
public void updatePersistentStore(PersistentStoreAPI persistentStore, T info);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.FileNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.FileIndexStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.WLFileStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.WLProjectStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.SQLiteWLDatabase;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 19/11/14.
|
||||
*/
|
||||
public class WLGBPersistentStore implements PersistentStoreAPI {
|
||||
|
||||
private final File rootGitDirectory;
|
||||
private final SQLiteWLDatabase database;
|
||||
|
||||
public WLGBPersistentStore(File rootGitDirectory) {
|
||||
this.rootGitDirectory = rootGitDirectory;
|
||||
try {
|
||||
database = new SQLiteWLDatabase(rootGitDirectory);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WLProjectStore loadProjectStore() {
|
||||
return new WLProjectStore(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WLFileStore loadFileStore() {
|
||||
return new WLFileStore(rootGitDirectory, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addProject(String name) {
|
||||
try {
|
||||
database.addProject(name);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSnapshot(String projectName, int versionID) {
|
||||
try {
|
||||
database.addSnapshot(projectName, versionID);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFileNodeBlob(String projectName, String fileName, boolean changed, byte[] blob) {
|
||||
try {
|
||||
database.addFileNodeBlob(projectName, fileName, Util.booleanToInt(changed), blob);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFileNodeExternal(String projectName, String fileName, boolean changed, String url) {
|
||||
try {
|
||||
database.addFileNodeExternal(projectName, fileName, Util.booleanToInt(changed), url);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURLIndex(String projectName, String url, byte[] blob) {
|
||||
try {
|
||||
database.addURLIndex(projectName, url, blob);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getProjectNames() {
|
||||
try {
|
||||
return database.getProjectNames();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> getVersionIDsForProjectName(String projectName) {
|
||||
try {
|
||||
return database.getVersionIDsForProjectName(projectName);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileNode> getFileNodesForProjectName(String projectName, FileIndexStore fileIndexStore) {
|
||||
try {
|
||||
return database.getFileNodesForProjectName(projectName, fileIndexStore);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, FileNode> getURLIndexTableForProjectName(String projectName) {
|
||||
try {
|
||||
return database.getURLIndexTableForProjectName(projectName);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteFileNodesForProjectName(String projectName) {
|
||||
try {
|
||||
database.deleteFileNodesForProjectName(projectName);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteURLIndexesForProjectName(String projectName) {
|
||||
try {
|
||||
database.deleteURLIndexesForProjectName(projectName);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db.sql;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 20/11/14.
|
||||
*/
|
||||
public interface SQLQuery<T> extends SQLUpdate {
|
||||
|
||||
public T processResultSet(ResultSet resultSet) throws SQLException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db.sql;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 20/11/14.
|
||||
*/
|
||||
public interface SQLUpdate {
|
||||
|
||||
public String getSQL();
|
||||
public void addParametersToStatement(PreparedStatement statement) throws SQLException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db.sql;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.FileNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.FileIndexStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.query.GetFileNodesForProjectNameSQLQuery;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.query.GetProjectNamesSQLQuery;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.query.GetURLIndexTableForProjectNameSQLQuery;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.query.GetVersionIDsForProjectNameSQLQuery;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.update.create.CreateFileNodeTableSQLUpdate;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.update.create.CreateProjectsTableSQLUpdate;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.update.create.CreateSnapshotsTableSQLUpdate;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.update.create.CreateURLIndexStoreSQLUpdate;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.update.delete.DeleteFileNodesForProjectNameSQLUpdate;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.update.delete.DeleteURLIndexesForProjectNameSQLUpdate;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.update.insert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 17/11/14.
|
||||
*/
|
||||
public class SQLiteWLDatabase {
|
||||
|
||||
private final Connection connection;
|
||||
|
||||
public SQLiteWLDatabase(File rootGitDirectory) throws SQLException, ClassNotFoundException {
|
||||
File databaseFile = new File(rootGitDirectory, "/.wlgb/wlgb.db");
|
||||
databaseFile.getParentFile().mkdirs();
|
||||
System.out.println("Loading data...");
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + databaseFile.getAbsolutePath());
|
||||
createTables();
|
||||
}
|
||||
|
||||
public void addProject(String projectName) throws SQLException {
|
||||
update(new AddProjectSQLUpdate(projectName));
|
||||
}
|
||||
|
||||
public void addSnapshot(String projectName, int versionID) throws SQLException {
|
||||
update(new AddSnapshotSQLUpdate(projectName, versionID));
|
||||
}
|
||||
|
||||
public void addFileNodeBlob(String projectName, String fileName, int changed, byte[] blob) throws SQLException {
|
||||
update(new AddFileNodeBlobSQLUpdate(projectName, fileName, changed, blob));
|
||||
}
|
||||
|
||||
public void addFileNodeExternal(String projectName, String fileName, int changed, String url) throws SQLException {
|
||||
update(new AddFileNodeExternalSQLUpdate(projectName, fileName, changed, url));
|
||||
}
|
||||
|
||||
public void addURLIndex(String projectName, String url, byte[] blob) throws SQLException {
|
||||
update(new AddURLIndexSQLUpdate(projectName, url, blob));
|
||||
|
||||
}
|
||||
|
||||
public List<String> getProjectNames() throws SQLException {
|
||||
return query(new GetProjectNamesSQLQuery());
|
||||
}
|
||||
|
||||
public List<Integer> getVersionIDsForProjectName(String projectName) throws SQLException {
|
||||
return query(new GetVersionIDsForProjectNameSQLQuery(projectName));
|
||||
}
|
||||
|
||||
public List<FileNode> getFileNodesForProjectName(String projectName, FileIndexStore fileIndexStore) throws SQLException {
|
||||
return query(new GetFileNodesForProjectNameSQLQuery(projectName, fileIndexStore));
|
||||
}
|
||||
|
||||
public Map<String, FileNode> getURLIndexTableForProjectName(String projectName) throws SQLException {
|
||||
return query(new GetURLIndexTableForProjectNameSQLQuery(projectName));
|
||||
}
|
||||
|
||||
public void deleteFileNodesForProjectName(String projectName) throws SQLException {
|
||||
update(new DeleteFileNodesForProjectNameSQLUpdate(projectName));
|
||||
}
|
||||
|
||||
public void deleteURLIndexesForProjectName(String projectName) throws SQLException {
|
||||
update(new DeleteURLIndexesForProjectNameSQLUpdate(projectName));
|
||||
}
|
||||
|
||||
private void createTables() throws SQLException {
|
||||
final SQLUpdate[] createTableUpdates = {
|
||||
new CreateProjectsTableSQLUpdate(),
|
||||
new CreateSnapshotsTableSQLUpdate(),
|
||||
new CreateFileNodeTableSQLUpdate(),
|
||||
new CreateURLIndexStoreSQLUpdate()
|
||||
};
|
||||
|
||||
for (SQLUpdate update : createTableUpdates) {
|
||||
update(update);
|
||||
}
|
||||
}
|
||||
|
||||
private void update(SQLUpdate update) throws SQLException {
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
statement = connection.prepareStatement(update.getSQL());
|
||||
update.addParametersToStatement(statement);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
throw e;
|
||||
} finally {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T query(SQLQuery<T> query) throws SQLException {
|
||||
PreparedStatement statement = null;
|
||||
ResultSet results = null;
|
||||
try {
|
||||
statement = connection.prepareStatement(query.getSQL());
|
||||
query.addParametersToStatement(statement);
|
||||
results = statement.executeQuery();
|
||||
return query.processResultSet(results);
|
||||
} catch (SQLException e) {
|
||||
throw e;
|
||||
} finally {
|
||||
if (statement != null) {
|
||||
statement.close();
|
||||
}
|
||||
if (results != null) {
|
||||
results.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db.sql.query;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.AttachmentNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.BlobNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.FileNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.FileIndexStore;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.SQLQuery;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 20/11/14.
|
||||
*/
|
||||
public class GetFileNodesForProjectNameSQLQuery implements SQLQuery<List<FileNode>> {
|
||||
|
||||
private static final String GET_FILE_NODES_FOR_PROJECT_NAME =
|
||||
"SELECT `file_name`, `changed`, `is_blob`, `blob`, `url` FROM `file_node_table` WHERE `project_name` = ?";
|
||||
|
||||
private final String projectName;
|
||||
private final FileIndexStore fileIndexStore;
|
||||
|
||||
public GetFileNodesForProjectNameSQLQuery(String projectName, FileIndexStore fileIndexStore) {
|
||||
this.projectName = projectName;
|
||||
this.fileIndexStore = fileIndexStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileNode> processResultSet(ResultSet resultSet) throws SQLException {
|
||||
List<FileNode> fileNodes = new LinkedList<FileNode>();
|
||||
while (resultSet.next()) {
|
||||
boolean isBlob = Util.intToBoolean(resultSet.getInt("is_blob"));
|
||||
FileNode fileNode;
|
||||
String fileName = resultSet.getString("file_name");
|
||||
boolean changed = Util.intToBoolean(resultSet.getInt("changed"));
|
||||
if (isBlob) {
|
||||
fileNode = new BlobNode(fileName, changed, resultSet.getBytes("blob"));
|
||||
} else {
|
||||
fileNode = new AttachmentNode(fileName, changed, resultSet.getString("url"), fileIndexStore);
|
||||
}
|
||||
fileNodes.add(fileNode);
|
||||
}
|
||||
return fileNodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSQL() {
|
||||
return GET_FILE_NODES_FOR_PROJECT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParametersToStatement(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, projectName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db.sql.query;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.SQLQuery;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 20/11/14.
|
||||
*/
|
||||
public class GetProjectNamesSQLQuery implements SQLQuery<List<String>> {
|
||||
|
||||
private static final String GET_PROJECT_NAMES =
|
||||
"SELECT * FROM `projects`;\n";
|
||||
|
||||
@Override
|
||||
public List<String> processResultSet(ResultSet resultSet) throws SQLException {
|
||||
List<String> projectNames = new LinkedList<String>();
|
||||
while (resultSet.next()) {
|
||||
projectNames.add(resultSet.getString("name"));
|
||||
}
|
||||
return projectNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSQL() {
|
||||
return GET_PROJECT_NAMES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParametersToStatement(PreparedStatement statement) throws SQLException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db.sql.query;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.AttachmentNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.filestore.node.FileNode;
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.SQLQuery;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Winston on 20/11/14.
|
||||
*/
|
||||
public class GetURLIndexTableForProjectNameSQLQuery implements SQLQuery<Map<String, FileNode>> {
|
||||
|
||||
private static final String GET_URL_INDEXES_FOR_PROJECT_NAME =
|
||||
"SELECT `url`, `blob` FROM `url_index_store` WHERE `project_name` = ?";
|
||||
|
||||
private final String projectName;
|
||||
|
||||
public GetURLIndexTableForProjectNameSQLQuery(String projectName) {
|
||||
this.projectName = projectName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, FileNode> processResultSet(ResultSet resultSet) throws SQLException {
|
||||
Map<String, FileNode> urlIndexTable = new HashMap<String, FileNode>();
|
||||
while (resultSet.next()) {
|
||||
String url = resultSet.getString("url");
|
||||
byte[] blob = resultSet.getBytes("blob");
|
||||
urlIndexTable.put(url, new AttachmentNode(url, blob));
|
||||
}
|
||||
return urlIndexTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSQL() {
|
||||
return GET_URL_INDEXES_FOR_PROJECT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParametersToStatement(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, projectName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db.sql.query;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.SQLQuery;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Winston on 20/11/14.
|
||||
*/
|
||||
public class GetVersionIDsForProjectNameSQLQuery implements SQLQuery<List<Integer>> {
|
||||
|
||||
private static final String GET_VERSION_IDS_FOR_PROJECT_NAME =
|
||||
"SELECT `version_id` FROM `snapshots` WHERE `project_name` = ?";
|
||||
|
||||
private final String projectName;
|
||||
|
||||
public GetVersionIDsForProjectNameSQLQuery(String projectName) {
|
||||
this.projectName = projectName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> processResultSet(ResultSet resultSet) throws SQLException {
|
||||
List<Integer> versionIDs = new LinkedList<Integer>();
|
||||
while (resultSet.next()) {
|
||||
versionIDs.add(resultSet.getInt("version_id"));
|
||||
}
|
||||
return versionIDs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSQL() {
|
||||
return GET_VERSION_IDS_FOR_PROJECT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParametersToStatement(PreparedStatement statement) throws SQLException {
|
||||
statement.setString(1, projectName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package uk.ac.ic.wlgitbridge.writelatex.model.db.sql.update.create;
|
||||
|
||||
import uk.ac.ic.wlgitbridge.writelatex.model.db.sql.SQLUpdate;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Created by Winston on 20/11/14.
|
||||
*/
|
||||
public class CreateFileNodeTableSQLUpdate implements SQLUpdate {
|
||||
|
||||
private static final String CREATE_FILE_NODE_TABLE =
|
||||
"CREATE TABLE IF NOT EXISTS `file_node_table` (\n" +
|
||||
" `project_name` varchar(10) NOT NULL DEFAULT '',\n" +
|
||||
" `file_name` varchar(255) NOT NULL DEFAULT '',\n" +
|
||||
" `changed` tinyint(1) NOT NULL,\n" +
|
||||
" `is_blob` tinyint(1) NOT NULL,\n" +
|
||||
" `blob` blob,\n" +
|
||||
" `url` varchar(128) DEFAULT NULL,\n" +
|
||||
" PRIMARY KEY (`project_name`,`file_name`),\n" +
|
||||
" CONSTRAINT `file_node_table_ibfk_1` FOREIGN KEY (`project_name`) REFERENCES `projects` (`name`) ON DELETE CASCADE ON UPDATE CASCADE\n" +
|
||||
")";
|
||||
|
||||
@Override
|
||||
public String getSQL() {
|
||||
return CREATE_FILE_NODE_TABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParametersToStatement(PreparedStatement statement) throws SQLException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user