/*
* Copyright (C) 2015 SeqWare
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.seqware.pipeline.engines.whitestar;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.SortedSet;
import java.util.TreeSet;
import net.sourceforge.seqware.common.metadata.Metadata;
import net.sourceforge.seqware.common.metadata.MetadataFactory;
import net.sourceforge.seqware.common.metadata.MetadataInMemory;
import net.sourceforge.seqware.common.model.Workflow;
import net.sourceforge.seqware.common.model.WorkflowParam;
import net.sourceforge.seqware.common.model.WorkflowRun;
import net.sourceforge.seqware.common.util.Log;
import static net.sourceforge.seqware.common.util.Rethrow.rethrow;
import net.sourceforge.seqware.common.util.configtools.ConfigTools;
import org.apache.commons.io.FileUtils;
/**
* This is a KISS implementation of persistence for WhiteStar relying upon JSON text files in the working directory.
*
* @author dyuen
*/
public class Persistence {
public static final String PERSISTENT_DIR = "whitestar";
public static final String WORKFLOW_RUN_FILENAME = "workflowRun.json";
public static final String WORKFLOW_FILENAME = "workflow.json";
public static final String STATE_FILENAME = "state.json";
private final File persistDir;
/**
*
* @param nfsWorkDir
*/
public Persistence(File nfsWorkDir) {
if (!nfsWorkDir.exists()) {
throw new RuntimeException("Unable to locate working directory");
}
this.persistDir = new File(nfsWorkDir, Persistence.PERSISTENT_DIR);
boolean dircreated = persistDir.exists() || persistDir.mkdir();
boolean writeable = persistDir.setWritable(true, false);
if (!dircreated || !writeable) {
throw new RuntimeException("Unable to write to working directory");
}
}
public synchronized SortedSet<String> readCompletedJobs() {
try {
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting().create();
String statesString = FileUtils.readFileToString(new File(persistDir, STATE_FILENAME));
Type collectionType = new TypeToken<SortedSet<String>>() {
}.getType();
SortedSet<String> states = gson.fromJson(statesString, collectionType);
return states;
} catch (IOException ex) {
Log.stdoutWithTime("Unable to read workflowrun state");
rethrow(ex);
}
return null;
}
public synchronized WorkflowRun readWorkflowRun() {
try {
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting().create();
String workflowRunString = FileUtils.readFileToString(new File(persistDir, WORKFLOW_RUN_FILENAME));
String workflowString = FileUtils.readFileToString(new File(persistDir, WORKFLOW_FILENAME));
WorkflowRun workflowRun = gson.fromJson(workflowRunString, WorkflowRun.class);
Workflow workflow = gson.fromJson(workflowString, Workflow.class);
workflowRun.setWorkflow(workflow);
SortedSet<WorkflowRun> runs = new TreeSet<>();
runs.add(workflowRun);
workflow.setWorkflowRuns(runs);
// load into persistence store if needed
Metadata metadata = MetadataFactory.get(ConfigTools.getSettings());
if (metadata instanceof MetadataInMemory) {
MetadataInMemory mim = (MetadataInMemory) metadata;
mim.loadEntity(workflow);
mim.loadEntity(workflowRun);
}
return workflowRun;
} catch (IOException ex) {
Log.stdoutWithTime("Unable to read workflowrun state");
rethrow(ex);
}
return null;
}
public synchronized void persistState(int swid, SortedSet<String> completedJobs) {
try {
// write state of workflow run
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting().create();
Metadata ws = MetadataFactory.get(ConfigTools.getSettings());
WorkflowRun workflowRun = ws.getWorkflowRunWithWorkflow(String.valueOf(swid));
Workflow workflow = workflowRun.getWorkflow();
workflowRun.setWorkflow(null);
workflow.setWorkflowRuns(null);
if (workflow.getWorkflowParams() != null) {
for (WorkflowParam param : workflow.getWorkflowParams()) {
param.setWorkflow(null);
}
}
// ugly, need to avoid circular reference before serialization
FileUtils.write(new File(persistDir, WORKFLOW_RUN_FILENAME), gson.toJson(workflowRun));
FileUtils.write(new File(persistDir, WORKFLOW_FILENAME), gson.toJson(workflow));
FileUtils.write(new File(persistDir, STATE_FILENAME), gson.toJson(completedJobs));
workflowRun.setWorkflow(workflow);
SortedSet<WorkflowRun> set = new TreeSet<>();
set.add(workflowRun);
workflow.setWorkflowRuns(set);
if (workflow.getWorkflowParams() != null) {
for (WorkflowParam param : workflow.getWorkflowParams()) {
param.setWorkflow(workflow);
}
}
} catch (IOException ex) {
Log.stdoutWithTime("Unable to write workflowrun state");
rethrow(ex);
}
}
}