Skip to content

Commit 4002f72

Browse files
authored
Merge pull request #27 from common-workflow-language/workflow-pages
Add persistent workflow pages using MongoDB
2 parents 95b5f36 + 567b461 commit 4002f72

File tree

14 files changed

+354
-97
lines changed

14 files changed

+354
-97
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919

2020
package org.commonwl.viewer.domain;
2121

22+
import java.io.Serializable;
23+
2224
/**
2325
* Represents all the parameters necessary to access a file/directory in Github
2426
*/
25-
public class GithubDetails {
27+
public class GithubDetails implements Serializable {
2628

2729
private String owner;
2830
private String repoName;

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

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

32+
import java.io.File;
3233
import java.io.IOException;
3334
import java.net.URI;
3435
import java.net.URISyntaxException;
@@ -146,11 +147,15 @@ private void addFiles(List<RepositoryContents> repoContents, Path path) throws I
146147

147148
/**
148149
* Save the Research Object bundle to disk
150+
* @param directory The directory in which the RO will be saved
151+
* @return The path to the research object
152+
* @throws IOException Any errors in saving
149153
*/
150-
public void saveToTempFile() throws IOException {
154+
public Path saveToFile(Path directory) throws IOException {
151155
// Save the Research Object Bundle
152-
Path zip = Files.createTempFile("bundle", ".zip");
153-
Bundles.closeAndSaveBundle(bundle, zip);
156+
Path bundleLocation = Files.createTempFile(directory, "bundle", ".zip");
157+
Bundles.closeAndSaveBundle(bundle, bundleLocation);
158+
return bundleLocation;
154159
}
155160

156161
}

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

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import org.slf4j.Logger;
2424
import org.slf4j.LoggerFactory;
2525
import org.springframework.data.annotation.Id;
26+
import org.springframework.data.mongodb.core.index.Indexed;
27+
import org.springframework.data.mongodb.core.mapping.Document;
2628
import org.springframework.format.annotation.DateTimeFormat;
2729

2830
import java.io.IOException;
@@ -31,24 +33,27 @@
3133
import java.util.Date;
3234
import java.util.Map;
3335

34-
import static java.util.Calendar.DATE;
35-
3636
/**
3737
* Representation of a workflow
3838
*/
39+
@Document
3940
public class Workflow {
4041

4142
static private final Logger logger = LoggerFactory.getLogger(Workflow.class);
4243

4344
// ID for database
4445
@Id
45-
private String id;
46+
public String id;
4647

4748
// Metadata
48-
@DateTimeFormat(pattern="MMM d yyyy 'at' hh:mm")
49-
private Date retrievedOn;
49+
@Indexed(unique = true)
5050
private GithubDetails retrievedFrom;
51-
private Path roBundle;
51+
@DateTimeFormat(pattern="MMM d yyyy 'at' hh:mm z")
52+
private Date retrievedOn;
53+
54+
// A String which represents the path to a RO bundle
55+
// Path types cannot be stored using Spring Data, unfortunately
56+
private String roBundle;
5257

5358
// Contents of the workflow
5459
private String label;
@@ -76,17 +81,10 @@ public Workflow(String label, String doc, Map<String, CWLElement> inputs, Map<St
7681
}
7782
}
7883

79-
@Override
80-
public String toString() {
81-
return "Workflow{" +
82-
"id='" + id + '\'' +
83-
", retrievedFrom=" + retrievedFrom +
84-
", roBundle=" + roBundle +
85-
", label='" + label + '\'' +
86-
", doc='" + doc + '\'' +
87-
", inputs=" + inputs +
88-
", outputs=" + outputs +
89-
'}';
84+
public String getID() { return id; }
85+
86+
public void setId(String id) {
87+
this.id = id;
9088
}
9189

9290
public String getLabel() {
@@ -121,11 +119,11 @@ public void setOutputs(Map<String, CWLElement> outputs) {
121119
this.outputs = outputs;
122120
}
123121

124-
public Path getRoBundle() {
122+
public String getRoBundle() {
125123
return roBundle;
126124
}
127125

128-
public void setRoBundle(Path roBundle) {
126+
public void setRoBundle(String roBundle) {
129127
this.roBundle = roBundle;
130128
}
131129

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

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@
2121

2222
import org.commonwl.viewer.domain.GithubDetails;
2323
import org.commonwl.viewer.domain.ROBundle;
24+
import org.commonwl.viewer.domain.Workflow;
2425
import org.slf4j.Logger;
2526
import org.slf4j.LoggerFactory;
27+
import org.springframework.beans.factory.annotation.Autowired;
2628
import org.springframework.beans.factory.annotation.Value;
2729
import org.springframework.scheduling.annotation.Async;
2830
import org.springframework.scheduling.annotation.EnableAsync;
2931
import org.springframework.stereotype.Component;
3032

3133
import java.io.IOException;
34+
import java.nio.file.Path;
3235

3336
/**
3437
* Class for the purpose of a Spring Framework Async method
@@ -42,25 +45,61 @@ public class ROBundleFactory {
4245

4346
private final Logger logger = LoggerFactory.getLogger(this.getClass());
4447

45-
@Value("${applicationName}")
46-
private String applicationName;
47-
@Value("${applicationURL}")
48-
private String applicationURL;
48+
private final String applicationName;
49+
private final String applicationURL;
50+
private final Path storageLocation;
51+
private final WorkflowRepository workflowRepository;
52+
53+
@Autowired
54+
public ROBundleFactory(@Value("${applicationName}") String applicationName,
55+
@Value("${applicationURL}") String applicationURL,
56+
@Value("${storageLocation}") Path storageLocation,
57+
WorkflowRepository workflowRepository) {
58+
this.applicationName = applicationName;
59+
this.applicationURL = applicationURL;
60+
this.storageLocation = storageLocation;
61+
this.workflowRepository = workflowRepository;
62+
}
4963

5064
/**
5165
* Creates a new Workflow Research Object Bundle from a Github URL
5266
* and saves it to a file
5367
* @param githubService The service for Github API functionality
5468
* @param githubInfo Details of the Github repository
55-
* @throws IOException Any API errors which may have occured
69+
* @throws IOException Any API errors which may have occurred
5670
*/
5771
@Async
58-
void workflowROFromGithub(GitHubService githubService, GithubDetails githubInfo) throws IOException {
59-
// TODO: Add the bundle link to the page when it is finished being created
72+
void workflowROFromGithub(GitHubService githubService, GithubDetails githubInfo)
73+
throws IOException, InterruptedException {
6074
logger.info("Creating Research Object Bundle");
75+
76+
// Create a new Research Object Bundle with Github contents
6177
ROBundle bundle = new ROBundle(githubService, githubInfo,
6278
applicationName, applicationURL);
63-
bundle.saveToTempFile();
64-
logger.info("Successfully saved Research Object Bundle");
79+
80+
// Save the bundle to the storage location in properties
81+
Path bundleLocation = bundle.saveToFile(storageLocation);
82+
83+
// Add the path to the bundle to the bundle
84+
Workflow workflow = workflowRepository.findByRetrievedFrom(githubInfo);
85+
86+
// Chance that this thread could be created before workflow model is saved
87+
int attempts = 5;
88+
while (attempts > 0 && workflow == null) {
89+
// Delay this thread by 0.5s and try again until success or too many attempts
90+
Thread.sleep(1000L);
91+
workflow = workflowRepository.findByRetrievedFrom(githubInfo);
92+
attempts--;
93+
}
94+
95+
if (workflow == null) {
96+
// If workflow is still null we can't find the workflow model
97+
logger.error("Workflow model could not be found when adding RO Bundle path");
98+
} else {
99+
// Add RO Bundle to associated workflow model
100+
workflow.setRoBundle(bundleLocation.toString());
101+
workflowRepository.save(workflow);
102+
logger.info("Finished saving Research Object Bundle");
103+
}
65104
}
66105
}

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

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -50,47 +50,34 @@ public WorkflowFactory(GitHubService githubService,
5050

5151
/**
5252
* Builds a new workflow from cwl files fetched from Github
53-
* @param githubURL Github directory URL to get the files from
53+
* @param githubInfo Github information for the workflow
5454
* @return The constructed model for the Workflow
5555
*/
56-
public Workflow workflowFromGithub(String githubURL) {
56+
public Workflow workflowFromGithub(GithubDetails githubInfo) {
5757

58-
GithubDetails githubInfo = githubService.detailsFromDirURL(githubURL);
58+
try {
59+
// Set up CWL utility to collect the documents
60+
CWLCollection cwlFiles = new CWLCollection(githubService, githubInfo);
5961

60-
// If the URL is valid and details could be extracted
61-
if (githubInfo != null) {
62+
// Get the workflow model
63+
Workflow workflowModel = cwlFiles.getWorkflow();
64+
if (workflowModel != null) {
65+
// Set origin details
66+
workflowModel.setRetrievedOn(new Date());
67+
workflowModel.setRetrievedFrom(githubInfo);
6268

63-
try {
64-
// Set up CWL utility to collect the documents
65-
CWLCollection cwlFiles = new CWLCollection(githubService, githubInfo);
69+
// Create a new research object bundle from Github details
70+
// This is Async so cannot just call constructor, needs intermediate as per Spring framework
71+
ROBundleFactory.workflowROFromGithub(githubService, githubInfo);
6672

67-
// Get the workflow model
68-
Workflow workflowModel = cwlFiles.getWorkflow();
69-
if (workflowModel != null) {
70-
// Set origin details
71-
workflowModel.setRetrievedOn(new Date());
72-
workflowModel.setRetrievedFrom(githubInfo);
73+
// Return this model to be displayed
74+
return workflowModel;
7375

74-
// Save to the MongoDB database
75-
logger.info("Storing workflow in DB");
76-
workflowRepository.save(workflowModel);
77-
78-
// Create a new research object bundle from Github details
79-
// This is Async so cannot just call constructor, needs intermediate as per Spring framework
80-
ROBundleFactory.workflowROFromGithub(githubService, githubInfo);
81-
82-
// Return this model to be displayed
83-
return workflowModel;
84-
85-
} else {
86-
logger.error("No workflow could be found");
87-
}
88-
} catch (IOException ex) {
89-
logger.error(ex.getMessage());
76+
} else {
77+
logger.error("No workflow could be found");
9078
}
91-
} else {
92-
// TODO: Refactor validator so this redundant step can be removed?
93-
logger.error("Error should never happen, already passed URL validation");
79+
} catch (Exception ex) {
80+
logger.error(ex.getMessage());
9481
}
9582

9683
return null;

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

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* Runs validation on the workflow form from the main page
3838
*/
3939
@Component
40-
public class WorkflowFormValidator implements Validator {
40+
public class WorkflowFormValidator {
4141

4242
private final Logger logger = LoggerFactory.getLogger(this.getClass());
4343

@@ -51,26 +51,16 @@ public WorkflowFormValidator(GitHubService githubService) {
5151
this.githubService = githubService;
5252
}
5353

54-
/**
55-
* Types of class the this validator supports, WorkflowForm
56-
* @param theClass The class which is being validated
57-
* @return Whether the class can be validated using this validator
58-
*/
59-
public boolean supports(Class theClass) {
60-
return WorkflowForm.class.equals(theClass);
61-
}
62-
6354
/**
6455
* Validates a WorkflowForm to ensure the URL is not empty and directory contains cwl files
65-
* @param obj The given WorkFlowForm
56+
* @param form The given WorkflowForm
6657
* @param e Any errors from validation
6758
*/
68-
public void validate(Object obj, Errors e) {
59+
public GithubDetails validateAndParse(WorkflowForm form, Errors e) {
6960
ValidationUtils.rejectIfEmptyOrWhitespace(e, "githubURL", "githubURL.emptyOrWhitespace");
7061

7162
// Only continue if not null and isn't just whitespace
7263
if (!e.hasErrors()) {
73-
WorkflowForm form = (WorkflowForm) obj;
7464
GithubDetails githubInfo = githubService.detailsFromDirURL(form.getGithubURL());
7565

7666
// If the URL is valid and details could be extracted
@@ -91,7 +81,10 @@ public void validate(Object obj, Errors e) {
9181
}
9282
}
9383
}
94-
if (!foundCWL) {
84+
if (foundCWL) {
85+
// Return the Github information
86+
return githubInfo;
87+
} else {
9588
// The URL does not contain any .cwl files
9689
logger.error("No .cwl files found at Github URL");
9790
e.rejectValue("githubURL", "githubURL.missingWorkflow");
@@ -109,5 +102,8 @@ public void validate(Object obj, Errors e) {
109102
} else {
110103
logger.error("Github URL is empty");
111104
}
105+
106+
// Errors will stop this being used anyway
107+
return null;
112108
}
113109
}

0 commit comments

Comments
 (0)