Implemented mock snapshot server.

This commit is contained in:
Winston Li 2015-01-10 08:41:14 +00:00
parent 2310aa124f
commit 26e2b1262d
51 changed files with 1109 additions and 159 deletions

View file

@ -1,9 +1,9 @@
{
"port": 80,
"rootGitDirectory": "/var/wlgb/git",
"apiBaseUrl": "https://www.overleaf.com/api/v0",
"apiBaseUrl": "http://127.0.0.1:60000/api/v0",
"username": "REDACTED",
"password": "REDACTED",
"postbackBaseUrl": "http://your-server-name-for-postbacks",
"postbackBaseUrl": "http://127.0.0.1",
"serviceName": "Overleaf"
}

View file

@ -25,25 +25,24 @@ public class AttsResourceHandler extends ResourceHandler {
@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();
String method = baseRequest.getMethod();
if (method.equals("GET")) {
HttpURI uri = baseRequest.getUri();
System.out.println(method + " " + 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();
}
super.handle(target, baseRequest, request, response);
}
try {
writeLatexDataSource.checkPostbackKey(pathSections[1], key);
} catch (InvalidPostbackKeyException e) {
throw new ServletException();
}
if (false) {
throw new ServletException();
}
super.handle(target, baseRequest, request, response);
}
}

View file

@ -1,5 +1,7 @@
package uk.ac.ic.wlgitbridge.application;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import uk.ac.ic.wlgitbridge.bridge.WriteLatexDataSource;
@ -24,22 +26,45 @@ public class SnapshotPushPostbackHandler extends AbstractHandler {
@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();
try {
if (request.getMethod().equals("POST") && target.endsWith("postback")) {
response.setContentType("application/json");
String contents = Util.getContentsOfReader(request.getReader());
String[] parts = request.getRequestURI().split("/");
if (parts.length < 4) {
System.out.println("Invalid postback url");
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);
JsonObject body = new JsonObject();
try {
postbackContents.processPostback();
} catch (UnexpectedPostbackException e) {
response.setStatus(HttpServletResponse.SC_CONFLICT);
body.add("code", new JsonPrimitive("unexpectedPostback"));
response.getWriter().println(body);
baseRequest.setHandled(true);
return;
}
response.setStatus(HttpServletResponse.SC_OK);
body.add("code", new JsonPrimitive("success"));
response.getWriter().println(body);
baseRequest.setHandled(true);
}
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);
} catch (IOException e) {
e.printStackTrace();
throw e;
} catch (ServletException e) {
e.printStackTrace();
throw e;
} catch (RuntimeException e) {
e.printStackTrace();
throw e;
}
}

View file

@ -2,8 +2,7 @@ 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 org.eclipse.jgit.transport.ServiceMayNotContinueException;
import java.io.File;
@ -12,6 +11,6 @@ import java.io.File;
*/
public interface RepositorySource {
public Repository getRepositoryWithNameAtRootDirectory(String name, File rootDirectory) throws RepositoryNotFoundException, ServiceNotEnabledException;
public Repository getRepositoryWithNameAtRootDirectory(String name, File rootDirectory) throws RepositoryNotFoundException, ServiceMayNotContinueException;
}

View file

