Winston Li 10 лет назад
Родитель
Сommit
25a988daa3
83 измененных файлов с 1449 добавлено и 480 удалено
  1. 19 0
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/Main.java
  2. 0 6
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/application/GitBridgeApp.java
  3. 4 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/application/config/Config.java
  4. 5 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/application/config/Oauth2.java
  5. 1 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/application/exception/ArgsException.java
  6. 350 18
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/Bridge.java
  7. 4 9
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/SqliteDBStore.java
  8. 3 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetLatestVersionForProjectSQLQuery.java
  9. 7 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetPathForURLInProjectSQLQuery.java
  10. 5 3
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetProjectNamesSQLQuery.java
  11. 6 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetProjectState.java
  12. 4 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/delete/DeleteFilesForProjectSQLUpdate.java
  13. 6 3
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/insert/SetProjectSQLUpdate.java
  14. 2 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepo.java
  15. 3 3
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/ProjectRepo.java
  16. 9 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/resource/ResourceCache.java
  17. 34 8
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/resource/UrlResourceCache.java
  18. 63 18
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/snapshot/NetSnapshotAPI.java
  19. 4 14
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/swap/job/NoopSwapJob.java
  20. 1 0
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/swap/job/SwapJob.java
  21. 3 10
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/swap/store/NoopSwapStore.java
  22. 1 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/data/LockAllWaiter.java
  23. 0 10
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/data/SnapshotFetcher.java
  24. 1 0
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/data/filestore/RawFile.java
  25. 0 9
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/data/model/ResourceFetcher.java
  26. 1 0
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/exception/GitUserException.java
  27. 0 8
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/exception/InvalidRootDirectoryPathException.java
  28. 5 3
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/exception/SizeLimitExceededException.java
  29. 1 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/exception/SnapshotAPIException.java
  30. 38 7
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/handler/WLReceivePackFactory.java
  31. 45 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/handler/WLRepositoryResolver.java
  32. 27 5
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/handler/WLUploadPackFactory.java
  33. 76 18
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/handler/hook/WriteLatexPutHook.java
  34. 6 5
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/handler/hook/exception/ForcedPushException.java
  35. 24 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/servlet/WLGitServlet.java
  36. 24 11
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/util/RepositoryObjectTreeWalker.java
  37. 18 10
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/FileHandler.java
  38. 4 4
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/GitBridgeServer.java
  39. 69 26
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/Oauth2Filter.java
  40. 20 4
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/PostbackContents.java
  41. 21 4
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/PostbackHandler.java
  42. 2 3
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/ForbiddenException.java
  43. 1 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/JSONSource.java
  44. 14 12
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/SnapshotAPIRequest.java
  45. 3 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getdoc/GetDocRequest.java
  46. 14 3
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getdoc/GetDocResult.java
  47. 0 29
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getdoc/exception/ProtectedProjectException.java
  48. 10 3
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getforversion/GetForVersionRequest.java
  49. 14 6
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getforversion/SnapshotData.java
  50. 5 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getsavedvers/GetSavedVersRequest.java
  51. 13 5
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getsavedvers/GetSavedVersResult.java
  52. 21 3
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getsavedvers/SnapshotInfo.java
  53. 3 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getsavedvers/WLUser.java
  54. 15 11
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/PostbackManager.java
  55. 7 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/PostbackPromise.java
  56. 8 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/PushRequest.java
  57. 4 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/PushResult.java
  58. 5 5
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/InternalErrorException.java
  59. 13 5
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/InvalidFilesException.java
  60. 1 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/InvalidPostbackKeyException.java
  61. 2 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/InvalidProjectException.java
  62. 2 6
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/OutOfDateException.java
  63. 7 4
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/PostbackTimeoutException.java
  64. 1 3
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/SnapshotPostException.java
  65. 4 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/SnapshotPostExceptionBuilder.java
  66. 3 4
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/UnexpectedErrorException.java
  67. 1 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/UnexpectedPostbackException.java
  68. 11 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/Main.java
  69. 34 11
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/response/SnapshotResponseBuilder.java
  70. 4 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/response/push/SnapshotPushResponse.java
  71. 3 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/response/push/postback/SnapshotPostbackRequestInvalidFiles.java
  72. 2 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/response/push/postback/SnapshotPostbackRequestInvalidProject.java
  73. 6 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/response/push/postback/invalidfile/InvalidFileError.java
  74. 20 7
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/server/MockSnapshotRequestHandler.java
  75. 7 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/server/PostbackThread.java
  76. 73 19
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIState.java
  77. 105 42
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIStateBuilder.java
  78. 0 10
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIStateManager.java
  79. 63 13
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/util/FileUtil.java
  80. 4 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/util/Files.java
  81. 2 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/util/Instance.java
  82. 27 11
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/util/Util.java
  83. 1 1
      services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java

+ 19 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/Main.java

@@ -1,11 +1,30 @@
 package uk.ac.ic.wlgitbridge;
 package uk.ac.ic.wlgitbridge;
 
 
 import uk.ac.ic.wlgitbridge.application.GitBridgeApp;
 import uk.ac.ic.wlgitbridge.application.GitBridgeApp;
+import uk.ac.ic.wlgitbridge.bridge.Bridge;
+import uk.ac.ic.wlgitbridge.server.GitBridgeServer;
 import uk.ac.ic.wlgitbridge.util.Log;
 import uk.ac.ic.wlgitbridge.util.Log;
 
 
 /**
 /**
  * Created by Winston on 01/11/14.
  * Created by Winston on 01/11/14.
  */
  */
+
+/**
+ * This is the entry point into the Git Bridge.
+ *
+ * It is responsible for creating the {@link GitBridgeApp} and then running it.
+ *
+ * The {@link GitBridgeApp} parses args and creates the {@link GitBridgeServer}.
+ *
+ * The {@link GitBridgeServer} creates the {@link Bridge}, among other things.
+ *
+ * The {@link Bridge} is the heart of the Git Bridge. Start there, and follow
+ * the links outwards (which lead back to the Git users and the postback from
+ * the snapshot API) and inwards (which lead into the components of the Git
+ * Bridge: the configurable repo store, db store, and swap store, along with
+ * the project lock, the swap job, the snapshot API, the resource cache
+ * and the postback manager).
+ */
 public class Main {
 public class Main {
 
 
     public static void main(String[] args) {
     public static void main(String[] args) {

+ 0 - 6
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/application/GitBridgeApp.java

@@ -3,7 +3,6 @@ package uk.ac.ic.wlgitbridge.application;
 import uk.ac.ic.wlgitbridge.application.config.Config;
 import uk.ac.ic.wlgitbridge.application.config.Config;
 import uk.ac.ic.wlgitbridge.application.exception.ArgsException;
 import uk.ac.ic.wlgitbridge.application.exception.ArgsException;
 import uk.ac.ic.wlgitbridge.application.exception.ConfigFileException;
 import uk.ac.ic.wlgitbridge.application.exception.ConfigFileException;
-import uk.ac.ic.wlgitbridge.git.exception.InvalidRootDirectoryPathException;
 import uk.ac.ic.wlgitbridge.server.GitBridgeServer;
 import uk.ac.ic.wlgitbridge.server.GitBridgeServer;
 import uk.ac.ic.wlgitbridge.util.Log;
 import uk.ac.ic.wlgitbridge.util.Log;
 
 
@@ -58,11 +57,6 @@ public class GitBridgeApp implements Runnable {
                     "Servlet exception when instantiating GitBridgeServer",
                     "Servlet exception when instantiating GitBridgeServer",
                     e
                     e
             );
             );
-        } catch (InvalidRootDirectoryPathException e) {
-            Log.error(
-                    "Invalid root git directory path. Check your config file."
-            );
-            System.exit(EXIT_CODE_FAILED);
         }
         }
     }
     }
 
 

+ 4 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/application/config/Config.java

