Added exception handling to postback and implemented waiting properly.

This commit is contained in:
Winston Li 2014-11-17 10:00:15 +00:00
parent 3e12845345
commit 3d86a3e149
25 changed files with 336 additions and 62 deletions

View file

@ -0,0 +1,35 @@
package uk.ac.ic.wlgitbridge.application;
import com.google.gson.JsonObject;
import uk.ac.ic.wlgitbridge.writelatex.InvalidFilesException;
import uk.ac.ic.wlgitbridge.writelatex.OutOfDateException;
import uk.ac.ic.wlgitbridge.writelatex.SnapshotPostException;
import uk.ac.ic.wlgitbridge.writelatex.UnexpectedErrorException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.getdoc.exception.InvalidProjectException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.UnexpectedPostbackException;
/**
* 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();
}
}
}

View file

@ -0,0 +1,68 @@
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.SnapshotPostException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.base.JSONSource;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.UnexpectedPostbackException;
/**
* 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 SnapshotPostExceptionBuilder snapshotPostExceptionBuilder;
private int versionID;
private SnapshotPostException exception;
public SnapshotPushPostbackContents(WriteLatexDataSource writeLatexDataSource, String projectName, String contents) {
this.projectName = projectName;
this.writeLatexDataSource = writeLatexDataSource;
snapshotPostExceptionBuilder = new SnapshotPostExceptionBuilder();
fromJSON(new Gson().fromJson(contents, JsonElement.class));
}
@Override
public void fromJSON(JsonElement json) {
JsonObject responseObject = json.getAsJsonObject();
String code = responseObject.get("code").getAsString();
setResult(responseObject, code);
}
public void sendPostback() throws UnexpectedPostbackException {
if (exception == null) {
writeLatexDataSource.postbackReceivedSuccessfully(projectName, versionID);
} else {
writeLatexDataSource.postbackReceivedWithException(projectName, 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);
}
}
}

View file

@ -1,10 +1,9 @@
package uk.ac.ic.wlgitbridge.application;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
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.writelatex.api.request.push.UnexpectedPostbackException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -30,17 +29,24 @@ public class SnapshotPushPostbackHandler extends AbstractHandler {
// response.setContentType("text/html;charset=utf-8");
// response.setStatus(HttpServletResponse.SC_OK);
if (request.getMethod().equals("POST") && request.getPathInfo().endsWith("postback")) {
BufferedReader reader = request.getReader();
StringBuilder sb = new StringBuilder();
for (String line; (line = reader.readLine()) != null; ) {
sb.append(line);
String contents = getContentsOfReader(request.getReader());
String projectName = request.getRequestURI().split("/")[1];
SnapshotPushPostbackContents postbackContents = new SnapshotPushPostbackContents(writeLatexDataSource, projectName, contents);
try {
postbackContents.sendPostback();
} catch (UnexpectedPostbackException e) {
throw new ServletException();
}
String data = sb.toString();
JsonObject dataObj = new Gson().fromJson(data, JsonObject.class);
System.out.println(request.getRequestURI());
writeLatexDataSource.postbackReceivedSuccessfully(request.getRequestURI().split("/")[1]);
baseRequest.setHandled(true);
}
}
private static String getContentsOfReader(BufferedReader reader) throws IOException {
StringBuilder sb = new StringBuilder();
for (String line; (line = reader.readLine()) != null; ) {
sb.append(line);
}
return sb.toString();
}
}

View file

@ -3,6 +3,7 @@ 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.SnapshotPostException;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.UnexpectedPostbackException;
import java.io.IOException;
import java.util.List;
@ -16,10 +17,9 @@ public interface WriteLatexDataSource {
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;
public void expectPostback(String projectName);
/* Called by postback thread. */
public void postbackReceivedSuccessfully(String projectName);
public void postbackReceivedWithException(String projectName, SnapshotPostException exception);
public void postbackReceivedSuccessfully(String projectName, int versionID) throws UnexpectedPostbackException;
public void postbackReceivedWithException(String projectName, SnapshotPostException exception) throws UnexpectedPostbackException;
}

View file