@ -5,8 +5,7 @@ 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 org.eclipse.jgit.transport.ServiceMayNotContinueException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
import uk.ac.ic.wlgitbridge.writelatex.filestore.store.WLFileStore;
@ -29,7 +28,7 @@ public class WLBridgedProject {
this.writeLatexDataSource = writeLatexDataSource;
}
public void buildRepository() throws RepositoryNotFoundException, ServiceNotEnabledException, FailedConnectionException {
public void buildRepository() throws RepositoryNotFoundException, ServiceMayNotContinueException {
writeLatexDataSource.lockForProject(name);
if (repository.getObjectDatabase().exists()) {
updateRepositoryFromSnapshots(repository);
@ -39,7 +38,7 @@ public class WLBridgedProject {
writeLatexDataSource.unlockForProject(name);
}
private void updateRepositoryFromSnapshots(Repository repository) throws ServiceNotEnabledException, RepositoryNotFoundException, FailedConnectionException {
private void updateRepositoryFromSnapshots(Repository repository) throws RepositoryNotFoundException, ServiceMayNotContinueException {
List<WritableRepositoryContents> writableRepositories;
try {
writableRepositories = writeLatexDataSource.getWritableRepositories(name);
@ -54,24 +53,23 @@ public class WLBridgedProject {
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();
throw new ServiceMayNotContinueException(e);
} catch (IOException e) {
throw new ServiceNotEnabledException();
throw new ServiceMayNotContinueException(e);
}
}
private void buildRepositoryFromScratch(Repository repository) throws RepositoryNotFoundException, ServiceNotEnabledException, FailedConnectionException {
private void buildRepositoryFromScratch(Repository repository) throws RepositoryNotFoundException, ServiceMayNotContinueException {
if (!writeLatexDataSource.repositoryExists(name)) {
throw new RepositoryNotFoundException(name);
}
try {
repository.create();
} catch (IOException e) {
throw new ServiceNotEnabledException();
throw new ServiceMayNotContinueException(e);
}
updateRepositoryFromSnapshots(repository);
}

View file

@ -32,14 +32,20 @@ public class WLRepositoryResolver implements RepositoryResolver<HttpServletReque
try {
return repositorySource.getRepositoryWithNameAtRootDirectory(Util.removeAllSuffixes(name, "/", ".git"), rootGitDirectory);
} catch (RepositoryNotFoundException e) {
e.printStackTrace();
throw e;
/*
} catch (ServiceNotAuthorizedException e) {
cannot occur
} catch (ServiceNotEnabledException e) {
cannot occur
*/
} catch (ServiceMayNotContinueException e) { /* Such as FailedConnectionException */
e.printStackTrace();
throw e;
} catch (Throwable e) {
} catch (RuntimeException e) {
e.printStackTrace();
System.out.println("An exception occurred");
throw new ServiceNotEnabledException();
throw new ServiceMayNotContinueException(e);
}
}

View file

@ -10,9 +10,10 @@ 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.exception.FailedConnectionException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.InternalErrorException;
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;
@ -36,26 +37,28 @@ public class WriteLatexPutHook implements PreReceiveHook {
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");
receivePack.sendError(e.getMessage());
receiveCommand.setResult(Result.REJECTED_OTHER_REASON, e.getMessage());
} 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);
handleSnapshotPostException(receivePack, receiveCommand, e);
} catch (Throwable t) {
t.printStackTrace();
handleSnapshotPostException(receivePack, receiveCommand, new InternalErrorException());
}
}
}
private void handleSnapshotPostException(ReceivePack receivePack, ReceiveCommand receiveCommand, 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);
}
private void handleReceiveCommand(Repository repository, ReceiveCommand receiveCommand) throws IOException, SnapshotPostException, FailedConnectionException {
checkBranch(receiveCommand);
checkForcedPush(receiveCommand);

View file

@ -0,0 +1,17 @@
package uk.ac.ic.wlgitbridge.test;
import uk.ac.ic.wlgitbridge.test.server.MockSnapshotServer;
import uk.ac.ic.wlgitbridge.test.state.SnapshotAPIState;
/**
* Created by Winston on 10/01/15.
*/
public class Main {
public static void main(String[] args) {
MockSnapshotServer server = new MockSnapshotServer();
server.setState(new SnapshotAPIState());
server.start();
}
}

View file

@ -1,46 +0,0 @@
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();
}
}

View file

@ -0,0 +1,12 @@
package uk.ac.ic.wlgitbridge.test.exception;
/**
* Created by Winston on 09/01/15.
*/
public class InvalidAPICallException extends Exception {
public InvalidAPICallException(String target) {
super(target);
}
}

View file

@ -0,0 +1,14 @@
package uk.ac.ic.wlgitbridge.test.response;
/**
* Created by Winston on 09/01/15.
*/
public abstract class SnapshotResponse {
public abstract String respond();
public String postback() {
return null;
}
}

View file