@@ -49,8 +49,10 @@ public class Config implements JSONSource {
     @Nullable
     @Nullable
     private SwapJobConfig swapJob;
     private SwapJobConfig swapJob;
 
 
-    public Config(String configFilePath) throws ConfigFileException,
-                                                IOException {
+    public Config(
+            String configFilePath
+    ) throws ConfigFileException,
+             IOException {
         this(new FileReader(configFilePath));
         this(new FileReader(configFilePath));
     }
     }
 
 

+ 5 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/application/config/Oauth2.java

@@ -9,7 +9,11 @@ public class Oauth2 {
     private final String oauth2ClientSecret;
     private final String oauth2ClientSecret;
     private final String oauth2Server;
     private final String oauth2Server;
 
 
-    public Oauth2(String oauth2ClientID, String oauth2ClientSecret, String oauth2Server) {
+    public Oauth2(
+            String oauth2ClientID,
+            String oauth2ClientSecret,
+            String oauth2Server
+    ) {
         this.oauth2ClientID = oauth2ClientID;
         this.oauth2ClientID = oauth2ClientID;
         this.oauth2ClientSecret = oauth2ClientSecret;
         this.oauth2ClientSecret = oauth2ClientSecret;
         this.oauth2Server = oauth2Server;
         this.oauth2Server = oauth2Server;

+ 1 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/application/exception/ArgsException.java

@@ -3,5 +3,4 @@ package uk.ac.ic.wlgitbridge.application.exception;
 /**
 /**
  * Created by Winston on 03/11/14.
  * Created by Winston on 03/11/14.
  */
  */
-public class ArgsException extends Exception {
-}
+public class ArgsException extends Exception {}

+ 350 - 18
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/Bridge.java

@@ -4,8 +4,11 @@ import com.google.api.client.auth.oauth2.Credential;
 import org.eclipse.jgit.transport.ServiceMayNotContinueException;
 import org.eclipse.jgit.transport.ServiceMayNotContinueException;
 import uk.ac.ic.wlgitbridge.bridge.db.DBStore;
 import uk.ac.ic.wlgitbridge.bridge.db.DBStore;
 import uk.ac.ic.wlgitbridge.bridge.db.ProjectState;
 import uk.ac.ic.wlgitbridge.bridge.db.ProjectState;
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SqliteDBStore;
 import uk.ac.ic.wlgitbridge.bridge.lock.LockGuard;
 import uk.ac.ic.wlgitbridge.bridge.lock.LockGuard;
 import uk.ac.ic.wlgitbridge.bridge.lock.ProjectLock;
 import uk.ac.ic.wlgitbridge.bridge.lock.ProjectLock;
+import uk.ac.ic.wlgitbridge.bridge.repo.FSGitRepoStore;
+import uk.ac.ic.wlgitbridge.bridge.repo.GitProjectRepo;
 import uk.ac.ic.wlgitbridge.bridge.repo.ProjectRepo;
 import uk.ac.ic.wlgitbridge.bridge.repo.ProjectRepo;
 import uk.ac.ic.wlgitbridge.bridge.repo.RepoStore;
 import uk.ac.ic.wlgitbridge.bridge.repo.RepoStore;
 import uk.ac.ic.wlgitbridge.bridge.resource.ResourceCache;
 import uk.ac.ic.wlgitbridge.bridge.resource.ResourceCache;
@@ -14,6 +17,8 @@ import uk.ac.ic.wlgitbridge.bridge.snapshot.NetSnapshotAPI;
 import uk.ac.ic.wlgitbridge.bridge.snapshot.SnapshotAPI;
 import uk.ac.ic.wlgitbridge.bridge.snapshot.SnapshotAPI;
 import uk.ac.ic.wlgitbridge.bridge.swap.job.SwapJob;
 import uk.ac.ic.wlgitbridge.bridge.swap.job.SwapJob;
 import uk.ac.ic.wlgitbridge.bridge.swap.job.SwapJobConfig;
 import uk.ac.ic.wlgitbridge.bridge.swap.job.SwapJobConfig;
+import uk.ac.ic.wlgitbridge.bridge.swap.job.SwapJobImpl;
+import uk.ac.ic.wlgitbridge.bridge.swap.store.S3SwapStore;
 import uk.ac.ic.wlgitbridge.bridge.swap.store.SwapStore;
 import uk.ac.ic.wlgitbridge.bridge.swap.store.SwapStore;
 import uk.ac.ic.wlgitbridge.data.CandidateSnapshot;
 import uk.ac.ic.wlgitbridge.data.CandidateSnapshot;
 import uk.ac.ic.wlgitbridge.data.ProjectLockImpl;
 import uk.ac.ic.wlgitbridge.data.ProjectLockImpl;
@@ -22,11 +27,20 @@ import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory;
 import uk.ac.ic.wlgitbridge.data.filestore.RawFile;
 import uk.ac.ic.wlgitbridge.data.filestore.RawFile;
 import uk.ac.ic.wlgitbridge.data.model.Snapshot;
 import uk.ac.ic.wlgitbridge.data.model.Snapshot;
 import uk.ac.ic.wlgitbridge.git.exception.GitUserException;
 import uk.ac.ic.wlgitbridge.git.exception.GitUserException;
+import uk.ac.ic.wlgitbridge.git.exception.SizeLimitExceededException;
+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.git.handler.hook.WriteLatexPutHook;
+import uk.ac.ic.wlgitbridge.server.FileHandler;
+import uk.ac.ic.wlgitbridge.server.PostbackContents;
+import uk.ac.ic.wlgitbridge.server.PostbackHandler;
 import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
 import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
 import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocRequest;
 import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocRequest;
 import uk.ac.ic.wlgitbridge.snapshot.getdoc.exception.InvalidProjectException;
 import uk.ac.ic.wlgitbridge.snapshot.getdoc.exception.InvalidProjectException;
 import uk.ac.ic.wlgitbridge.snapshot.getforversion.SnapshotAttachment;
 import uk.ac.ic.wlgitbridge.snapshot.getforversion.SnapshotAttachment;
 import uk.ac.ic.wlgitbridge.snapshot.push.PostbackManager;
 import uk.ac.ic.wlgitbridge.snapshot.push.PostbackManager;
+import uk.ac.ic.wlgitbridge.snapshot.push.PostbackPromise;
 import uk.ac.ic.wlgitbridge.snapshot.push.PushRequest;
 import uk.ac.ic.wlgitbridge.snapshot.push.PushRequest;
 import uk.ac.ic.wlgitbridge.snapshot.push.PushResult;
 import uk.ac.ic.wlgitbridge.snapshot.push.PushResult;
 import uk.ac.ic.wlgitbridge.snapshot.push.exception.*;
 import uk.ac.ic.wlgitbridge.snapshot.push.exception.*;
@@ -41,6 +55,91 @@ import java.util.*;
 /**
 /**
  * Created by Winston on 16/11/14.
  * Created by Winston on 16/11/14.
  */
  */
+/**
+ * This is the heart of the Git Bridge. You plug in all the parts (project
+ * lock, repo store, db store, swap store, snapshot api, resource cache and
+ * postback manager) is called by Git user requests and Overleaf postback
+ * requests.
+ *
+ * Follow these links to go "outward" (to input from Git users and Overleaf):
+ *
+ * 1. JGit hooks, which handle user Git requests:
+ *
+ *    @see WLRepositoryResolver - used on all requests associate a repo with a
+ *                                project name, or fail
+ *
+*     @see WLUploadPackFactory - used to handle clones and fetches
+ *
+ *    @see WLReceivePackFactory - used to handle pushes by setting a hook
+ *    @see WriteLatexPutHook - the hook used to handle pushes
+ *
+ * 2. The Postback Servlet, which handles postbacks from the Overleaf app
+ *    to confirm that a project is pushed. If a postback is lost, it's fine, we
+ *    just update ourselves on the next access.
+ *
+ *    @see PostbackHandler - the entry point for postbacks
+ *
+ * Follow these links to go "inward" (to the Git Bridge components):
+ *
+ * 1. The Project Lock, used to synchronise accesses to projects and shutdown
+ *    the Git Bridge gracefully by preventing further lock acquiring.
+ *
+ *    @see ProjectLock - the interface used for the Project Lock
+ *    @see ProjectLockImpl - the default concrete implementation
+ *
+ * 2. The Repo Store, used to provide repository objects.
+ *
+ *    The default implementation uses Git on the file system.
+ *
+ *    @see RepoStore - the interface for the Repo Store
+ *    @see FSGitRepoStore - the default concrete implementation
+ *    @see ProjectRepo - an interface for an actual repo instance
+ *    @see GitProjectRepo - the default concrete implementation
+ *
+ * 3. The DB Store, used to store persistent data such as the latest version
+ *    of each project that we have (used for querying the Snapshot API), along
+ *    with caching remote blobs.
+ *
+ *    The default implementation is SQLite based.
+ *
+ *    @see DBStore - the interface for the DB store
+ *    @see SqliteDBStore - the default concrete implementation
+ *
+ * 4. The Swap Store, used to swap projects to when the disk goes over a
+ *    certain data usage.
+ *
+ *    The default implementation tarbzips projects to/from Amazon S3.
+ *
+ *    @see SwapStore - the interface for the Swap Store
+ *    @see S3SwapStore - the default concrete implementation
+ *
+ * 5. The Swap Job, which performs the actual swapping on the swap store based
+ *    on various configuration options.
+ *
+ *    @see SwapJob - the interface for the Swap Job
+ *    @see SwapJobImpl - the default concrete implementation
+ *
+ * 6. The Snapshot API, which provides data from the Overleaf app.
+ *
+ *    @see SnapshotAPI - the interface for the Snapshot API.
+ *    @see NetSnapshotAPI - the default concrete implementation
+ *
+ * 7. The Resource Cache, which provides the data for attachment resources from
+ *    URLs. It will generally fetch from the source on a cache miss.
+ *
+ *    The default implementation uses the DB Store to maintain a mapping from
+ *    URLs to files in an actual repo.
+ *
+ *    @see ResourceCache - the interface for the Resource Cache
+ *    @see UrlResourceCache - the default concrete implementation
+ *
+ * 8. The Postback Manager, which keeps track of pending postbacks. It stores a
+ *    mapping from project names to postback promises.
+ *
+ *    @see PostbackManager - the class
+ *    @see PostbackPromise - the object waited on for a postback.
+ *
+ */
 public class Bridge {
 public class Bridge {
 
 
     private final ProjectLock lock;
     private final ProjectLock lock;
@@ -53,9 +152,19 @@ public class Bridge {
     private final SnapshotAPI snapshotAPI;
     private final SnapshotAPI snapshotAPI;
     private final ResourceCache resourceCache;
     private final ResourceCache resourceCache;
 
 
-
     private final PostbackManager postbackManager;
     private final PostbackManager postbackManager;
 
 
+    /**
+     * Creates a Bridge from its configurable parts, which are the repo, db and
+     * swap store, and the swap job config.
+     *
+     * This should be the method used to create a Bridge.
+     * @param repoStore The repo store to use
+     * @param dbStore The db store to use
+     * @param swapStore The swap store to use
+     * @param swapJobConfig The swap config to use, or empty for no-op
+     * @return The constructed Bridge.
+     */
     public static Bridge make(
     public static Bridge make(
             RepoStore repoStore,
             RepoStore repoStore,
             DBStore dbStore,
             DBStore dbStore,
@@ -82,6 +191,18 @@ public class Bridge {
         );
         );
     }
     }
 
 
+    /**
+     * Creates a bridge from all of its components, not just its configurable
+     * parts. This is for substituting mock/stub components for testing.
+     * It's also used by Bridge.make to actually construct the bridge.
+     * @param lock the {@link ProjectLock} to use
+     * @param repoStore the {@link RepoStore} to use
+     * @param dbStore the {@link DBStore} to use
+     * @param swapStore the {@link SwapStore} to use
+     * @param swapJob the {@link SwapJob} to use
+     * @param snapshotAPI the {@link SnapshotAPI} to use
+     * @param resourceCache the {@link ResourceCache} to use
+     */
     Bridge(
     Bridge(
             ProjectLock lock,
             ProjectLock lock,
             RepoStore repoStore,
             RepoStore repoStore,
@@ -103,6 +224,15 @@ public class Bridge {
         repoStore.purgeNonexistentProjects(dbStore.getProjectNames());
         repoStore.purgeNonexistentProjects(dbStore.getProjectNames());
     }
     }
 
 
+    /**
+     * This performs the graceful shutdown of the Bridge, which is called by the
+     * shutdown hook. It acquires the project write lock, which prevents
+     * work being done for new projects (which acquire the read lock).
+     * Once it has the write lock, there are no readers left, so the git bridge
+     * can shut down gracefully.
+     *
+     * It is also used by the tests.
+     */
     void doShutdown() {
     void doShutdown() {
         Log.info("Shutdown received.");
         Log.info("Shutdown received.");
         Log.info("Stopping SwapJob");
         Log.info("Stopping SwapJob");
@@ -112,10 +242,18 @@ public class Bridge {
         Log.info("Bye");
         Log.info("Bye");
     }
     }
 
 
+    /**
+     * Starts the swap job, which will begin checking whether projects should be
+     * swapped with a configurable frequency.
+     */
     public void startSwapJob() {
     public void startSwapJob() {
         swapJob.start();
         swapJob.start();
     }
     }
 
 
+    /**
+     * Performs a check of inconsistencies in the DB. This was used to upgrade
+     * the schema.
+     */
     public void checkDB() {
     public void checkDB() {
         Log.info("Checking DB");
         Log.info("Checking DB");
         File rootDir = repoStore.getRootDirectory();
         File rootDir = repoStore.getRootDirectory();
@@ -143,6 +281,19 @@ public class Bridge {
         }
         }
     }
     }
 
 
+    /**
+     * Checks if a project exists by asking the snapshot API.
+     *
+     * The snapshot API is the source of truth because we can't know by
+     * ourselves whether a project exists. If a user creates a project on the
+     * app, and clones, the project is not on the git bridge disk and must ask
+     * the snapshot API whether it exists.
+     * @param oauth2 The oauth2 to use for the snapshot API
+     * @param projectName The project name
+     * @return true iff the project exists
+     * @throws ServiceMayNotContinueException if the connection fails
+     * @throws GitUserException if the user is not allowed access
+     */
     public boolean projectExists(
     public boolean projectExists(
             Credential oauth2,
             Credential oauth2,
             String projectName
             String projectName
@@ -161,6 +312,16 @@ public class Bridge {
         }
         }
     }
     }
 
 
+    /**
+     * Synchronises the given repository with Overleaf.
+     *
+     * It acquires the project lock and calls
+     * {@link #updateRepositoryCritical(Credential, ProjectRepo)}
+     * @param oauth2 The oauth2 to use
+     * @param repo the repository to use
+     * @throws IOException
+     * @throws GitUserException
+     */
     public void updateRepository(
     public void updateRepository(
             Credential oauth2,
             Credential oauth2,
             ProjectRepo repo
             ProjectRepo repo
@@ -172,6 +333,24 @@ public class Bridge {
         }
         }
     }
     }
 
 
+    /**
+     * Synchronises the given repository with Overleaf. The project lock must
+     * be acquired.
+     *
+     * If the project has never been cloned, it is git init'd. If the project
+     * is in swap, it is restored to disk. Otherwise, the project was already
+     * present.
+     *
+     * With the project present, snapshots are downloaded from the snapshot
+     * API with {@link #updateProject(Credential, ProjectRepo)}.
+     *
+     * Then, the last accessed time of the project is set to the current time.
+     * This is to support the LRU of the swap store.
+     * @param oauth2
+     * @param repo
+     * @throws IOException
+     * @throws GitUserException
+     */
     private void updateRepositoryCritical(
     private void updateRepositoryCritical(
             Credential oauth2,
             Credential oauth2,
             ProjectRepo repo
             ProjectRepo repo
@@ -195,7 +374,25 @@ public class Bridge {
         );
         );
     }
     }
 
 
-    public void putDirectoryContentsToProjectWithName(
+    /**
+     * The public call to push a project.
+     *
+     * It acquires the lock and calls {@link #pushCritical(
+     *      Credential,
+     *      String,
+     *      RawDirectory,
+     *      RawDirectory
+     * )}, catching exceptions, logging, and rethrowing them.
+     * @param oauth2 The oauth2 to use for the snapshot API
+     * @param projectName The name of the project to push to
+     * @param directoryContents The new contents of the project
+     * @param oldDirectoryContents The old contents of the project
+     * @param hostname
+     * @throws SnapshotPostException
+     * @throws IOException
+     * @throws ForbiddenException
+     */
+    public void push(
             Credential oauth2,
             Credential oauth2,
             String projectName,
             String projectName,
             RawDirectory directoryContents,
             RawDirectory directoryContents,
@@ -203,7 +400,7 @@ public class Bridge {
             String hostname
             String hostname
     ) throws SnapshotPostException, IOException, ForbiddenException {
     ) throws SnapshotPostException, IOException, ForbiddenException {
         try (LockGuard __ = lock.lockGuard(projectName)) {
         try (LockGuard __ = lock.lockGuard(projectName)) {
-            pushToProjectCritical(
+            pushCritical(
                     oauth2,
                     oauth2,
                     projectName,
                     projectName,
                     directoryContents,
                     directoryContents,
@@ -226,7 +423,51 @@ public class Bridge {
         }
         }
     }
     }
 
 
-    private void pushToProjectCritical(
+    /**
+     * Does the work of pushing to a project, assuming the project lock is held.
+     * The {@link WriteLatexPutHook} is the original caller, and when we return
+     * without throwing, the commit is committed.
+     *
+     * We start off by creating a postback key, which is given in the url when
+     * the Overleaf app tries to access the atts.
+     *
+     * Then creates a {@link CandidateSnapshot} from the old and new project
+     * contents. The
+     * {@link CandidateSnapshot} is created using
+     * {@link #createCandidateSnapshot(String, RawDirectory, RawDirectory)},
+     * which creates the snapshot object and writes the push files to the
+     * atts directory, which is served by the {@link PostbackHandler}.
+     * The files are deleted at the end of a try-with-resources block.
+     *
+     * Then 3 things are used to make the push request to the snapshot API:
+     * 1. The oauth2
+     * 2. The candidate snapshot
+     * 3. The postback key
+     *
+     * If the snapshot API reports this as not successful, we immediately throw
+     * an {@link OutOfDateException}, which goes back to the user.
+     *
+     * Otherwise, we wait (with a timeout) on a promise from the postback
+     * manager, which can throw back to the user.
+     *
+     * If this is successful, we approve the snapshot with
+     * {@link #approveSnapshot(int, CandidateSnapshot)}, which updates our side
+     * of the push: the latest version and the URL index store.
+     *
+     * Then, we set the last accessed time for the swap store.
+     *
+     * Finally, after we return, the push to the repo from the hook is
+     * successful and the repo gets updated.
+     *
+     * @param oauth2
+     * @param projectName
+     * @param directoryContents
+     * @param oldDirectoryContents
+     * @throws IOException
+     * @throws ForbiddenException
+     * @throws SnapshotPostException
+     */
+    private void pushCritical(
             Credential oauth2,
             Credential oauth2,
             String projectName,
             String projectName,
             RawDirectory directoryContents,
             RawDirectory directoryContents,
@@ -291,16 +532,45 @@ public class Bridge {
         }
         }
     }
     }
 
 
+    /**
+     * A public call that should originate from the {@link FileHandler}.
+     *
+     * The {@link FileHandler} serves atts to the Overleaf app during a push.
+     * The Overleaf app includes the postback key in the request, which was
+     * originally given on a push request.
+     *
+     * This method checks that the postback key matches, and throws if not.
+     *
+     * The FileHandler should not serve the file if this throws.
+     * @param projectName The project name that this key belongs to
+     * @param postbackKey The key
+     * @throws InvalidPostbackKeyException If the key doesn't match
+     */
     public void checkPostbackKey(String projectName, String postbackKey)
     public void checkPostbackKey(String projectName, String postbackKey)
             throws InvalidPostbackKeyException {
             throws InvalidPostbackKeyException {
         postbackManager.checkPostbackKey(projectName, postbackKey);
         postbackManager.checkPostbackKey(projectName, postbackKey);
     }
     }
 
 
-    /* Called by postback thread. */
-    public void postbackReceivedSuccessfully(String projectName,
-                                             String postbackKey,
-                                             int versionID)
-            throws UnexpectedPostbackException {
+    /**
+     * A public call that originates from the postback thread
+     * {@link PostbackContents#processPostback()}, i.e. once the Overleaf app
+     * has fetched all the atts and has committed the push and is happy, it
+     * calls back here, fulfilling the promise that the push
+     * {@link #push(Credential, String, RawDirectory, RawDirectory, String)}
+     * is waiting on.
+     *
+     * The Overleaf app will have invented a new version for the push, which is
+     * passed to the promise for the original push request to update the app.
+     * @param projectName The name of the project being pushed to
+     * @param postbackKey The postback key being used
+     * @param versionID the new version id to use
+     * @throws UnexpectedPostbackException if the postback key is invalid
+     */
+    public void postbackReceivedSuccessfully(
+            String projectName,
+            String postbackKey,
+            int versionID
+    ) throws UnexpectedPostbackException {
         Log.info(
         Log.info(
                 "[{}]" +
                 "[{}]" +
                         " Postback received by postback thread, version: {}",
                         " Postback received by postback thread, version: {}",
@@ -313,10 +583,23 @@ public class Bridge {
         );
         );
     }
     }
 
 
-    public void postbackReceivedWithException(String projectName,
-                                              String postbackKey,
-                                              SnapshotPostException exception)
-            throws UnexpectedPostbackException {
+    /**
+     * As with {@link #postbackReceivedSuccessfully(String, String, int)},
+     * but with an exception instead.
+     *
+     * This is based on the JSON body of the postback from the Overleaf app.
+     *
+     * The most likely problem is an {@link OutOfDateException}.
+     * @param projectName The name of the project
+     * @param postbackKey The postback key being used
+     * @param exception The exception encountered
+     * @throws UnexpectedPostbackException If the postback key is invalid
+     */
+    public void postbackReceivedWithException(
+            String projectName,
+            String postbackKey,
+            SnapshotPostException exception
+    ) throws UnexpectedPostbackException {
         Log.warn("[{}] Postback received with exception", projectName);
         Log.warn("[{}] Postback received with exception", projectName);
         postbackManager.postExceptionForProject(
         postbackManager.postExceptionForProject(
                 projectName,
                 projectName,
@@ -327,6 +610,19 @@ public class Bridge {
 
 
     /* PRIVATE */
     /* PRIVATE */
 
 
+    /**
+     * Called by {@link #updateRepositoryCritical(Credential, ProjectRepo)}.
+     *
+     * Does the actual work of getting the snapshots for a project from the
+     * snapshot API and committing them to a repo.
+     *
+     * If any snapshots were found, sets the latest version for the project.
+     *
+     * @param oauth2
+     * @param repo
+     * @throws IOException
+     * @throws GitUserException
+     */
     private void updateProject(
     private void updateProject(
             Credential oauth2,
             Credential oauth2,
             ProjectRepo repo
             ProjectRepo repo
@@ -349,9 +645,23 @@ public class Bridge {
         }
         }
     }
     }
 
 
-    private void makeCommitsFromSnapshots(ProjectRepo repo,
-                                          Collection<Snapshot> snapshots)
-            throws IOException, GitUserException {
+    /**
+     * Called by {@link #updateProject(Credential, ProjectRepo)}.
+     *
+     * Performs the actual Git commits on the disk.
+     *
+     * Each commit adds files to the db store
+     * ({@link ResourceCache#get(String, String, String, Map, Map)},
+     * and then removes any files that were deleted.
+     * @param repo The repository to commit to
+     * @param snapshots The snapshots to commit
+     * @throws IOException If an IOException occurred
+     * @throws SizeLimitExceededException If one of the files was too big.
+     */
+    private void makeCommitsFromSnapshots(
+            ProjectRepo repo,
+            Collection<Snapshot> snapshots
+    ) throws IOException, SizeLimitExceededException {
         String name = repo.getProjectName();
         String name = repo.getProjectName();
         for (Snapshot snapshot : snapshots) {
         for (Snapshot snapshot : snapshots) {
             Map<String, RawFile> fileTable = repo.getFiles();
             Map<String, RawFile> fileTable = repo.getFiles();
@@ -389,6 +699,20 @@ public class Bridge {
         }
         }
     }
     }
 
 
+    /**
+     * Called by
+     * {@link #pushCritical(Credential, String, RawDirectory, RawDirectory)}.
+     *
+     * This call consists of 2 things: Creating the candidate snapshot,
+     * and writing the atts to the atts directory.
+     *
+     * The candidate snapshot RAIIs away those atts (use try-with-resources).
+     * @param projectName The name of the project
+     * @param directoryContents The new directory contents
+     * @param oldDirectoryContents The old directory contents
+     * @return The {@link CandidateSnapshot} created
+     * @throws IOException If an I/O exception occurred on writing
+     */
     private CandidateSnapshot createCandidateSnapshot(
     private CandidateSnapshot createCandidateSnapshot(
             String projectName,
             String projectName,
             RawDirectory directoryContents,
             RawDirectory directoryContents,
@@ -404,6 +728,16 @@ public class Bridge {
         return candidateSnapshot;
         return candidateSnapshot;
     }
     }
 
 
+    /**
+     * Called by
+     * {@link #pushCritical(Credential, String, RawDirectory, RawDirectory)}.
+     *
+     * This method approves a push by setting the latest version and removing
+     * any deleted files from the db store (files were already added by the
+     * resources cache).
+     * @param versionID
+     * @param candidateSnapshot
+     */
     private void approveSnapshot(
     private void approveSnapshot(
             int versionID,
             int versionID,
             CandidateSnapshot candidateSnapshot
             CandidateSnapshot candidateSnapshot
@@ -419,6 +753,4 @@ public class Bridge {
         );
         );
     }
     }
 
 
-
-
 }
 }

+ 4 - 9
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/SqliteDBStore.java

@@ -5,15 +5,10 @@ import uk.ac.ic.wlgitbridge.bridge.db.DBInitException;
 import uk.ac.ic.wlgitbridge.bridge.db.DBStore;
 import uk.ac.ic.wlgitbridge.bridge.db.DBStore;
 import uk.ac.ic.wlgitbridge.bridge.db.ProjectState;
 import uk.ac.ic.wlgitbridge.bridge.db.ProjectState;
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.query.*;
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.query.*;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.alter.ProjectsAddLastAccessed;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create.CreateIndexURLIndexStore;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create.CreateProjectsIndexLastAccessed;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create.CreateProjectsTableSQLUpdate;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create.CreateURLIndexStoreSQLUpdate;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.delete.DeleteFilesForProjectSQLUpdate;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.insert.AddURLIndexSQLUpdate;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.insert.SetProjectLastAccessedTime;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.insert.SetProjectSQLUpdate;
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.alter.*;
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create.*;
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.delete.*;
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.insert.*;
 
 
 import java.io.File;
 import java.io.File;
 import java.sql.*;
 import java.sql.*;

+ 3 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetLatestVersionForProjectSQLQuery.java

@@ -35,7 +35,9 @@ public class GetLatestVersionForProjectSQLQuery implements SQLQuery<Integer> {
     }
     }
 
 
     @Override
     @Override
-    public void addParametersToStatement(PreparedStatement statement) throws SQLException {
+    public void addParametersToStatement(
+            PreparedStatement statement
+    ) throws SQLException {
         statement.setString(1, projectName);
         statement.setString(1, projectName);
     }
     }
 }
 }

+ 7 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetPathForURLInProjectSQLQuery.java

@@ -12,7 +12,10 @@ import java.sql.SQLException;
 public class GetPathForURLInProjectSQLQuery implements SQLQuery<String> {
 public class GetPathForURLInProjectSQLQuery implements SQLQuery<String> {
 
 
     private static final String GET_URL_INDEXES_FOR_PROJECT_NAME =
     private static final String GET_URL_INDEXES_FOR_PROJECT_NAME =
-            "SELECT `path` FROM `url_index_store` WHERE `project_name` = ? AND `url` = ?";
+            "SELECT `path` "
+                    + "FROM `url_index_store` "
+                    + "WHERE `project_name` = ? "
+                    + "AND `url` = ?";
 
 
     private final String projectName;
     private final String projectName;
     private final String url;
     private final String url;
@@ -37,7 +40,9 @@ public class GetPathForURLInProjectSQLQuery implements SQLQuery<String> {
     }
     }
 
 
     @Override
     @Override
-    public void addParametersToStatement(PreparedStatement statement) throws SQLException {
+    public void addParametersToStatement(
+            PreparedStatement statement
+    ) throws SQLException {
         statement.setString(1, projectName);
         statement.setString(1, projectName);
         statement.setString(2, url);
         statement.setString(2, url);
     }
     }

+ 5 - 3
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetProjectNamesSQLQuery.java

@@ -4,7 +4,7 @@ import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLQuery;
 
 
 import java.sql.ResultSet;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLException;
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 
 
 /**
 /**
@@ -16,8 +16,10 @@ public class GetProjectNamesSQLQuery implements SQLQuery<List<String>> {
             "SELECT `name` FROM `projects`";
             "SELECT `name` FROM `projects`";
 
 
     @Override
     @Override
-    public List<String> processResultSet(ResultSet resultSet) throws SQLException {
-        List<String> projectNames = new LinkedList<String>();
+    public List<String> processResultSet(
+            ResultSet resultSet
+    ) throws SQLException {
+        List<String> projectNames = new ArrayList<>();
         while (resultSet.next()) {
         while (resultSet.next()) {
             projectNames.add(resultSet.getString("name"));
             projectNames.add(resultSet.getString("name"));
         }
         }

+ 6 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetProjectState.java

@@ -29,7 +29,9 @@ public class GetProjectState implements SQLQuery<ProjectState> {
     }
     }
 
 
     @Override
     @Override
-    public ProjectState processResultSet(ResultSet resultSet) throws SQLException {
+    public ProjectState processResultSet(
+            ResultSet resultSet
+    ) throws SQLException {
         while (resultSet.next()) {
         while (resultSet.next()) {
             if (resultSet.getTimestamp("last_accessed") == null) {
             if (resultSet.getTimestamp("last_accessed") == null) {
                 return ProjectState.SWAPPED;
                 return ProjectState.SWAPPED;
@@ -40,7 +42,9 @@ public class GetProjectState implements SQLQuery<ProjectState> {
     }
     }
 
 
     @Override
     @Override
-    public void addParametersToStatement(PreparedStatement statement) throws SQLException {
+    public void addParametersToStatement(
+            PreparedStatement statement
+    ) throws SQLException {
         statement.setString(1, projectName);
         statement.setString(1, projectName);
     }
     }
 
 

+ 4 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/delete/DeleteFilesForProjectSQLUpdate.java

@@ -17,7 +17,10 @@ public class DeleteFilesForProjectSQLUpdate implements SQLUpdate {
     private final String projectName;
     private final String projectName;
     private final String[] paths;
     private final String[] paths;
 
 
-    public DeleteFilesForProjectSQLUpdate(String projectName, String... paths) {
+    public DeleteFilesForProjectSQLUpdate(
+            String projectName,
+            String... paths
+    ) {
         this.projectName = projectName;
         this.projectName = projectName;
         this.paths = paths;
         this.paths = paths;
     }
     }

+ 6 - 3
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/insert/SetProjectSQLUpdate.java

@@ -11,8 +11,9 @@ import java.sql.SQLException;
 public class SetProjectSQLUpdate implements SQLUpdate {
 public class SetProjectSQLUpdate implements SQLUpdate {
 
 
     private static final String SET_PROJECT =
     private static final String SET_PROJECT =
-            "INSERT OR REPLACE INTO `projects`(`name`, `version_id`, `last_accessed`) " +
-            "VALUES (?, ?, DATETIME('now'));\n";
+            "INSERT OR REPLACE "
+                    + "INTO `projects`(`name`, `version_id`, `last_accessed`) "
+                    + "VALUES (?, ?, DATETIME('now'));\n";
 
 
     private final String projectName;
     private final String projectName;
     private final int versionID;
     private final int versionID;
@@ -28,7 +29,9 @@ public class SetProjectSQLUpdate implements SQLUpdate {
     }
     }
 
 
     @Override
     @Override
-    public void addParametersToStatement(PreparedStatement statement) throws SQLException {
+    public void addParametersToStatement(
+            PreparedStatement statement
+    ) throws SQLException {
         statement.setString(1, projectName);
         statement.setString(1, projectName);
         statement.setInt(2, versionID);
         statement.setInt(2, versionID);
     }
     }

+ 2 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/GitProjectRepo.java

@@ -9,7 +9,7 @@ import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
 import uk.ac.ic.wlgitbridge.data.filestore.GitDirectoryContents;
 import uk.ac.ic.wlgitbridge.data.filestore.GitDirectoryContents;
 import uk.ac.ic.wlgitbridge.data.filestore.RawFile;
 import uk.ac.ic.wlgitbridge.data.filestore.RawFile;
-import uk.ac.ic.wlgitbridge.git.exception.GitUserException;
+import uk.ac.ic.wlgitbridge.git.exception.SizeLimitExceededException;
 import uk.ac.ic.wlgitbridge.git.util.RepositoryObjectTreeWalker;
 import uk.ac.ic.wlgitbridge.git.util.RepositoryObjectTreeWalker;
 import uk.ac.ic.wlgitbridge.util.Log;
 import uk.ac.ic.wlgitbridge.util.Log;
 import uk.ac.ic.wlgitbridge.util.Project;
 import uk.ac.ic.wlgitbridge.util.Project;
@@ -62,7 +62,7 @@ public class GitProjectRepo implements ProjectRepo {
 
 
     @Override
     @Override
     public Map<String, RawFile> getFiles()
     public Map<String, RawFile> getFiles()
-            throws IOException, GitUserException {
+            throws IOException, SizeLimitExceededException {
         Preconditions.checkState(repository.isPresent());
         Preconditions.checkState(repository.isPresent());
         return new RepositoryObjectTreeWalker(
         return new RepositoryObjectTreeWalker(
                 repository.get()
                 repository.get()

+ 3 - 3
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/repo/ProjectRepo.java

@@ -1,9 +1,8 @@
 package uk.ac.ic.wlgitbridge.bridge.repo;
 package uk.ac.ic.wlgitbridge.bridge.repo;
 
 
-import uk.ac.ic.wlgitbridge.bridge.repo.RepoStore;
 import uk.ac.ic.wlgitbridge.data.filestore.GitDirectoryContents;
 import uk.ac.ic.wlgitbridge.data.filestore.GitDirectoryContents;
 import uk.ac.ic.wlgitbridge.data.filestore.RawFile;
 import uk.ac.ic.wlgitbridge.data.filestore.RawFile;
-import uk.ac.ic.wlgitbridge.git.exception.GitUserException;
+import uk.ac.ic.wlgitbridge.git.exception.SizeLimitExceededException;
 
 
 import java.io.IOException;
 import java.io.IOException;
 import java.util.Collection;
 import java.util.Collection;
@@ -24,7 +23,8 @@ public interface ProjectRepo {
             RepoStore repoStore
             RepoStore repoStore
     ) throws IOException;
     ) throws IOException;
 
 
-    Map<String, RawFile> getFiles() throws IOException, GitUserException;
+    Map<String, RawFile> getFiles(
+    ) throws IOException, SizeLimitExceededException;
 
 
     Collection<String> commitAndGetMissing(
     Collection<String> commitAndGetMissing(
             GitDirectoryContents gitDirectoryContents
             GitDirectoryContents gitDirectoryContents

+ 9 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/resource/ResourceCache.java

@@ -9,5 +9,13 @@ import java.util.Map;
  * Created by winston on 20/08/2016.
  * Created by winston on 20/08/2016.
  */
  */
 public interface ResourceCache {
 public interface ResourceCache {
-    RawFile get(String projectName, String url, String newPath, Map<String, RawFile> fileTable, Map<String, byte[]> fetchedUrls) throws IOException;
+
+    RawFile get(
+            String projectName,
+            String url,
+            String newPath,
+            Map<String, RawFile> fileTable,
+            Map<String, byte[]> fetchedUrls
+    ) throws IOException;
+
 }
 }

+ 34 - 8
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/resource/UrlResourceCache.java

@@ -27,7 +27,13 @@ public class UrlResourceCache implements ResourceCache {
     }
     }
 
 
     @Override
     @Override
-    public RawFile get(String projectName, String url, String newPath, Map<String, RawFile> fileTable, Map<String, byte[]> fetchedUrls) throws IOException {
+    public RawFile get(
+            String projectName,
+            String url,
+            String newPath,
+            Map<String, RawFile> fileTable,
+            Map<String, byte[]> fetchedUrls
+    ) throws IOException {
         String path = dbStore.getPathForURLInProject(projectName, url);
         String path = dbStore.getPathForURLInProject(projectName, url);
         byte[] contents;
         byte[] contents;
         if (path == null) {
         if (path == null) {
@@ -42,8 +48,11 @@ public class UrlResourceCache implements ResourceCache {
                 RawFile rawFile = fileTable.get(path);
                 RawFile rawFile = fileTable.get(path);
                 if (rawFile == null) {
                 if (rawFile == null) {
                     Log.warn(
                     Log.warn(
-                            "File " + path + " was not in the current commit, or the git tree, yet path was not null. " +
-                                    "File url is: " + url
+                            "File " + path
+                                    + " was not in the current commit, "
+                                    + "or the git tree, yet path was not null. "
+                                    + "File url is: "
+                                    + url
                     );
                     );
                     contents = fetch(projectName, url, path);
                     contents = fetch(projectName, url, path);
                 } else {
                 } else {
@@ -54,25 +63,42 @@ public class UrlResourceCache implements ResourceCache {
         return new RepositoryFile(newPath, contents);
         return new RepositoryFile(newPath, contents);
     }
     }
 
 
-    private byte[] fetch(String projectName, final String url, String path) throws FailedConnectionException {
+    private byte[] fetch(
+            String projectName,
+            final String url,
+            String path
+    ) throws FailedConnectionException {
         byte[] contents;
         byte[] contents;
         Log.info("GET -> " + url);
         Log.info("GET -> " + url);
         try {
         try {
-            contents = Request.httpClient.prepareGet(url).execute(new AsyncCompletionHandler<byte[]>() {
+            contents = Request.httpClient.prepareGet(url).execute(
+                    new AsyncCompletionHandler<byte[]>() {
 
 
                 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
 
 
                 @Override
                 @Override
-                public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
+                public STATE onBodyPartReceived(
+                        HttpResponseBodyPart bodyPart
+                ) throws Exception {
                     bytes.write(bodyPart.getBodyPartBytes());
                     bytes.write(bodyPart.getBodyPartBytes());
                     return STATE.CONTINUE;
                     return STATE.CONTINUE;
                 }
                 }
 
 
                 @Override
                 @Override
-                public byte[] onCompleted(Response response) throws Exception {
+                public byte[] onCompleted(
+                        Response response
+                ) throws Exception {
                     byte[] data = bytes.toByteArray();
                     byte[] data = bytes.toByteArray();
                     bytes.close();
                     bytes.close();
-                    Log.info(response.getStatusCode() + " " + response.getStatusText() + " (" + data.length + "B) -> " + url);
+                    Log.info(
+                            response.getStatusCode()
+                                    + " "
+                                    + response.getStatusText()
+                                    + " ("
+                                    + data.length
+                                    + "B) -> "
+                                    + url
+                    );
                     return data;
                     return data;
                 }
                 }
 
 

+ 63 - 18
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/snapshot/NetSnapshotAPI.java

@@ -20,54 +20,99 @@ import java.util.*;
 public class NetSnapshotAPI implements SnapshotAPI {
 public class NetSnapshotAPI implements SnapshotAPI {
 
 
     @Override
     @Override
-    public Deque<Snapshot> getSnapshotsForProjectAfterVersion(Credential oauth2, String projectName, int version) throws FailedConnectionException, GitUserException {
-        List<SnapshotInfo> snapshotInfos = getSnapshotInfosAfterVersion(oauth2, projectName, version);
-        List<SnapshotData> snapshotDatas = getMatchingSnapshotData(oauth2, projectName, snapshotInfos);
-        LinkedList<Snapshot> snapshots = combine(snapshotInfos, snapshotDatas);
-        return snapshots;
+    public Deque<Snapshot> getSnapshotsForProjectAfterVersion(
+            Credential oauth2,
+            String projectName,
+            int version
+    ) throws FailedConnectionException, GitUserException {
+        List<SnapshotInfo> snapshotInfos = getSnapshotInfosAfterVersion(
+                oauth2,
+                projectName,
+                version
+        );
+        List<SnapshotData> snapshotDatas = getMatchingSnapshotData(
+                oauth2,
+                projectName,
+                snapshotInfos
+        );
+        return combine(snapshotInfos, snapshotDatas);
     }
     }
 
 
-    private List<SnapshotInfo> getSnapshotInfosAfterVersion(Credential oauth2, String projectName, int version) throws FailedConnectionException, GitUserException {
-        SortedSet<SnapshotInfo> versions = new TreeSet<SnapshotInfo>();
+    private List<SnapshotInfo> getSnapshotInfosAfterVersion(
+            Credential oauth2,
+            String projectName,
+            int version
+    ) throws FailedConnectionException, GitUserException {
+        SortedSet<SnapshotInfo> versions = new TreeSet<>();
         GetDocRequest getDoc = new GetDocRequest(oauth2, projectName);
         GetDocRequest getDoc = new GetDocRequest(oauth2, projectName);
-        GetSavedVersRequest getSavedVers = new GetSavedVersRequest(oauth2, projectName);
+        GetSavedVersRequest getSavedVers = new GetSavedVersRequest(
+                oauth2,
+                projectName
+        );
         getDoc.request();
         getDoc.request();
         getSavedVers.request();
         getSavedVers.request();
         GetDocResult latestDoc = getDoc.getResult();
         GetDocResult latestDoc = getDoc.getResult();
         int latest = latestDoc.getVersionID();
         int latest = latestDoc.getVersionID();
         if (latest > version) {
         if (latest > version) {
-            for (SnapshotInfo snapshotInfo : getSavedVers.getResult().getSavedVers()) {
+            for (
+                    SnapshotInfo snapshotInfo :
+                    getSavedVers.getResult().getSavedVers()
+            ) {
                 if (snapshotInfo.getVersionId() > version) {
                 if (snapshotInfo.getVersionId() > version) {
                     versions.add(snapshotInfo);
                     versions.add(snapshotInfo);
                 }
                 }
             }
             }
-            versions.add(new SnapshotInfo(latest, latestDoc.getCreatedAt(), latestDoc.getName(), latestDoc.getEmail()));
+            versions.add(new SnapshotInfo(
+                    latest,
+                    latestDoc.getCreatedAt(),
+                    latestDoc.getName(),
+                    latestDoc.getEmail()
+            ));
 
 
         }
         }
         return new LinkedList<SnapshotInfo>(versions);
         return new LinkedList<SnapshotInfo>(versions);
     }
     }
 
 
-    private List<SnapshotData> getMatchingSnapshotData(Credential oauth2, String projectName, List<SnapshotInfo> snapshotInfos) throws FailedConnectionException, ForbiddenException {
-        List<GetForVersionRequest> firedRequests = fireDataRequests(oauth2, projectName, snapshotInfos);
-        List<SnapshotData> snapshotDataList = new LinkedList<SnapshotData>();
+    private List<SnapshotData> getMatchingSnapshotData(
+            Credential oauth2,
+            String projectName,
+            List<SnapshotInfo> snapshotInfos
+    ) throws FailedConnectionException, ForbiddenException {
+        List<GetForVersionRequest> firedRequests = fireDataRequests(
+                oauth2,
+                projectName,
+                snapshotInfos
+        );
+        List<SnapshotData> snapshotDataList = new ArrayList<>();
         for (GetForVersionRequest fired : firedRequests) {
         for (GetForVersionRequest fired : firedRequests) {
             snapshotDataList.add(fired.getResult().getSnapshotData());
             snapshotDataList.add(fired.getResult().getSnapshotData());
         }
         }
         return snapshotDataList;
         return snapshotDataList;
     }
     }
 
 
-    private List<GetForVersionRequest> fireDataRequests(Credential oauth2, String projectName, List<SnapshotInfo> snapshotInfos) {
-        List<GetForVersionRequest> requests = new LinkedList<GetForVersionRequest>();
+    private List<GetForVersionRequest> fireDataRequests(
+            Credential oauth2,
+            String projectName,
+            List<SnapshotInfo> snapshotInfos
+    ) {
+        List<GetForVersionRequest> requests = new ArrayList<>();
         for (SnapshotInfo snapshotInfo : snapshotInfos) {
         for (SnapshotInfo snapshotInfo : snapshotInfos) {
-            GetForVersionRequest request = new GetForVersionRequest(oauth2, projectName, snapshotInfo.getVersionId());
+            GetForVersionRequest request = new GetForVersionRequest(
+                    oauth2,
+                    projectName,
+                    snapshotInfo.getVersionId()
+            );
             requests.add(request);
             requests.add(request);
             request.request();
             request.request();
         }
         }
         return requests;
         return requests;
     }
     }
 
 
-    private LinkedList<Snapshot> combine(List<SnapshotInfo> snapshotInfos, List<SnapshotData> snapshotDatas) {
-        LinkedList<Snapshot> snapshots = new LinkedList<Snapshot>();
+    private Deque<Snapshot> combine(
+            List<SnapshotInfo> snapshotInfos,
+            List<SnapshotData> snapshotDatas
+    ) {
+        Deque<Snapshot> snapshots = new LinkedList<>();
         Iterator<SnapshotInfo> infos = snapshotInfos.iterator();
         Iterator<SnapshotInfo> infos = snapshotInfos.iterator();
         Iterator<SnapshotData> datas = snapshotDatas.iterator();
         Iterator<SnapshotData> datas = snapshotDatas.iterator();
         while (infos.hasNext()) {
         while (infos.hasNext()) {

+ 4 - 14
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/swap/job/NoopSwapJob.java

@@ -1,30 +1,20 @@
 package uk.ac.ic.wlgitbridge.bridge.swap.job;
 package uk.ac.ic.wlgitbridge.bridge.swap.job;
 
 
-import java.io.IOException;
-
 /**
 /**
  * Created by winston on 24/08/2016.
  * Created by winston on 24/08/2016.
  */
  */
 public class NoopSwapJob implements SwapJob {
 public class NoopSwapJob implements SwapJob {
 
 
     @Override
     @Override
-    public void start() {
-
-    }
+    public void start() {}
 
 
     @Override
     @Override
-    public void stop() {
-
-    }
+    public void stop() {}
 
 
     @Override
     @Override
-    public void evict(String projName) throws IOException {
-
-    }
+    public void evict(String projName) {}
 
 
     @Override
     @Override
-    public void restore(String projName) throws IOException {
-
-    }
+    public void restore(String projName) {}
 
 
 }
 }

+ 1 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/swap/job/SwapJob.java

@@ -39,4 +39,5 @@ public interface SwapJob {
     void evict(String projName) throws IOException;
     void evict(String projName) throws IOException;
 
 
     void restore(String projName) throws IOException;
     void restore(String projName) throws IOException;
+
 }
 }

+ 3 - 10
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/swap/store/NoopSwapStore.java

@@ -1,7 +1,6 @@
 package uk.ac.ic.wlgitbridge.bridge.swap.store;
 package uk.ac.ic.wlgitbridge.bridge.swap.store;
 
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayInputStream;
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStream;
 
 
 /**
 /**
@@ -9,18 +8,14 @@ import java.io.InputStream;
  */
  */
 public class NoopSwapStore implements SwapStore {
 public class NoopSwapStore implements SwapStore {
 
 
-    public NoopSwapStore(SwapStoreConfig config) {
-
-    }
+    public NoopSwapStore(SwapStoreConfig __) {}
 
 
     @Override
     @Override
     public void upload(
     public void upload(
             String projectName,
             String projectName,
             InputStream uploadStream,
             InputStream uploadStream,
             long contentLength
             long contentLength
-    ) throws IOException {
-
-    }
+    ) {}
 
 
     @Override
     @Override
     public InputStream openDownloadStream(String projectName) {
     public InputStream openDownloadStream(String projectName) {
@@ -28,8 +23,6 @@ public class NoopSwapStore implements SwapStore {
     }
     }
 
 
     @Override
     @Override
-    public void remove(String projectName) {
-
-    }
+    public void remove(String projectName) {}
 
 
 }
 }

+ 1 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/data/LockAllWaiter.java

@@ -5,6 +5,6 @@ package uk.ac.ic.wlgitbridge.data;
  */
  */
 public interface LockAllWaiter {
 public interface LockAllWaiter {
 
 
-    public void threadsRemaining(int threads);
+    void threadsRemaining(int threads);
 
 
 }
 }

+ 0 - 10
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/data/SnapshotFetcher.java

@@ -1,10 +0,0 @@
-package uk.ac.ic.wlgitbridge.data;
-
-/**
- * Created by Winston on 07/11/14.
- */
-public class SnapshotFetcher {
-
-
-
-}

+ 1 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/data/filestore/RawFile.java

@@ -14,6 +14,7 @@ import java.util.Arrays;
 public abstract class RawFile {
 public abstract class RawFile {
 
 
     public abstract String getPath();
     public abstract String getPath();
+
     public abstract byte[] getContents();
     public abstract byte[] getContents();
 
 
     public final void writeToDisk(File directory) throws IOException {
     public final void writeToDisk(File directory) throws IOException {

+ 0 - 9
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/data/model/ResourceFetcher.java

@@ -1,9 +0,0 @@
-package uk.ac.ic.wlgitbridge.data.model;
-
-/**
- * Created by Winston on 21/02/15.
- */
-public class ResourceFetcher {
-
-
-}

+ 1 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/exception/GitUserException.java

@@ -8,6 +8,7 @@ import java.util.List;
 public abstract class GitUserException extends Exception {
 public abstract class GitUserException extends Exception {
 
 
     public abstract String getMessage();
     public abstract String getMessage();
+
     public abstract List<String> getDescriptionLines();
     public abstract List<String> getDescriptionLines();
 
 
 }
 }

+ 0 - 8
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/exception/InvalidRootDirectoryPathException.java

@@ -1,8 +0,0 @@
-package uk.ac.ic.wlgitbridge.git.exception;
-
-/**
- * Created by Winston on 03/11/14.
- */
-public class InvalidRootDirectoryPathException extends Exception {
-
-}

+ 5 - 3
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/exception/SizeLimitExceededException.java

@@ -21,10 +21,12 @@ public class SizeLimitExceededException extends GitUserException {
 
 
     @Override
     @Override
     public List<String> getDescriptionLines() {
     public List<String> getDescriptionLines() {
-        String filename = path != null ? "File '" + path + "' is" : "There's a file";
+        String filename =
+                path != null ? "File '" + path + "' is" : "There's a file";
         return Arrays.asList(
         return Arrays.asList(
-            filename + " too large to push to " + Util.getServiceName() + " via git",
-            "the recommended maximum file size is 50 MiB"
+                filename + " too large to push to "
+                        + Util.getServiceName() + " via git",
+                        "the recommended maximum file size is 50 MiB"
         );
         );
     }
     }
 
 

+ 1 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/exception/SnapshotAPIException.java

@@ -7,5 +7,4 @@ import uk.ac.ic.wlgitbridge.snapshot.base.JSONSource;
  */
  */
 public abstract class SnapshotAPIException
 public abstract class SnapshotAPIException
         extends GitUserException
         extends GitUserException
-        implements JSONSource {
-}
+        implements JSONSource {}

+ 38 - 7
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/handler/WLReceivePackFactory.java

@@ -4,10 +4,10 @@ import com.google.api.client.auth.oauth2.Credential;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.ReceivePack;
 import org.eclipse.jgit.transport.ReceivePack;
 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
 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.Bridge;
 import uk.ac.ic.wlgitbridge.bridge.Bridge;
+import uk.ac.ic.wlgitbridge.bridge.snapshot.SnapshotAPI;
 import uk.ac.ic.wlgitbridge.git.handler.hook.WriteLatexPutHook;
 import uk.ac.ic.wlgitbridge.git.handler.hook.WriteLatexPutHook;
+import uk.ac.ic.wlgitbridge.git.servlet.WLGitServlet;
 import uk.ac.ic.wlgitbridge.server.Oauth2Filter;
 import uk.ac.ic.wlgitbridge.server.Oauth2Filter;
 import uk.ac.ic.wlgitbridge.util.Util;
 import uk.ac.ic.wlgitbridge.util.Util;
 
 
@@ -16,8 +16,15 @@ import javax.servlet.http.HttpServletRequest;
 /**
 /**
  * Created by Winston on 02/11/14.
  * Created by Winston on 02/11/14.
  */
  */
-/* */
-public class WLReceivePackFactory implements ReceivePackFactory<HttpServletRequest> {
+/**
+ * One of the "big three" interfaces created by {@link WLGitServlet} to handle
+ * user Git requests.
+ *
+ * This class just puts a {@link WriteLatexPutHook} into the {@link ReceivePack}
+ * that it returns.
+ */
+public class WLReceivePackFactory
+        implements ReceivePackFactory<HttpServletRequest> {
 
 
     private final Bridge bridge;
     private final Bridge bridge;
 
 
@@ -25,15 +32,39 @@ public class WLReceivePackFactory implements ReceivePackFactory<HttpServletReque
         this.bridge = bridge;
         this.bridge = bridge;
     }
     }
 
 
+    /**
+     * Puts a {@link WriteLatexPutHook} into the returned {@link ReceivePack}.
+     *
+     * The {@link WriteLatexPutHook} needs our hostname, which we get from the
+     * original {@link HttpServletRequest}, used to provide a postback URL to
+     * the {@link SnapshotAPI}. We also give it the oauth2 that we injected in
+     * the {@link Oauth2Filter}, and the {@link Bridge}.
+     *
+     * At this point, the repository will have been synced to the latest on
+     * Overleaf, but it's possible that an update happens on Overleaf while our
+     * put hook is running. In this case, we fail, and the user tries again,
+     * triggering another sync, and so on.
+     * @param httpServletRequest the original request
+     * @param repository the JGit {@link Repository} provided by
+     * {@link WLRepositoryResolver}
+     * @return a correctly hooked {@link ReceivePack}
+     */
     @Override
     @Override
-    public ReceivePack create(HttpServletRequest httpServletRequest, Repository repository) throws ServiceNotEnabledException, ServiceNotAuthorizedException {
-        Credential oauth2 = (Credential) httpServletRequest.getAttribute(Oauth2Filter.ATTRIBUTE_KEY);
+    public ReceivePack create(
+            HttpServletRequest httpServletRequest,
+            Repository repository
+    ) {
+        Credential oauth2 = (Credential) httpServletRequest.getAttribute(
+                Oauth2Filter.ATTRIBUTE_KEY
+        );
         ReceivePack receivePack = new ReceivePack(repository);
         ReceivePack receivePack = new ReceivePack(repository);
         String hostname = Util.getPostbackURL();
         String hostname = Util.getPostbackURL();
         if (hostname == null) {
         if (hostname == null) {
             hostname = httpServletRequest.getLocalName();
             hostname = httpServletRequest.getLocalName();
         }
         }
-        receivePack.setPreReceiveHook(new WriteLatexPutHook(bridge, hostname, oauth2));
+        receivePack.setPreReceiveHook(
+                new WriteLatexPutHook(bridge, hostname, oauth2)
+        );
         return receivePack;
         return receivePack;
     }
     }
 
 

+ 45 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/handler/WLRepositoryResolver.java

@@ -6,10 +6,12 @@ import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.ServiceMayNotContinueException;
 import org.eclipse.jgit.transport.ServiceMayNotContinueException;
 import org.eclipse.jgit.transport.resolver.RepositoryResolver;
 import org.eclipse.jgit.transport.resolver.RepositoryResolver;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
 import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
-import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
 import uk.ac.ic.wlgitbridge.bridge.Bridge;
 import uk.ac.ic.wlgitbridge.bridge.Bridge;
 import uk.ac.ic.wlgitbridge.bridge.repo.GitProjectRepo;
 import uk.ac.ic.wlgitbridge.bridge.repo.GitProjectRepo;
 import uk.ac.ic.wlgitbridge.git.exception.GitUserException;
 import uk.ac.ic.wlgitbridge.git.exception.GitUserException;
+import uk.ac.ic.wlgitbridge.git.handler.hook.WriteLatexPutHook;
+import uk.ac.ic.wlgitbridge.git.servlet.WLGitServlet;
+import uk.ac.ic.wlgitbridge.server.GitBridgeServer;
 import uk.ac.ic.wlgitbridge.server.Oauth2Filter;
 import uk.ac.ic.wlgitbridge.server.Oauth2Filter;
 import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
 import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
 import uk.ac.ic.wlgitbridge.util.Log;
 import uk.ac.ic.wlgitbridge.util.Log;
@@ -21,6 +23,18 @@ import java.io.IOException;
 /**
 /**
  * Created by Winston on 02/11/14.
  * Created by Winston on 02/11/14.
  */
  */
+/**
+ * One of the "big three" interfaces created by {@link WLGitServlet} to handle
+ * user Git requests.
+ *
+ * This class is used by all Git requests to resolve a project name to a
+ * JGit {@link Repository}, or fail by throwing an exception.
+ *
+ * It has a single method, {@link #open(HttpServletRequest, String)}, which
+ * calls into the {@link Bridge} to synchronise the project with Overleaf, i.e.
+ * bringing it onto disk and applying commits to it until it is up-to-date with
+ * Overleaf.
+ */
 public class WLRepositoryResolver
 public class WLRepositoryResolver
         implements RepositoryResolver<HttpServletRequest> {
         implements RepositoryResolver<HttpServletRequest> {
 
 
@@ -30,13 +44,42 @@ public class WLRepositoryResolver
         this.bridge = bridge;
         this.bridge = bridge;
     }
     }
 
 
+    /**
+     * Calls into the Bridge to resolve a project name to a JGit
+     * {@link Repository}, or throw an exception.
+     *
+     * On success, the repository will have been brought onto disk and updated
+     * to the latest (synced).
+     *
+     * In the case of clones and fetches, upload packs are created from the
+     * returned JGit {@link Repository} by the {@link WLUploadPackFactory}.
+     *
+     * The project lock is acquired for this process so it can't be swapped out.
+     *
+     * However, it can still be swapped out between this and a Git push. The
+     * push would fail due to the project changed on Overleaf between the sync
+     * and the actual push to Overleaf (performed by the
+     * {@link WLReceivePackFactory} and {@link WriteLatexPutHook}. In this case,
+     * the user will have to try again (which prompts another update, etc. until
+     * this no longer happens).
+     * @param httpServletRequest The HttpServletRequest as required by the
+     * interface. We injected the oauth2 creds into it with
+     * {@link Oauth2Filter}, which was set up by the {@link GitBridgeServer}.
+     * @param name The name of the project
+     * @return the JGit {@link Repository}.
+     * @throws RepositoryNotFoundException If the project does not exist
+     * @throws ServiceNotAuthorizedException If the user did not auth when
+     * required to
+     * @throws ServiceMayNotContinueException If any other general user
+     * exception occurs that must be propogated back to the user, e.g.
+     * internal errors (IOException, etc), too large file, and so on.
+     */
     @Override
     @Override
     public Repository open(
     public Repository open(
             HttpServletRequest httpServletRequest,
             HttpServletRequest httpServletRequest,
             String name
             String name
     ) throws RepositoryNotFoundException,
     ) throws RepositoryNotFoundException,
              ServiceNotAuthorizedException,
              ServiceNotAuthorizedException,
-             ServiceNotEnabledException,
              ServiceMayNotContinueException {
              ServiceMayNotContinueException {
         Credential oauth2 = (Credential) httpServletRequest.getAttribute(
         Credential oauth2 = (Credential) httpServletRequest.getAttribute(
                 Oauth2Filter.ATTRIBUTE_KEY
                 Oauth2Filter.ATTRIBUTE_KEY

+ 27 - 5
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/handler/WLUploadPackFactory.java

@@ -2,9 +2,8 @@ package uk.ac.ic.wlgitbridge.git.handler;
 
 
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.transport.UploadPack;
 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 org.eclipse.jgit.transport.resolver.UploadPackFactory;
+import uk.ac.ic.wlgitbridge.git.servlet.WLGitServlet;
 import uk.ac.ic.wlgitbridge.util.Util;
 import uk.ac.ic.wlgitbridge.util.Util;
 
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequest;
@@ -12,11 +11,34 @@ import javax.servlet.http.HttpServletRequest;
 /**
 /**
  * Created by Winston on 02/11/14.
  * Created by Winston on 02/11/14.
  */
  */
-public class WLUploadPackFactory implements UploadPackFactory<HttpServletRequest> {
+/**
+ * One of the "big three" interfaces created by {@link WLGitServlet} to handle
+ * user Git requests.
+ *
+ * The actual class doesn't do much, and most of the work is done when the
+ * project name is being resolved by the {@link WLRepositoryResolver}.
+ */
+public class WLUploadPackFactory
+        implements UploadPackFactory<HttpServletRequest> {
+
+    /**
+     * This does nothing special. Synchronising the project with Overleaf will
+     * have been performed by {@link WLRepositoryResolver}.
+     * @param __ Not used, required by the {@link UploadPackFactory} interface
+     * @param repository The JGit repository provided by the
+     * {@link WLRepositoryResolver}
+     * @return the {@link UploadPack}, used by JGit to serve the request
+     */
     @Override
     @Override
-    public UploadPack create(HttpServletRequest httpServletRequest, Repository repository) throws ServiceNotEnabledException, ServiceNotAuthorizedException {
+    public UploadPack create(
+            HttpServletRequest __,
+            Repository repository
+    ) {
         UploadPack uploadPack = new UploadPack(repository);
         UploadPack uploadPack = new UploadPack(repository);
-        uploadPack.sendMessage("Downloading files from " + Util.getServiceName());
+        uploadPack.sendMessage(
+                "Downloading files from " + Util.getServiceName()
+        );
         return uploadPack;
         return uploadPack;
     }
     }
+
 }
 }

+ 76 - 18
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/handler/hook/WriteLatexPutHook.java

@@ -9,6 +9,7 @@ import org.eclipse.jgit.transport.ReceivePack;
 import uk.ac.ic.wlgitbridge.bridge.Bridge;
 import uk.ac.ic.wlgitbridge.bridge.Bridge;
 import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory;
 import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory;
 import uk.ac.ic.wlgitbridge.git.exception.GitUserException;
 import uk.ac.ic.wlgitbridge.git.exception.GitUserException;
+import uk.ac.ic.wlgitbridge.git.handler.WLReceivePackFactory;
 import uk.ac.ic.wlgitbridge.git.handler.hook.exception.ForcedPushException;
 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.handler.hook.exception.WrongBranchException;
 import uk.ac.ic.wlgitbridge.git.util.RepositoryObjectTreeWalker;
 import uk.ac.ic.wlgitbridge.git.util.RepositoryObjectTreeWalker;
@@ -24,42 +25,80 @@ import java.util.Iterator;
 /**
 /**
  * Created by Winston on 03/11/14.
  * Created by Winston on 03/11/14.
  */
  */
+/**
+ * Created by {@link WLReceivePackFactory} to update the {@link Bridge} for a
+ * user's Git push request, or fail with an error. The hook is able to approve
+ * or reject a request.
+ */
 public class WriteLatexPutHook implements PreReceiveHook {
 public class WriteLatexPutHook implements PreReceiveHook {
 
 
     private final Bridge bridge;
     private final Bridge bridge;
     private final String hostname;
     private final String hostname;
     private final Credential oauth2;
     private final Credential oauth2;
 
 
-    public WriteLatexPutHook(Bridge bridge, String hostname, Credential oauth2) {
+    /**
+     * The constructor to use, which provides the hook with the {@link Bridge},
+     * the hostname (used to construct a URL to give to Overleaf to postback),
+     * and the oauth2 (used to authenticate with the Snapshot API).
+     * @param bridge the {@link Bridge}
+     * @param hostname the hostname used for postback from the Snapshot API
+     * @param oauth2 used to authenticate with the snapshot API, or null
+     */
+    public WriteLatexPutHook(
+            Bridge bridge,
+            String hostname,
+            Credential oauth2
+    ) {
         this.bridge = bridge;
         this.bridge = bridge;
         this.hostname = hostname;
         this.hostname = hostname;
         this.oauth2 = oauth2;
         this.oauth2 = oauth2;
     }
     }
 
 
     @Override
     @Override
-    public void onPreReceive(ReceivePack receivePack, Collection<ReceiveCommand> receiveCommands) {
+    public void onPreReceive(
+            ReceivePack receivePack,
+            Collection<ReceiveCommand> receiveCommands
+    ) {
         for (ReceiveCommand receiveCommand : receiveCommands) {
         for (ReceiveCommand receiveCommand : receiveCommands) {
             try {
             try {
-                handleReceiveCommand(oauth2, receivePack.getRepository(), receiveCommand);
+                handleReceiveCommand(
+                        oauth2,
+                        receivePack.getRepository(),
+                        receiveCommand
+                );
             } catch (IOException e) {
             } catch (IOException e) {
                 receivePack.sendError(e.getMessage());
                 receivePack.sendError(e.getMessage());
-                receiveCommand.setResult(Result.REJECTED_OTHER_REASON, e.getMessage());
+                receiveCommand.setResult(
+                        Result.REJECTED_OTHER_REASON,
+                        e.getMessage()
+                );
             } catch (OutOfDateException e) {
             } catch (OutOfDateException e) {
                 receiveCommand.setResult(Result.REJECTED_NONFASTFORWARD);
                 receiveCommand.setResult(Result.REJECTED_NONFASTFORWARD);
             } catch (SnapshotPostException e) {
             } catch (SnapshotPostException e) {
                 handleSnapshotPostException(receivePack, receiveCommand, e);
                 handleSnapshotPostException(receivePack, receiveCommand, e);
             } catch (Throwable t) {
             } catch (Throwable t) {
                 Log.warn("Throwable on pre receive: ", t);
                 Log.warn("Throwable on pre receive: ", t);
-                handleSnapshotPostException(receivePack, receiveCommand, new InternalErrorException());
+                handleSnapshotPostException(
+                        receivePack,
+                        receiveCommand,
+                        new InternalErrorException()
+                );
             }
             }
         }
         }
     }
     }
 
 
-    private void handleSnapshotPostException(ReceivePack receivePack, ReceiveCommand receiveCommand, SnapshotPostException e) {
+    private void handleSnapshotPostException(
+            ReceivePack receivePack,
+            ReceiveCommand receiveCommand,
+            SnapshotPostException e
+    ) {
         String message = e.getMessage();
         String message = e.getMessage();
         receivePack.sendError(message);
         receivePack.sendError(message);
         StringBuilder msg = new StringBuilder();
         StringBuilder msg = new StringBuilder();
-        for (Iterator<String> it = e.getDescriptionLines().iterator(); it.hasNext();) {
+        for (
+                Iterator<String> it = e.getDescriptionLines().iterator();
+                it.hasNext();
+        ) {
             String line = it.next();
             String line = it.next();
             msg.append("hint: ");
             msg.append("hint: ");
             msg.append(line);
             msg.append(line);
@@ -72,10 +111,14 @@ public class WriteLatexPutHook implements PreReceiveHook {
         receiveCommand.setResult(Result.REJECTED_OTHER_REASON, message);
         receiveCommand.setResult(Result.REJECTED_OTHER_REASON, message);
     }
     }
 
 
-    private void handleReceiveCommand(Credential oauth2, Repository repository, ReceiveCommand receiveCommand) throws IOException, GitUserException {
+    private void handleReceiveCommand(
+            Credential oauth2,
+            Repository repository,
+            ReceiveCommand receiveCommand
+    ) throws IOException, GitUserException {
         checkBranch(receiveCommand);
         checkBranch(receiveCommand);
         checkForcedPush(receiveCommand);
         checkForcedPush(receiveCommand);
-        bridge.putDirectoryContentsToProjectWithName(
+        bridge.push(
                 oauth2,
                 oauth2,
                 repository.getWorkTree().getName(),
                 repository.getWorkTree().getName(),
                 getPushedDirectoryContents(repository,
                 getPushedDirectoryContents(repository,
@@ -85,26 +128,41 @@ public class WriteLatexPutHook implements PreReceiveHook {
         );
         );
     }
     }
 
 
-    private void checkBranch(ReceiveCommand receiveCommand) throws WrongBranchException {
+    private void checkBranch(
+            ReceiveCommand receiveCommand
+    ) throws WrongBranchException {
         if (!receiveCommand.getRefName().equals("refs/heads/master")) {
         if (!receiveCommand.getRefName().equals("refs/heads/master")) {
             throw new WrongBranchException();
             throw new WrongBranchException();
         }
         }
     }
     }
 
 
-    private void checkForcedPush(ReceiveCommand receiveCommand) throws ForcedPushException {
-        if (receiveCommand.getType() == ReceiveCommand.Type.UPDATE_NONFASTFORWARD) {
+    private void checkForcedPush(
+            ReceiveCommand receiveCommand
+    ) throws ForcedPushException {
+        if (
+                receiveCommand.getType()
+                        == ReceiveCommand.Type.UPDATE_NONFASTFORWARD
+        ) {
             throw new ForcedPushException();
             throw new ForcedPushException();
         }
         }
     }
     }
 
 
-    private RawDirectory getPushedDirectoryContents(Repository repository, ReceiveCommand receiveCommand) throws IOException, GitUserException {
-        return new RepositoryObjectTreeWalker(repository,
-                                              receiveCommand.getNewId())
-               .getDirectoryContents();
+    private RawDirectory getPushedDirectoryContents(
+            Repository repository,
+            ReceiveCommand receiveCommand
+    ) throws IOException, GitUserException {
+        return new RepositoryObjectTreeWalker(
+                repository,
+                receiveCommand.getNewId()
+        ).getDirectoryContents();
     }
     }
 
 
-    private RawDirectory getOldDirectoryContents(Repository repository) throws IOException, GitUserException {
-        return new RepositoryObjectTreeWalker(repository).getDirectoryContents();
+    private RawDirectory getOldDirectoryContents(
+            Repository repository
+    ) throws IOException, GitUserException {
+        return new RepositoryObjectTreeWalker(
+                repository
+        ).getDirectoryContents();
     }
     }
 
 
 }
 }

+ 6 - 5
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/handler/hook/exception/ForcedPushException.java

@@ -13,9 +13,12 @@ import java.util.List;
 public class ForcedPushException extends SnapshotPostException {
 public class ForcedPushException extends SnapshotPostException {
 
 
     private static final String[] DESCRIPTION_LINES = {
     private static final String[] DESCRIPTION_LINES = {
-            "You can't git push --force to a " + Util.getServiceName() + " project.",
+            "You can't git push --force to a "
+                    + Util.getServiceName()
+                    + " project.",
             "Try to put your changes on top of the current head.",
             "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."
+            "If everything else fails, delete and reclone your repository, "
+                    + "make your changes, then push again."
     };
     };
 
 
     @Override
     @Override
@@ -29,8 +32,6 @@ public class ForcedPushException extends SnapshotPostException {
     }
     }
 
 
     @Override
     @Override
-    public void fromJSON(JsonElement json) {
-
-    }
+    public void fromJSON(JsonElement json) {}
 
 
 }
 }

+ 24 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/servlet/WLGitServlet.java

@@ -3,22 +3,44 @@ package uk.ac.ic.wlgitbridge.git.servlet;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jgit.http.server.GitServlet;
 import org.eclipse.jgit.http.server.GitServlet;
 import uk.ac.ic.wlgitbridge.bridge.Bridge;
 import uk.ac.ic.wlgitbridge.bridge.Bridge;
-import uk.ac.ic.wlgitbridge.git.exception.InvalidRootDirectoryPathException;
 import uk.ac.ic.wlgitbridge.git.handler.WLReceivePackFactory;
 import uk.ac.ic.wlgitbridge.git.handler.WLReceivePackFactory;
 import uk.ac.ic.wlgitbridge.git.handler.WLRepositoryResolver;
 import uk.ac.ic.wlgitbridge.git.handler.WLRepositoryResolver;
 import uk.ac.ic.wlgitbridge.git.handler.WLUploadPackFactory;
 import uk.ac.ic.wlgitbridge.git.handler.WLUploadPackFactory;
+import uk.ac.ic.wlgitbridge.server.GitBridgeServer;
 
 
 import javax.servlet.ServletException;
 import javax.servlet.ServletException;
 
 
 /**
 /**
  * Created by Winston on 02/11/14.
  * Created by Winston on 02/11/14.
  */
  */
+/**
+ * This is the Servlet created by the {@link GitBridgeServer} that does all of
+ * the work in handling user Git requests and directing them to the
+ * {@link Bridge}.
+ *
+ * The {@link GitServlet} does all of the Git work, and these main three
+ * interfaces do all of the Git Bridge work:
+ *
+ * @see WLRepositoryResolver
+ * @see WLReceivePackFactory
+ * @see WLUploadPackFactory
+ */
 public class WLGitServlet extends GitServlet {
 public class WLGitServlet extends GitServlet {
 
 
+    /**
+     * Constructor that sets all of the resolvers and factories for the
+     * {@link GitServlet}.
+     *
+     * Also needs to call init with a config ({@link WLGitServletConfig}, as
+     * required by the {@link GitServlet}.
+     * @param ctxHandler
+     * @param bridge
+     * @throws ServletException
+     */
     public WLGitServlet(
     public WLGitServlet(
             ServletContextHandler ctxHandler,
             ServletContextHandler ctxHandler,
             Bridge bridge
             Bridge bridge
-    ) throws ServletException, InvalidRootDirectoryPathException {
+    ) throws ServletException {
         setRepositoryResolver(new WLRepositoryResolver(bridge));
         setRepositoryResolver(new WLRepositoryResolver(bridge));
         setReceivePackFactory(new WLReceivePackFactory(bridge));
         setReceivePackFactory(new WLReceivePackFactory(bridge));
         setUploadPackFactory(new WLUploadPackFactory());
         setUploadPackFactory(new WLUploadPackFactory());

+ 24 - 11
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/git/util/RepositoryObjectTreeWalker.java

@@ -8,7 +8,6 @@ import org.eclipse.jgit.treewalk.TreeWalk;
 import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory;
 import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory;
 import uk.ac.ic.wlgitbridge.data.filestore.RawFile;
 import uk.ac.ic.wlgitbridge.data.filestore.RawFile;
 import uk.ac.ic.wlgitbridge.data.filestore.RepositoryFile;
 import uk.ac.ic.wlgitbridge.data.filestore.RepositoryFile;
-import uk.ac.ic.wlgitbridge.git.exception.GitUserException;
 import uk.ac.ic.wlgitbridge.git.exception.SizeLimitExceededException;
 import uk.ac.ic.wlgitbridge.git.exception.SizeLimitExceededException;
 
 
 import java.io.IOException;
 import java.io.IOException;
@@ -23,24 +22,36 @@ public class RepositoryObjectTreeWalker {
     private final TreeWalk treeWalk;
     private final TreeWalk treeWalk;
     private final Repository repository;
     private final Repository repository;
 
 
-    public RepositoryObjectTreeWalker(Repository repository, ObjectId objectId) throws IOException {
+    public RepositoryObjectTreeWalker(
+            Repository repository,
+            ObjectId objectId
+    ) throws IOException {
         treeWalk = initTreeWalk(repository, objectId);
         treeWalk = initTreeWalk(repository, objectId);
         this.repository = repository;
         this.repository = repository;
     }
     }
 
 
-    public RepositoryObjectTreeWalker(Repository repository) throws IOException {
+    public RepositoryObjectTreeWalker(
+            Repository repository
+    ) throws IOException {
         this(repository, 0);
         this(repository, 0);
     }
     }
 
 
-    public RepositoryObjectTreeWalker(Repository repository, int fromHead) throws IOException {
+    public RepositoryObjectTreeWalker(
+            Repository repository,
+            int fromHead
+    ) throws IOException {
         this(repository, repository.resolve("HEAD~" + fromHead));
         this(repository, repository.resolve("HEAD~" + fromHead));
     }
     }
 
 
-    public RawDirectory getDirectoryContents() throws IOException, GitUserException {
+    public RawDirectory getDirectoryContents(
+    ) throws IOException, SizeLimitExceededException {
         return new RawDirectory(walkGitObjectTree());
         return new RawDirectory(walkGitObjectTree());
     }
     }
 
 
-    private TreeWalk initTreeWalk(Repository repository, ObjectId objectId) throws IOException {
+    private TreeWalk initTreeWalk(
+            Repository repository,
+            ObjectId objectId
+    ) throws IOException {
         if (objectId == null) {
         if (objectId == null) {
             return null;
             return null;
         }
         }
@@ -51,8 +62,9 @@ public class RepositoryObjectTreeWalker {
         return treeWalk;
         return treeWalk;
     }
     }
 
 
-    private Map<String, RawFile> walkGitObjectTree() throws IOException, GitUserException {
-        Map<String, RawFile> fileContentsTable = new HashMap<String, RawFile>();
+    private Map<String, RawFile> walkGitObjectTree(
+    ) throws IOException, SizeLimitExceededException {
+        Map<String, RawFile> fileContentsTable = new HashMap<>();
         if (treeWalk == null) {
         if (treeWalk == null) {
             return fileContentsTable;
             return fileContentsTable;
         }
         }
@@ -60,10 +72,11 @@ public class RepositoryObjectTreeWalker {
             String path = treeWalk.getPathString();
             String path = treeWalk.getPathString();
 
 
             try {
             try {
-                byte[] content = repository.open(treeWalk.getObjectId(0)).getBytes();
+                byte[] content = repository.open(
+                        treeWalk.getObjectId(0)
+                ).getBytes();
                 fileContentsTable.put(path, new RepositoryFile(path, content));
                 fileContentsTable.put(path, new RepositoryFile(path, content));
-            }
-            catch (LargeObjectException e) {
+            } catch (LargeObjectException e) {
                 throw new SizeLimitExceededException(path);
                 throw new SizeLimitExceededException(path);
             }
             }
         }
         }

+ 18 - 10
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/FileHandler.java

@@ -20,20 +20,23 @@ import java.util.regex.Pattern;
  * Requests must include the postback key.
  * Requests must include the postback key.
  */
  */
 public class FileHandler extends ResourceHandler {
 public class FileHandler extends ResourceHandler {
-    private static final Logger LOG = LoggerFactory.getLogger(FileHandler.class);
+    private static final Logger LOG
+            = LoggerFactory.getLogger(FileHandler.class);
 
 
-    private final Bridge writeLatexDataSource;
+    private final Bridge bridge;
     private final Pattern DOC_KEY_PATTERN = Pattern.compile("^/(\\w+)/.+$");
     private final Pattern DOC_KEY_PATTERN = Pattern.compile("^/(\\w+)/.+$");
 
 
-    public FileHandler(Bridge writeLatexDataSource) {
-        this.writeLatexDataSource = writeLatexDataSource;
+    public FileHandler(Bridge bridge) {
+        this.bridge = bridge;
     }
     }
 
 
     @Override
     @Override
-    public void handle(String target,
-                       Request baseRequest,
-                       HttpServletRequest request,
-                       HttpServletResponse response) throws IOException, ServletException {
+    public void handle(
+            String target,
+            Request baseRequest,
+            HttpServletRequest request,
+            HttpServletResponse response
+    ) throws IOException, ServletException {
         if (!"GET".equals(baseRequest.getMethod())) return;
         if (!"GET".equals(baseRequest.getMethod())) return;
         LOG.info("GET <- {}", baseRequest.getRequestURI());
         LOG.info("GET <- {}", baseRequest.getRequestURI());
 
 
@@ -45,12 +48,17 @@ public class FileHandler extends ResourceHandler {
         if (apiKey == null) return;
         if (apiKey == null) return;
 
 
         try {
         try {
-            writeLatexDataSource.checkPostbackKey(docKey, apiKey);
+            bridge.checkPostbackKey(docKey, apiKey);
         } catch (InvalidPostbackKeyException e) {
         } catch (InvalidPostbackKeyException e) {
-            LOG.warn("INVALID POST BACK KEY: docKey={} apiKey={}", docKey, apiKey);
+            LOG.warn(
+                    "INVALID POST BACK KEY: docKey={} apiKey={}",
+                    docKey,
+                    apiKey
+            );
             return;
             return;
         }
         }
 
 
         super.handle(target, baseRequest, request, response);
         super.handle(target, baseRequest, request, response);
     }
     }
+
 }
 }

+ 4 - 4
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/GitBridgeServer.java

@@ -14,7 +14,6 @@ import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SqliteDBStore;
 import uk.ac.ic.wlgitbridge.bridge.repo.FSGitRepoStore;
 import uk.ac.ic.wlgitbridge.bridge.repo.FSGitRepoStore;
 import uk.ac.ic.wlgitbridge.bridge.repo.RepoStore;
 import uk.ac.ic.wlgitbridge.bridge.repo.RepoStore;
 import uk.ac.ic.wlgitbridge.bridge.swap.store.SwapStore;
 import uk.ac.ic.wlgitbridge.bridge.swap.store.SwapStore;
-import uk.ac.ic.wlgitbridge.git.exception.InvalidRootDirectoryPathException;
 import uk.ac.ic.wlgitbridge.git.servlet.WLGitServlet;
 import uk.ac.ic.wlgitbridge.git.servlet.WLGitServlet;
 import uk.ac.ic.wlgitbridge.snapshot.base.SnapshotAPIRequest;
 import uk.ac.ic.wlgitbridge.snapshot.base.SnapshotAPIRequest;
 import uk.ac.ic.wlgitbridge.util.Log;
 import uk.ac.ic.wlgitbridge.util.Log;
@@ -47,7 +46,7 @@ public class GitBridgeServer {
 
 
     public GitBridgeServer(
     public GitBridgeServer(
             Config config
             Config config
-    ) throws ServletException, InvalidRootDirectoryPathException {
+    ) throws ServletException {
         org.eclipse.jetty.util.log.Log.setLog(new NullLogger());
         org.eclipse.jetty.util.log.Log.setLog(new NullLogger());
         this.port = config.getPort();
         this.port = config.getPort();
         this.rootGitDirectoryPath = config.getRootGitDirectory();
         this.rootGitDirectoryPath = config.getRootGitDirectory();
@@ -107,7 +106,7 @@ public class GitBridgeServer {
 
 
     private void configureJettyServer(
     private void configureJettyServer(
             Config config
             Config config
-    ) throws ServletException, InvalidRootDirectoryPathException {
+    ) throws ServletException {
         HandlerCollection handlers = new HandlerList();
         HandlerCollection handlers = new HandlerList();
         handlers.addHandler(initApiHandler());
         handlers.addHandler(initApiHandler());
         handlers.addHandler(initGitHandler(config));
         handlers.addHandler(initGitHandler(config));
@@ -129,7 +128,7 @@ public class GitBridgeServer {
 
 
     private Handler initGitHandler(
     private Handler initGitHandler(
             Config config
             Config config
-    ) throws ServletException, InvalidRootDirectoryPathException {
+    ) throws ServletException {
         final ServletContextHandler servletContextHandler =
         final ServletContextHandler servletContextHandler =
                 new ServletContextHandler(ServletContextHandler.SESSIONS);
                 new ServletContextHandler(ServletContextHandler.SESSIONS);
         if (config.isUsingOauth2()) {
         if (config.isUsingOauth2()) {
@@ -160,4 +159,5 @@ public class GitBridgeServer {
         );
         );
         return resourceHandler;
         return resourceHandler;
     }
     }
+
 }
 }

+ 69 - 26
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/Oauth2Filter.java

@@ -2,13 +2,8 @@ package uk.ac.ic.wlgitbridge.server;
 
 
 import com.google.api.client.auth.oauth2.*;
 import com.google.api.client.auth.oauth2.*;
 import com.google.api.client.http.GenericUrl;
 import com.google.api.client.http.GenericUrl;
-import com.google.api.client.http.javanet.NetHttpTransport;
-import com.google.api.client.json.gson.GsonFactory;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.lang.StringUtils;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Request;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import uk.ac.ic.wlgitbridge.application.config.Oauth2;
 import uk.ac.ic.wlgitbridge.application.config.Oauth2;
 import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
 import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
 import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocRequest;
 import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocRequest;
@@ -37,26 +32,40 @@ public class Oauth2Filter implements Filter {
     }
     }
 
 
     @Override
     @Override
-    public void init(FilterConfig filterConfig) throws ServletException {
-
-    }
+    public void init(FilterConfig filterConfig) {}
 
 
     @Override
     @Override
-    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
-            throws IOException, ServletException {
-        String project = Util.removeAllSuffixes(((Request) servletRequest).getRequestURI().split("/")[1], ".git");
+    public void doFilter(
+            ServletRequest servletRequest,
+            ServletResponse servletResponse,
+            FilterChain filterChain
+    ) throws IOException, ServletException {
+        String project = Util.removeAllSuffixes(
+                ((Request) servletRequest).getRequestURI().split("/")[1],
+                ".git"
+        );
         GetDocRequest doc = new GetDocRequest(project);
         GetDocRequest doc = new GetDocRequest(project);
         doc.request();
         doc.request();
         try {
         try {
             doc.getResult();
             doc.getResult();
         } catch (ForbiddenException e) {
         } catch (ForbiddenException e) {
-            getAndInjectCredentials(servletRequest, servletResponse, filterChain);
+            getAndInjectCredentials(
+                    servletRequest,
+                    servletResponse,
+                    filterChain
+            );
             return;
             return;
         }
         }
         filterChain.doFilter(servletRequest, servletResponse);
         filterChain.doFilter(servletRequest, servletResponse);
     }
     }
 
 
-    private void getAndInjectCredentials(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+    // TODO: this is ridiculous. Check for error cases first, then return/throw
+    // TODO: also, use an Optional credential, since we treat it as optional
+    private void getAndInjectCredentials(
+            ServletRequest servletRequest,
+            ServletResponse servletResponse,
+            FilterChain filterChain
+    ) throws IOException, ServletException {
         HttpServletRequest request = (HttpServletRequest) servletRequest;
         HttpServletRequest request = (HttpServletRequest) servletRequest;
         HttpServletResponse response = (HttpServletResponse) servletResponse;
         HttpServletResponse response = (HttpServletResponse) servletResponse;
 
 
@@ -67,26 +76,47 @@ public class Oauth2Filter implements Filter {
                 String basic = st.nextToken();
                 String basic = st.nextToken();
                 if (basic.equalsIgnoreCase("Basic")) {
                 if (basic.equalsIgnoreCase("Basic")) {
                     try {
                     try {
-                        String credentials = new String(Base64.decodeBase64(st.nextToken()), "UTF-8");
+                        String credentials = new String(
+                                Base64.decodeBase64(st.nextToken()),
+                                "UTF-8"
+                        );
                         String[] split = credentials.split(":");
                         String[] split = credentials.split(":");
                         if (split.length == 2) {
                         if (split.length == 2) {
                             String username = split[0];
                             String username = split[0];
                             String password = split[1];
                             String password = split[1];
                             String accessToken = null;
                             String accessToken = null;
                             try {
                             try {
-                                accessToken = new PasswordTokenRequest(Instance.httpTransport, Instance.jsonFactory, new GenericUrl(oauth2.getOauth2Server() + "/oauth/token"), username, password)
-                                        .setClientAuthentication(new ClientParametersAuthentication(oauth2.getOauth2ClientID(), oauth2.getOauth2ClientSecret()))
+                                accessToken = new PasswordTokenRequest(
+                                        Instance.httpTransport,
+                                        Instance.jsonFactory,
+                                        new GenericUrl(
+                                                oauth2.getOauth2Server()
+                                                        + "/oauth/token"
+                                        ),
+                                        username,
+                                        password
+                                ).setClientAuthentication(
+                                        new ClientParametersAuthentication(
+                                                oauth2.getOauth2ClientID(),
+                                                oauth2.getOauth2ClientSecret()
+                                        )
+                                )
                                         .execute().getAccessToken();
                                         .execute().getAccessToken();
                             } catch (TokenResponseException e) {
                             } catch (TokenResponseException e) {
                                 unauthorized(response);
                                 unauthorized(response);
                                 return;
                                 return;
                             }
                             }
-                            final Credential cred = new Credential.Builder(BearerToken.authorizationHeaderAccessMethod())
-                                    .build();
+                            final Credential cred = new Credential.Builder(
+                                    BearerToken.authorizationHeaderAccessMethod(
+                                    )
+                            ).build();
                             cred.setAccessToken(accessToken);
                             cred.setAccessToken(accessToken);
                             servletRequest.setAttribute(ATTRIBUTE_KEY, cred);
                             servletRequest.setAttribute(ATTRIBUTE_KEY, cred);
 
 
-                            filterChain.doFilter(servletRequest, servletResponse);
+                            filterChain.doFilter(
+                                    servletRequest,
+                                    servletResponse
+                            );
                         } else {
                         } else {
                             unauthorized(response);
                             unauthorized(response);
                         }
                         }
@@ -101,22 +131,35 @@ public class Oauth2Filter implements Filter {
     }
     }
 
 
     @Override
     @Override
-    public void destroy() {
-    }
+    public void destroy() {}
 
 
-    private void unauthorized(ServletResponse servletResponse) throws IOException {
+    private void unauthorized(
+            ServletResponse servletResponse
+    ) throws IOException {
         HttpServletResponse response = (HttpServletResponse) servletResponse;
         HttpServletResponse response = (HttpServletResponse) servletResponse;
         response.setContentType("text/plain");
         response.setContentType("text/plain");
         response.setHeader("WWW-Authenticate", "Basic realm=\"Git Bridge\"");
         response.setHeader("WWW-Authenticate", "Basic realm=\"Git Bridge\"");
         response.setStatus(401);
         response.setStatus(401);
 
 
         PrintWriter w = response.getWriter();
         PrintWriter w = response.getWriter();
-        w.println("Please sign in using your email address and Overleaf password.");
+        w.println(
+                "Please sign in using your email address and Overleaf password."
+        );
         w.println();
         w.println();
-        w.println("*Note*: if you sign in to Overleaf using another provider, such ");
-        w.println("as Google or Twitter, you need to set a password on your Overleaf ");
-        w.println("account first. Please see https://www.overleaf.com/blog/195 for ");
+        w.println(
+                "*Note*: if you sign in to Overleaf using another provider, "
+                        + "such "
+        );
+        w.println(
+                "as Google or Twitter, you need to set a password "
+                        + "on your Overleaf "
+        );
+        w.println(
+                "account first. "
+                        + "Please see https://www.overleaf.com/blog/195 for "
+        );
         w.println("more information.");
         w.println("more information.");
         w.close();
         w.close();
     }
     }
+
 }
 }

+ 20 - 4
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/PostbackContents.java

@@ -26,7 +26,12 @@ public class PostbackContents implements JSONSource {
     private int versionID;
     private int versionID;
     private SnapshotPostException exception;
     private SnapshotPostException exception;
 
 
-    public PostbackContents(Bridge bridge, String projectName, String postbackKey, String contents) {
+    public PostbackContents(
+            Bridge bridge,
+            String projectName,
+            String postbackKey,
+            String contents
+    ) {
         this.bridge = bridge;
         this.bridge = bridge;
         this.projectName = projectName;
         this.projectName = projectName;
         this.postbackKey = postbackKey;
         this.postbackKey = postbackKey;
@@ -43,9 +48,17 @@ public class PostbackContents implements JSONSource {
 
 
     public void processPostback() throws UnexpectedPostbackException {
     public void processPostback() throws UnexpectedPostbackException {
         if (exception == null) {
         if (exception == null) {
-            bridge.postbackReceivedSuccessfully(projectName, postbackKey, versionID);
+            bridge.postbackReceivedSuccessfully(
+                    projectName,
+                    postbackKey,
+                    versionID
+            );
         } else {
         } else {
-            bridge.postbackReceivedWithException(projectName, postbackKey, exception);
+            bridge.postbackReceivedWithException(
+                    projectName,
+                    postbackKey,
+                    exception
+            );
         }
         }
     }
     }
 
 
@@ -63,7 +76,10 @@ public class PostbackContents implements JSONSource {
 
 
     private void setException(JsonObject responseObject, String code) {
     private void setException(JsonObject responseObject, String code) {
         try {
         try {
-            exception = snapshotPostExceptionBuilder.build(code, responseObject);
+            exception = snapshotPostExceptionBuilder.build(
+                    code,
+                    responseObject
+            );
         } catch (UnexpectedPostbackException e) {
         } catch (UnexpectedPostbackException e) {
             throw new RuntimeException(e);
             throw new RuntimeException(e);
         }
         }

+ 21 - 4
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/server/PostbackHandler.java

@@ -26,10 +26,18 @@ public class PostbackHandler extends AbstractHandler {
     }
     }
 
 
     @Override
     @Override
-    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+    public void handle(
+            String target,
+            Request baseRequest,
+            HttpServletRequest request,
+            HttpServletResponse response
+    ) throws IOException, ServletException {
 
 
         try {
         try {
-            if (request.getMethod().equals("POST") && target.endsWith("postback")) {
+            if (
+                    request.getMethod().equals("POST")
+                            && target.endsWith("postback")
+            ) {
                 response.setContentType("application/json");
                 response.setContentType("application/json");
                 String contents = Util.getContentsOfReader(request.getReader());
                 String contents = Util.getContentsOfReader(request.getReader());
                 String[] parts = target.split("/");
                 String[] parts = target.split("/");
@@ -38,8 +46,17 @@ public class PostbackHandler extends AbstractHandler {
                 }
                 }
                 String projectName = parts[1];
                 String projectName = parts[1];
                 String postbackKey = parts[2];
                 String postbackKey = parts[2];
-                Log.info(baseRequest.getMethod() + " <- " + baseRequest.getHttpURI());
-                PostbackContents postbackContents = new PostbackContents(bridge, projectName, postbackKey, contents);
+                Log.info(
+                        baseRequest.getMethod()
+                                + " <- "
+                                + baseRequest.getHttpURI()
+                );
+                PostbackContents postbackContents = new PostbackContents(
+                        bridge,
+                        projectName,
+                        postbackKey,
+                        contents
+                );
                 JsonObject body = new JsonObject();
                 JsonObject body = new JsonObject();
 
 
                 try {
                 try {

+ 2 - 3
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/ForbiddenException.java

@@ -10,10 +10,9 @@ import java.util.List;
  * Created by winston on 25/10/15.
  * Created by winston on 25/10/15.
  */
  */
 public class ForbiddenException extends SnapshotAPIException {
 public class ForbiddenException extends SnapshotAPIException {
-    @Override
-    public void fromJSON(JsonElement json) {
 
 
-    }
+    @Override
+    public void fromJSON(JsonElement json) {}
 
 
     @Override
     @Override
     public String getMessage() {
     public String getMessage() {

+ 1 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/JSONSource.java

@@ -7,6 +7,6 @@ import com.google.gson.JsonElement;
  */
  */
 public interface JSONSource {
 public interface JSONSource {
 
 
-    public abstract void fromJSON(JsonElement json);
+    void fromJSON(JsonElement json);
 
 
 }
 }

+ 14 - 12
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/base/SnapshotAPIRequest.java

@@ -2,9 +2,7 @@ package uk.ac.ic.wlgitbridge.snapshot.base;
 
 
 import com.google.api.client.auth.oauth2.Credential;
 import com.google.api.client.auth.oauth2.Credential;
 import com.google.api.client.http.BasicAuthentication;
 import com.google.api.client.http.BasicAuthentication;
-import com.google.api.client.http.HttpExecuteInterceptor;
 import com.google.api.client.http.HttpRequest;
 import com.google.api.client.http.HttpRequest;
-import com.ning.http.client.Realm;
 
 
 import java.io.IOException;
 import java.io.IOException;
 
 
@@ -20,22 +18,26 @@ public abstract class SnapshotAPIRequest<T extends Result> extends Request<T> {
 
 
     private final Credential oauth2;
     private final Credential oauth2;
 
 
-    public SnapshotAPIRequest(String projectName, String apiCall, Credential oauth2) {
+    public SnapshotAPIRequest(
+            String projectName,
+            String apiCall,
+            Credential oauth2
+    ) {
         super(BASE_URL + projectName + apiCall);
         super(BASE_URL + projectName + apiCall);
         this.oauth2 = oauth2;
         this.oauth2 = oauth2;
     }
     }
 
 
     @Override
     @Override
-    protected void onBeforeRequest(HttpRequest request) throws IOException {
+    protected void onBeforeRequest(
+            HttpRequest request
+    ) throws IOException {
         if (oauth2 != null) {
         if (oauth2 != null) {
-            request.setInterceptor(new HttpExecuteInterceptor() {
-
-                @Override
-                public void intercept(HttpRequest request) throws IOException {
-                    new BasicAuthentication(USERNAME, PASSWORD).intercept(request);
-                    oauth2.intercept(request);
-                }
-
+            request.setInterceptor(request1 -> {
+                new BasicAuthentication(
+                        USERNAME,
+                        PASSWORD
+                ).intercept(request1);
+                oauth2.intercept(request1);
             });
             });
         }
         }
     }
     }

+ 3 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getdoc/GetDocRequest.java

@@ -27,7 +27,9 @@ public class GetDocRequest extends SnapshotAPIRequest<GetDocResult> {
     }
     }
 
 
     @Override
     @Override
-    protected GetDocResult parseResponse(JsonElement json) throws FailedConnectionException {
+    protected GetDocResult parseResponse(
+            JsonElement json
+    ) throws FailedConnectionException {
         return new GetDocResult(this, json);
         return new GetDocResult(this, json);
     }
     }
 
 

+ 14 - 3
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getdoc/GetDocResult.java

@@ -24,11 +24,20 @@ public class GetDocResult extends Result {
     private SnapshotAPIException exception;
     private SnapshotAPIException exception;
     private ForbiddenException forbidden;
     private ForbiddenException forbidden;
 
 
-    public GetDocResult(Request request, JsonElement json) throws FailedConnectionException {
+    public GetDocResult(
+            Request request,
+            JsonElement json
+    ) throws FailedConnectionException {
         super(request, json);
         super(request, json);
     }
     }
 
 
-    public GetDocResult(JsonElement error, int versionID, String createdAt, String email, String name) {
+    public GetDocResult(
+            JsonElement error,
+            int versionID,
+            String createdAt,
+            String email,
+            String name
+    ) {
         if (error == null) {
         if (error == null) {
             this.error = -1;
             this.error = -1;
         } else {
         } else {
@@ -75,7 +84,9 @@ public class GetDocResult extends Result {
                 exception = new InvalidProjectException();
                 exception = new InvalidProjectException();
                 break;
                 break;
             default:
             default:
-                throw new IllegalArgumentException("unknown get doc error code");
+                throw new IllegalArgumentException(
+                        "unknown get doc error code"
+                );
             }
             }
         } else {
         } else {
             versionID = jsonObject.get("latestVerId").getAsInt();
             versionID = jsonObject.get("latestVerId").getAsInt();

+ 0 - 29
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getdoc/exception/ProtectedProjectException.java

@@ -1,29 +0,0 @@
-package uk.ac.ic.wlgitbridge.snapshot.getdoc.exception;
-
-import com.google.gson.JsonElement;
-import uk.ac.ic.wlgitbridge.snapshot.push.exception.SnapshotPostException;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Created by Winston on 20/02/15.
- */
-public class ProtectedProjectException extends SnapshotPostException {
-
-    @Override
-    public String getMessage() {
-        return "Your project is protected, and can't be cloned (yet).";
-    }
-
-    @Override
-    public List<String> getDescriptionLines() {
-        return Arrays.asList("You can't currently clone a protected project.");
-    }
-
-    @Override
-    public void fromJSON(JsonElement json) {
-
-    }
-
-}

+ 10 - 3
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getforversion/GetForVersionRequest.java

@@ -9,13 +9,18 @@ import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException;
 /**
 /**
  * Created by Winston on 06/11/14.
  * Created by Winston on 06/11/14.
  */
  */
-public class GetForVersionRequest extends SnapshotAPIRequest<GetForVersionResult> {
+public class GetForVersionRequest
+        extends SnapshotAPIRequest<GetForVersionResult> {
 
 
     public static final String API_CALL = "/snapshots";
     public static final String API_CALL = "/snapshots";
 
 
     private int versionID;
     private int versionID;
 
 
-    public GetForVersionRequest(Credential oauth2, String projectName, int versionID) {
+    public GetForVersionRequest(
+            Credential oauth2,
+            String projectName,
+            int versionID
+    ) {
         super(projectName, API_CALL + "/" + versionID, oauth2);
         super(projectName, API_CALL + "/" + versionID, oauth2);
         this.versionID = versionID;
         this.versionID = versionID;
     }
     }
@@ -26,7 +31,9 @@ public class GetForVersionRequest extends SnapshotAPIRequest<GetForVersionResult
     }
     }
 
 
     @Override
     @Override
-    protected GetForVersionResult parseResponse(JsonElement json) throws FailedConnectionException {
+    protected GetForVersionResult parseResponse(
+            JsonElement json
+    ) throws FailedConnectionException {
         return new GetForVersionResult(this, json);
         return new GetForVersionResult(this, json);
     }
     }
 
 

+ 14 - 6
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getforversion/SnapshotData.java

@@ -5,7 +5,7 @@ import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonObject;
 import uk.ac.ic.wlgitbridge.snapshot.base.JSONSource;
 import uk.ac.ic.wlgitbridge.snapshot.base.JSONSource;
 
 
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 
 
 /**
 /**
@@ -20,12 +20,15 @@ public class SnapshotData implements JSONSource {
     private List<SnapshotAttachment> atts;
     private List<SnapshotAttachment> atts;
 
 
     public SnapshotData(JsonElement json) {
     public SnapshotData(JsonElement json) {
-        srcs = new LinkedList<SnapshotFile>();
-        atts = new LinkedList<SnapshotAttachment>();
+        srcs = new ArrayList<>();
+        atts = new ArrayList<>();
         fromJSON(json);
         fromJSON(json);
     }
     }
 
 
-    public SnapshotData(List<SnapshotFile> srcs, List<SnapshotAttachment> atts) {
+    public SnapshotData(
+            List<SnapshotFile> srcs,
+            List<SnapshotAttachment> atts
+    ) {
         this.srcs = srcs;
         this.srcs = srcs;
         this.atts = atts;
         this.atts = atts;
     }
     }
@@ -47,8 +50,12 @@ public class SnapshotData implements JSONSource {
 
 
     @Override
     @Override
     public void fromJSON(JsonElement json) {
     public void fromJSON(JsonElement json) {
-        populateSrcs(json.getAsJsonObject().get(JSON_KEY_SRCS).getAsJsonArray());
-        populateAtts(json.getAsJsonObject().get(JSON_KEY_ATTS).getAsJsonArray());
+        populateSrcs(
+                json.getAsJsonObject().get(JSON_KEY_SRCS).getAsJsonArray()
+        );
+        populateAtts(
+                json.getAsJsonObject().get(JSON_KEY_ATTS).getAsJsonArray()
+        );
     }
     }
 
 
     private void populateSrcs(JsonArray jsonArray) {
     private void populateSrcs(JsonArray jsonArray) {
@@ -70,4 +77,5 @@ public class SnapshotData implements JSONSource {
     public List<SnapshotAttachment> getAtts() {
     public List<SnapshotAttachment> getAtts() {
         return atts;
         return atts;
     }
     }
+
 }
 }

+ 5 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getsavedvers/GetSavedVersRequest.java

@@ -9,7 +9,8 @@ import uk.ac.ic.wlgitbridge.snapshot.base.HTTPMethod;
 /**
 /**
  * Created by Winston on 06/11/14.
  * Created by Winston on 06/11/14.
  */
  */
-public class GetSavedVersRequest extends SnapshotAPIRequest<GetSavedVersResult> {
+public class GetSavedVersRequest
+        extends SnapshotAPIRequest<GetSavedVersResult> {
 
 
     public static final String API_CALL = "/saved_vers";
     public static final String API_CALL = "/saved_vers";
 
 
@@ -23,7 +24,9 @@ public class GetSavedVersRequest extends SnapshotAPIRequest<GetSavedVersResult>
     }
     }
 
 
     @Override
     @Override
-    protected GetSavedVersResult parseResponse(JsonElement json) throws FailedConnectionException {
+    protected GetSavedVersResult parseResponse(
+            JsonElement json
+    ) throws FailedConnectionException {
         return new GetSavedVersResult(this, json);
         return new GetSavedVersResult(this, json);
     }
     }
 
 

+ 13 - 5
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getsavedvers/GetSavedVersResult.java

@@ -4,11 +4,11 @@ import com.google.gson.Gson;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonObject;
-import uk.ac.ic.wlgitbridge.snapshot.base.Result;
 import uk.ac.ic.wlgitbridge.snapshot.base.Request;
 import uk.ac.ic.wlgitbridge.snapshot.base.Request;
+import uk.ac.ic.wlgitbridge.snapshot.base.Result;
 import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException;
 import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException;
 
 
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 
 
 /**
 /**
@@ -18,7 +18,10 @@ public class GetSavedVersResult extends Result {
 
 
     private List<SnapshotInfo> savedVers;
     private List<SnapshotInfo> savedVers;
 
 
-    public GetSavedVersResult(Request request, JsonElement json) throws FailedConnectionException {
+    public GetSavedVersResult(
+            Request request,
+            JsonElement json
+    ) throws FailedConnectionException {
         super(request, json);
         super(request, json);
     }
     }
 
 
@@ -46,9 +49,14 @@ public class GetSavedVersResult extends Result {
 
 
     @Override
     @Override
     public void fromJSON(JsonElement json) {
     public void fromJSON(JsonElement json) {
-        savedVers = new LinkedList<SnapshotInfo>();
+        savedVers = new ArrayList<>();
         for (JsonElement elem : json.getAsJsonArray()) {
         for (JsonElement elem : json.getAsJsonArray()) {
-            savedVers.add(new Gson().fromJson(elem.getAsJsonObject(), SnapshotInfo.class));
+            savedVers.add(
+                    new Gson().fromJson(
+                            elem.getAsJsonObject(),
+                            SnapshotInfo.class
+                    )
+            );
         }
         }
     }
     }
 
 

+ 21 - 3
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getsavedvers/SnapshotInfo.java

@@ -12,11 +12,28 @@ public class SnapshotInfo implements Comparable<SnapshotInfo> {
     private WLUser user;
     private WLUser user;
     private String createdAt;
     private String createdAt;
 
 
-    public SnapshotInfo(int versionID, String createdAt, String name, String email) {
-        this(versionID, "Update on " + Util.getServiceName() + ".", email, name, createdAt);
+    public SnapshotInfo(
+            int versionID,
+            String createdAt,
+            String name,
+            String email
+    ) {
+        this(
+                versionID,
+                "Update on " + Util.getServiceName() + ".",
+                email,
+                name,
+                createdAt
+        );
     }
     }
 
 
-    public SnapshotInfo(int versionID, String comment, String email, String name, String createdAt) {
+    public SnapshotInfo(
+            int versionID,
+            String comment,
+            String email,
+            String name,
+            String createdAt
+    ) {
         versionId = versionID;
         versionId = versionID;
         this.comment = comment;
         this.comment = comment;
         user = new WLUser(name, email);
         user = new WLUser(name, email);
@@ -52,4 +69,5 @@ public class SnapshotInfo implements Comparable<SnapshotInfo> {
     public int compareTo(SnapshotInfo o) {
     public int compareTo(SnapshotInfo o) {
         return Integer.compare(versionId, o.versionId);
         return Integer.compare(versionId, o.versionId);
     }
     }
+
 }
 }

+ 3 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/getsavedvers/WLUser.java

@@ -20,7 +20,9 @@ public class WLUser {
             this.email = email;
             this.email = email;
         } else {
         } else {
             this.name = "Anonymous";
             this.name = "Anonymous";
-            this.email = "anonymous@" + Util.getServiceName().toLowerCase() + ".com";
+            this.email = "anonymous@"
+                    + Util.getServiceName().toLowerCase()
+                    + ".com";
         }
         }
     }
     }
 
 

+ 15 - 11
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/PostbackManager.java

@@ -30,8 +30,9 @@ public class PostbackManager {
         this(new SecureRandom());
         this(new SecureRandom());
     }
     }
 
 
-    public int waitForVersionIdOrThrow(String projectName)
-            throws SnapshotPostException {
+    public int waitForVersionIdOrThrow(
+            String projectName
+    ) throws SnapshotPostException {
         try {
         try {
             PostbackPromise postbackPromise =
             PostbackPromise postbackPromise =
                     postbackContentsTable.get(projectName);
                     postbackContentsTable.get(projectName);
@@ -42,19 +43,21 @@ public class PostbackManager {
         }
         }
     }
     }
 
 
-    public void postVersionIDForProject(String projectName,
-                                        int versionID,
-                                        String postbackKey)
-            throws UnexpectedPostbackException {
+    public void postVersionIDForProject(
+            String projectName,
+            int versionID,
+            String postbackKey
+    ) throws UnexpectedPostbackException {
         getPostbackForProject(
         getPostbackForProject(
                 projectName
                 projectName
         ).receivedVersionID(versionID, postbackKey);
         ).receivedVersionID(versionID, postbackKey);
     }
     }
 
 
-    public void postExceptionForProject(String projectName,
-                                        SnapshotPostException exception,
-                                        String postbackKey)
-            throws UnexpectedPostbackException {
+    public void postExceptionForProject(
+            String projectName,
+            SnapshotPostException exception,
+            String postbackKey
+    ) throws UnexpectedPostbackException {
         getPostbackForProject(
         getPostbackForProject(
                 projectName
                 projectName
         ).receivedException(exception, postbackKey);
         ).receivedException(exception, postbackKey);
@@ -80,7 +83,8 @@ public class PostbackManager {
             throws InvalidPostbackKeyException {
             throws InvalidPostbackKeyException {
         PostbackPromise postbackPromise = postbackContentsTable.get(projectName);
         PostbackPromise postbackPromise = postbackContentsTable.get(projectName);
         if (postbackPromise == null) {
         if (postbackPromise == null) {
-            throw new InvalidPostbackKeyException(); // project not found; can't check key
+            // project not found; can't check key
+            throw new InvalidPostbackKeyException();
         } else {
         } else {
             postbackPromise.checkPostbackKey(postbackKey);
             postbackPromise.checkPostbackKey(postbackKey);
         }
         }

+ 7 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/PostbackPromise.java

@@ -64,7 +64,10 @@ public class PostbackPromise {
         }
         }
     }
     }
 
 
-    public void receivedException(SnapshotPostException exception, String postbackKey) {
+    public void receivedException(
+            SnapshotPostException exception,
+            String postbackKey
+    ) {
         lock.lock();
         lock.lock();
         try {
         try {
             if (postbackKey.equals(this.postbackKey)) {
             if (postbackKey.equals(this.postbackKey)) {
@@ -77,7 +80,9 @@ public class PostbackPromise {
         }
         }
     }
     }
 
 
-    public void checkPostbackKey(String postbackKey) throws InvalidPostbackKeyException {
+    public void checkPostbackKey(
+            String postbackKey
+    ) throws InvalidPostbackKeyException {
         if (!postbackKey.equals(this.postbackKey)) {
         if (!postbackKey.equals(this.postbackKey)) {
             throw new InvalidPostbackKeyException();
             throw new InvalidPostbackKeyException();
         }
         }

+ 8 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/PushRequest.java

@@ -17,7 +17,11 @@ public class PushRequest extends SnapshotAPIRequest<PushResult> {
     private final CandidateSnapshot candidateSnapshot;
     private final CandidateSnapshot candidateSnapshot;
     private final String postbackKey;
     private final String postbackKey;
 
 
-    public PushRequest(Credential oauth2, CandidateSnapshot candidateSnapshot, String postbackKey) {
+    public PushRequest(
+            Credential oauth2,
+            CandidateSnapshot candidateSnapshot,
+            String postbackKey
+    ) {
         super(candidateSnapshot.getProjectName(), API_CALL, oauth2);
         super(candidateSnapshot.getProjectName(), API_CALL, oauth2);
         this.candidateSnapshot = candidateSnapshot;
         this.candidateSnapshot = candidateSnapshot;
         this.postbackKey = postbackKey;
         this.postbackKey = postbackKey;
@@ -34,7 +38,9 @@ public class PushRequest extends SnapshotAPIRequest<PushResult> {
     }
     }
 
 
     @Override
     @Override
-    protected PushResult parseResponse(JsonElement json) throws FailedConnectionException {
+    protected PushResult parseResponse(
+            JsonElement json
+    ) throws FailedConnectionException {
         return new PushResult(this, json);
         return new PushResult(this, json);
     }
     }
 
 

+ 4 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/PushResult.java

@@ -14,7 +14,10 @@ public class PushResult extends Result {
 
 
     private boolean success;
     private boolean success;
 
 
-    public PushResult(Request request, JsonElement json) throws FailedConnectionException {
+    public PushResult(
+            Request request,
+            JsonElement json
+    ) throws FailedConnectionException {
         super(request, json);
         super(request, json);
     }
     }
 
 

+ 5 - 5
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/InternalErrorException.java

@@ -18,13 +18,13 @@ public class InternalErrorException extends SevereSnapshotPostException {
 
 
     @Override
     @Override
     public List<String> getDescriptionLines() {
     public List<String> getDescriptionLines() {
-        return Arrays.asList("There was an internal error with the Git server.",
-                             "Please contact " + Util.getServiceName() + ".");
+        return Arrays.asList(
+                "There was an internal error with the Git server.",
+                "Please contact " + Util.getServiceName() + "."
+        );
     }
     }
 
 
     @Override
     @Override
-    public void fromJSON(JsonElement json) {
-
-    }
+    public void fromJSON(JsonElement json) {}
 
 
 }
 }

+ 13 - 5
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/InvalidFilesException.java

@@ -5,7 +5,7 @@ import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonObject;
 import uk.ac.ic.wlgitbridge.util.Util;
 import uk.ac.ic.wlgitbridge.util.Util;
 
 
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 
 
 /**
 /**
@@ -31,16 +31,24 @@ public class InvalidFilesException extends SnapshotPostException {
 
 
     @Override
     @Override
     public void fromJSON(JsonElement json) {
     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:");
+        descriptionLines = new ArrayList<>();
+        JsonArray errors =
+                json.getAsJsonObject().get("errors").getAsJsonArray();
+        descriptionLines.add(
+                "You have "
+                        + errors.size()
+                        + " invalid files in your "
+                        + Util.getServiceName()
+                        + " project:"
+        );
         for (JsonElement error : errors) {
         for (JsonElement error : errors) {
             descriptionLines.add(describeError(error.getAsJsonObject()));
             descriptionLines.add(describeError(error.getAsJsonObject()));
         }
         }
     }
     }
 
 
     private String describeError(JsonObject jsonObject) {
     private String describeError(JsonObject jsonObject) {
-        return jsonObject.get("file").getAsString() + " (" + describeFile(jsonObject) + ")";
+        return jsonObject.get("file").getAsString()
+                + " (" + describeFile(jsonObject) + ")";
     }
     }
 
 
     private String describeFile(JsonObject file) {
     private String describeFile(JsonObject file) {

+ 1 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/InvalidPostbackKeyException.java

@@ -3,5 +3,4 @@ package uk.ac.ic.wlgitbridge.snapshot.push.exception;
 /**
 /**
  * Created by Winston on 04/12/14.
  * Created by Winston on 04/12/14.
  */
  */
-public class InvalidPostbackKeyException extends Exception {
-}
+public class InvalidPostbackKeyException extends Exception {}

+ 2 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/InvalidProjectException.java

@@ -30,7 +30,8 @@ public class InvalidProjectException extends SnapshotPostException {
     @Override
     @Override
     public void fromJSON(JsonElement json) {
     public void fromJSON(JsonElement json) {
         descriptionLines = new LinkedList<String>();
         descriptionLines = new LinkedList<String>();
-        JsonArray errors = json.getAsJsonObject().get("errors").getAsJsonArray();
+        JsonArray errors =
+                json.getAsJsonObject().get("errors").getAsJsonArray();
         for (JsonElement error : errors) {
         for (JsonElement error : errors) {
             descriptionLines.add(error.getAsString());
             descriptionLines.add(error.getAsString());
         }
         }

+ 2 - 6
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/OutOfDateException.java

@@ -15,9 +15,7 @@ public class OutOfDateException extends SnapshotPostException {
         super(json);
         super(json);
     }
     }
 
 
-    public OutOfDateException() {
-
-    }
+    public OutOfDateException() {}
 
 
     @Override
     @Override
     public String getMessage() {
     public String getMessage() {
@@ -30,8 +28,6 @@ public class OutOfDateException extends SnapshotPostException {
     }
     }
 
 
     @Override
     @Override
-    public void fromJSON(JsonElement json) {
-
-    }
+    public void fromJSON(JsonElement json) {}
 
 
 }
 }

+ 7 - 4
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/PostbackTimeoutException.java

@@ -18,12 +18,15 @@ public class PostbackTimeoutException extends SevereSnapshotPostException {
 
 
     @Override
     @Override
     public List<String> getDescriptionLines() {
     public List<String> getDescriptionLines() {
-        return Arrays.asList("The " + Util.getServiceName() + " server is currently unavailable.", "Please try again later.");
+        return Arrays.asList(
+                "The "
+                        + Util.getServiceName()
+                        + " server is currently unavailable.",
+                "Please try again later."
+        );
     }
     }
 
 
     @Override
     @Override
-    public void fromJSON(JsonElement json) {
-
-    }
+    public void fromJSON(JsonElement json) {}
 
 
 }
 }

+ 1 - 3
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/SnapshotPostException.java

@@ -8,9 +8,7 @@ import uk.ac.ic.wlgitbridge.git.exception.SnapshotAPIException;
  */
  */
 public abstract class SnapshotPostException extends SnapshotAPIException {
 public abstract class SnapshotPostException extends SnapshotAPIException {
 
 
-    public SnapshotPostException() {
-
-    }
+    public SnapshotPostException() {}
 
 
     public SnapshotPostException(JsonElement jsonElement) {
     public SnapshotPostException(JsonElement jsonElement) {
         fromJSON(jsonElement);
         fromJSON(jsonElement);

+ 4 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/SnapshotPostExceptionBuilder.java

@@ -12,7 +12,10 @@ public class SnapshotPostExceptionBuilder {
     private static final String CODE_ERROR_INVALID_PROJECT = "invalidProject";
     private static final String CODE_ERROR_INVALID_PROJECT = "invalidProject";
     private static final String CODE_ERROR_UNKNOWN = "error";
     private static final String CODE_ERROR_UNKNOWN = "error";
 
 
-    public SnapshotPostException build(String errorCode, JsonObject json) throws UnexpectedPostbackException {
+    public SnapshotPostException build(
+            String errorCode,
+            JsonObject json
+    ) throws UnexpectedPostbackException {
         if (errorCode.equals(CODE_ERROR_OUT_OF_DATE)) {
         if (errorCode.equals(CODE_ERROR_OUT_OF_DATE)) {
             return new OutOfDateException(json);
             return new OutOfDateException(json);
         } else if (errorCode.equals(CODE_ERROR_INVALID_FILES)) {
         } else if (errorCode.equals(CODE_ERROR_INVALID_FILES)) {

+ 3 - 4
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/UnexpectedErrorException.java

@@ -13,7 +13,8 @@ import java.util.List;
 public class UnexpectedErrorException extends SevereSnapshotPostException {
 public class UnexpectedErrorException extends SevereSnapshotPostException {
 
 
     private static final String[] DESCRIPTION_LINES = {
     private static final String[] DESCRIPTION_LINES = {
-            "There was an internal error with the " + Util.getServiceName() + " server.",
+            "There was an internal error with the "
+                    + Util.getServiceName() + " server.",
             "Please contact " + Util.getServiceName() + "."
             "Please contact " + Util.getServiceName() + "."
     };
     };
 
 
@@ -32,8 +33,6 @@ public class UnexpectedErrorException extends SevereSnapshotPostException {
     }
     }
 
 
     @Override
     @Override
-    public void fromJSON(JsonElement json) {
-
-    }
+    public void fromJSON(JsonElement json) {}
 
 
 }
 }

+ 1 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/push/exception/UnexpectedPostbackException.java

@@ -3,5 +3,4 @@ package uk.ac.ic.wlgitbridge.snapshot.push.exception;
 /**
 /**
  * Created by Winston on 17/11/14.
  * Created by Winston on 17/11/14.
  */
  */
-public class UnexpectedPostbackException extends Exception {
-}
+public class UnexpectedPostbackException extends Exception {}

+ 11 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/Main.java

@@ -13,8 +13,17 @@ import java.io.FileNotFoundException;
 public class Main {
 public class Main {
 
 
     public static void main(String[] args) throws FileNotFoundException {
     public static void main(String[] args) throws FileNotFoundException {
-        MockSnapshotServer server = new MockSnapshotServer(60000, new File("/Users/Roxy/Code/java/writelatex-git-bridge"));
-        server.setState(new SnapshotAPIStateBuilder(new FileInputStream(new File("/Users/Roxy/Desktop/state.json"))).build());
+        MockSnapshotServer server = new MockSnapshotServer(
+                60000,
+                new File("/Users/Roxy/Code/java/writelatex-git-bridge")
+        );
+        server.setState(
+                new SnapshotAPIStateBuilder(
+                        new FileInputStream(
+                                new File("/Users/Roxy/Desktop/state.json")
+                        )
+                ).build()
+        );
         server.start();
         server.start();
     }
     }
 
 

+ 34 - 11
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/response/SnapshotResponseBuilder.java

@@ -1,10 +1,15 @@
 package uk.ac.ic.wlgitbridge.snapshot.servermock.response;
 package uk.ac.ic.wlgitbridge.snapshot.servermock.response;
 
 
-import uk.ac.ic.wlgitbridge.snapshot.servermock.exception.InvalidAPICallException;
-import uk.ac.ic.wlgitbridge.snapshot.servermock.response.getdoc.SnapshotGetDocResponse;
-import uk.ac.ic.wlgitbridge.snapshot.servermock.response.getforver.SnapshotGetForVerResponse;
-import uk.ac.ic.wlgitbridge.snapshot.servermock.response.getsavedver.SnapshotGetSavedVersResponse;
-import uk.ac.ic.wlgitbridge.snapshot.servermock.response.push.SnapshotPushResponse;
+import uk.ac.ic.wlgitbridge.snapshot.servermock.exception
+        .InvalidAPICallException;
+import uk.ac.ic.wlgitbridge.snapshot.servermock.response.getdoc
+        .SnapshotGetDocResponse;
+import uk.ac.ic.wlgitbridge.snapshot.servermock.response.getforver
+        .SnapshotGetForVerResponse;
+import uk.ac.ic.wlgitbridge.snapshot.servermock.response.getsavedver
+        .SnapshotGetSavedVersResponse;
+import uk.ac.ic.wlgitbridge.snapshot.servermock.response.push
+        .SnapshotPushResponse;
 import uk.ac.ic.wlgitbridge.snapshot.servermock.state.SnapshotAPIState;
 import uk.ac.ic.wlgitbridge.snapshot.servermock.state.SnapshotAPIState;
 
 
 /**
 /**
@@ -14,7 +19,10 @@ public class SnapshotResponseBuilder {
 
 
     private SnapshotAPIState state;
     private SnapshotAPIState state;
 
 
-    public SnapshotResponse buildWithTarget(String target, String method) throws InvalidAPICallException {
+    public SnapshotResponse buildWithTarget(
+            String target,
+            String method
+    ) throws InvalidAPICallException {
         checkPrefix(target);
         checkPrefix(target);
         return parseTarget(target, target.split("/"), method);
         return parseTarget(target, target.split("/"), method);
     }
     }
@@ -25,23 +33,38 @@ public class SnapshotResponseBuilder {
         }
         }
     }
     }
 
 
-    private SnapshotResponse parseTarget(String target, String[] parts, String method) throws InvalidAPICallException {
+    private SnapshotResponse parseTarget(
+            String target,
+            String[] parts,
+            String method
+    ) throws InvalidAPICallException {
         String projectName = parts[4];
         String projectName = parts[4];
         if (parts.length == 5) {
         if (parts.length == 5) {
             if (method.equals("GET")) {
             if (method.equals("GET")) {
-                return new SnapshotGetDocResponse(state.getStateForGetDoc(projectName));
+                return new SnapshotGetDocResponse(
+                        state.getStateForGetDoc(projectName)
+                );
             }
             }
         } else if (parts.length == 6) {
         } else if (parts.length == 6) {
             String type = parts[5];
             String type = parts[5];
             if (type.equals("snapshots") && method.equals("POST")) {
             if (type.equals("snapshots") && method.equals("POST")) {
-                return new SnapshotPushResponse(state.getStateForPush(projectName), state.getStateForPostback(projectName));
+                return new SnapshotPushResponse(
+                        state.getStateForPush(projectName),
+                        state.getStateForPostback(projectName)
+                );
             } else if (type.equals("saved_vers") && method.equals("GET")) {
             } else if (type.equals("saved_vers") && method.equals("GET")) {
-                return new SnapshotGetSavedVersResponse(state.getStateForGetSavedVers(projectName));
+                return new SnapshotGetSavedVersResponse(
+                        state.getStateForGetSavedVers(projectName)
+                );
             }
             }
         } else if (parts.length == 7) {
         } else if (parts.length == 7) {
             if (parts[5].equals("snapshots") && method.equals("GET")) {
             if (parts[5].equals("snapshots") && method.equals("GET")) {
                 try {
                 try {
-                    return new SnapshotGetForVerResponse(state.getStateForGetForVers(projectName, Integer.parseInt(parts[6])));
+                    return new SnapshotGetForVerResponse(
+                            state.getStateForGetForVers(
+                                    projectName, Integer.parseInt(parts[6])
+                            )
+                    );
                 } catch (NumberFormatException e) {
                 } catch (NumberFormatException e) {
 
 
                 }
                 }

+ 4 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/response/push/SnapshotPushResponse.java

@@ -12,7 +12,10 @@ public class SnapshotPushResponse extends SnapshotResponse {
     private final SnapshotPushResult stateForPush;
     private final SnapshotPushResult stateForPush;
     private final SnapshotPostbackRequest stateForPostback;
     private final SnapshotPostbackRequest stateForPostback;
 
 
-    public SnapshotPushResponse(SnapshotPushResult stateForPush, SnapshotPostbackRequest stateForPostback) {
+    public SnapshotPushResponse(
+            SnapshotPushResult stateForPush,
+            SnapshotPostbackRequest stateForPostback
+    ) {
         this.stateForPush = stateForPush;
         this.stateForPush = stateForPush;
         this.stateForPostback = stateForPostback;
         this.stateForPostback = stateForPostback;
     }
     }

+ 3 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/response/push/postback/SnapshotPostbackRequestInvalidFiles.java

@@ -23,7 +23,9 @@ public class SnapshotPostbackRequestInvalidFiles extends SnapshotPostbackRequest
     public SnapshotPostbackRequestInvalidFiles(JsonArray errors) {
     public SnapshotPostbackRequestInvalidFiles(JsonArray errors) {
         this(new ArrayList<InvalidFileError>());
         this(new ArrayList<InvalidFileError>());
         for (JsonElement error : errors) {
         for (JsonElement error : errors) {
-            this.errors.add(InvalidFileError.buildFromJsonError(error.getAsJsonObject()));
+            this.errors.add(InvalidFileError.buildFromJsonError(
+                    error.getAsJsonObject()
+            ));
         }
         }
     }
     }
 
 

+ 2 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/response/push/postback/SnapshotPostbackRequestInvalidProject.java

@@ -11,7 +11,8 @@ import java.util.List;
 /**
 /**
  * Created by Winston on 10/01/15.
  * Created by Winston on 10/01/15.
  */
  */
-public class SnapshotPostbackRequestInvalidProject extends SnapshotPostbackRequest {
+public class SnapshotPostbackRequestInvalidProject
+        extends SnapshotPostbackRequest {
 
 
     private final List<String> errors;
     private final List<String> errors;
 
 

+ 6 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/response/push/postback/invalidfile/InvalidFileError.java

@@ -30,9 +30,13 @@ public abstract class InvalidFileError {
         } else if (state.equals("disallowed")) {
         } else if (state.equals("disallowed")) {
             return new InvalidFileErrorDisallowed(file);
             return new InvalidFileErrorDisallowed(file);
         } else if (state.equals("unclean_name")) {
         } else if (state.equals("unclean_name")) {
-            return new InvalidFileErrorUnclean(file, error.get("cleanFile").getAsString());
+            return new InvalidFileErrorUnclean(
+                    file, error.get("cleanFile").getAsString()
+            );
         } else {
         } else {
-            throw new IllegalArgumentException("bad invalid file state: " + state);
+            throw new IllegalArgumentException(
+                    "bad invalid file state: " + state
+            );
         }
         }
     }
     }
 
 

+ 20 - 7
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/server/MockSnapshotRequestHandler.java

@@ -2,9 +2,9 @@ package uk.ac.ic.wlgitbridge.snapshot.servermock.server;
 
 
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.handler.AbstractHandler;
 import org.eclipse.jetty.server.handler.AbstractHandler;
-import uk.ac.ic.wlgitbridge.snapshot.servermock.exception.InvalidAPICallException;
-import uk.ac.ic.wlgitbridge.snapshot.servermock.response.SnapshotResponse;
-import uk.ac.ic.wlgitbridge.snapshot.servermock.response.SnapshotResponseBuilder;
+import uk.ac.ic.wlgitbridge.snapshot.servermock.exception.
+        InvalidAPICallException;
+import uk.ac.ic.wlgitbridge.snapshot.servermock.response.*;
 import uk.ac.ic.wlgitbridge.util.Log;
 import uk.ac.ic.wlgitbridge.util.Log;
 
 
 import javax.servlet.ServletException;
 import javax.servlet.ServletException;
@@ -19,17 +19,30 @@ public class MockSnapshotRequestHandler extends AbstractHandler {
 
 
     private final SnapshotResponseBuilder responseBuilder;
     private final SnapshotResponseBuilder responseBuilder;
 
 
-    public MockSnapshotRequestHandler(SnapshotResponseBuilder responseBuilder) {
+    public MockSnapshotRequestHandler(
+            SnapshotResponseBuilder responseBuilder
+    ) {
         this.responseBuilder = responseBuilder;
         this.responseBuilder = responseBuilder;
     }
     }
 
 
     @Override
     @Override
-    public void handle(String target, final Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+    public void handle(
+            String target,
+            final Request baseRequest,
+            HttpServletRequest request,
+            HttpServletResponse response
+    ) throws IOException, ServletException {
         boolean handled;
         boolean handled;
         try {
         try {
-            final SnapshotResponse snapshotResponse = responseBuilder.buildWithTarget(target, baseRequest.getMethod());
+            final SnapshotResponse snapshotResponse
+                    = responseBuilder.buildWithTarget(
+                            target, baseRequest.getMethod()
+                    );
             response.getWriter().println(snapshotResponse.respond());
             response.getWriter().println(snapshotResponse.respond());
-            new PostbackThread(baseRequest.getReader(), snapshotResponse.postback()).startIfNotNull();
+            new PostbackThread(
+                    baseRequest.getReader(),
+                    snapshotResponse.postback()
+            ).startIfNotNull();
             handled = true;
             handled = true;
         } catch (InvalidAPICallException e) {
         } catch (InvalidAPICallException e) {
             handled = false;
             handled = false;

+ 7 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/server/PostbackThread.java

@@ -19,7 +19,10 @@ public class PostbackThread extends Thread {
 
 
     public PostbackThread(Reader reader, String postback) {
     public PostbackThread(Reader reader, String postback) {
         if (postback != null) {
         if (postback != null) {
-            url = new Gson().fromJson(reader, JsonObject.class).get("postbackUrl").getAsString();
+            url = new Gson().fromJson(
+                    reader,
+                    JsonObject.class
+            ).get("postbackUrl").getAsString();
             this.postback = postback;
             this.postback = postback;
         }
         }
     }
     }
@@ -27,7 +30,9 @@ public class PostbackThread extends Thread {
     @Override
     @Override
     public void run() {
     public void run() {
         try {
         try {
-            new AsyncHttpClient().preparePost(url).setBody(postback).execute().get().getResponseBody();
+            new AsyncHttpClient().preparePost(
+                    url
+            ).setBody(postback).execute().get().getResponseBody();
         } catch (IOException e) {
         } catch (IOException e) {
             Log.warn(
             Log.warn(
                     "IOException on postback, url: " +
                     "IOException on postback, url: " +

+ 73 - 19
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIState.java

@@ -25,12 +25,13 @@ public class SnapshotAPIState {
     private Map<String, SnapshotPushResult> push;
     private Map<String, SnapshotPushResult> push;
     private Map<String, SnapshotPostbackRequest> postback;
     private Map<String, SnapshotPostbackRequest> postback;
 
 
-    public SnapshotAPIState(Map<String, GetDocResult> getDoc,
-                            Map<String, GetSavedVersResult> getSavedVers,
-                            Map<String, Map<Integer, GetForVersionResult>> getForVers,
-                            Map<String, SnapshotPushResult> push,
-                            Map<String, SnapshotPostbackRequest> postback) {
-
+    public SnapshotAPIState(
+            Map<String, GetDocResult> getDoc,
+            Map<String, GetSavedVersResult> getSavedVers,
+            Map<String, Map<Integer, GetForVersionResult>> getForVers,
+            Map<String, SnapshotPushResult> push,
+            Map<String, SnapshotPostbackRequest> postback
+    ) {
         this.getDoc = getDoc;
         this.getDoc = getDoc;
         this.getSavedVers = getSavedVers;
         this.getSavedVers = getSavedVers;
         this.getForVers = getForVers;
         this.getForVers = getForVers;
@@ -39,19 +40,45 @@ public class SnapshotAPIState {
     }
     }
 
 
     public SnapshotAPIState() {
     public SnapshotAPIState() {
-
-        getDoc = new HashMap<String, GetDocResult>();
-        getDoc.put("1826rqgsdb", new GetDocResult(null, 243, "2014-11-30T18:40:58Z", "jdleesmiller+1@gmail.com", "John+1"));
+        getDoc = new HashMap<>();
+        getDoc.put(
+                "1826rqgsdb",
+                new GetDocResult(
+                        null,
+                        243,
+                        "2014-11-30T18:40:58Z",
+                        "jdleesmiller+1@gmail.com",
+                        "John+1"
+                )
+        );
 
 
         getSavedVers = new HashMap<String, GetSavedVersResult>();
         getSavedVers = new HashMap<String, GetSavedVersResult>();
         List<SnapshotInfo> savedVers = new LinkedList<SnapshotInfo>();
         List<SnapshotInfo> savedVers = new LinkedList<SnapshotInfo>();
-        savedVers.add(new SnapshotInfo(243, "added more info on doc GET and error details", "jdleesmiller+1@gmail.com", "John+1", "2014-11-30T18:47:01Z"));
-        savedVers.add(new SnapshotInfo(185, "with more details on POST request", "jdleesmiller+1@gmail.com", "John+1", "2014-11-11T17:18:40Z"));
-        savedVers.add(new SnapshotInfo(175, "with updated PUT/POST request", "jdleesmiller+1@gmail.com", "John+1", "2014-11-09T23:09:13Z"));
-        savedVers.add(new SnapshotInfo(146, "added PUT format", "jdleesmiller@gmail.com", "John Lees-Miller", "2014-11-07T15:11:35Z"));
-        savedVers.add(new SnapshotInfo(74, "with example output", "jdleesmiller@gmail.com", "John Lees-Miller", "2014-11-05T18:09:41Z"));
-        savedVers.add(new SnapshotInfo(39, "with more files", "jdleesmiller@gmail.com", "John Lees-Miller", "2014-11-05T18:02:19Z"));
-        savedVers.add(new SnapshotInfo(24, "first draft", "jdleesmiller@gmail.com", "John Lees-Miller", "2014-11-05T17:56:58Z"));
+        savedVers.add(new SnapshotInfo(
+                243,
+                "added more info on doc GET and error details",
+                "jdleesmiller+1@gmail.com",
+                "John+1",
+                "2014-11-30T18:47:01Z"
+        ));
+        savedVers.add(new SnapshotInfo(
+                185, "with more details on POST request", "jdleesmiller+1@gmail.com", "John+1", "2014-11-11T17:18:40Z"
+        ));
+        savedVers.add(new SnapshotInfo(
+                175, "with updated PUT/POST request", "jdleesmiller+1@gmail.com", "John+1", "2014-11-09T23:09:13Z"
+        ));
+        savedVers.add(new SnapshotInfo(
+                146, "added PUT format", "jdleesmiller@gmail.com", "John Lees-Miller", "2014-11-07T15:11:35Z"
+        ));
+        savedVers.add(new SnapshotInfo(
+                74, "with example output", "jdleesmiller@gmail.com", "John Lees-Miller", "2014-11-05T18:09:41Z"
+        ));
+        savedVers.add(new SnapshotInfo(
+                39, "with more files", "jdleesmiller@gmail.com", "John Lees-Miller", "2014-11-05T18:02:19Z"
+        ));
+        savedVers.add(new SnapshotInfo(
+                24, "first draft", "jdleesmiller@gmail.com", "John Lees-Miller", "2014-11-05T17:56:58Z"
+        ));
         getSavedVers.put("1826rqgsdb", new GetSavedVersResult(savedVers));
         getSavedVers.put("1826rqgsdb", new GetSavedVersResult(savedVers));
 
 
         getForVers = new HashMap<String, Map<Integer, GetForVersionResult>>() {{
         getForVers = new HashMap<String, Map<Integer, GetForVersionResult>>() {{
@@ -105,9 +132,33 @@ public class SnapshotAPIState {
         }};
         }};
 
 
         postback = new HashMap<String, SnapshotPostbackRequest>() {{
         postback = new HashMap<String, SnapshotPostbackRequest>() {{
-//            put("1826rqgsdb", new SnapshotPostbackRequestInvalidFiles(Arrays.<InvalidFileError>asList(new InvalidFileErrorDefault("file1.invalid"), new InvalidFileErrorDisallowed("file2.exe"), new InvalidFileErrorUnclean("hello world.png", "hello_world.png"))));
+//            put(
+//                    "1826rqgsdb",
+//                    new SnapshotPostbackRequestInvalidFiles(
+//                            Arrays.<InvalidFileError>asList(
+//                                    new InvalidFileErrorDefault(
+//                                            "file1.invalid"
+//                                    ),
+//                                    new InvalidFileErrorDisallowed(
+//                                            "file2.exe"
+//                                    ),
+//                                    new InvalidFileErrorUnclean(
+//                                            "hello world.png",
+//                                            "hello_world.png"
+//                                    )
+//                            )
+//                    )
+//            );
 //            put("1826rqgsdb", new SnapshotPostbackRequestOutOfDate());
 //            put("1826rqgsdb", new SnapshotPostbackRequestOutOfDate());
-            put("1826rqgsdb", new SnapshotPostbackRequestInvalidProject(Arrays.asList("Your project is missing main.tex.", "Please name your main latex file main.tex.")));
+            put(
+                    "1826rqgsdb",
+                    new SnapshotPostbackRequestInvalidProject(
+                            Arrays.asList(
+                                    "Your project is missing main.tex.",
+                                    "Please name your main latex file main.tex."
+                            )
+                    )
+            );
 //            put("1826rqgsdb", new SnapshotPostbackRequestError());
 //            put("1826rqgsdb", new SnapshotPostbackRequestError());
         }};
         }};
     }
     }
@@ -120,7 +171,10 @@ public class SnapshotAPIState {
         return getSavedVers.get(projectName);
         return getSavedVers.get(projectName);
     }
     }
 
 
-    public GetForVersionResult getStateForGetForVers(String projectName, int versionID) {
+    public GetForVersionResult getStateForGetForVers(
+            String projectName,
+            int versionID
+    ) {
         return getForVers.get(projectName).get(versionID);
         return getForVers.get(projectName).get(versionID);
     }
     }
 
 

+ 105 - 42
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIStateBuilder.java

@@ -18,10 +18,7 @@ import uk.ac.ic.wlgitbridge.snapshot.servermock.response.push.postback.*;
 
 
 import java.io.InputStream;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.InputStreamReader;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 
 /**
 /**
  * Created by Winston on 11/01/15.
  * Created by Winston on 11/01/15.
@@ -30,70 +27,127 @@ public class SnapshotAPIStateBuilder {
 
 
     private final JsonArray projects;
     private final JsonArray projects;
 
 
-    private Map<String, GetDocResult> getDoc = new HashMap<String, GetDocResult>();
-    private Map<String, GetSavedVersResult> getSavedVers = new HashMap<String, GetSavedVersResult>();
-    private Map<String, Map<Integer, GetForVersionResult>> getForVers = new HashMap<String, Map<Integer, GetForVersionResult>>();
-    private Map<String, SnapshotPushResult> push = new HashMap<String, SnapshotPushResult>();
-    private Map<String, SnapshotPostbackRequest> postback = new HashMap<String, SnapshotPostbackRequest>();
+    private Map<String, GetDocResult> getDoc = new HashMap<>();
+    private Map<String, GetSavedVersResult> getSavedVers = new HashMap<>();
+    private Map<String, Map<Integer, GetForVersionResult>> getForVers
+            = new HashMap<>();
+    private Map<String, SnapshotPushResult> push
+            = new HashMap<>();
+    private Map<String, SnapshotPostbackRequest> postback
+            = new HashMap<>();
 
 
     public SnapshotAPIStateBuilder(InputStream stream) {
     public SnapshotAPIStateBuilder(InputStream stream) {
-        projects = new Gson().fromJson(new InputStreamReader(stream), JsonArray.class);
+        projects = new Gson().fromJson(
+                new InputStreamReader(stream), JsonArray.class
+        );
     }
     }
 
 
     public SnapshotAPIState build() {
     public SnapshotAPIState build() {
         for (JsonElement project : projects) {
         for (JsonElement project : projects) {
             addProject(project.getAsJsonObject());
             addProject(project.getAsJsonObject());
         }
         }
-        return new SnapshotAPIState(getDoc, getSavedVers, getForVers, push, postback);
+        return new SnapshotAPIState(
+                getDoc,
+                getSavedVers,
+                getForVers,
+                push,
+                postback
+        );
     }
     }
 
 
     private void addProject(JsonObject project) {
     private void addProject(JsonObject project) {
         String projectName = project.get("project").getAsString();
         String projectName = project.get("project").getAsString();
-        addGetDocForProject(projectName, project.get("getDoc").getAsJsonObject());
-        addGetSavedVersForProject(projectName, project.get("getSavedVers").getAsJsonArray());
-        addGetForVersForProject(projectName, project.get("getForVers").getAsJsonArray());
-        addPushForProject(projectName, project.get("push").getAsString());
-        addPostbackForProject(projectName, project.get("postback").getAsJsonObject());
+        addGetDocForProject(
+                projectName,
+                project.get("getDoc").getAsJsonObject()
+        );
+        addGetSavedVersForProject(
+                projectName,
+                project.get("getSavedVers").getAsJsonArray()
+        );
+        addGetForVersForProject(
+                projectName,
+                project.get("getForVers").getAsJsonArray()
+        );
+        addPushForProject(
+                projectName,
+                project.get("push").getAsString()
+        );
+        addPostbackForProject(
+                projectName,
+                project.get("postback").getAsJsonObject()
+        );
     }
     }
 
 
-    private void addGetDocForProject(String projectName, JsonObject jsonGetDoc) {
-        getDoc.put(projectName,
-                   new GetDocResult(jsonGetDoc.get("error"),
-                                            jsonGetDoc.get("versionID").getAsInt(),
-                                            jsonGetDoc.get("createdAt").getAsString(),
-                                            jsonGetDoc.get("email").getAsString(),
-                                            jsonGetDoc.get("name").getAsString()));
+    private void addGetDocForProject(
+            String projectName,
+            JsonObject jsonGetDoc
+    ) {
+        getDoc.put(
+                projectName,
+                new GetDocResult(
+                        jsonGetDoc.get("error"),
+                        jsonGetDoc.get("versionID").getAsInt(),
+                        jsonGetDoc.get("createdAt").getAsString(),
+                        jsonGetDoc.get("email").getAsString(),
+                        jsonGetDoc.get("name").getAsString()
+                )
+        );
     }
     }
 
 
-    private void addGetSavedVersForProject(String projectName, JsonArray jsonGetSavedVers) {
-        List<SnapshotInfo> savedVers = new LinkedList<SnapshotInfo>();
+    private void addGetSavedVersForProject(
+            String projectName,
+            JsonArray jsonGetSavedVers
+    ) {
+        List<SnapshotInfo> savedVers = new ArrayList<>();
         for (JsonElement ver : jsonGetSavedVers) {
         for (JsonElement ver : jsonGetSavedVers) {
             savedVers.add(getSnapshotInfo(ver.getAsJsonObject()));
             savedVers.add(getSnapshotInfo(ver.getAsJsonObject()));
         }
         }
         getSavedVers.put(projectName, new GetSavedVersResult(savedVers));
         getSavedVers.put(projectName, new GetSavedVersResult(savedVers));
     }
     }
 
 
-    private SnapshotInfo getSnapshotInfo(JsonObject jsonSnapshotInfo) {
-        return new SnapshotInfo(jsonSnapshotInfo.get("versionID").getAsInt(),
-                                jsonSnapshotInfo.get("comment").getAsString(),
-                                jsonSnapshotInfo.get("email").getAsString(),
-                                jsonSnapshotInfo.get("name").getAsString(),
-                                jsonSnapshotInfo.get("createdAt").getAsString());
+    private SnapshotInfo getSnapshotInfo(
+            JsonObject jsonSnapshotInfo
+    ) {
+        return new SnapshotInfo(
+                jsonSnapshotInfo.get("versionID").getAsInt(),
+                jsonSnapshotInfo.get("comment").getAsString(),
+                jsonSnapshotInfo.get("email").getAsString(),
+                jsonSnapshotInfo.get("name").getAsString(),
+                jsonSnapshotInfo.get("createdAt").getAsString()
+        );
     }
     }
 
 
-    private void addGetForVersForProject(String projectName, JsonArray jsonGetForVers) {
-        Map<Integer, GetForVersionResult> forVers = new HashMap<Integer, GetForVersionResult>();
+    private void addGetForVersForProject(
+            String projectName,
+            JsonArray jsonGetForVers
+    ) {
+        Map<Integer, GetForVersionResult> forVers = new HashMap<>();
         for (JsonElement forVer : jsonGetForVers) {
         for (JsonElement forVer : jsonGetForVers) {
             JsonObject forVerObj = forVer.getAsJsonObject();
             JsonObject forVerObj = forVer.getAsJsonObject();
-            forVers.put(forVerObj.get("versionID").getAsInt(),
-                        new GetForVersionResult(new SnapshotData(getSrcs(forVerObj.get("srcs").getAsJsonArray()),
-                                                                         getAtts(forVerObj.get("atts").getAsJsonArray()))));
+            forVers.put(
+                    forVerObj.get("versionID").getAsInt(),
+                    new GetForVersionResult(
+                            new SnapshotData(
+                                    getSrcs(
+                                            forVerObj.get(
+                                                    "srcs"
+                                            ).getAsJsonArray()
+                                    ),
+                                    getAtts(
+                                            forVerObj.get(
+                                                    "atts"
+                                            ).getAsJsonArray()
+                                    )
+                            )
+                    )
+            );
         }
         }
         getForVers.put(projectName, forVers);
         getForVers.put(projectName, forVers);
     }
     }
 
 
     private List<SnapshotFile> getSrcs(JsonArray jsonSrcs) {
     private List<SnapshotFile> getSrcs(JsonArray jsonSrcs) {
-        List<SnapshotFile> srcs = new LinkedList<SnapshotFile>();
+        List<SnapshotFile> srcs = new ArrayList<>();
         for (JsonElement src : jsonSrcs) {
         for (JsonElement src : jsonSrcs) {
             srcs.add(getSrc(src.getAsJsonObject()));
             srcs.add(getSrc(src.getAsJsonObject()));
         }
         }
@@ -106,7 +160,7 @@ public class SnapshotAPIStateBuilder {
     }
     }
 
 
     private List<SnapshotAttachment> getAtts(JsonArray jsonAtts) {
     private List<SnapshotAttachment> getAtts(JsonArray jsonAtts) {
-        List<SnapshotAttachment> atts = new LinkedList<SnapshotAttachment>();
+        List<SnapshotAttachment> atts = new LinkedList<>();
         for (JsonElement att : jsonAtts) {
         for (JsonElement att : jsonAtts) {
             atts.add(getAtt(att.getAsJsonObject()));
             atts.add(getAtt(att.getAsJsonObject()));
         }
         }
@@ -130,17 +184,26 @@ public class SnapshotAPIStateBuilder {
         push.put(projectName, p);
         push.put(projectName, p);
     }
     }
 
 
-    private void addPostbackForProject(String projectName, JsonObject jsonPostback) {
+    private void addPostbackForProject(
+            String projectName,
+            JsonObject jsonPostback
+    ) {
         SnapshotPostbackRequest p;
         SnapshotPostbackRequest p;
         String type = jsonPostback.get("type").getAsString();
         String type = jsonPostback.get("type").getAsString();
         if (type.equals("success")) {
         if (type.equals("success")) {
-            p = new SnapshotPostbackRequestSuccess(jsonPostback.get("versionID").getAsInt());
+            p = new SnapshotPostbackRequestSuccess(
+                    jsonPostback.get("versionID").getAsInt()
+            );
         } else if (type.equals("outOfDate")) {
         } else if (type.equals("outOfDate")) {
             p = new SnapshotPostbackRequestOutOfDate();
             p = new SnapshotPostbackRequestOutOfDate();
         } else if (type.equals("invalidFiles")) {
         } else if (type.equals("invalidFiles")) {
-            p = new SnapshotPostbackRequestInvalidFiles(jsonPostback.get("errors").getAsJsonArray());
+            p = new SnapshotPostbackRequestInvalidFiles(
+                    jsonPostback.get("errors").getAsJsonArray()
+            );
         } else if (type.equals("invalidProject")) {
         } else if (type.equals("invalidProject")) {
-            p = new SnapshotPostbackRequestInvalidProject(jsonPostback.get("errors").getAsJsonArray());
+            p = new SnapshotPostbackRequestInvalidProject(
+                    jsonPostback.get("errors").getAsJsonArray()
+            );
         } else if (type.equals("error")) {
         } else if (type.equals("error")) {
             p = new SnapshotPostbackRequestError();
             p = new SnapshotPostbackRequestError();
         } else {
         } else {

+ 0 - 10
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/state/SnapshotAPIStateManager.java

@@ -1,10 +0,0 @@
-package uk.ac.ic.wlgitbridge.snapshot.servermock.state;
-
-/**
- * Created by Winston on 11/01/15.
- */
-public class SnapshotAPIStateManager {
-
-
-
-}

+ 63 - 13
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/snapshot/servermock/util/FileUtil.java

@@ -21,8 +21,16 @@ public class FileUtil {
 
 
     public static boolean currentCommitsAreEqual(Path dir1, Path dir2) {
     public static boolean currentCommitsAreEqual(Path dir1, Path dir2) {
         try {
         try {
-            RevCommit commit1 = new Git(new FileRepositoryBuilder().setWorkTree(dir1.toFile().getAbsoluteFile()).build()).log().call().iterator().next();
-            RevCommit commit2 = new Git(new FileRepositoryBuilder().setWorkTree(dir2.toFile().getAbsoluteFile()).build()).log().call().iterator().next();
+            RevCommit commit1 = new Git(
+                    new FileRepositoryBuilder().setWorkTree(
+                            dir1.toFile().getAbsoluteFile()
+                    ).build()
+            ).log().call().iterator().next();
+            RevCommit commit2 = new Git(
+                    new FileRepositoryBuilder().setWorkTree(
+                            dir2.toFile().getAbsoluteFile()
+                    ).build()
+            ).log().call().iterator().next();
             return commit1.equals(commit2);
             return commit1.equals(commit2);
         } catch (IOException e) {
         } catch (IOException e) {
             throw new RuntimeException(e);
             throw new RuntimeException(e);
@@ -34,22 +42,42 @@ public class FileUtil {
     }
     }
 
 
     public static boolean gitDirectoriesAreEqual(Path dir1, Path dir2) {
     public static boolean gitDirectoriesAreEqual(Path dir1, Path dir2) {
-        Set<String> dir1Contents = getAllRecursivelyInDirectoryApartFrom(dir1, dir1.resolve(".git"));
-        Set<String> dir2Contents = getAllRecursivelyInDirectoryApartFrom(dir2, dir2.resolve(".git"));
+        Set<String> dir1Contents = getAllRecursivelyInDirectoryApartFrom(
+                dir1,
+                dir1.resolve(".git")
+        );
+        Set<String> dir2Contents = getAllRecursivelyInDirectoryApartFrom(
+                dir2,
+                dir2.resolve(".git")
+        );
         boolean filesEqual = dir1Contents.equals(dir2Contents);
         boolean filesEqual = dir1Contents.equals(dir2Contents);
         if (!filesEqual) {
         if (!filesEqual) {
-            System.out.println("Not equal: (" + dir1Contents + ", " + dir2Contents + ")");
+            System.out.println(
+                    "Not equal: ("
+                            + dir1Contents
+                            + ", "
+                            + dir2Contents
+                            + ")"
+            );
             System.out.println(dir1 + ": " + dir1Contents);
             System.out.println(dir1 + ": " + dir1Contents);
             System.out.println(dir2 + ": " + dir2Contents);
             System.out.println(dir2 + ": " + dir2Contents);
         }
         }
         return filesEqual && directoryContentsEqual(dir1Contents, dir1, dir2);
         return filesEqual && directoryContentsEqual(dir1Contents, dir1, dir2);
     }
     }
 
 
-    static boolean directoryContentsEqual(Set<String> dirContents, Path dir1, Path dir2) {
+    static boolean directoryContentsEqual(
+            Set<String> dirContents,
+            Path dir1,
+            Path dir2
+    ) {
         for (String file : dirContents) {
         for (String file : dirContents) {
             Path path1 = dir1.resolve(file);
             Path path1 = dir1.resolve(file);
             Path path2 = dir2.resolve(file);
             Path path2 = dir2.resolve(file);
-            if (!path1.toFile().isDirectory() && !path2.toFile().isDirectory() && !fileContentsEqual(path1, path2)) {
+            if (
+                    !path1.toFile().isDirectory()
+                            && !path2.toFile().isDirectory()
+                            && !fileContentsEqual(path1, path2)
+            ) {
                 return false;
                 return false;
             }
             }
         }
         }
@@ -62,7 +90,9 @@ public class FileUtil {
             byte[] secondContents = Files.readAllBytes(second);
             byte[] secondContents = Files.readAllBytes(second);
             boolean equals = Arrays.equals(firstContents, secondContents);
             boolean equals = Arrays.equals(firstContents, secondContents);
             if (!equals) {
             if (!equals) {
-                System.out.println("Not equal: (" + first + ", " + second + ")");
+                System.out.println(
+                        "Not equal: (" + first + ", " + second + ")"
+                );
                 System.out.println(first + ": " + new String(firstContents));
                 System.out.println(first + ": " + new String(firstContents));
                 System.out.println(second + ": " + new String(secondContents));
                 System.out.println(second + ": " + new String(secondContents));
             }
             }
@@ -72,22 +102,37 @@ public class FileUtil {
         }
         }
     }
     }
 
 
-    public static Set<String> getAllRecursivelyInDirectoryApartFrom(Path dir, Path excluded) {
+    public static Set<String> getAllRecursivelyInDirectoryApartFrom(
+            Path dir,
+            Path excluded
+    ) {
         return getAllRecursivelyInDirectoryApartFrom(dir, excluded, true);
         return getAllRecursivelyInDirectoryApartFrom(dir, excluded, true);
     }
     }
 
 
-    public static Set<String> getOnlyFilesRecursivelyInDirectoryApartFrom(Path dir, Path excluded) {
+    public static Set<String> getOnlyFilesRecursivelyInDirectoryApartFrom(
+            Path dir,
+            Path excluded
+    ) {
         return getAllRecursivelyInDirectoryApartFrom(dir, excluded, false);
         return getAllRecursivelyInDirectoryApartFrom(dir, excluded, false);
     }
     }
 
 
-    private static Set<String> getAllRecursivelyInDirectoryApartFrom(Path dir, Path excluded, boolean directories) {
+    private static Set<String> getAllRecursivelyInDirectoryApartFrom(
+            Path dir,
+            Path excluded,
+            boolean directories
+    ) {
         if (!dir.toFile().isDirectory()) {
         if (!dir.toFile().isDirectory()) {
             throw new IllegalArgumentException("need a directory");
             throw new IllegalArgumentException("need a directory");
         }
         }
         return getAllFilesRecursively(dir, dir, excluded, directories);
         return getAllFilesRecursively(dir, dir, excluded, directories);
     }
     }
 
 
-    static Set<String> getAllFilesRecursively(Path baseDir, Path dir, Path excluded, boolean directories) {
+    static Set<String> getAllFilesRecursively(
+            Path baseDir,
+            Path dir,
+            Path excluded,
+            boolean directories
+    ) {
         Set<String> files = new HashSet<String>();
         Set<String> files = new HashSet<String>();
         for (File file : dir.toFile().listFiles()) {
         for (File file : dir.toFile().listFiles()) {
             if (!file.equals(excluded.toFile())) {
             if (!file.equals(excluded.toFile())) {
@@ -96,7 +141,12 @@ public class FileUtil {
                     files.add(baseDir.relativize(file.toPath()).toString());
                     files.add(baseDir.relativize(file.toPath()).toString());
                 }
                 }
                 if (isDirectory) {
                 if (isDirectory) {
-                    files.addAll(getAllFilesRecursively(baseDir, file.toPath(), excluded, directories));
+                    files.addAll(getAllFilesRecursively(
+                            baseDir,
+                            file.toPath(),
+                            excluded,
+                            directories
+                    ));
                 }
                 }
             }
             }
         }
         }

+ 4 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/util/Files.java

@@ -59,7 +59,10 @@ public class Files {
         return renamed;
         return renamed;
     }
     }
 
 
-    private static boolean uncheckedContentsAreEqual(File f0, File f1) throws IOException {
+    private static boolean uncheckedContentsAreEqual(
+            File f0,
+            File f1
+    ) throws IOException {
         if (f0.equals(f1)) {
         if (f0.equals(f1)) {
             return true;
             return true;
         }
         }

+ 2 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/util/Instance.java

@@ -22,7 +22,8 @@ public class Instance {
     public static final JsonFactory jsonFactory = new GsonFactory();
     public static final JsonFactory jsonFactory = new GsonFactory();
 
 
     public static final Gson prettyGson =
     public static final Gson prettyGson =
-            new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
+            new GsonBuilder(
+            ).setPrettyPrinting().disableHtmlEscaping().create();
 
 
     public static final Gson gson = new Gson();
     public static final Gson gson = new Gson();
 
 

+ 27 - 11
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/util/Util.java

@@ -17,7 +17,8 @@ public class Util {
     private static String HOSTNAME;
     private static String HOSTNAME;
     private static int PORT;
     private static int PORT;
     private static String POSTBACK_URL;
     private static String POSTBACK_URL;
-    private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
+    private static final DateFormat dateFormat
+            = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
 
 
     public static String entries(int entries) {
     public static String entries(int entries) {
         if (entries == 1) {
         if (entries == 1) {
@@ -57,9 +58,11 @@ public class Util {
         return result;
         return result;
     }
     }
 
 
-    public static String getContentsOfReader(BufferedReader reader) throws IOException {
+    public static String getContentsOfReader(
+            BufferedReader reader
+    ) throws IOException {
         StringBuilder sb = new StringBuilder();
         StringBuilder sb = new StringBuilder();
-        for (String line; (line = reader.readLine()) != null; ) {
+        for (String line; (line = reader.readLine()) != null;) {
             sb.append(line);
             sb.append(line);
         }
         }
         return sb.toString();
         return sb.toString();
@@ -102,9 +105,12 @@ public class Util {
         }
         }
     }
     }
 
 
-    public static void deleteInDirectoryApartFrom(File directory, String... apartFrom) {
+    public static void deleteInDirectoryApartFrom(
+            File directory,
+            String... apartFrom
+    ) {
         if (directory != null) {
         if (directory != null) {
-            Set<String> excluded = new HashSet<String>(Arrays.asList(apartFrom));
+            Set<String> excluded = new HashSet<>(Arrays.asList(apartFrom));
             File [] files = directory.listFiles();
             File [] files = directory.listFiles();
             if (files != null) {
             if (files != null) {
                 for (File file : files) {
                 for (File file : files) {
@@ -120,9 +126,15 @@ public class Util {
         }
         }
     }
     }
 
 
-    public static List<String> linesFromStream(InputStream stream, int skip, String trimSuffix) throws IOException {
-        List<String> lines = new ArrayList<String>();
-        BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
+    public static List<String> linesFromStream(
+            InputStream stream,
+            int skip,
+            String trimSuffix
+    ) throws IOException {
+        List<String> lines = new ArrayList<>();
+        BufferedReader reader = new BufferedReader(
+                new InputStreamReader(stream)
+        );
         String line;
         String line;
         for (int i = 0; i < skip; i++) {
         for (int i = 0; i < skip; i++) {
             reader.readLine();
             reader.readLine();
@@ -139,8 +151,13 @@ public class Util {
         return lines;
         return lines;
     }
     }
 
 
-    public static String fromStream(InputStream stream, int skip) throws IOException {
-        BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
+    public static String fromStream(
+            InputStream stream,
+            int skip
+    ) throws IOException {
+        BufferedReader reader = new BufferedReader(
+                new InputStreamReader(stream)
+        );
         StringBuilder out = new StringBuilder();
         StringBuilder out = new StringBuilder();
         String newLine = System.getProperty("line.separator");
         String newLine = System.getProperty("line.separator");
         String line;
         String line;
@@ -182,7 +199,6 @@ public class Util {
         } else {
         } else {
             code = codeElement.getAsString();
             code = codeElement.getAsString();
         }
         }
-
         return code;
         return code;
     }
     }
 
 

+ 1 - 1
services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/application/WLGitBridgeIntegrationTest.java

@@ -323,11 +323,11 @@ public class WLGitBridgeIntegrationTest {
     public void canPushFilesSuccessfully() throws IOException, GitAPIException, InterruptedException {
     public void canPushFilesSuccessfully() throws IOException, GitAPIException, InterruptedException {
         MockSnapshotServer server = new MockSnapshotServer(3866, getResource("/canPushFilesSuccessfully").toFile());
         MockSnapshotServer server = new MockSnapshotServer(3866, getResource("/canPushFilesSuccessfully").toFile());
         server.start();
         server.start();
-        server.setState(states.get("canPushFilesSuccessfully").get("state"));
         GitBridgeApp wlgb = new GitBridgeApp(new String[] {
         GitBridgeApp wlgb = new GitBridgeApp(new String[] {
             makeConfigFile(33866, 3866)
             makeConfigFile(33866, 3866)
         });
         });
         wlgb.run();
         wlgb.run();
+        server.setState(states.get("canPushFilesSuccessfully").get("state"));
         File dir = folder.newFolder();
         File dir = folder.newFolder();
         File testprojDir = cloneRepository("testproj", 33866, dir);
         File testprojDir = cloneRepository("testproj", 33866, dir);
         assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPushFilesSuccessfully/state/testproj"), testprojDir.toPath()));
         assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPushFilesSuccessfully/state/testproj"), testprojDir.toPath()));