/******************************************************************************* * Copyright 2006 - 2014 Vienna University of Technology, * Department of Software Technology and Interactive Systems, IFS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package eu.scape_project.planning.plato.wf; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import javax.ejb.Stateful; import javax.enterprise.context.ConversationScoped; import javax.inject.Inject; import org.dom4j.Document; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; import org.slf4j.Logger; import eu.scape_project.planning.exception.PlanningException; import eu.scape_project.planning.manager.StorageException; import eu.scape_project.planning.model.ByteStream; import eu.scape_project.planning.model.DigitalObject; import eu.scape_project.planning.model.Plan; import eu.scape_project.planning.model.PlanState; import eu.scape_project.planning.services.taverna.parser.T2FlowParser; import eu.scape_project.planning.services.taverna.parser.TavernaParserException; import eu.scape_project.planning.utils.FileUtils; import eu.scape_project.planning.xml.PlanXMLConstants; import eu.scape_project.planning.xml.PreservationActionPlanGenerator; /** * Workflow step to configure the executable plan. * * @author Michael Kraxner */ @Stateful @ConversationScoped public class CreateExecutablePlan extends AbstractWorkflowStep { private static final long serialVersionUID = -971490825722362606L; @Inject private Logger log; @Inject private PreservationActionPlanGenerator generator; /** * Constructs a new create executable plan object. */ public CreateExecutablePlan() { requiredPlanState = PlanState.ANALYSED; correspondingPlanState = PlanState.EXECUTEABLE_PLAN_CREATED; } @Override public void init(Plan p) { super.init(p); // If we don't have tool parameters, we copy them from the chosen // alternative's config settings: if (plan.getExecutablePlanDefinition().getToolParameters() == null || "".equals(plan.getExecutablePlanDefinition().getToolParameters())) { plan.getExecutablePlanDefinition().setToolParameters( plan.getRecommendation().getAlternative().getExperiment().getSettings()); } } @Override protected void saveStepSpecific() { saveEntity(plan); } /** * Reads an executable plan from the provided inputstream and stores it. * * @param stream * the executable plan * @throws PlanningException * if an error occurred * @throws TavernaParserException * if the executable plan could not be parsed */ public void readT2flowExecutablePlan(InputStream stream) throws PlanningException, TavernaParserException { ByteStream bsData = this.convertToByteStream(stream); if (bsData == null) { throw new PlanningException("An error occurred while storing the executable plan"); } T2FlowParser parser = T2FlowParser.createParser(new ByteArrayInputStream(bsData.getData())); String name = parser.getName(); storeExecutablePlan(FileUtils.makeFilename(name) + ".t2flow", bsData); } /** * Generates the preservation action plan other plan information and stores * it in the plan. * * @throws PlanningException * if an error occurred */ public void generatePreservationActionPlan() throws PlanningException { try { Document papDoc = generator.generatePreservationActionPlanDocument(plan.getSampleRecordsDefinition() .getCollectionProfile(), plan.getExecutablePlanDefinition(), plan); ByteArrayOutputStream out = new ByteArrayOutputStream(); OutputFormat outputFormat = OutputFormat.createPrettyPrint(); outputFormat.setEncoding(PlanXMLConstants.ENCODING); XMLWriter writer = new XMLWriter(out, outputFormat); writer.write(papDoc); writer.close(); ByteStream bs = new ByteStream(); bs.setData(out.toByteArray()); bs.setSize(out.size()); DigitalObject digitalObject = new DigitalObject(); digitalObject.setFullname(PreservationActionPlanGenerator.FULL_NAME); digitalObject.setContentType("application/xml"); digitalObject.setData(bs); digitalObjectManager.moveDataToStorage(digitalObject); if (plan.getPreservationActionPlan() != null && plan.getPreservationActionPlan().isDataExistent()) { bytestreamsToRemove.add(plan.getPreservationActionPlan().getPid()); } plan.setPreservationActionPlan(digitalObject); addedBytestreams.add(digitalObject.getPid()); plan.getPreservationActionPlan().touch(); } catch (IOException e) { log.error("Error generating preservation action plan {}.", e.getMessage()); throw new PlanningException("Error generating preservation action plan.", e); } catch (StorageException e) { log.error("An error occurred while storing the executable plan: {}", e.getMessage()); throw new PlanningException("An error occurred while storing the profile", e); } } /** * Uses the experiment workflow from the recommended alternative as * executable plan. * * @throws PlanningException * if an error occurred during storing */ public void copyRecommendedExperimentWorkflow() throws PlanningException { if (plan.getRecommendation().getAlternative().getExperiment() == null) { throw new PlanningException("The recommendation has no experiment defined."); } if (plan.getRecommendation().getAlternative().getExperiment().getWorkflow() == null) { throw new PlanningException("The recommendation experiment has no workflow defined."); } DigitalObject workflow = plan.getRecommendation().getAlternative().getExperiment().getWorkflow(); DigitalObject copy = digitalObjectManager.getCopyOfDataFilledDigitalObject(workflow); digitalObjectManager.moveDataToStorage(copy); addedBytestreams.add(copy.getPid()); plan.getExecutablePlanDefinition().setT2flowExecutablePlan(copy); plan.getExecutablePlanDefinition().getT2flowExecutablePlan().touch(); } /** * Converts the input stream object to a {@link ByteStream} wrapper. * * @param stream * the stream to wrap. * @return the new {@link ByteStream} or null if an error occurred. */ private ByteStream convertToByteStream(InputStream stream) { ByteStream bsData = null; byte[] bytes = null; try { bytes = FileUtils.inputStreamToBytes(stream); bsData = new ByteStream(); bsData.setData(bytes); bsData.setSize(bytes.length); } catch (IOException e) { log.error("An error occurred while converting the stream: {}", e.getMessage()); } return bsData; } /** * Stores the provided executable plan in the executable plan definition. * * @param name * the name of the plan * @param executablePlan * the executable plan as t2flow * @throws PlanningException * if an error occurred during storing */ private void storeExecutablePlan(String name, ByteStream executablePlan) throws PlanningException { DigitalObject object = new DigitalObject(); object.setContentType("application/vnd.taverna.t2flow+xml"); object.setFullname(name); object.setData(executablePlan); try { digitalObjectManager.moveDataToStorage(object); plan.getExecutablePlanDefinition().setT2flowExecutablePlan(object); plan.getExecutablePlanDefinition().getT2flowExecutablePlan().touch(); addedBytestreams.add(object.getPid()); } catch (StorageException e) { log.error("An error occurred while storing the executable plan: {}", e.getMessage()); throw new PlanningException("An error occurred while storing the profile", e); } } }