@ -0,0 +1,57 @@
package uk.ac.ic.wlgitbridge.test.response;
import uk.ac.ic.wlgitbridge.test.exception.InvalidAPICallException;
import uk.ac.ic.wlgitbridge.test.response.getdoc.SnapshotGetDocResponse;
import uk.ac.ic.wlgitbridge.test.response.getforver.SnapshotGetForVerResponse;
import uk.ac.ic.wlgitbridge.test.response.getsavedver.SnapshotGetSavedVersResponse;
import uk.ac.ic.wlgitbridge.test.response.push.SnapshotPushResponse;
import uk.ac.ic.wlgitbridge.test.state.SnapshotAPIState;
/**
* Created by Winston on 09/01/15.
*/
public class SnapshotResponseBuilder {
private SnapshotAPIState state;
public SnapshotResponse buildWithTarget(String target, String method) throws InvalidAPICallException {
checkPrefix(target);
return parseTarget(target, target.split("/"), method);
}
private void checkPrefix(String target) throws InvalidAPICallException {
if (!target.startsWith("/api/v0/docs/")) {
throw new InvalidAPICallException(target);
}
}
private SnapshotResponse parseTarget(String target, String[] parts, String method) throws InvalidAPICallException {
String projectName = parts[4];
if (parts.length == 5) {
if (method.equals("GET")) {
return new SnapshotGetDocResponse(state.getStateForGetDoc(projectName));
}
} else if (parts.length == 6) {
String type = parts[5];
if (type.equals("snapshots") && method.equals("POST")) {
return new SnapshotPushResponse(state.getStateForPush(projectName), state.getStateForPostback(projectName));
} else if (type.equals("saved_vers") && method.equals("GET")) {
return new SnapshotGetSavedVersResponse(state.getStateForGetSavedVers(projectName));
}
} else if (parts.length == 7) {
if (parts[5].equals("snapshots") && method.equals("GET")) {
try {
return new SnapshotGetForVerResponse(state.getStateForGetForVers(projectName, Integer.parseInt(parts[6])));
} catch (NumberFormatException e) {
}
}
}
throw new InvalidAPICallException(target);
}
public void setState(SnapshotAPIState state) {
this.state = state;
}
}

View file

@ -0,0 +1,22 @@
package uk.ac.ic.wlgitbridge.test.response.getdoc;
import uk.ac.ic.wlgitbridge.test.response.SnapshotResponse;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.SnapshotGetDocResult;
/**
* Created by Winston on 09/01/15.
*/
public class SnapshotGetDocResponse extends SnapshotResponse {
private final SnapshotGetDocResult state;
public SnapshotGetDocResponse(SnapshotGetDocResult state) {
this.state = state;
}
@Override
public String respond() {
return state.toJson().toString();
}
}

View file

@ -0,0 +1,22 @@
package uk.ac.ic.wlgitbridge.test.response.getforver;
import uk.ac.ic.wlgitbridge.test.response.SnapshotResponse;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion.SnapshotGetForVersionResult;
/**
* Created by Winston on 09/01/15.
*/
public class SnapshotGetForVerResponse extends SnapshotResponse {
private final SnapshotGetForVersionResult state;
public SnapshotGetForVerResponse(SnapshotGetForVersionResult state) {
this.state = state;
}
@Override
public String respond() {
return state.toJson().toString();
}
}

View file

@ -0,0 +1,22 @@
package uk.ac.ic.wlgitbridge.test.response.getsavedver;
import uk.ac.ic.wlgitbridge.test.response.SnapshotResponse;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers.SnapshotGetSavedVersResult;
/**
* Created by Winston on 09/01/15.
*/
public class SnapshotGetSavedVersResponse extends SnapshotResponse {
private final SnapshotGetSavedVersResult state;
public SnapshotGetSavedVersResponse(SnapshotGetSavedVersResult state) {
this.state = state;
}
@Override
public String respond() {
return state.toJson().toString();
}
}

View file

@ -0,0 +1,34 @@
package uk.ac.ic.wlgitbridge.test.response.push;
import uk.ac.ic.wlgitbridge.test.response.SnapshotResponse;
import uk.ac.ic.wlgitbridge.test.response.push.postback.SnapshotPostbackRequest;
import uk.ac.ic.wlgitbridge.test.response.push.data.SnapshotPushResult;
/**
* Created by Winston on 09/01/15.
*/
public class SnapshotPushResponse extends SnapshotResponse {
private final SnapshotPushResult stateForPush;
private final SnapshotPostbackRequest stateForPostback;
public SnapshotPushResponse(SnapshotPushResult stateForPush, SnapshotPostbackRequest stateForPostback) {
this.stateForPush = stateForPush;
this.stateForPostback = stateForPostback;
}
@Override
public String respond() {
return stateForPush.toJson().toString();
}
@Override
public String postback() {
if (stateForPush.hasPostback()) {
return stateForPostback.toJson().toString();
} else {
return null;
}
}
}

View file

@ -0,0 +1,31 @@
package uk.ac.ic.wlgitbridge.test.response.push.data;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/**
* Created by Winston on 09/01/15.
*/
public abstract class SnapshotPushResult {
private final int status;
private final String code;
private final String message;
public SnapshotPushResult(int status, String code, String message) {
this.status = status;
this.code = code;
this.message = message;
}
public JsonElement toJson() {
JsonObject jsonThis = new JsonObject();
jsonThis.addProperty("status", status);
jsonThis.addProperty("code", code);
jsonThis.addProperty("message", message);
return jsonThis;
}
public abstract boolean hasPostback();
}

