mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-29 12:01:32 +02:00
Add JavaDoc, minor refactor
This commit is contained in:
@@ -1,11 +1,30 @@
|
||||
package uk.ac.ic.wlgitbridge;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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 static void main(String[] args) {
|
||||
|
||||
@@ -3,7 +3,6 @@ package uk.ac.ic.wlgitbridge.application;
|
||||
import uk.ac.ic.wlgitbridge.application.config.Config;
|
||||
import uk.ac.ic.wlgitbridge.application.exception.ArgsException;
|
||||
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.util.Log;
|
||||
|
||||
@@ -58,11 +57,6 @@ public class GitBridgeApp implements Runnable {
|
||||
"Servlet exception when instantiating GitBridgeServer",
|
||||
e
|
||||
);
|
||||
} catch (InvalidRootDirectoryPathException e) {
|
||||
Log.error(
|
||||
"Invalid root git directory path. Check your config file."
|
||||
);
|
||||
System.exit(EXIT_CODE_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,10 @@ public class Config implements JSONSource {
|
||||
@Nullable
|
||||
private SwapJobConfig swapJob;
|
||||
|
||||
public Config(String configFilePath) throws ConfigFileException,
|
||||
IOException {
|
||||
public Config(
|
||||
String configFilePath
|
||||
) throws ConfigFileException,
|
||||
IOException {
|
||||
this(new FileReader(configFilePath));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,11 @@ public class Oauth2 {
|
||||
private final String oauth2ClientSecret;
|
||||
private final String oauth2Server;
|
||||
|
||||
public Oauth2(String oauth2ClientID, String oauth2ClientSecret, String oauth2Server) {
|
||||
public Oauth2(
|
||||
String oauth2ClientID,
|
||||
String oauth2ClientSecret,
|
||||
String oauth2Server
|
||||
) {
|
||||
this.oauth2ClientID = oauth2ClientID;
|
||||
this.oauth2ClientSecret = oauth2ClientSecret;
|
||||
this.oauth2Server = oauth2Server;
|
||||
|
||||
@@ -3,5 +3,4 @@ package uk.ac.ic.wlgitbridge.application.exception;
|
||||
/**
|
||||
* Created by Winston on 03/11/14.
|
||||
*/
|
||||
public class ArgsException extends Exception {
|
||||
}
|
||||
public class ArgsException extends Exception {}
|
||||
|
||||
@@ -4,8 +4,11 @@ import com.google.api.client.auth.oauth2.Credential;
|
||||
import org.eclipse.jgit.transport.ServiceMayNotContinueException;
|
||||
import uk.ac.ic.wlgitbridge.bridge.db.DBStore;
|
||||
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.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.RepoStore;
|
||||
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.swap.job.SwapJob;
|
||||
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.data.CandidateSnapshot;
|
||||
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.model.Snapshot;
|
||||
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.getdoc.GetDocRequest;
|
||||
import uk.ac.ic.wlgitbridge.snapshot.getdoc.exception.InvalidProjectException;
|
||||
import uk.ac.ic.wlgitbridge.snapshot.getforversion.SnapshotAttachment;
|
||||
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.PushResult;
|
||||
import uk.ac.ic.wlgitbridge.snapshot.push.exception.*;
|
||||
@@ -41,6 +55,91 @@ import java.util.*;
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
private final ProjectLock lock;
|
||||
@@ -53,9 +152,19 @@ public class Bridge {
|
||||
private final SnapshotAPI snapshotAPI;
|
||||
private final ResourceCache resourceCache;
|
||||
|
||||
|
||||
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(
|
||||
RepoStore repoStore,
|
||||
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(
|
||||
ProjectLock lock,
|
||||
RepoStore repoStore,
|
||||
@@ -103,6 +224,15 @@ public class Bridge {
|
||||
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() {
|
||||
Log.info("Shutdown received.");
|
||||
Log.info("Stopping SwapJob");
|
||||
@@ -112,10 +242,18 @@ public class Bridge {
|
||||
Log.info("Bye");
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the swap job, which will begin checking whether projects should be
|
||||
* swapped with a configurable frequency.
|
||||
*/
|
||||
public void startSwapJob() {
|
||||
swapJob.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a check of inconsistencies in the DB. This was used to upgrade
|
||||
* the schema.
|
||||
*/
|
||||
public void checkDB() {
|
||||
Log.info("Checking DB");
|
||||
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(
|
||||
Credential oauth2,
|
||||
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(
|
||||
Credential oauth2,
|
||||
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(
|
||||
Credential oauth2,
|
||||
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,
|
||||
String projectName,
|
||||
RawDirectory directoryContents,
|
||||
@@ -203,7 +400,7 @@ public class Bridge {
|
||||
String hostname
|
||||
) throws SnapshotPostException, IOException, ForbiddenException {
|
||||
try (LockGuard __ = lock.lockGuard(projectName)) {
|
||||
pushToProjectCritical(
|
||||
pushCritical(
|
||||
oauth2,
|
||||
projectName,
|
||||
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,
|
||||
String projectName,
|
||||
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)
|
||||
throws InvalidPostbackKeyException {
|
||||
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(
|
||||
"[{}]" +
|
||||
" 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);
|
||||
postbackManager.postExceptionForProject(
|
||||
projectName,
|
||||
@@ -327,6 +610,19 @@ public class Bridge {
|
||||
|
||||
/* 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(
|
||||
Credential oauth2,
|
||||
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();
|
||||
for (Snapshot snapshot : snapshots) {
|
||||
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(
|
||||
String projectName,
|
||||
RawDirectory directoryContents,
|
||||
@@ -404,6 +728,16 @@ public class Bridge {
|
||||
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(
|
||||
int versionID,
|
||||
CandidateSnapshot candidateSnapshot
|
||||
@@ -419,6 +753,4 @@ public class Bridge {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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.ProjectState;
|
||||
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.sql.*;
|
||||
|
||||
@@ -35,7 +35,9 @@ public class GetLatestVersionForProjectSQLQuery implements SQLQuery<Integer> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParametersToStatement(PreparedStatement statement) throws SQLException {
|
||||
public void addParametersToStatement(
|
||||
PreparedStatement statement
|
||||
) throws SQLException {
|
||||
statement.setString(1, projectName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,10 @@ import java.sql.SQLException;
|
||||
public class GetPathForURLInProjectSQLQuery implements SQLQuery<String> {
|
||||
|
||||
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 url;
|
||||
@@ -37,7 +40,9 @@ public class GetPathForURLInProjectSQLQuery implements SQLQuery<String> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParametersToStatement(PreparedStatement statement) throws SQLException {
|
||||
public void addParametersToStatement(
|
||||
PreparedStatement statement
|
||||
) throws SQLException {
|
||||
statement.setString(1, projectName);
|
||||
statement.setString(2, url);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLQuery;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -16,8 +16,10 @@ public class GetProjectNamesSQLQuery implements SQLQuery<List<String>> {
|
||||
"SELECT `name` FROM `projects`";
|
||||
|
||||
@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()) {
|
||||
projectNames.add(resultSet.getString("name"));
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ public class GetProjectState implements SQLQuery<ProjectState> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectState processResultSet(ResultSet resultSet) throws SQLException {
|
||||
public ProjectState processResultSet(
|
||||
ResultSet resultSet
|
||||
) throws SQLException {
|
||||
while (resultSet.next()) {
|
||||
if (resultSet.getTimestamp("last_accessed") == null) {
|
||||
return ProjectState.SWAPPED;
|
||||
@@ -40,7 +42,9 @@ public class GetProjectState implements SQLQuery<ProjectState> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParametersToStatement(PreparedStatement statement) throws SQLException {
|
||||
public void addParametersToStatement(
|
||||
PreparedStatement statement
|
||||
) throws SQLException {
|
||||
statement.setString(1, projectName);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,10 @@ public class DeleteFilesForProjectSQLUpdate implements SQLUpdate {
|
||||
private final String projectName;
|
||||
private final String[] paths;
|
||||
|
||||
public DeleteFilesForProjectSQLUpdate(String projectName, String... paths) {
|
||||
public DeleteFilesForProjectSQLUpdate(
|
||||
String projectName,
|
||||
String... paths
|
||||
) {
|
||||
this.projectName = projectName;
|
||||
this.paths = paths;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@ import java.sql.SQLException;
|
||||
public class SetProjectSQLUpdate implements SQLUpdate {
|
||||
|
||||
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 int versionID;
|
||||
@@ -28,7 +29,9 @@ public class SetProjectSQLUpdate implements SQLUpdate {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParametersToStatement(PreparedStatement statement) throws SQLException {
|
||||
public void addParametersToStatement(
|
||||
PreparedStatement statement
|
||||
) throws SQLException {
|
||||
statement.setString(1, projectName);
|
||||
statement.setInt(2, versionID);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
|
||||
import uk.ac.ic.wlgitbridge.data.filestore.GitDirectoryContents;
|
||||
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.util.Log;
|
||||
import uk.ac.ic.wlgitbridge.util.Project;
|
||||
@@ -62,7 +62,7 @@ public class GitProjectRepo implements ProjectRepo {
|
||||
|
||||
@Override
|
||||
public Map<String, RawFile> getFiles()
|
||||
throws IOException, GitUserException {
|
||||
throws IOException, SizeLimitExceededException {
|
||||
Preconditions.checkState(repository.isPresent());
|
||||
return new RepositoryObjectTreeWalker(
|
||||
repository.get()
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
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.RawFile;
|
||||
import uk.ac.ic.wlgitbridge.git.exception.GitUserException;
|
||||
import uk.ac.ic.wlgitbridge.git.exception.SizeLimitExceededException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
@@ -24,7 +23,8 @@ public interface ProjectRepo {
|
||||
RepoStore repoStore
|
||||
) throws IOException;
|
||||
|
||||
Map<String, RawFile> getFiles() throws IOException, GitUserException;
|
||||
Map<String, RawFile> getFiles(
|
||||
) throws IOException, SizeLimitExceededException;
|
||||
|
||||
Collection<String> commitAndGetMissing(
|
||||
GitDirectoryContents gitDirectoryContents
|
||||
|
||||
@@ -9,5 +9,13 @@ import java.util.Map;
|
||||
* Created by winston on 20/08/2016.
|
||||
*/
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,13 @@ public class UrlResourceCache implements ResourceCache {
|
||||
}
|
||||
|
||||
@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);
|
||||
byte[] contents;
|
||||
if (path == null) {
|
||||
@@ -42,8 +48,11 @@ public class UrlResourceCache implements ResourceCache {
|
||||
RawFile rawFile = fileTable.get(path);
|
||||
if (rawFile == null) {
|
||||
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);
|
||||
} else {
|
||||
@@ -54,25 +63,42 @@ public class UrlResourceCache implements ResourceCache {
|
||||
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;
|
||||
Log.info("GET -> " + url);
|
||||
try {
|
||||
contents = Request.httpClient.prepareGet(url).execute(new AsyncCompletionHandler<byte[]>() {
|
||||
contents = Request.httpClient.prepareGet(url).execute(
|
||||
new AsyncCompletionHandler<byte[]>() {
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
@Override
|
||||
public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
|
||||
public STATE onBodyPartReceived(
|
||||
HttpResponseBodyPart bodyPart
|
||||
) throws Exception {
|
||||
bytes.write(bodyPart.getBodyPartBytes());
|
||||
return STATE.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] onCompleted(Response response) throws Exception {
|
||||
public byte[] onCompleted(
|
||||
Response response
|
||||
) throws Exception {
|
||||
byte[] data = bytes.toByteArray();
|
||||
bytes.close();
|
||||
Log.info(response.getStatusCode() + " " + response.getStatusText() + " (" + data.length + "B) -> " + url);
|
||||
Log.info(
|
||||
response.getStatusCode()
|
||||
+ " "
|
||||
+ response.getStatusText()
|
||||
+ " ("
|
||||
+ data.length
|
||||
+ "B) -> "
|
||||
+ url
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,54 +20,99 @@ import java.util.*;
|
||||
public class NetSnapshotAPI implements SnapshotAPI {
|
||||
|
||||
@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);
|
||||
GetSavedVersRequest getSavedVers = new GetSavedVersRequest(oauth2, projectName);
|
||||
GetSavedVersRequest getSavedVers = new GetSavedVersRequest(
|
||||
oauth2,
|
||||
projectName
|
||||
);
|
||||
getDoc.request();
|
||||
getSavedVers.request();
|
||||
GetDocResult latestDoc = getDoc.getResult();
|
||||
int latest = latestDoc.getVersionID();
|
||||
if (latest > version) {
|
||||
for (SnapshotInfo snapshotInfo : getSavedVers.getResult().getSavedVers()) {
|
||||
for (
|
||||
SnapshotInfo snapshotInfo :
|
||||
getSavedVers.getResult().getSavedVers()
|
||||
) {
|
||||
if (snapshotInfo.getVersionId() > version) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
snapshotDataList.add(fired.getResult().getSnapshotData());
|
||||
}
|
||||
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) {
|
||||
GetForVersionRequest request = new GetForVersionRequest(oauth2, projectName, snapshotInfo.getVersionId());
|
||||
GetForVersionRequest request = new GetForVersionRequest(
|
||||
oauth2,
|
||||
projectName,
|
||||
snapshotInfo.getVersionId()
|
||||
);
|
||||
requests.add(request);
|
||||
request.request();
|
||||
}
|
||||
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<SnapshotData> datas = snapshotDatas.iterator();
|
||||
while (infos.hasNext()) {
|
||||
|
||||
@@ -1,30 +1,20 @@
|
||||
package uk.ac.ic.wlgitbridge.bridge.swap.job;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by winston on 24/08/2016.
|
||||
*/
|
||||
public class NoopSwapJob implements SwapJob {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
|
||||
}
|
||||
public void start() {}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
|
||||
}
|
||||
public void stop() {}
|
||||
|
||||
@Override
|
||||
public void evict(String projName) throws IOException {
|
||||
|
||||
}
|
||||
public void evict(String projName) {}
|
||||
|
||||
@Override
|
||||
public void restore(String projName) throws IOException {
|
||||
|
||||
}
|
||||
public void restore(String projName) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,4 +39,5 @@ public interface SwapJob {
|
||||
void evict(String projName) throws IOException;
|
||||
|
||||
void restore(String projName) throws IOException;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package uk.ac.ic.wlgitbridge.bridge.swap.store;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
@@ -9,18 +8,14 @@ import java.io.InputStream;
|
||||
*/
|
||||
public class NoopSwapStore implements SwapStore {
|
||||
|
||||
public NoopSwapStore(SwapStoreConfig config) {
|
||||
|
||||
}
|
||||
public NoopSwapStore(SwapStoreConfig __) {}
|
||||
|
||||
@Override
|
||||
public void upload(
|
||||
String projectName,
|
||||
InputStream uploadStream,
|
||||
long contentLength
|
||||
) throws IOException {
|
||||
|
||||
}
|
||||
) {}
|
||||
|
||||
@Override
|
||||
public InputStream openDownloadStream(String projectName) {
|
||||
@@ -28,8 +23,6 @@ public class NoopSwapStore implements SwapStore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String projectName) {
|
||||
|
||||
}
|
||||
public void remove(String projectName) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,6 @@ package uk.ac.ic.wlgitbridge.data;
|
||||
*/
|
||||
public interface LockAllWaiter {
|
||||
|
||||
public void threadsRemaining(int threads);
|
||||
void threadsRemaining(int threads);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package uk.ac.ic.wlgitbridge.data;
|
||||
|
||||
/**
|
||||
* Created by Winston on 07/11/14.
|
||||
*/
|
||||
public class SnapshotFetcher {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import java.util.Arrays;
|
||||
public abstract class RawFile {
|
||||
|
||||
public abstract String getPath();
|
||||
|
||||
public abstract byte[] getContents();
|
||||
|
||||
public final void writeToDisk(File directory) throws IOException {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package uk.ac.ic.wlgitbridge.data.model;
|
||||
|
||||
/**
|
||||
* Created by Winston on 21/02/15.
|
||||
*/
|
||||
public class ResourceFetcher {
|
||||
|
||||
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import java.util.List;
|
||||
public abstract class GitUserException extends Exception {
|
||||
|
||||
public abstract String getMessage();
|
||||
|
||||
public abstract List<String> getDescriptionLines();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package uk.ac.ic.wlgitbridge.git.exception;
|
||||
|
||||
/**
|
||||
* Created by Winston on 03/11/14.
|
||||
*/
|
||||
public class InvalidRootDirectoryPathException extends Exception {
|
||||
|
||||
}
|
||||
@@ -21,10 +21,12 @@ public class SizeLimitExceededException extends GitUserException {
|
||||
|
||||
@Override
|
||||
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(
|
||||
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"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,5 +7,4 @@ import uk.ac.ic.wlgitbridge.snapshot.base.JSONSource;
|
||||
*/
|
||||
public abstract class SnapshotAPIException
|
||||
extends GitUserException
|
||||
implements JSONSource {
|
||||
}
|
||||
implements JSONSource {}
|
||||
|
||||
@@ -4,10 +4,10 @@ import com.google.api.client.auth.oauth2.Credential;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.ReceivePack;
|
||||
import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
|
||||
import uk.ac.ic.wlgitbridge.bridge.Bridge;
|
||||
import uk.ac.ic.wlgitbridge.bridge.snapshot.SnapshotAPI;
|
||||
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.util.Util;
|
||||
|
||||
@@ -16,8 +16,15 @@ import javax.servlet.http.HttpServletRequest;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@@ -25,15 +32,39 @@ public class WLReceivePackFactory implements ReceivePackFactory<HttpServletReque
|
||||
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
|
||||
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);
|
||||
String hostname = Util.getPostbackURL();
|
||||
if (hostname == null) {
|
||||
hostname = httpServletRequest.getLocalName();
|
||||
}
|
||||
receivePack.setPreReceiveHook(new WriteLatexPutHook(bridge, hostname, oauth2));
|
||||
receivePack.setPreReceiveHook(
|
||||
new WriteLatexPutHook(bridge, hostname, oauth2)
|
||||
);
|
||||
return receivePack;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,12 @@ import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.ServiceMayNotContinueException;
|
||||
import org.eclipse.jgit.transport.resolver.RepositoryResolver;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
|
||||
import uk.ac.ic.wlgitbridge.bridge.Bridge;
|
||||
import uk.ac.ic.wlgitbridge.bridge.repo.GitProjectRepo;
|
||||
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.snapshot.base.ForbiddenException;
|
||||
import uk.ac.ic.wlgitbridge.util.Log;
|
||||
@@ -21,6 +23,18 @@ import java.io.IOException;
|
||||
/**
|
||||
* 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
|
||||
implements RepositoryResolver<HttpServletRequest> {
|
||||
|
||||
@@ -30,13 +44,42 @@ public class WLRepositoryResolver
|
||||
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
|
||||
public Repository open(
|
||||
HttpServletRequest httpServletRequest,
|
||||
String name
|
||||
) throws RepositoryNotFoundException,
|
||||
ServiceNotAuthorizedException,
|
||||
ServiceNotEnabledException,
|
||||
ServiceMayNotContinueException {
|
||||
Credential oauth2 = (Credential) httpServletRequest.getAttribute(
|
||||
Oauth2Filter.ATTRIBUTE_KEY
|
||||
|
||||
@@ -2,9 +2,8 @@ package uk.ac.ic.wlgitbridge.git.handler;
|
||||
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.UploadPack;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
|
||||
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
|
||||
import org.eclipse.jgit.transport.resolver.UploadPackFactory;
|
||||
import uk.ac.ic.wlgitbridge.git.servlet.WLGitServlet;
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -12,11 +11,34 @@ import javax.servlet.http.HttpServletRequest;
|
||||
/**
|
||||
* 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
|
||||
public UploadPack create(HttpServletRequest httpServletRequest, Repository repository) throws ServiceNotEnabledException, ServiceNotAuthorizedException {
|
||||
public UploadPack create(
|
||||
HttpServletRequest __,
|
||||
Repository repository
|
||||
) {
|
||||
UploadPack uploadPack = new UploadPack(repository);
|
||||
uploadPack.sendMessage("Downloading files from " + Util.getServiceName());
|
||||
uploadPack.sendMessage(
|
||||
"Downloading files from " + Util.getServiceName()
|
||||
);
|
||||
return uploadPack;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.eclipse.jgit.transport.ReceivePack;
|
||||
import uk.ac.ic.wlgitbridge.bridge.Bridge;
|
||||
import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory;
|
||||
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.WrongBranchException;
|
||||
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 {@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 {
|
||||
|
||||
private final Bridge bridge;
|
||||
private final String hostname;
|
||||
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.hostname = hostname;
|
||||
this.oauth2 = oauth2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreReceive(ReceivePack receivePack, Collection<ReceiveCommand> receiveCommands) {
|
||||
public void onPreReceive(
|
||||
ReceivePack receivePack,
|
||||
Collection<ReceiveCommand> receiveCommands
|
||||
) {
|
||||
for (ReceiveCommand receiveCommand : receiveCommands) {
|
||||
try {
|
||||
handleReceiveCommand(oauth2, receivePack.getRepository(), receiveCommand);
|
||||
handleReceiveCommand(
|
||||
oauth2,
|
||||
receivePack.getRepository(),
|
||||
receiveCommand
|
||||
);
|
||||
} catch (IOException e) {
|
||||
receivePack.sendError(e.getMessage());
|
||||
receiveCommand.setResult(Result.REJECTED_OTHER_REASON, e.getMessage());
|
||||
receiveCommand.setResult(
|
||||
Result.REJECTED_OTHER_REASON,
|
||||
e.getMessage()
|
||||
);
|
||||
} catch (OutOfDateException e) {
|
||||
receiveCommand.setResult(Result.REJECTED_NONFASTFORWARD);
|
||||
} catch (SnapshotPostException e) {
|
||||
handleSnapshotPostException(receivePack, receiveCommand, e);
|
||||
} catch (Throwable 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();
|
||||
receivePack.sendError(message);
|
||||
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();
|
||||
msg.append("hint: ");
|
||||
msg.append(line);
|
||||
@@ -72,10 +111,14 @@ public class WriteLatexPutHook implements PreReceiveHook {
|
||||
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);
|
||||
checkForcedPush(receiveCommand);
|
||||
bridge.putDirectoryContentsToProjectWithName(
|
||||
bridge.push(
|
||||
oauth2,
|
||||
repository.getWorkTree().getName(),
|
||||
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")) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,9 +13,12 @@ import java.util.List;
|
||||
public class ForcedPushException extends SnapshotPostException {
|
||||
|
||||
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.",
|
||||
"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
|
||||
@@ -29,8 +32,6 @@ public class ForcedPushException extends SnapshotPostException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
|
||||
}
|
||||
public void fromJSON(JsonElement json) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,22 +3,44 @@ package uk.ac.ic.wlgitbridge.git.servlet;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jgit.http.server.GitServlet;
|
||||
import uk.ac.ic.wlgitbridge.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.WLRepositoryResolver;
|
||||
import uk.ac.ic.wlgitbridge.git.handler.WLUploadPackFactory;
|
||||
import uk.ac.ic.wlgitbridge.server.GitBridgeServer;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
/**
|
||||
* 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(
|
||||
ServletContextHandler ctxHandler,
|
||||
Bridge bridge
|
||||
) throws ServletException, InvalidRootDirectoryPathException {
|
||||
) throws ServletException {
|
||||
setRepositoryResolver(new WLRepositoryResolver(bridge));
|
||||
setReceivePackFactory(new WLReceivePackFactory(bridge));
|
||||
setUploadPackFactory(new WLUploadPackFactory());
|
||||
|
||||
@@ -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.RawFile;
|
||||
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 java.io.IOException;
|
||||
@@ -23,24 +22,36 @@ public class RepositoryObjectTreeWalker {
|
||||
private final TreeWalk treeWalk;
|
||||
private final Repository repository;
|
||||
|
||||
public RepositoryObjectTreeWalker(Repository repository, ObjectId objectId) throws IOException {
|
||||
public RepositoryObjectTreeWalker(
|
||||
Repository repository,
|
||||
ObjectId objectId
|
||||
) throws IOException {
|
||||
treeWalk = initTreeWalk(repository, objectId);
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public RepositoryObjectTreeWalker(Repository repository) throws IOException {
|
||||
public RepositoryObjectTreeWalker(
|
||||
Repository repository
|
||||
) throws IOException {
|
||||
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));
|
||||
}
|
||||
|
||||
public RawDirectory getDirectoryContents() throws IOException, GitUserException {
|
||||
public RawDirectory getDirectoryContents(
|
||||
) throws IOException, SizeLimitExceededException {
|
||||
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) {
|
||||
return null;
|
||||
}
|
||||
@@ -51,8 +62,9 @@ public class RepositoryObjectTreeWalker {
|
||||
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) {
|
||||
return fileContentsTable;
|
||||
}
|
||||
@@ -60,10 +72,11 @@ public class RepositoryObjectTreeWalker {
|
||||
String path = treeWalk.getPathString();
|
||||
|
||||
try {
|
||||
byte[] content = repository.open(treeWalk.getObjectId(0)).getBytes();
|
||||
byte[] content = repository.open(
|
||||
treeWalk.getObjectId(0)
|
||||
).getBytes();
|
||||
fileContentsTable.put(path, new RepositoryFile(path, content));
|
||||
}
|
||||
catch (LargeObjectException e) {
|
||||
} catch (LargeObjectException e) {
|
||||
throw new SizeLimitExceededException(path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,20 +20,23 @@ import java.util.regex.Pattern;
|
||||
* Requests must include the postback key.
|
||||
*/
|
||||
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+)/.+$");
|
||||
|
||||
public FileHandler(Bridge writeLatexDataSource) {
|
||||
this.writeLatexDataSource = writeLatexDataSource;
|
||||
public FileHandler(Bridge bridge) {
|
||||
this.bridge = bridge;
|
||||
}
|
||||
|
||||
@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;
|
||||
LOG.info("GET <- {}", baseRequest.getRequestURI());
|
||||
|
||||
@@ -45,12 +48,17 @@ public class FileHandler extends ResourceHandler {
|
||||
if (apiKey == null) return;
|
||||
|
||||
try {
|
||||
writeLatexDataSource.checkPostbackKey(docKey, apiKey);
|
||||
bridge.checkPostbackKey(docKey, apiKey);
|
||||
} catch (InvalidPostbackKeyException e) {
|
||||
LOG.warn("INVALID POST BACK KEY: docKey={} apiKey={}", docKey, apiKey);
|
||||
LOG.warn(
|
||||
"INVALID POST BACK KEY: docKey={} apiKey={}",
|
||||
docKey,
|
||||
apiKey
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
super.handle(target, baseRequest, request, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.RepoStore;
|
||||
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.snapshot.base.SnapshotAPIRequest;
|
||||
import uk.ac.ic.wlgitbridge.util.Log;
|
||||
@@ -47,7 +46,7 @@ public class GitBridgeServer {
|
||||
|
||||
public GitBridgeServer(
|
||||
Config config
|
||||
) throws ServletException, InvalidRootDirectoryPathException {
|
||||
) throws ServletException {
|
||||
org.eclipse.jetty.util.log.Log.setLog(new NullLogger());
|
||||
this.port = config.getPort();
|
||||
this.rootGitDirectoryPath = config.getRootGitDirectory();
|
||||
@@ -107,7 +106,7 @@ public class GitBridgeServer {
|
||||
|
||||
private void configureJettyServer(
|
||||
Config config
|
||||
) throws ServletException, InvalidRootDirectoryPathException {
|
||||
) throws ServletException {
|
||||
HandlerCollection handlers = new HandlerList();
|
||||
handlers.addHandler(initApiHandler());
|
||||
handlers.addHandler(initGitHandler(config));
|
||||
@@ -129,7 +128,7 @@ public class GitBridgeServer {
|
||||
|
||||
private Handler initGitHandler(
|
||||
Config config
|
||||
) throws ServletException, InvalidRootDirectoryPathException {
|
||||
) throws ServletException {
|
||||
final ServletContextHandler servletContextHandler =
|
||||
new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
if (config.isUsingOauth2()) {
|
||||
@@ -160,4 +159,5 @@ public class GitBridgeServer {
|
||||
);
|
||||
return resourceHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,13 +2,8 @@ package uk.ac.ic.wlgitbridge.server;
|
||||
|
||||
import com.google.api.client.auth.oauth2.*;
|
||||
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.lang.StringUtils;
|
||||
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.snapshot.base.ForbiddenException;
|
||||
import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocRequest;
|
||||
@@ -37,26 +32,40 @@ public class Oauth2Filter implements Filter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
|
||||
}
|
||||
public void init(FilterConfig filterConfig) {}
|
||||
|
||||
@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);
|
||||
doc.request();
|
||||
try {
|
||||
doc.getResult();
|
||||
} catch (ForbiddenException e) {
|
||||
getAndInjectCredentials(servletRequest, servletResponse, filterChain);
|
||||
getAndInjectCredentials(
|
||||
servletRequest,
|
||||
servletResponse,
|
||||
filterChain
|
||||
);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
|
||||
@@ -67,26 +76,47 @@ public class Oauth2Filter implements Filter {
|
||||
String basic = st.nextToken();
|
||||
if (basic.equalsIgnoreCase("Basic")) {
|
||||
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(":");
|
||||
if (split.length == 2) {
|
||||
String username = split[0];
|
||||
String password = split[1];
|
||||
String accessToken = null;
|
||||
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();
|
||||
} catch (TokenResponseException e) {
|
||||
unauthorized(response);
|
||||
return;
|
||||
}
|
||||
final Credential cred = new Credential.Builder(BearerToken.authorizationHeaderAccessMethod())
|
||||
.build();
|
||||
final Credential cred = new Credential.Builder(
|
||||
BearerToken.authorizationHeaderAccessMethod(
|
||||
)
|
||||
).build();
|
||||
cred.setAccessToken(accessToken);
|
||||
servletRequest.setAttribute(ATTRIBUTE_KEY, cred);
|
||||
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
filterChain.doFilter(
|
||||
servletRequest,
|
||||
servletResponse
|
||||
);
|
||||
} else {
|
||||
unauthorized(response);
|
||||
}
|
||||
@@ -101,22 +131,35 @@ public class Oauth2Filter implements Filter {
|
||||
}
|
||||
|
||||
@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;
|
||||
response.setContentType("text/plain");
|
||||
response.setHeader("WWW-Authenticate", "Basic realm=\"Git Bridge\"");
|
||||
response.setStatus(401);
|
||||
|
||||
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("*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.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,12 @@ public class PostbackContents implements JSONSource {
|
||||
private int versionID;
|
||||
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.projectName = projectName;
|
||||
this.postbackKey = postbackKey;
|
||||
@@ -43,9 +48,17 @@ public class PostbackContents implements JSONSource {
|
||||
|
||||
public void processPostback() throws UnexpectedPostbackException {
|
||||
if (exception == null) {
|
||||
bridge.postbackReceivedSuccessfully(projectName, postbackKey, versionID);
|
||||
bridge.postbackReceivedSuccessfully(
|
||||
projectName,
|
||||
postbackKey,
|
||||
versionID
|
||||
);
|
||||
} 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) {
|
||||
try {
|
||||
exception = snapshotPostExceptionBuilder.build(code, responseObject);
|
||||
exception = snapshotPostExceptionBuilder.build(
|
||||
code,
|
||||
responseObject
|
||||
);
|
||||
} catch (UnexpectedPostbackException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -26,10 +26,18 @@ public class PostbackHandler extends AbstractHandler {
|
||||
}
|
||||
|
||||
@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 {
|
||||
if (request.getMethod().equals("POST") && target.endsWith("postback")) {
|
||||
if (
|
||||
request.getMethod().equals("POST")
|
||||
&& target.endsWith("postback")
|
||||
) {
|
||||
response.setContentType("application/json");
|
||||
String contents = Util.getContentsOfReader(request.getReader());
|
||||
String[] parts = target.split("/");
|
||||
@@ -38,8 +46,17 @@ public class PostbackHandler extends AbstractHandler {
|
||||
}
|
||||
String projectName = parts[1];
|
||||
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();
|
||||
|
||||
try {
|
||||
|
||||
@@ -10,10 +10,9 @@ import java.util.List;
|
||||
* Created by winston on 25/10/15.
|
||||
*/
|
||||
public class ForbiddenException extends SnapshotAPIException {
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
|
||||
}
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
|
||||
@@ -7,6 +7,6 @@ import com.google.gson.JsonElement;
|
||||
*/
|
||||
public interface JSONSource {
|
||||
|
||||
public abstract void fromJSON(JsonElement json);
|
||||
void fromJSON(JsonElement json);
|
||||
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@ package uk.ac.ic.wlgitbridge.snapshot.base;
|
||||
|
||||
import com.google.api.client.auth.oauth2.Credential;
|
||||
import com.google.api.client.http.BasicAuthentication;
|
||||
import com.google.api.client.http.HttpExecuteInterceptor;
|
||||
import com.google.api.client.http.HttpRequest;
|
||||
import com.ning.http.client.Realm;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -20,22 +18,26 @@ public abstract class SnapshotAPIRequest<T extends Result> extends Request<T> {
|
||||
|
||||
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);
|
||||
this.oauth2 = oauth2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBeforeRequest(HttpRequest request) throws IOException {
|
||||
protected void onBeforeRequest(
|
||||
HttpRequest request
|
||||
) throws IOException {
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ public class GetDocRequest extends SnapshotAPIRequest<GetDocResult> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GetDocResult parseResponse(JsonElement json) throws FailedConnectionException {
|
||||
protected GetDocResult parseResponse(
|
||||
JsonElement json
|
||||
) throws FailedConnectionException {
|
||||
return new GetDocResult(this, json);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,20 @@ public class GetDocResult extends Result {
|
||||
private SnapshotAPIException exception;
|
||||
private ForbiddenException forbidden;
|
||||
|
||||
public GetDocResult(Request request, JsonElement json) throws FailedConnectionException {
|
||||
public GetDocResult(
|
||||
Request request,
|
||||
JsonElement json
|
||||
) throws FailedConnectionException {
|
||||
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) {
|
||||
this.error = -1;
|
||||
} else {
|
||||
@@ -75,7 +84,9 @@ public class GetDocResult extends Result {
|
||||
exception = new InvalidProjectException();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown get doc error code");
|
||||
throw new IllegalArgumentException(
|
||||
"unknown get doc error code"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
versionID = jsonObject.get("latestVerId").getAsInt();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,13 +9,18 @@ import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException;
|
||||
/**
|
||||
* 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";
|
||||
|
||||
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);
|
||||
this.versionID = versionID;
|
||||
}
|
||||
@@ -26,7 +31,9 @@ public class GetForVersionRequest extends SnapshotAPIRequest<GetForVersionResult
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GetForVersionResult parseResponse(JsonElement json) throws FailedConnectionException {
|
||||
protected GetForVersionResult parseResponse(
|
||||
JsonElement json
|
||||
) throws FailedConnectionException {
|
||||
return new GetForVersionResult(this, json);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.snapshot.base.JSONSource;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -20,12 +20,15 @@ public class SnapshotData implements JSONSource {
|
||||
private List<SnapshotAttachment> atts;
|
||||
|
||||
public SnapshotData(JsonElement json) {
|
||||
srcs = new LinkedList<SnapshotFile>();
|
||||
atts = new LinkedList<SnapshotAttachment>();
|
||||
srcs = new ArrayList<>();
|
||||
atts = new ArrayList<>();
|
||||
fromJSON(json);
|
||||
}
|
||||
|
||||
public SnapshotData(List<SnapshotFile> srcs, List<SnapshotAttachment> atts) {
|
||||
public SnapshotData(
|
||||
List<SnapshotFile> srcs,
|
||||
List<SnapshotAttachment> atts
|
||||
) {
|
||||
this.srcs = srcs;
|
||||
this.atts = atts;
|
||||
}
|
||||
@@ -47,8 +50,12 @@ public class SnapshotData implements JSONSource {
|
||||
|
||||
@Override
|
||||
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) {
|
||||
@@ -70,4 +77,5 @@ public class SnapshotData implements JSONSource {
|
||||
public List<SnapshotAttachment> getAtts() {
|
||||
return atts;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ import uk.ac.ic.wlgitbridge.snapshot.base.HTTPMethod;
|
||||
/**
|
||||
* 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";
|
||||
|
||||
@@ -23,7 +24,9 @@ public class GetSavedVersRequest extends SnapshotAPIRequest<GetSavedVersResult>
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GetSavedVersResult parseResponse(JsonElement json) throws FailedConnectionException {
|
||||
protected GetSavedVersResult parseResponse(
|
||||
JsonElement json
|
||||
) throws FailedConnectionException {
|
||||
return new GetSavedVersResult(this, json);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.snapshot.base.Result;
|
||||
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 java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -18,7 +18,10 @@ public class GetSavedVersResult extends Result {
|
||||
|
||||
private List<SnapshotInfo> savedVers;
|
||||
|
||||
public GetSavedVersResult(Request request, JsonElement json) throws FailedConnectionException {
|
||||
public GetSavedVersResult(
|
||||
Request request,
|
||||
JsonElement json
|
||||
) throws FailedConnectionException {
|
||||
super(request, json);
|
||||
}
|
||||
|
||||
@@ -46,9 +49,14 @@ public class GetSavedVersResult extends Result {
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
savedVers = new LinkedList<SnapshotInfo>();
|
||||
savedVers = new ArrayList<>();
|
||||
for (JsonElement elem : json.getAsJsonArray()) {
|
||||
savedVers.add(new Gson().fromJson(elem.getAsJsonObject(), SnapshotInfo.class));
|
||||
savedVers.add(
|
||||
new Gson().fromJson(
|
||||
elem.getAsJsonObject(),
|
||||
SnapshotInfo.class
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,28 @@ public class SnapshotInfo implements Comparable<SnapshotInfo> {
|
||||
private WLUser user;
|
||||
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;
|
||||
this.comment = comment;
|
||||
user = new WLUser(name, email);
|
||||
@@ -52,4 +69,5 @@ public class SnapshotInfo implements Comparable<SnapshotInfo> {
|
||||
public int compareTo(SnapshotInfo o) {
|
||||
return Integer.compare(versionId, o.versionId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ public class WLUser {
|
||||
this.email = email;
|
||||
} else {
|
||||
this.name = "Anonymous";
|
||||
this.email = "anonymous@" + Util.getServiceName().toLowerCase() + ".com";
|
||||
this.email = "anonymous@"
|
||||
+ Util.getServiceName().toLowerCase()
|
||||
+ ".com";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,9 @@ public class PostbackManager {
|
||||
this(new SecureRandom());
|
||||
}
|
||||
|
||||
public int waitForVersionIdOrThrow(String projectName)
|
||||
throws SnapshotPostException {
|
||||
public int waitForVersionIdOrThrow(
|
||||
String projectName
|
||||
) throws SnapshotPostException {
|
||||
try {
|
||||
PostbackPromise postbackPromise =
|
||||
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(
|
||||
projectName
|
||||
).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(
|
||||
projectName
|
||||
).receivedException(exception, postbackKey);
|
||||
@@ -80,7 +83,8 @@ public class PostbackManager {
|
||||
throws InvalidPostbackKeyException {
|
||||
PostbackPromise postbackPromise = postbackContentsTable.get(projectName);
|
||||
if (postbackPromise == null) {
|
||||
throw new InvalidPostbackKeyException(); // project not found; can't check key
|
||||
// project not found; can't check key
|
||||
throw new InvalidPostbackKeyException();
|
||||
} else {
|
||||
postbackPromise.checkPostbackKey(postbackKey);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,10 @@ public class PostbackPromise {
|
||||
}
|
||||
}
|
||||
|
||||
public void receivedException(SnapshotPostException exception, String postbackKey) {
|
||||
public void receivedException(
|
||||
SnapshotPostException exception,
|
||||
String postbackKey
|
||||
) {
|
||||
lock.lock();
|
||||
try {
|
||||
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)) {
|
||||
throw new InvalidPostbackKeyException();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,11 @@ public class PushRequest extends SnapshotAPIRequest<PushResult> {
|
||||
private final CandidateSnapshot candidateSnapshot;
|
||||
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);
|
||||
this.candidateSnapshot = candidateSnapshot;
|
||||
this.postbackKey = postbackKey;
|
||||
@@ -34,7 +38,9 @@ public class PushRequest extends SnapshotAPIRequest<PushResult> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PushResult parseResponse(JsonElement json) throws FailedConnectionException {
|
||||
protected PushResult parseResponse(
|
||||
JsonElement json
|
||||
) throws FailedConnectionException {
|
||||
return new PushResult(this, json);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,10 @@ public class PushResult extends Result {
|
||||
|
||||
private boolean success;
|
||||
|
||||
public PushResult(Request request, JsonElement json) throws FailedConnectionException {
|
||||
public PushResult(
|
||||
Request request,
|
||||
JsonElement json
|
||||
) throws FailedConnectionException {
|
||||
super(request, json);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ public class InternalErrorException extends SevereSnapshotPostException {
|
||||
|
||||
@Override
|
||||
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
|
||||
public void fromJSON(JsonElement json) {
|
||||
|
||||
}
|
||||
public void fromJSON(JsonElement json) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import uk.ac.ic.wlgitbridge.util.Util;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -31,16 +31,24 @@ public class InvalidFilesException extends SnapshotPostException {
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
descriptionLines = new LinkedList<String>();
|
||||
JsonArray errors = json.getAsJsonObject().get("errors").getAsJsonArray();
|
||||
descriptionLines.add("You have " + errors.size() + " invalid files in your " + Util.getServiceName() + " project:");
|
||||
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) {
|
||||
descriptionLines.add(describeError(error.getAsJsonObject()));
|
||||
}
|
||||
}
|
||||
|
||||
private String describeError(JsonObject jsonObject) {
|
||||
return jsonObject.get("file").getAsString() + " (" + describeFile(jsonObject) + ")";
|
||||
return jsonObject.get("file").getAsString()
|
||||
+ " (" + describeFile(jsonObject) + ")";
|
||||
}
|
||||
|
||||
private String describeFile(JsonObject file) {
|
||||
|
||||
@@ -3,5 +3,4 @@ package uk.ac.ic.wlgitbridge.snapshot.push.exception;
|
||||
/**
|
||||
* Created by Winston on 04/12/14.
|
||||
*/
|
||||
public class InvalidPostbackKeyException extends Exception {
|
||||
}
|
||||
public class InvalidPostbackKeyException extends Exception {}
|
||||
|
||||
@@ -30,7 +30,8 @@ public class InvalidProjectException extends SnapshotPostException {
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
descriptionLines = new LinkedList<String>();
|
||||
JsonArray errors = json.getAsJsonObject().get("errors").getAsJsonArray();
|
||||
JsonArray errors =
|
||||
json.getAsJsonObject().get("errors").getAsJsonArray();
|
||||
for (JsonElement error : errors) {
|
||||
descriptionLines.add(error.getAsString());
|
||||
}
|
||||
|
||||
@@ -15,9 +15,7 @@ public class OutOfDateException extends SnapshotPostException {
|
||||
super(json);
|
||||
}
|
||||
|
||||
public OutOfDateException() {
|
||||
|
||||
}
|
||||
public OutOfDateException() {}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
@@ -30,8 +28,6 @@ public class OutOfDateException extends SnapshotPostException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
|
||||
}
|
||||
public void fromJSON(JsonElement json) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,12 +18,15 @@ public class PostbackTimeoutException extends SevereSnapshotPostException {
|
||||
|
||||
@Override
|
||||
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
|
||||
public void fromJSON(JsonElement json) {
|
||||
|
||||
}
|
||||
public void fromJSON(JsonElement json) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,9 +8,7 @@ import uk.ac.ic.wlgitbridge.git.exception.SnapshotAPIException;
|
||||
*/
|
||||
public abstract class SnapshotPostException extends SnapshotAPIException {
|
||||
|
||||
public SnapshotPostException() {
|
||||
|
||||
}
|
||||
public SnapshotPostException() {}
|
||||
|
||||
public SnapshotPostException(JsonElement jsonElement) {
|
||||
fromJSON(jsonElement);
|
||||
|
||||
@@ -12,7 +12,10 @@ public class SnapshotPostExceptionBuilder {
|
||||
private static final String CODE_ERROR_INVALID_PROJECT = "invalidProject";
|
||||
private static final String CODE_ERROR_UNKNOWN = "error";
|
||||
|
||||
public SnapshotPostException build(String errorCode, JsonObject json) throws UnexpectedPostbackException {
|
||||
public SnapshotPostException build(
|
||||
String errorCode,
|
||||
JsonObject json
|
||||
) throws UnexpectedPostbackException {
|
||||
if (errorCode.equals(CODE_ERROR_OUT_OF_DATE)) {
|
||||
return new OutOfDateException(json);
|
||||
} else if (errorCode.equals(CODE_ERROR_INVALID_FILES)) {
|
||||
|
||||
@@ -13,7 +13,8 @@ import java.util.List;
|
||||
public class UnexpectedErrorException extends SevereSnapshotPostException {
|
||||
|
||||
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() + "."
|
||||
};
|
||||
|
||||
@@ -32,8 +33,6 @@ public class UnexpectedErrorException extends SevereSnapshotPostException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJSON(JsonElement json) {
|
||||
|
||||
}
|
||||
public void fromJSON(JsonElement json) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,5 +3,4 @@ package uk.ac.ic.wlgitbridge.snapshot.push.exception;
|
||||
/**
|
||||
* Created by Winston on 17/11/14.
|
||||
*/
|
||||
public class UnexpectedPostbackException extends Exception {
|
||||
}
|
||||
public class UnexpectedPostbackException extends Exception {}
|
||||
|
||||
@@ -13,8 +13,17 @@ import java.io.FileNotFoundException;
|
||||
public class Main {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -14,7 +19,10 @@ public class SnapshotResponseBuilder {
|
||||
|
||||
private SnapshotAPIState state;
|
||||
|
||||
public SnapshotResponse buildWithTarget(String target, String method) throws InvalidAPICallException {
|
||||
public SnapshotResponse buildWithTarget(
|
||||
String target,
|
||||
String method
|
||||
) throws InvalidAPICallException {
|
||||
checkPrefix(target);
|
||||
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];
|
||||
if (parts.length == 5) {
|
||||
if (method.equals("GET")) {
|
||||
return new SnapshotGetDocResponse(state.getStateForGetDoc(projectName));
|
||||
return new SnapshotGetDocResponse(
|
||||
state.getStateForGetDoc(projectName)
|
||||
);
|
||||
}
|
||||
} else if (parts.length == 6) {
|
||||
String type = parts[5];
|
||||
if (type.equals("snapshots") && method.equals("POST")) {
|
||||
return new SnapshotPushResponse(state.getStateForPush(projectName), state.getStateForPostback(projectName));
|
||||
return new SnapshotPushResponse(
|
||||
state.getStateForPush(projectName),
|
||||
state.getStateForPostback(projectName)
|
||||
);
|
||||
} 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) {
|
||||
if (parts[5].equals("snapshots") && method.equals("GET")) {
|
||||
try {
|
||||
return new SnapshotGetForVerResponse(state.getStateForGetForVers(projectName, Integer.parseInt(parts[6])));
|
||||
return new SnapshotGetForVerResponse(
|
||||
state.getStateForGetForVers(
|
||||
projectName, Integer.parseInt(parts[6])
|
||||
)
|
||||
);
|
||||
} catch (NumberFormatException e) {
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,10 @@ public class SnapshotPushResponse extends SnapshotResponse {
|
||||
private final SnapshotPushResult stateForPush;
|
||||
private final SnapshotPostbackRequest stateForPostback;
|
||||
|
||||
public SnapshotPushResponse(SnapshotPushResult stateForPush, SnapshotPostbackRequest stateForPostback) {
|
||||
public SnapshotPushResponse(
|
||||
SnapshotPushResult stateForPush,
|
||||
SnapshotPostbackRequest stateForPostback
|
||||
) {
|
||||
this.stateForPush = stateForPush;
|
||||
this.stateForPostback = stateForPostback;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ public class SnapshotPostbackRequestInvalidFiles extends SnapshotPostbackRequest
|
||||
public SnapshotPostbackRequestInvalidFiles(JsonArray errors) {
|
||||
this(new ArrayList<InvalidFileError>());
|
||||
for (JsonElement error : errors) {
|
||||
this.errors.add(InvalidFileError.buildFromJsonError(error.getAsJsonObject()));
|
||||
this.errors.add(InvalidFileError.buildFromJsonError(
|
||||
error.getAsJsonObject()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ import java.util.List;
|
||||
/**
|
||||
* Created by Winston on 10/01/15.
|
||||
*/
|
||||
public class SnapshotPostbackRequestInvalidProject extends SnapshotPostbackRequest {
|
||||
public class SnapshotPostbackRequestInvalidProject
|
||||
extends SnapshotPostbackRequest {
|
||||
|
||||
private final List<String> errors;
|
||||
|
||||
|
||||
@@ -30,9 +30,13 @@ public abstract class InvalidFileError {
|
||||
} else if (state.equals("disallowed")) {
|
||||
return new InvalidFileErrorDisallowed(file);
|
||||
} else if (state.equals("unclean_name")) {
|
||||
return new InvalidFileErrorUnclean(file, error.get("cleanFile").getAsString());
|
||||
return new InvalidFileErrorUnclean(
|
||||
file, error.get("cleanFile").getAsString()
|
||||
);
|
||||
} else {
|
||||
throw new IllegalArgumentException("bad invalid file state: " + state);
|
||||
throw new IllegalArgumentException(
|
||||
"bad invalid file state: " + state
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ package uk.ac.ic.wlgitbridge.snapshot.servermock.server;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
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 javax.servlet.ServletException;
|
||||
@@ -19,17 +19,30 @@ public class MockSnapshotRequestHandler extends AbstractHandler {
|
||||
|
||||
private final SnapshotResponseBuilder responseBuilder;
|
||||
|
||||
public MockSnapshotRequestHandler(SnapshotResponseBuilder responseBuilder) {
|
||||
public MockSnapshotRequestHandler(
|
||||
SnapshotResponseBuilder responseBuilder
|
||||
) {
|
||||
this.responseBuilder = responseBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(String target, final Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
public void handle(
|
||||
String target,
|
||||
final Request baseRequest,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response
|
||||
) throws IOException, ServletException {
|
||||
boolean handled;
|
||||
try {
|
||||
final SnapshotResponse snapshotResponse = responseBuilder.buildWithTarget(target, baseRequest.getMethod());
|
||||
final SnapshotResponse snapshotResponse
|
||||
= responseBuilder.buildWithTarget(
|
||||
target, baseRequest.getMethod()
|
||||
);
|
||||
response.getWriter().println(snapshotResponse.respond());
|
||||
new PostbackThread(baseRequest.getReader(), snapshotResponse.postback()).startIfNotNull();
|
||||
new PostbackThread(
|
||||
baseRequest.getReader(),
|
||||
snapshotResponse.postback()
|
||||
).startIfNotNull();
|
||||
handled = true;
|
||||
} catch (InvalidAPICallException e) {
|
||||
handled = false;
|
||||
|
||||
@@ -19,7 +19,10 @@ public class PostbackThread extends Thread {
|
||||
|
||||
public PostbackThread(Reader reader, String postback) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -27,7 +30,9 @@ public class PostbackThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
new AsyncHttpClient().preparePost(url).setBody(postback).execute().get().getResponseBody();
|
||||
new AsyncHttpClient().preparePost(
|
||||
url
|
||||
).setBody(postback).execute().get().getResponseBody();
|
||||
} catch (IOException e) {
|
||||
Log.warn(
|
||||
"IOException on postback, url: " +
|
||||
|
||||
@@ -25,12 +25,13 @@ public class SnapshotAPIState {
|
||||
private Map<String, SnapshotPushResult> push;
|
||||
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.getSavedVers = getSavedVers;
|
||||
this.getForVers = getForVers;
|
||||
@@ -39,19 +40,45 @@ public class 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>();
|
||||
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));
|
||||
|
||||
getForVers = new HashMap<String, Map<Integer, GetForVersionResult>>() {{
|
||||
@@ -105,9 +132,33 @@ public class SnapshotAPIState {
|
||||
}};
|
||||
|
||||
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 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());
|
||||
}};
|
||||
}
|
||||
@@ -120,7 +171,10 @@ public class SnapshotAPIState {
|
||||
return getSavedVers.get(projectName);
|
||||
}
|
||||
|
||||
public GetForVersionResult getStateForGetForVers(String projectName, int versionID) {
|
||||
public GetForVersionResult getStateForGetForVers(
|
||||
String projectName,
|
||||
int versionID
|
||||
) {
|
||||
return getForVers.get(projectName).get(versionID);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,7 @@ import uk.ac.ic.wlgitbridge.snapshot.servermock.response.push.postback.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
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.
|
||||
@@ -30,70 +27,127 @@ public class SnapshotAPIStateBuilder {
|
||||
|
||||
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) {
|
||||
projects = new Gson().fromJson(new InputStreamReader(stream), JsonArray.class);
|
||||
projects = new Gson().fromJson(
|
||||
new InputStreamReader(stream), JsonArray.class
|
||||
);
|
||||
}
|
||||
|
||||
public SnapshotAPIState build() {
|
||||
for (JsonElement project : projects) {
|
||||
addProject(project.getAsJsonObject());
|
||||
}
|
||||
return new SnapshotAPIState(getDoc, getSavedVers, getForVers, push, postback);
|
||||
return new SnapshotAPIState(
|
||||
getDoc,
|
||||
getSavedVers,
|
||||
getForVers,
|
||||
push,
|
||||
postback
|
||||
);
|
||||
}
|
||||
|
||||
private void addProject(JsonObject project) {
|
||||
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) {
|
||||
savedVers.add(getSnapshotInfo(ver.getAsJsonObject()));
|
||||
}
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
private List<SnapshotFile> getSrcs(JsonArray jsonSrcs) {
|
||||
List<SnapshotFile> srcs = new LinkedList<SnapshotFile>();
|
||||
List<SnapshotFile> srcs = new ArrayList<>();
|
||||
for (JsonElement src : jsonSrcs) {
|
||||
srcs.add(getSrc(src.getAsJsonObject()));
|
||||
}
|
||||
@@ -106,7 +160,7 @@ public class SnapshotAPIStateBuilder {
|
||||
}
|
||||
|
||||
private List<SnapshotAttachment> getAtts(JsonArray jsonAtts) {
|
||||
List<SnapshotAttachment> atts = new LinkedList<SnapshotAttachment>();
|
||||
List<SnapshotAttachment> atts = new LinkedList<>();
|
||||
for (JsonElement att : jsonAtts) {
|
||||
atts.add(getAtt(att.getAsJsonObject()));
|
||||
}
|
||||
@@ -130,17 +184,26 @@ public class SnapshotAPIStateBuilder {
|
||||
push.put(projectName, p);
|
||||
}
|
||||
|
||||
private void addPostbackForProject(String projectName, JsonObject jsonPostback) {
|
||||
private void addPostbackForProject(
|
||||
String projectName,
|
||||
JsonObject jsonPostback
|
||||
) {
|
||||
SnapshotPostbackRequest p;
|
||||
String type = jsonPostback.get("type").getAsString();
|
||||
if (type.equals("success")) {
|
||||
p = new SnapshotPostbackRequestSuccess(jsonPostback.get("versionID").getAsInt());
|
||||
p = new SnapshotPostbackRequestSuccess(
|
||||
jsonPostback.get("versionID").getAsInt()
|
||||
);
|
||||
} else if (type.equals("outOfDate")) {
|
||||
p = new SnapshotPostbackRequestOutOfDate();
|
||||
} else if (type.equals("invalidFiles")) {
|
||||
p = new SnapshotPostbackRequestInvalidFiles(jsonPostback.get("errors").getAsJsonArray());
|
||||
p = new SnapshotPostbackRequestInvalidFiles(
|
||||
jsonPostback.get("errors").getAsJsonArray()
|
||||
);
|
||||
} else if (type.equals("invalidProject")) {
|
||||
p = new SnapshotPostbackRequestInvalidProject(jsonPostback.get("errors").getAsJsonArray());
|
||||
p = new SnapshotPostbackRequestInvalidProject(
|
||||
jsonPostback.get("errors").getAsJsonArray()
|
||||
);
|
||||
} else if (type.equals("error")) {
|
||||
p = new SnapshotPostbackRequestError();
|
||||
} else {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package uk.ac.ic.wlgitbridge.snapshot.servermock.state;
|
||||
|
||||
/**
|
||||
* Created by Winston on 11/01/15.
|
||||
*/
|
||||
public class SnapshotAPIStateManager {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -21,8 +21,16 @@ public class FileUtil {
|
||||
|
||||
public static boolean currentCommitsAreEqual(Path dir1, Path dir2) {
|
||||
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);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -34,22 +42,42 @@ public class FileUtil {
|
||||
}
|
||||
|
||||
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);
|
||||
if (!filesEqual) {
|
||||
System.out.println("Not equal: (" + dir1Contents + ", " + dir2Contents + ")");
|
||||
System.out.println(
|
||||
"Not equal: ("
|
||||
+ dir1Contents
|
||||
+ ", "
|
||||
+ dir2Contents
|
||||
+ ")"
|
||||
);
|
||||
System.out.println(dir1 + ": " + dir1Contents);
|
||||
System.out.println(dir2 + ": " + dir2Contents);
|
||||
}
|
||||
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) {
|
||||
Path path1 = dir1.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;
|
||||
}
|
||||
}
|
||||
@@ -62,7 +90,9 @@ public class FileUtil {
|
||||
byte[] secondContents = Files.readAllBytes(second);
|
||||
boolean equals = Arrays.equals(firstContents, secondContents);
|
||||
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(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);
|
||||
}
|
||||
|
||||
public static Set<String> getOnlyFilesRecursivelyInDirectoryApartFrom(Path dir, Path excluded) {
|
||||
public static Set<String> getOnlyFilesRecursivelyInDirectoryApartFrom(
|
||||
Path dir,
|
||||
Path excluded
|
||||
) {
|
||||
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()) {
|
||||
throw new IllegalArgumentException("need a directory");
|
||||
}
|
||||
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>();
|
||||
for (File file : dir.toFile().listFiles()) {
|
||||
if (!file.equals(excluded.toFile())) {
|
||||
@@ -96,7 +141,12 @@ public class FileUtil {
|
||||
files.add(baseDir.relativize(file.toPath()).toString());
|
||||
}
|
||||
if (isDirectory) {
|
||||
files.addAll(getAllFilesRecursively(baseDir, file.toPath(), excluded, directories));
|
||||
files.addAll(getAllFilesRecursively(
|
||||
baseDir,
|
||||
file.toPath(),
|
||||
excluded,
|
||||
directories
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,10 @@ public class Files {
|
||||
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)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ public class Instance {
|
||||
public static final JsonFactory jsonFactory = new GsonFactory();
|
||||
|
||||
public static final Gson prettyGson =
|
||||
new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
|
||||
new GsonBuilder(
|
||||
).setPrettyPrinting().disableHtmlEscaping().create();
|
||||
|
||||
public static final Gson gson = new Gson();
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ public class Util {
|
||||
private static String HOSTNAME;
|
||||
private static int PORT;
|
||||
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) {
|
||||
if (entries == 1) {
|
||||
@@ -57,9 +58,11 @@ public class Util {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getContentsOfReader(BufferedReader reader) throws IOException {
|
||||
public static String getContentsOfReader(
|
||||
BufferedReader reader
|
||||
) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String line; (line = reader.readLine()) != null; ) {
|
||||
for (String line; (line = reader.readLine()) != null;) {
|
||||
sb.append(line);
|
||||
}
|
||||
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) {
|
||||
Set<String> excluded = new HashSet<String>(Arrays.asList(apartFrom));
|
||||
Set<String> excluded = new HashSet<>(Arrays.asList(apartFrom));
|
||||
File [] files = directory.listFiles();
|
||||
if (files != null) {
|
||||
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;
|
||||
for (int i = 0; i < skip; i++) {
|
||||
reader.readLine();
|
||||
@@ -139,8 +151,13 @@ public class Util {
|
||||
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();
|
||||
String newLine = System.getProperty("line.separator");
|
||||
String line;
|
||||
@@ -182,7 +199,6 @@ public class Util {
|
||||
} else {
|
||||
code = codeElement.getAsString();
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
@@ -323,11 +323,11 @@ public class WLGitBridgeIntegrationTest {
|
||||
public void canPushFilesSuccessfully() throws IOException, GitAPIException, InterruptedException {
|
||||
MockSnapshotServer server = new MockSnapshotServer(3866, getResource("/canPushFilesSuccessfully").toFile());
|
||||
server.start();
|
||||
server.setState(states.get("canPushFilesSuccessfully").get("state"));
|
||||
GitBridgeApp wlgb = new GitBridgeApp(new String[] {
|
||||
makeConfigFile(33866, 3866)
|
||||
});
|
||||
wlgb.run();
|
||||
server.setState(states.get("canPushFilesSuccessfully").get("state"));
|
||||
File dir = folder.newFolder();
|
||||
File testprojDir = cloneRepository("testproj", 33866, dir);
|
||||
assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPushFilesSuccessfully/state/testproj"), testprojDir.toPath()));
|
||||
|
||||
Reference in New Issue
Block a user