Skip to content

Commit b0ca353

Browse files
author
Mark Robinson
committed
Merge branch 'master' into highlighting
# Conflicts: # src/main/resources/static/css/main.css # src/main/resources/static/js/workflow.js
2 parents bb11a4e + 5e8ca27 commit b0ca353

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3272
-23406
lines changed

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
FROM maven:3.3-jdk-8-alpine
22
MAINTAINER Stian Soiland-Reyes <[email protected]>
33

4+
RUN apk add --update graphviz && rm -rf /var/cache/apk/*
5+
46
RUN mkdir /usr/share/maven/ref/repository
57

68
RUN mkdir -p /usr/src/app

pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
<java.version>1.8</java.version>
2525
</properties>
2626

27+
<repositories>
28+
<repository>
29+
<id>jitpack.io</id>
30+
<url>https://jitpack.io</url>
31+
</repository>
32+
</repositories>
33+
2734
<dependencies>
2835
<dependency>
2936
<groupId>org.springframework.boot</groupId>
@@ -57,6 +64,11 @@
5764
<artifactId>snakeyaml</artifactId>
5865
<version>1.7</version>
5966
</dependency>
67+
<dependency>
68+
<groupId>com.github.jabbalaci</groupId>
69+
<artifactId>graphviz-java-api</artifactId>
70+
<version>f9bf94896776de6e98b5004e819b63fb4c15b15d</version>
71+
</dependency>
6072
<dependency>
6173
<groupId>org.apache.taverna.language</groupId>
6274
<artifactId>taverna-robundle</artifactId>

src/main/java/org/commonwl/viewer/domain/CWLCollection.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class CWLCollection {
3939

4040
private GitHubService githubService;
4141
private GithubDetails githubInfo;
42+
private String commitSha;
4243

4344
// Maps of ID to associated JSON
4445
private Map<String, JsonNode> cwlDocs = new HashMap<>();
@@ -78,11 +79,14 @@ public class CWLCollection {
7879
* Creates a new collection of CWL files from a Github repository
7980
* @param githubService Service to provide the Github API functionality
8081
* @param githubInfo The information necessary to access the Github directory associated with the RO
82+
* @param commitSha The sha hash of the latest commit used for caching
8183
* @throws IOException Any API errors which may have occurred
8284
*/
83-
public CWLCollection(GitHubService githubService, GithubDetails githubInfo) throws IOException {
85+
public CWLCollection(GitHubService githubService, GithubDetails githubInfo,
86+
String commitSha) throws IOException {
8487
this.githubInfo = githubInfo;
8588
this.githubService = githubService;
89+
this.commitSha = commitSha;
8690

8791
// Add any CWL files from the Github repo to this collection
8892
List<RepositoryContents> repoContents = githubService.getContents(githubInfo);
@@ -122,7 +126,7 @@ private void addDocs(List<RepositoryContents> repoContents) throws IOException {
122126
// Get the content of this file from Github
123127
GithubDetails githubFile = new GithubDetails(githubInfo.getOwner(),
124128
githubInfo.getRepoName(), githubInfo.getBranch(), repoContent.getPath());
125-
String fileContent = githubService.downloadFile(githubFile);
129+
String fileContent = githubService.downloadFile(githubFile, commitSha);
126130

127131
// Parse yaml to JsonNode
128132
Yaml reader = new Yaml();

src/main/java/org/commonwl/viewer/domain/GithubDetails.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public class GithubDetails implements Serializable {
2828

2929
private String owner;
3030
private String repoName;
31+
private String sha;
3132
private String branch;
3233
private String path;
3334

src/main/java/org/commonwl/viewer/domain/ROBundle.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import org.slf4j.Logger;
3030
import org.slf4j.LoggerFactory;
3131

32-
import java.io.File;
3332
import java.io.IOException;
3433
import java.net.URI;
3534
import java.net.URISyntaxException;
@@ -49,20 +48,22 @@ public class ROBundle {
4948

5049
private Bundle bundle;
5150
private GithubDetails githubInfo;
51+
private String commitSha;
5252

5353
/**
5454
* Creates a new research object bundle for a workflow from a Github repository
5555
* @param githubInfo The information necessary to access the Github directory associated with the RO
5656
* @throws IOException Any API errors which may have occurred
5757
*/
58-
public ROBundle(GitHubService githubService, GithubDetails githubInfo,
58+
public ROBundle(GitHubService githubService, GithubDetails githubInfo, String commitSha,
5959
String appName, String appURL) throws IOException {
6060
// TODO: Add back file size checking on individual files as well as whole bundle
6161

6262
// Create a new RO bundle
6363
this.bundle = Bundles.createBundle();
6464
this.githubInfo = githubInfo;
6565
this.githubService = githubService;
66+
this.commitSha = commitSha;
6667

6768
Manifest manifest = bundle.getManifest();
6869

@@ -135,7 +136,7 @@ private void addFiles(List<RepositoryContents> repoContents, Path path) throws I
135136
// Get the content of this file from Github
136137
GithubDetails githubFile = new GithubDetails(githubInfo.getOwner(),
137138
githubInfo.getRepoName(), githubInfo.getBranch(), repoContent.getPath());
138-
String fileContent = githubService.downloadFile(githubFile);
139+
String fileContent = githubService.downloadFile(githubFile, commitSha);
139140

140141
// Save file to research object bundle
141142
Path newFilePort = path.resolve(repoContent.getName());

src/main/java/org/commonwl/viewer/domain/Workflow.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929

3030
import java.io.IOException;
3131
import java.io.StringWriter;
32-
import java.nio.file.Path;
3332
import java.util.Date;
3433
import java.util.Map;
3534

@@ -51,6 +50,10 @@ public class Workflow {
5150
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss z")
5251
private Date retrievedOn;
5352

53+
// The last commit from the branch at the time of fetching
54+
// Used for caching purposes
55+
private String lastCommit;
56+
5457
// A String which represents the path to a RO bundle
5558
// Path types cannot be stored using Spring Data, unfortunately
5659
private String roBundle;
@@ -161,4 +164,12 @@ public String getDotGraph() {
161164
public void setDotGraph(String dotGraph) {
162165
this.dotGraph = dotGraph;
163166
}
167+
168+
public String getLastCommit() {
169+
return lastCommit;
170+
}
171+
172+
public void setLastCommit(String lastCommit) {
173+
this.lastCommit = lastCommit;
174+
}
164175
}

src/main/java/org/commonwl/viewer/services/GitHubService.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@
2121

2222
import org.apache.commons.io.IOUtils;
2323
import org.commonwl.viewer.domain.GithubDetails;
24-
import org.eclipse.egit.github.core.RepositoryContents;
25-
import org.eclipse.egit.github.core.RepositoryId;
26-
import org.eclipse.egit.github.core.User;
24+
import org.eclipse.egit.github.core.*;
2725
import org.eclipse.egit.github.core.client.GitHubClient;
26+
import org.eclipse.egit.github.core.service.CommitService;
2827
import org.eclipse.egit.github.core.service.ContentsService;
2928
import org.eclipse.egit.github.core.service.UserService;
3029
import org.springframework.beans.factory.annotation.Autowired;
@@ -47,6 +46,7 @@ public class GitHubService {
4746
// Github API services
4847
private final ContentsService contentsService;
4948
private final UserService userService;
49+
private final CommitService commitService;
5050

5151
// URL validation for directory links
5252
private final String GITHUB_DIR_REGEX = "^https:\\/\\/github\\.com\\/([A-Za-z0-9_.-]+)\\/([A-Za-z0-9_.-]+)\\/?(?:tree\\/([^/]+)\\/(.*))?$";
@@ -62,6 +62,7 @@ public GitHubService(@Value("${githubAPI.authentication}") boolean authEnabled,
6262
}
6363
this.contentsService = new ContentsService(client);
6464
this.userService = new UserService(client);
65+
this.commitService = new CommitService(client);
6566
}
6667

6768
/**
@@ -81,7 +82,7 @@ public GithubDetails detailsFromDirURL(String url) {
8182
* Get contents of a Github path from the API
8283
* @param githubInfo The information to access the repository
8384
* @return A list of details for the file(s) or false if there is an API error
84-
* @throws IOException Any API errors which may have occured
85+
* @throws IOException Any API errors which may have occurred
8586
*/
8687
public List<RepositoryContents> getContents(GithubDetails githubInfo) throws IOException {
8788
return contentsService.getContents(new RepositoryId(githubInfo.getOwner(), githubInfo.getRepoName()),
@@ -92,7 +93,7 @@ public List<RepositoryContents> getContents(GithubDetails githubInfo) throws IOE
9293
* Get the details of a user from the Github API
9394
* @param username The username of the user we want to get data about
9495
* @return A user object containing the API information
95-
* @throws IOException Any API errors which may have occured
96+
* @throws IOException Any API errors which may have occurred
9697
*/
9798
public User getUser(String username) throws IOException {
9899
return userService.getUser(username);
@@ -101,21 +102,34 @@ public User getUser(String username) throws IOException {
101102
/**
102103
* Download a single file from a Github repository
103104
* @param githubInfo The information to access the repository
105+
* @param sha The commit ID to download a specific version of a file
104106
* @return A string with the contents of the file
105-
* @throws IOException Any API errors which may have occured
107+
* @throws IOException Any API errors which may have occurred
106108
*/
107-
public String downloadFile(GithubDetails githubInfo) throws IOException {
109+
public String downloadFile(GithubDetails githubInfo, String sha) throws IOException {
108110
// Download the file and return the contents
109111
// rawgit.com used to download individual files from git with the correct media type
110112
String url = String.format("https://cdn.rawgit.com/%s/%s/%s/%s", githubInfo.getOwner(),
111-
githubInfo.getRepoName(), githubInfo.getBranch(), githubInfo.getPath());
113+
githubInfo.getRepoName(), sha, githubInfo.getPath());
112114
URL downloadURL = new URL(url);
113115
InputStream download = downloadURL.openStream();
114116
try {
115117
return IOUtils.toString(download);
116118
} finally {
117119
IOUtils.closeQuietly(download);
118120
}
121+
}
119122

123+
/**
124+
* Gets the latest commit sha hash from a particular branch
125+
* If hash is given as a branch, this will return the same hash if valid
126+
* @param githubInfo The information to access the repository
127+
* @return A sha hash for the latest commit
128+
* @throws IOException Any API errors which may have occurred
129+
*/
130+
public String getCommitSha(GithubDetails githubInfo) throws IOException {
131+
RepositoryId repo = new RepositoryId(githubInfo.getOwner(), githubInfo.getRepoName());
132+
RepositoryCommit currentCommit = commitService.getCommit(repo, githubInfo.getBranch());
133+
return currentCommit.getSha();
120134
}
121135
}

src/main/java/org/commonwl/viewer/services/ROBundleFactory.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@ public class ROBundleFactory {
5353
@Autowired
5454
public ROBundleFactory(@Value("${applicationName}") String applicationName,
5555
@Value("${applicationURL}") String applicationURL,
56-
@Value("${storageLocation}") Path storageLocation,
56+
@Value("${graphvizStorage}") Path graphvizStorage,
5757
WorkflowRepository workflowRepository) {
5858
this.applicationName = applicationName;
5959
this.applicationURL = applicationURL;
60-
this.storageLocation = storageLocation;
60+
this.storageLocation = graphvizStorage;
6161
this.workflowRepository = workflowRepository;
6262
}
6363

@@ -69,12 +69,12 @@ public ROBundleFactory(@Value("${applicationName}") String applicationName,
6969
* @throws IOException Any API errors which may have occurred
7070
*/
7171
@Async
72-
void workflowROFromGithub(GitHubService githubService, GithubDetails githubInfo)
72+
void workflowROFromGithub(GitHubService githubService, GithubDetails githubInfo, String commitSha)
7373
throws IOException, InterruptedException {
7474
logger.info("Creating Research Object Bundle");
7575

7676
// Create a new Research Object Bundle with Github contents
77-
ROBundle bundle = new ROBundle(githubService, githubInfo,
77+
ROBundle bundle = new ROBundle(githubService, githubInfo, commitSha,
7878
applicationName, applicationURL);
7979

8080
// Save the bundle to the storage location in properties

src/main/java/org/commonwl/viewer/services/WorkflowFactory.java renamed to src/main/java/org/commonwl/viewer/services/WorkflowService.java

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,46 +25,59 @@
2525
import org.slf4j.Logger;
2626
import org.slf4j.LoggerFactory;
2727
import org.springframework.beans.factory.annotation.Autowired;
28+
import org.springframework.beans.factory.annotation.Value;
2829
import org.springframework.stereotype.Service;
2930

31+
import java.io.File;
32+
import java.util.Calendar;
3033
import java.util.Date;
3134

3235
@Service
33-
public class WorkflowFactory {
36+
public class WorkflowService {
3437

3538
private final Logger logger = LoggerFactory.getLogger(this.getClass());
3639

3740
private final GitHubService githubService;
41+
private final WorkflowRepository workflowRepository;
3842
private final ROBundleFactory ROBundleFactory;
43+
private final int cacheDays;
3944

4045
@Autowired
41-
public WorkflowFactory(GitHubService githubService,
42-
ROBundleFactory ROBundleFactory) {
46+
public WorkflowService(GitHubService githubService,
47+
WorkflowRepository workflowRepository,
48+
ROBundleFactory ROBundleFactory,
49+
@Value("${cacheDays}") int cacheDays) {
4350
this.githubService = githubService;
51+
this.workflowRepository = workflowRepository;
4452
this.ROBundleFactory = ROBundleFactory;
53+
this.cacheDays = cacheDays;
4554
}
4655

4756
/**
4857
* Builds a new workflow from cwl files fetched from Github
4958
* @param githubInfo Github information for the workflow
5059
* @return The constructed model for the Workflow
5160
*/
52-
public Workflow workflowFromGithub(GithubDetails githubInfo) {
61+
public Workflow newWorkflowFromGithub(GithubDetails githubInfo) {
5362

5463
try {
64+
// Get the sha hash from a branch reference
65+
String latestCommit = githubService.getCommitSha(githubInfo);
66+
5567
// Set up CWL utility to collect the documents
56-
CWLCollection cwlFiles = new CWLCollection(githubService, githubInfo);
68+
CWLCollection cwlFiles = new CWLCollection(githubService, githubInfo, latestCommit);
5769

5870
// Get the workflow model
5971
Workflow workflowModel = cwlFiles.getWorkflow();
6072
if (workflowModel != null) {
6173
// Set origin details
6274
workflowModel.setRetrievedOn(new Date());
6375
workflowModel.setRetrievedFrom(githubInfo);
76+
workflowModel.setLastCommit(latestCommit);
6477

6578
// Create a new research object bundle from Github details
6679
// This is Async so cannot just call constructor, needs intermediate as per Spring framework
67-
ROBundleFactory.workflowROFromGithub(githubService, githubInfo);
80+
ROBundleFactory.workflowROFromGithub(githubService, githubInfo, latestCommit);
6881

6982
// Return this model to be displayed
7083
return workflowModel;
@@ -79,6 +92,65 @@ public Workflow workflowFromGithub(GithubDetails githubInfo) {
7992
return null;
8093
}
8194

95+
/**
96+
* Removes a workflow and its research object bundle
97+
* @param workflow The workflow to be deleted
98+
*/
99+
public void removeWorkflow(Workflow workflow) {
100+
// Delete the Research Object Bundle from disk
101+
File roBundle = new File(workflow.getRoBundle());
102+
if (roBundle.delete()) {
103+
logger.debug("Deleted Research Object Bundle");
104+
} else {
105+
logger.debug("Failed to delete Research Object Bundle");
106+
}
107+
108+
// TODO: Delete cached graphviz images when serverside graphviz is merged
109+
110+
// Remove the workflow from the database
111+
workflowRepository.delete(workflow);
112+
}
113+
114+
/**
115+
* Check for cache expiration based on time and commit sha
116+
* @param workflow The cached workflow model
117+
* @return Whether or not there are new commits
118+
*/
119+
public boolean cacheExpired(Workflow workflow) {
120+
try {
121+
// Calculate expiration
122+
Calendar expireCal = Calendar.getInstance();
123+
expireCal.setTime(workflow.getRetrievedOn());
124+
expireCal.add(Calendar.DATE, cacheDays);
125+
Date expirationDate = expireCal.getTime();
126+
127+
// Check cached retrievedOn date
128+
if (expirationDate.before(new Date())) {
129+
// Cache expiry time has elapsed
130+
// Check current head of the branch with the cached head
131+
logger.debug("Time has expired for caching, checking commits...");
132+
String currentHead = githubService.getCommitSha(workflow.getRetrievedFrom());
133+
logger.debug("Current: " + workflow.getLastCommit() + ", HEAD: " + currentHead);
134+
135+
// Reset date in database if there are still no changes
136+
boolean expired = !workflow.getLastCommit().equals(currentHead);
137+
if (!expired) {
138+
workflow.setRetrievedOn(new Date());
139+
workflowRepository.save(workflow);
140+
}
141+
142+
// Return whether the cache has expired
143+
return expired;
144+
} else {
145+
// Cache expiry time has not elapsed yet
146+
return false;
147+
}
148+
} catch (Exception ex) {
149+
// Default to no expiry if there was an API error
150+
return false;
151+
}
152+
}
153+
82154
/*
83155
// Check total file size
84156
int totalFileSize = 0;

0 commit comments

Comments
 (0)