View file

@ -0,0 +1,17 @@
package uk.ac.ic.wlgitbridge.test.response.push.data;
/**
* Created by Winston on 09/01/15.
*/
public class SnapshotPushResultOutOfDate extends SnapshotPushResult {
public SnapshotPushResultOutOfDate() {
super(409, "outOfDate", "Out of Date");
}
@Override
public boolean hasPostback() {
return false;
}
}

View file

@ -0,0 +1,17 @@
package uk.ac.ic.wlgitbridge.test.response.push.data;
/**
* Created by Winston on 09/01/15.
*/
public class SnapshotPushResultSuccess extends SnapshotPushResult {
public SnapshotPushResultSuccess() {
super(402, "accepted", "Accepted");
}
@Override
public boolean hasPostback() {
return true;
}
}

View file

@ -0,0 +1,22 @@
package uk.ac.ic.wlgitbridge.test.response.push.postback;
import com.google.gson.JsonObject;
/**
* Created by Winston on 09/01/15.
*/
public abstract class SnapshotPostbackRequest {
private final String code;
public SnapshotPostbackRequest(String code) {
this.code = code;
}
public JsonObject toJson() {
JsonObject jsonThis = new JsonObject();
jsonThis.addProperty("code", code);
return jsonThis;
}
}

View file

@ -0,0 +1,21 @@
package uk.ac.ic.wlgitbridge.test.response.push.postback;
import com.google.gson.JsonObject;
/**
* Created by Winston on 10/01/15.
*/
public class SnapshotPostbackRequestError extends SnapshotPostbackRequest {
public SnapshotPostbackRequestError() {
super("error");
}
@Override
public JsonObject toJson() {
JsonObject jsonThis = super.toJson();
jsonThis.addProperty("message", "Unexpected Error");
return jsonThis;
}
}

View file

@ -0,0 +1,32 @@
package uk.ac.ic.wlgitbridge.test.response.push.postback;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import uk.ac.ic.wlgitbridge.test.response.push.postback.invalidfile.InvalidFileError;
import java.util.List;
/**
* Created by Winston on 09/01/15.
*/
public class SnapshotPostbackRequestInvalidFiles extends SnapshotPostbackRequest {
private final List<InvalidFileError> errors;
public SnapshotPostbackRequestInvalidFiles(List<InvalidFileError> errors) {
super("invalidFiles");
this.errors = errors;
}
@Override
public JsonObject toJson() {
JsonObject jsonThis = super.toJson();
JsonArray jsonErrors = new JsonArray();
for (InvalidFileError error : errors) {
jsonErrors.add(error.toJson());
}
jsonThis.add("errors", jsonErrors);
return jsonThis;
}
}

View file

@ -0,0 +1,33 @@
package uk.ac.ic.wlgitbridge.test.response.push.postback;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import java.util.List;
/**
* Created by Winston on 10/01/15.
*/
public class SnapshotPostbackRequestInvalidProject extends SnapshotPostbackRequest {
private final List<String> errors;
public SnapshotPostbackRequestInvalidProject(List<String> errors) {
super("invalidProject");
this.errors = errors;
}
@Override
public JsonObject toJson() {
JsonObject jsonThis = super.toJson();
jsonThis.addProperty("message", "short string message for debugging");
JsonArray jsonErrors = new JsonArray();
for (String error : errors) {
jsonErrors.add(new JsonPrimitive(error));
}
jsonThis.add("errors", jsonErrors);
return jsonThis;
}
}

View file

@ -0,0 +1,21 @@
package uk.ac.ic.wlgitbridge.test.response.push.postback;
import com.google.gson.JsonObject;
/**
* Created by Winston on 09/01/15.
*/
public class SnapshotPostbackRequestOutOfDate extends SnapshotPostbackRequest {
public SnapshotPostbackRequestOutOfDate() {
super("outOfDate");
}
@Override
public JsonObject toJson() {
JsonObject jsonThis = super.toJson();
jsonThis.addProperty("message", "Out of Date");
return jsonThis;
}
}

View file