@ -51,6 +51,7 @@ public class WriteLatexPutHook implements PreReceiveHook {
receiveCommand.setResult(Result.REJECTED_OTHER_REASON, message);
}
}
System.out.println("success");
}
private void handleReceiveCommand(Repository repository, ReceiveCommand receiveCommand) throws IOException, SnapshotPostException, FailedConnectionException {

View file

@ -1,5 +1,6 @@
package uk.ac.ic.wlgitbridge.git.handler.hook.exception;
import com.google.gson.JsonElement;
import uk.ac.ic.wlgitbridge.writelatex.SnapshotPostException;
import java.util.Arrays;
@ -26,4 +27,8 @@ public class ForcedPushException extends SnapshotPostException {
return Arrays.asList(DESCRIPTION_LINES);
}
@Override
public void fromJSON(JsonElement json) {
}
}

View file

@ -1,5 +1,8 @@
package uk.ac.ic.wlgitbridge.writelatex;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.List;
/**
@ -7,6 +10,10 @@ import java.util.List;
*/
public class InvalidFilesException extends SnapshotPostException {
public InvalidFilesException(JsonObject json) {
super(json);
}
@Override
public String getMessage() {
return null;
@ -17,4 +24,9 @@ public class InvalidFilesException extends SnapshotPostException {
return null;
}
@Override
public void fromJSON(JsonElement json) {
}
}

View file

@ -1,5 +1,7 @@
package uk.ac.ic.wlgitbridge.writelatex;
import com.google.gson.JsonElement;
import java.util.List;
/**
@ -7,6 +9,10 @@ import java.util.List;
*/
public class InvalidProjectException extends SnapshotPostException {
public InvalidProjectException(JsonElement jsonElement) {
super(jsonElement);
}
@Override
public String getMessage() {
return null;
@ -17,4 +23,9 @@ public class InvalidProjectException extends SnapshotPostException {
return null;
}
@Override
public void fromJSON(JsonElement json) {
}
}

View file

@ -1,5 +1,8 @@
package uk.ac.ic.wlgitbridge.writelatex;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.List;
/**
@ -7,6 +10,10 @@ import java.util.List;
*/
public class OutOfDateException extends SnapshotPostException {
public OutOfDateException(JsonObject json) {
super(json);
}
@Override
public String getMessage() {
return null;
@ -17,4 +24,9 @@ public class OutOfDateException extends SnapshotPostException {
return null;
}
@Override
public void fromJSON(JsonElement json) {
}
}

View file

@ -1,11 +1,22 @@
package uk.ac.ic.wlgitbridge.writelatex;
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 {
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();

View file

@ -1,5 +1,8 @@
package uk.ac.ic.wlgitbridge.writelatex;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.List;
/**
@ -7,6 +10,10 @@ import java.util.List;
*/
public class UnexpectedErrorException extends SnapshotPostException {
public UnexpectedErrorException(JsonObject json) {
super(json);
}
@Override
public String getMessage() {
return null;
@ -17,4 +24,9 @@ public class UnexpectedErrorException extends SnapshotPostException {
return null;
}
@Override
public void fromJSON(JsonElement json) {
}
}

View file

@ -7,7 +7,9 @@ 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.PostbackManager;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.SnapshotPushRequest;
import uk.ac.ic.wlgitbridge.writelatex.api.request.push.UnexpectedPostbackException;
import uk.ac.ic.wlgitbridge.writelatex.model.WLDataModel;
import java.io.IOException;
@ -21,13 +23,13 @@ import java.util.Map;
public class WriteLatexAPI implements WriteLatexDataSource {
private final WLDataModel dataModel;
private final Map<String, Object> postbackConds;
private final PostbackManager postbackManager;
boolean cond = false;
public WriteLatexAPI(WLDataModel dataModel) {
this.dataModel = dataModel;
postbackConds = new HashMap<String, Object>();
postbackManager = new PostbackManager();
}
@Override
@ -51,37 +53,18 @@ public class WriteLatexAPI implements WriteLatexDataSource {
public void putDirectoryContentsToProjectWithName(String projectName, RawDirectoryContents directoryContents, String hostname) throws SnapshotPostException, IOException, FailedConnectionException {
CandidateSnapshot candidate = dataModel.createCandidateSnapshotFromProjectWithContents(projectName, directoryContents, hostname);
new SnapshotPushRequest(candidate).request();
expectPostback(projectName);
candidate.approveWithVersionID(100);
}
@Override
public void expectPostback(String projectName) {
Object value = new Object();
postbackConds.put(projectName, value);
cond = false;
System.out.println("sleeping");
try {
while (!cond) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("finished sleep");
candidate.approveWithVersionID(postbackManager.getVersionID(projectName));
}
/* Called by postback thread. */
@Override
public void postbackReceivedSuccessfully(String projectName) {
System.out.println("successfully received postback for " + projectName);
cond = true;
notifyAll();
public void postbackReceivedSuccessfully(String projectName, int versionID) throws UnexpectedPostbackException {
postbackManager.postVersionIDForProject(projectName, versionID);
}
@Override
public void postbackReceivedWithException(String projectName, SnapshotPostException exception) {
postbackReceivedSuccessfully(projectName);
public void postbackReceivedWithException(String projectName, SnapshotPostException exception) throws UnexpectedPostbackException {
postbackManager.postExceptionForProject(projectName, exception);
}
}

View file

@ -1,13 +1,12 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.base;
import com.google.gson.JsonElement;
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
/**
* Created by Winston on 06/11/14.
*/
public interface JSONSource {
public abstract void fromJSON(JsonElement json) throws FailedConnectionException;
public abstract void fromJSON(JsonElement json);
}

View file

@ -1,7 +1,6 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.base;
import com.google.gson.JsonElement;
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
/**
* Created by Winston on 06/11/14.
@ -11,7 +10,7 @@ public abstract class Result implements JSONSource {
private JsonElement json;
private final Request request;
public Result(Request request, JsonElement json) throws FailedConnectionException {
public Result(Request request, JsonElement json) {
this.request = request;
this.json = json;
fromJSON(json);

View file

@ -1,7 +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.SnapshotPostException;
import java.util.List;
/**
* Created by Winston on 08/11/14.
*/
public class InvalidProjectException extends Exception {
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) {
}
}

View file

@ -10,7 +10,6 @@ import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionExc
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
@ -21,7 +20,7 @@ public class SnapshotAttachment extends SnapshotFile {
private Future<byte[]> future;
private String url;
public SnapshotAttachment(JsonElement json) throws FailedConnectionException {
public SnapshotAttachment(JsonElement json) {
super(json);
}
@ -38,7 +37,7 @@ public class SnapshotAttachment extends SnapshotFile {
}
@Override
protected void getContentsFromJSON(JsonArray jsonArray) throws FailedConnectionException {
protected void getContentsFromJSON(JsonArray jsonArray) {
url = jsonArray.get(0).getAsString();
// fetchContents(jsonArray.get(0).getAsString());
}

View file

@ -3,7 +3,6 @@ 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 uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
import java.util.LinkedList;
import java.util.List;
@ -19,25 +18,25 @@ public class SnapshotData implements JSONSource {
private List<SnapshotFile> srcs;
private List<SnapshotAttachment> atts;
public SnapshotData(JsonElement json) throws FailedConnectionException {
public SnapshotData(JsonElement json) {
srcs = new LinkedList<SnapshotFile>();
atts = new LinkedList<SnapshotAttachment>();
fromJSON(json);
}
@Override
public void fromJSON(JsonElement json) throws FailedConnectionException {
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) throws FailedConnectionException {
private void populateSrcs(JsonArray jsonArray) {
for (JsonElement json : jsonArray) {
srcs.add(new SnapshotFile(json));
}
}
private void populateAtts(JsonArray jsonArray) throws FailedConnectionException {
private void populateAtts(JsonArray jsonArray) {
for (JsonElement json : jsonArray) {
atts.add(new SnapshotAttachment(json));
}

View file

@ -4,7 +4,6 @@ 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;
import uk.ac.ic.wlgitbridge.writelatex.api.request.exception.FailedConnectionException;
/**
* Created by Winston on 06/11/14.
@ -14,7 +13,7 @@ public class SnapshotFile implements JSONSource, RawFile {
protected byte[] contents;
private String path;
public SnapshotFile(JsonElement json) throws FailedConnectionException {
public SnapshotFile(JsonElement json) {
fromJSON(json);
}
@ -29,13 +28,13 @@ public class SnapshotFile implements JSONSource, RawFile {
}
@Override
public void fromJSON(JsonElement json) throws FailedConnectionException {
public void fromJSON(JsonElement json) {
JsonArray jsonArray = json.getAsJsonArray();
getContentsFromJSON(jsonArray);
getPathFromJSON(jsonArray);
}
protected void getContentsFromJSON(JsonArray jsonArray) throws FailedConnectionException {
protected void getContentsFromJSON(JsonArray jsonArray) {
contents = jsonArray.get(0).getAsString().getBytes();
}

View file

@ -12,12 +12,12 @@ public class SnapshotGetForVersionResult extends Result {
private SnapshotData snapshotData;
public SnapshotGetForVersionResult(Request request, JsonElement json) throws FailedConnectionException {
public SnapshotGetForVersionResult(Request request, JsonElement json) {
super(request, json);
}
@Override
public void fromJSON(JsonElement json) throws FailedConnectionException {
public void fromJSON(JsonElement json) {
snapshotData = new SnapshotData(json);
}

View file

@ -0,0 +1,44 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.push;
import uk.ac.ic.wlgitbridge.writelatex.SnapshotPostException;
/**
* Created by Winston on 17/11/14.
*/
public class PostbackContents {
private boolean received;
private int versionID;
private SnapshotPostException exception;
public PostbackContents() {
received = false;
}
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) {
this.versionID = versionID;
received = true;
notifyAll();
}
public synchronized void receivedException(SnapshotPostException exception) {
this.exception = exception;
received = true;
notifyAll();
}
}

View file

@ -0,0 +1,43 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.push;
import uk.ac.ic.wlgitbridge.writelatex.SnapshotPostException;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Winston on 17/11/14.
*/
public class PostbackManager {
private final Map<String, PostbackContents> postbackContentsTable;
public PostbackManager() {
postbackContentsTable = new HashMap<String, PostbackContents>();
}
public int getVersionID(String projectName) throws SnapshotPostException {
PostbackContents contents = new PostbackContents();
postbackContentsTable.put(projectName, contents);
int versionID = contents.waitForPostback();
postbackContentsTable.remove(projectName);
return versionID;
}
public void postVersionIDForProject(String projectName, int versionID) throws UnexpectedPostbackException {
getPostbackForProject(projectName).receivedVersionID(versionID);
}
public void postExceptionForProject(String projectName, SnapshotPostException exception) throws UnexpectedPostbackException {
getPostbackForProject(projectName).receivedException(exception);
}
private PostbackContents getPostbackForProject(String projectName) throws UnexpectedPostbackException {
PostbackContents contents = postbackContentsTable.get(projectName);
if (contents == null) {
throw new UnexpectedPostbackException();
}
return contents;
}
}

View file

@ -15,7 +15,7 @@ public class SnapshotPushRequestResult extends Result {
}
@Override
public void fromJSON(JsonElement json) throws FailedConnectionException {
public void fromJSON(JsonElement json) {
}

View file

@ -0,0 +1,7 @@
package uk.ac.ic.wlgitbridge.writelatex.api.request.push;
/**
* Created by Winston on 17/11/14.
*/
public class UnexpectedPostbackException extends Throwable {
}

View file

@ -60,7 +60,7 @@ public class WLFileStore {
return getDirectoryNodeForProjectName(project.getName()).createFromRawDirectoryContents(directoryContents, attDirectory);
}
public void approveCandidateSnapshot(int versionID, CandidateSnapshot candidateSnapshot) {
public void approveCandidateSnapshot(CandidateSnapshot candidateSnapshot) {
fileStore.put(candidateSnapshot.getProjectName(), candidateSnapshot.getDirectoryNode());
}

View file

@ -54,7 +54,7 @@ public class WLDataModel implements CandidateSnapshotCallback {
@Override
public void approveSnapshot(int versionID, CandidateSnapshot candidateSnapshot) {
getProjectWithName(candidateSnapshot.getProjectName()).putLatestSnapshot(versionID);
fileStore.approveCandidateSnapshot(versionID, candidateSnapshot);
fileStore.approveCandidateSnapshot(candidateSnapshot);
}
}