@ -0,0 +1,24 @@
package uk.ac.ic.wlgitbridge.test.response.push.postback;
import com.google.gson.JsonObject;
/**
* Created by Winston on 09/01/15.
*/
public class SnapshotPostbackRequestSuccess extends SnapshotPostbackRequest {
private final int latestVerId;
public SnapshotPostbackRequestSuccess(int latestVerId) {
super("upToDate");
this.latestVerId = latestVerId;
}
@Override
public JsonObject toJson() {
JsonObject jsonThis = super.toJson();
jsonThis.addProperty("latestVerId", latestVerId);
return jsonThis;
}
}

View file

@ -0,0 +1,25 @@
package uk.ac.ic.wlgitbridge.test.response.push.postback.invalidfile;
import com.google.gson.JsonObject;
/**
* Created by Winston on 09/01/15.
*/
public abstract class InvalidFileError {
private final String file;
public InvalidFileError(String file) {
this.file = file;
}
public JsonObject toJson() {
JsonObject jsonThis = new JsonObject();
jsonThis.addProperty("file", file);
jsonThis.addProperty("state", getState());
return jsonThis;
}
protected abstract String getState();
}

View file

@ -0,0 +1,17 @@
package uk.ac.ic.wlgitbridge.test.response.push.postback.invalidfile;
/**
* Created by Winston on 09/01/15.
*/
public class InvalidFileErrorDefault extends InvalidFileError {
public InvalidFileErrorDefault(String file) {
super(file);
}
@Override
protected String getState() {
return "error";
}
}

View file

@ -0,0 +1,17 @@
package uk.ac.ic.wlgitbridge.test.response.push.postback.invalidfile;
/**
* Created by Winston on 09/01/15.
*/
public class InvalidFileErrorDisallowed extends InvalidFileError {
public InvalidFileErrorDisallowed(String file) {
super(file);
}
@Override
protected String getState() {
return "disallowed";
}
}

View file

@ -0,0 +1,29 @@
package uk.ac.ic.wlgitbridge.test.response.push.postback.invalidfile;
import com.google.gson.JsonObject;
/**
* Created by Winston on 09/01/15.
*/
public class InvalidFileErrorUnclean extends InvalidFileError {
private final String cleanFile;
public InvalidFileErrorUnclean(String file, String cleanFile) {
super(file);
this.cleanFile = cleanFile;
}
@Override
public JsonObject toJson() {
JsonObject jsonThis = super.toJson();
jsonThis.addProperty("cleanFile", cleanFile);
return jsonThis;
}
@Override
protected String getState() {
return "unclean_name";
}
}

View file

@ -0,0 +1,40 @@
package uk.ac.ic.wlgitbridge.test.server;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import uk.ac.ic.wlgitbridge.test.exception.InvalidAPICallException;
import uk.ac.ic.wlgitbridge.test.response.SnapshotResponse;
import uk.ac.ic.wlgitbridge.test.response.SnapshotResponseBuilder;
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 MockSnapshotRequestHandler extends AbstractHandler {
private final SnapshotResponseBuilder responseBuilder;
public MockSnapshotRequestHandler(SnapshotResponseBuilder responseBuilder) {
this.responseBuilder = responseBuilder;
}
@Override
public void handle(String target, final Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
try {
final SnapshotResponse snapshotResponse = responseBuilder.buildWithTarget(target, baseRequest.getMethod());
response.getWriter().println(snapshotResponse.respond());
new PostbackThread(baseRequest.getReader(), snapshotResponse.postback()).startIfNotNull();
} catch (InvalidAPICallException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
}
baseRequest.setHandled(true);
}
}

View file

@ -0,0 +1,37 @@
package uk.ac.ic.wlgitbridge.test.server;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server;
import uk.ac.ic.wlgitbridge.test.response.SnapshotResponseBuilder;
import uk.ac.ic.wlgitbridge.test.state.SnapshotAPIState;
/**
* Created by Winston on 09/01/15.
*/
public class MockSnapshotServer {
private final Server server;
private final SnapshotResponseBuilder responseBuilder;
private int port;
public MockSnapshotServer() {
server = new Server(60000);
responseBuilder = new SnapshotResponseBuilder();
server.setHandler(new MockSnapshotRequestHandler(responseBuilder));
}
public void start() {
try {
server.start();
} catch (Exception e) {
e.printStackTrace();
}
port = ((NetworkConnector) server.getConnectors()[0]).getLocalPort();
System.out.println(port);
}
public void setState(SnapshotAPIState state) {
responseBuilder.setState(state);
}
}

View file

@ -0,0 +1,45 @@
package uk.ac.ic.wlgitbridge.test.server;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.ning.http.client.AsyncHttpClient;
import java.io.IOException;
import java.io.Reader;
import java.util.concurrent.ExecutionException;
/**
* Created by Winston on 10/01/15.
*/
public class PostbackThread extends Thread {
private String url;
private String postback;
public PostbackThread(Reader reader, String postback) {
if (postback != null) {
url = new Gson().fromJson(reader, JsonObject.class).get("postbackUrl").getAsString();
this.postback = postback;
}
}
@Override
public void run() {
try {
new AsyncHttpClient().preparePost(url).setBody(postback).execute().get().getResponseBody();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
public void startIfNotNull() {
if (url != null && postback != null) {
start();
}
}
}

File diff suppressed because one or more lines are too long

View file

@ -3,11 +3,11 @@ 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 org.eclipse.jgit.transport.ServiceMayNotContinueException;
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 uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.InternalErrorException;
import java.io.File;
import java.io.IOException;
@ -24,13 +24,9 @@ public class SnapshotRepositoryBuilder implements RepositorySource {
}
@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();
public Repository getRepositoryWithNameAtRootDirectory(String name, File rootDirectory) throws RepositoryNotFoundException, ServiceMayNotContinueException {
if (!writeLatexDataSource.repositoryExists(name)) {
throw new RepositoryNotFoundException(name);
}
File repositoryDirectory = new File(rootDirectory, name);
@ -38,11 +34,8 @@ public class SnapshotRepositoryBuilder implements RepositorySource {
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();
throw new ServiceMayNotContinueException(new InternalErrorException().getDescriptionLines().get(0));
}
return repository;
}

View file

@ -69,7 +69,7 @@ public class WriteLatexAPI implements WriteLatexDataSource {
}
@Override
public void putDirectoryContentsToProjectWithName(String projectName, RawDirectoryContents directoryContents, String hostname) throws SnapshotPostException, IOException, FailedConnectionException {
public void putDirectoryContentsToProjectWithName(String projectName, RawDirectoryContents directoryContents, String hostname) throws SnapshotPostException, IOException {
mainProjectLock.lockForProject(projectName);
try {
System.out.println("Pushing project: " + projectName);
@ -87,8 +87,6 @@ public class WriteLatexAPI implements WriteLatexDataSource {
throw e;
} catch (IOException e) {
throw e;
} catch (FailedConnectionException e) {
throw e;
} finally {
mainProjectLock.unlockForProject(projectName);
}

View file

@ -8,7 +8,7 @@ import com.google.gson.JsonElement;
public abstract class Result implements JSONSource {
private JsonElement json;
private final Request request;
private Request request;
public Result(Request request, JsonElement json) {
this.request = request;
@ -16,12 +16,20 @@ public abstract class Result implements JSONSource {
fromJSON(json);
}
protected Result() {
}
public Request getRequest() {
return request;
}
public abstract JsonElement toJson();
@Override
public String toString() {
if (json == null) {
return "result";
}
return json.toString();
}

View file

@ -32,7 +32,7 @@ public abstract class SnapshotAPIRequest<T extends Result> extends Request<T> {
/* baseURL ends with / */
public static void setBaseURL(String baseURL) {
BASE_URL = baseURL + "/docs/";
BASE_URL = baseURL + "docs/";
}
}

View file

@ -1,7 +1,15 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.exception;
import org.eclipse.jgit.transport.ServiceMayNotContinueException;
import uk.ac.ic.wlgitbridge.util.Util;
/**
* Created by Winston on 08/11/14.
*/
public class FailedConnectionException extends Exception {
public class FailedConnectionException extends ServiceMayNotContinueException {
public FailedConnectionException() {
super(Util.getServiceName() + " server not available. Please try again later.");
}
}

View file

@ -23,6 +23,25 @@ public class SnapshotGetDocResult extends Result {
super(request, json);
}
public SnapshotGetDocResult(int versionID, String createdAt, String email, String name) {
this.versionID = versionID;
this.createdAt = createdAt;
this.name = name;
this.email = email;
}
@Override
public JsonElement toJson() {
JsonObject jsonThis = new JsonObject();
jsonThis.addProperty("latestVerId", versionID);
jsonThis.addProperty("latestVerAt", createdAt);
JsonObject latestVerBy = new JsonObject();
latestVerBy.addProperty("email", email);
latestVerBy.addProperty("name", name);
jsonThis.add("latestVerBy", latestVerBy);
return jsonThis;
}
@Override
public void fromJSON(JsonElement json) {
JsonObject jsonObject = json.getAsJsonObject();

View file

@ -1,9 +1,11 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
import java.util.LinkedList;
import java.util.List;
/**
@ -11,26 +13,34 @@ import java.util.List;
*/
public class InvalidProjectException extends SnapshotPostException {
private List<String> errors;
public InvalidProjectException(JsonObject json) {
super(json);
}
public InvalidProjectException() {
super();
errors = new LinkedList<String>();
}
@Override
public String getMessage() {
return null;
return "invalid project";
}
@Override
public List<String> getDescriptionLines() {
return null;
return errors;
}
@Override
public void fromJSON(JsonElement json) {
errors = new LinkedList<String>();
JsonArray errors = json.getAsJsonObject().get("errors").getAsJsonArray();
System.out.println(errors);
for (JsonElement error : errors) {
this.errors.add(error.getAsString());
}
}
}

View file

@ -2,6 +2,7 @@ package uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
/**
* Created by Winston on 06/11/14.
@ -14,6 +15,19 @@ public class SnapshotAttachment extends SnapshotFile {
super(json);
}
public SnapshotAttachment(String url, String path) {
super(null, path);
this.url = url;
}
@Override
public JsonElement toJson() {
JsonArray jsonThis = new JsonArray();
jsonThis.add(new JsonPrimitive(url));
jsonThis.add(new JsonPrimitive(getPath()));
return jsonThis;
}
@Override
public byte[] getContents() {
return null;

View file

@ -2,6 +2,7 @@ package uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.JSONSource;
import java.util.LinkedList;
@ -24,6 +25,26 @@ public class SnapshotData implements JSONSource {
fromJSON(json);
}
public SnapshotData(List<SnapshotFile> srcs, List<SnapshotAttachment> atts) {
this.srcs = srcs;
this.atts = atts;
}
public JsonElement toJson() {
JsonObject jsonThis = new JsonObject();
JsonArray jsonSrcs = new JsonArray();
for (SnapshotFile src : srcs) {
jsonSrcs.add(src.toJson());
}
jsonThis.add("srcs", jsonSrcs);
JsonArray jsonAtts = new JsonArray();
for (SnapshotAttachment att : atts) {
jsonAtts.add(att.toJson());
}
jsonThis.add("atts", jsonAtts);
return jsonThis;
}
@Override
public void fromJSON(JsonElement json) {
populateSrcs(json.getAsJsonObject().get(JSON_KEY_SRCS).getAsJsonArray());

View file

@ -2,6 +2,7 @@ package uk.ac.ic.wlgitbridge.writelatex.api.request.getforversion;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import uk.ac.ic.wlgitbridge.bridge.RawFile;
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.JSONSource;
@ -17,6 +18,20 @@ public class SnapshotFile implements JSONSource, RawFile {
fromJSON(json);
}
public SnapshotFile(String contents, String path) {
this.path = path;
if (contents != null) {
this.contents = contents.getBytes();
}
}
public JsonElement toJson() {
JsonArray jsonThis = new JsonArray();
jsonThis.add(new JsonPrimitive(new String(contents)));
jsonThis.add(new JsonPrimitive(path));
return jsonThis;
}
@Override
public String getPath() {
return path;

View file

@ -3,7 +3,6 @@ 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.
@ -16,6 +15,15 @@ public class SnapshotGetForVersionResult extends Result {
super(request, json);
}
public SnapshotGetForVersionResult(SnapshotData snapshotData) {
this.snapshotData = snapshotData;
}
@Override
public JsonElement toJson() {
return snapshotData.toJson();
}
@Override
public void fromJSON(JsonElement json) {
snapshotData = new SnapshotData(json);

View file

@ -1,7 +1,9 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.getsavedvers;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
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;
@ -20,6 +22,28 @@ public class SnapshotGetSavedVersResult extends Result {
super(request, json);
}
public SnapshotGetSavedVersResult(List<SnapshotInfo> savedVers) {
this.savedVers = savedVers;
}
@Override
public JsonElement toJson() {
JsonArray jsonThis = new JsonArray();
for (SnapshotInfo savedVer : savedVers) {
JsonObject jsonSavedVer = new JsonObject();
jsonSavedVer.addProperty("versionId", savedVer.getVersionId());
jsonSavedVer.addProperty("comment", savedVer.getComment());
WLUser user = savedVer.getUser();
JsonObject jsonUser = new JsonObject();
jsonUser.addProperty("email", user.getEmail());
jsonUser.addProperty("name", user.getName());
jsonSavedVer.add("user", jsonUser);
jsonSavedVer.addProperty("createdAt", savedVer.getCreatedAt());
jsonThis.add(jsonSavedVer);
}
return jsonThis;
}
@Override
public void fromJSON(JsonElement json) {
savedVers = new LinkedList<SnapshotInfo>();

View file

@ -13,8 +13,12 @@ public class SnapshotInfo {
private String createdAt;
public SnapshotInfo(int versionID, String createdAt, String name, String email) {
this.versionId = versionID;
comment = "Update on " + Util.getServiceName() + ".";
this(versionID, "Update on " + Util.getServiceName() + ".", name, email, createdAt);
}
public SnapshotInfo(int versionID, String comment, String email, String name, String createdAt) {
versionId = versionID;
this.comment = comment;
user = new WLUser(name, email);
this.createdAt = createdAt;
}

View file

@ -1,14 +1,22 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.push;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.InternalErrorException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.InvalidPostbackKeyException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.PostbackTimeoutException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception.SnapshotPostException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by Winston on 17/11/14.
*/
public class PostbackContents {
private final String postbackKey;
private final ReentrantLock lock;
private final Condition cond;
private boolean received;
private int versionID;
@ -16,37 +24,57 @@ public class PostbackContents {
public PostbackContents(String postbackKey) {
this.postbackKey = postbackKey;
lock = new ReentrantLock();
cond = lock.newCondition();
received = false;
exception = null;
}
public synchronized int waitForPostback() throws SnapshotPostException {
while (!received) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
public int waitForPostback() throws SnapshotPostException {
lock.lock();
try {
while (!received) {
try {
if (!cond.await(30, TimeUnit.SECONDS)) {
throw new PostbackTimeoutException();
}
} catch (InterruptedException e) {
e.printStackTrace();
throw new InternalErrorException();
}
}
}
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();
if (exception != null) {
throw exception;
}
return versionID;
} finally {
lock.unlock();
}
}
public synchronized void receivedException(SnapshotPostException exception, String postbackKey) {
if (postbackKey.equals(this.postbackKey)) {
this.exception = exception;
received = true;
notifyAll();
public void receivedVersionID(int versionID, String postbackKey) {
lock.lock();
try {
if (postbackKey.equals(this.postbackKey)) {
this.versionID = versionID;
received = true;
cond.signalAll();
}
} finally {
lock.unlock();
}
}
public void receivedException(SnapshotPostException exception, String postbackKey) {
lock.lock();
try {
if (postbackKey.equals(this.postbackKey)) {
this.exception = exception;
received = true;
cond.signalAll();
}
} finally {
lock.unlock();
}
}

View file

@ -23,9 +23,13 @@ public class PostbackManager {
}
public int getVersionID(String projectName) throws SnapshotPostException {
int versionID = postbackContentsTable.get(projectName).waitForPostback();
postbackContentsTable.remove(projectName);
return versionID;
try {
return postbackContentsTable.get(projectName).waitForPostback();
} catch (SnapshotPostException e) {
throw e;
} finally {
postbackContentsTable.remove(projectName);
}
}
public void postVersionIDForProject(String projectName, int versionID, String postbackKey) throws UnexpectedPostbackException {

View file

@ -17,6 +17,11 @@ public class SnapshotPushRequestResult extends Result {
super(request, json);
}
@Override
public JsonElement toJson() {
return null;
}
public boolean wasSuccessful() {
return success;
}

View file

@ -0,0 +1,30 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception;
import com.google.gson.JsonElement;
import uk.ac.ic.wlgitbridge.util.Util;
import java.util.Arrays;
import java.util.List;
/**
* Created by Winston on 09/01/15.
*/
public class InternalErrorException extends SnapshotPostException {
@Override
public String getMessage() {
return "internal error";
}
@Override
public List<String> getDescriptionLines() {
return Arrays.asList("There as an internal error with the Git server.",
"Please contact " + Util.getServiceName() + ".");
}
@Override
public void fromJSON(JsonElement json) {
}
}

View file

@ -0,0 +1,29 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.push.exception;
import com.google.gson.JsonElement;
import uk.ac.ic.wlgitbridge.util.Util;
import java.util.Arrays;
import java.util.List;
/**
* Created by Winston on 09/01/15.
*/
public class PostbackTimeoutException extends SnapshotPostException {
@Override
public String getMessage() {
return "timeout";
}
@Override
public List<String> getDescriptionLines() {
return Arrays.asList("The " + Util.getServiceName() + " server is currently unavailable.", "Please try again later.");
}
@Override
public void fromJSON(JsonElement json) {
}
}