/******************************************************************************* * 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.wfview.full; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import javax.enterprise.context.ConversationScoped; import javax.inject.Inject; import javax.inject.Named; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.scape_project.planning.exception.PlanningException; import eu.scape_project.planning.manager.ByteStreamManager; import eu.scape_project.planning.model.Alternative; import eu.scape_project.planning.model.DigitalObject; import eu.scape_project.planning.model.Parameter; import eu.scape_project.planning.model.Plan; import eu.scape_project.planning.model.PlanState; import eu.scape_project.planning.model.PreservationActionDefinition; import eu.scape_project.planning.model.SampleObject; import eu.scape_project.planning.model.User; import eu.scape_project.planning.model.tree.Leaf; import eu.scape_project.planning.model.tree.TreeNode; import eu.scape_project.planning.plato.bean.IServiceLoader; import eu.scape_project.planning.plato.bean.MyExperimentServices; import eu.scape_project.planning.plato.bean.ServiceInfoDataModel; import eu.scape_project.planning.plato.bean.TreeHelperBean; import eu.scape_project.planning.plato.wf.AbstractWorkflowStep; import eu.scape_project.planning.plato.wf.DevelopExperiments; import eu.scape_project.planning.plato.wfview.AbstractView; import eu.scape_project.planning.services.IServiceInfo; import eu.scape_project.planning.services.PlanningServiceException; import eu.scape_project.planning.services.action.ActionInfo; import eu.scape_project.planning.services.action.ActionInfoFactory; import eu.scape_project.planning.services.myexperiment.MyExperimentAsyncBuilder; import eu.scape_project.planning.services.myexperiment.MyExperimentExecutablePlanGenerator; import eu.scape_project.planning.services.myexperiment.MyExperimentSearch; import eu.scape_project.planning.services.myexperiment.RecommendedComponent; import eu.scape_project.planning.utils.Downloader; /** * Class used as backing-bean for the view developexperiments.xhtml. * * @author Markus Hamm */ @Named("developExperiments") @ConversationScoped public class DevelopExperimentsView extends AbstractView { private static final long serialVersionUID = -4042576732990053101L; private static final Logger LOG = LoggerFactory.getLogger(DevelopExperimentsView.class); @Inject private DevelopExperiments developExperiments; @Inject private ByteStreamManager byteStreamManager; @Inject private User user; @Inject private Downloader downloader; private List<Alternative> alternatives; private List<Leaf> mappedLeaves; private List<String> measures; /** * Cache for myExperiment service details. */ @Inject private MyExperimentServices myExperimentServices; private MyExperimentSearch myExperimentSearch; private Map<String, IServiceLoader> serviceLoaders; private String sourceMimetype; private HashMap<Alternative, String> targetMimetypes; private HashMap<Alternative, ActionInfo> actionInfos; private Alternative selectedAlternative; private Leaf selectedLeaf; private List<RecommendedComponent> recommendedComponents; private List<String> openMeasures; private ServiceInfoDataModel serviceInfoData; @Inject private MyExperimentAsyncBuilder asyncBuilder; /** * This is a pseudo list which only contains the tree's root node. */ private List<TreeNode> treeRoot; @Inject private TreeHelperBean treeHelper; /** * Constructs a new object. */ public DevelopExperimentsView() { currentPlanState = PlanState.GO_CHOSEN; name = "Develop Experiments"; viewUrl = "/plan/developexperiments.jsf"; group = "menu.evaluateAlternatives"; myExperimentSearch = new MyExperimentSearch(); serviceLoaders = new HashMap<String, IServiceLoader>(); recommendedComponents = new ArrayList<RecommendedComponent>(); openMeasures = new ArrayList<String>(); } @Override public void init(Plan plan) { super.init(plan); alternatives = plan.getAlternativesDefinition().getConsideredAlternatives(); targetMimetypes = new HashMap<Alternative, String>(alternatives.size()); actionInfos = new HashMap<Alternative, ActionInfo>(alternatives.size()); for (Alternative a : alternatives) { PreservationActionDefinition pad = a.getAction(); if (pad != null) { targetMimetypes.put(a, ""); ActionInfo actionInfo = ActionInfoFactory.createActionInfo(pad); actionInfos.put(a, actionInfo); myExperimentServices.load(actionInfo); } } measures = new ArrayList<String>(); mappedLeaves = plan.getTree().getRoot().getAllLeaves(); Iterator<Leaf> mappedLeavesIt = mappedLeaves.iterator(); while (mappedLeavesIt.hasNext()) { Leaf leaf = mappedLeavesIt.next(); if (leaf.isMapped()) { measures.add(leaf.getMeasure().getUri()); } else { mappedLeavesIt.remove(); } } SampleObject sampleWithFormat = plan.getSampleRecordsDefinition().getFirstSampleWithFormat(); if (sampleWithFormat != null) { sourceMimetype = sampleWithFormat.getFormatInfo().getMimeType(); } myExperimentSearch.setSourceMimetype(sourceMimetype); serviceLoaders.put("myExperiment", myExperimentServices); serviceLoaders.put("myExperiment-plan", myExperimentServices); treeRoot = new ArrayList<TreeNode>(); treeRoot.add(plan.getTree().getRoot()); treeHelper.expandAll(plan.getTree().getRoot()); } /** * Generates an experiment workflow for the provided alternative. * * @param alternative * the alternative */ public void generateExperimentWorkflow(Alternative alternative) { if (!targetMimetypeValid(alternative)) { facesMessages.addError("Target mimetype is empty. Please specify a target mimetype."); return; } try { Future<DigitalObject> generatedWorkflow = asyncBuilder.generateExecutablePlan(plan.getPlanProperties() .getName(), alternative, measures, sourceMimetype, targetMimetypes.get(alternative)); DigitalObject workflow = generatedWorkflow.get(); developExperiments.setAlternativeWorkflow(alternative, workflow); facesMessages.addInfo("Experiment workflow generated."); } catch (PlanningException e) { facesMessages.addError("An error occured generating the executable plan."); } catch (InterruptedException e) { facesMessages.addError("Generating the experiment plan was interrupted. Please try again."); } catch (ExecutionException e) { facesMessages.addError("The experiment plan could not be generated. Please try again."); } } /** * Starts a download for the workflow of the provided alternative. Uses * {@link eu.scape_project.planning.util.Downloader} to perform the * download. * * @param alternative * the alternative download the workflow from */ public void downloadExperimentWorkflow(final Alternative alternative) { DigitalObject workflow = alternative.getExperiment().getWorkflow(); File file = byteStreamManager.getTempFile(workflow.getPid()); downloader.download(workflow, file); } /** * Selects an alternative to create a workflow. * * @param alternative * the alternative to select */ public void selectAlternative(Alternative alternative) { if (!targetMimetypeValid(alternative)) { facesMessages.addError("Target mimetype is empty. Please specify a target mimetype."); return; } selectedAlternative = alternative; selectedLeaf = null; recommendedComponents.clear(); openMeasures.clear(); openMeasures.addAll(measures); serviceInfoData = null; } /** * Selects a leaf for adding components. * * @param leaf * the leaf to select */ public void selectLeaf(Leaf leaf) { this.selectedLeaf = leaf; if (leaf.isMapped()) { myExperimentSearch.setMeasure(leaf.getMeasure().getUri()); } myExperimentSearch.setSourceMimetype(sourceMimetype); myExperimentSearch.setTargetMimetype(targetMimetypes.get(selectedAlternative)); Set<IServiceInfo> searchResults = new HashSet<IServiceInfo>(); try { searchResults.addAll(myExperimentSearch.searchObjectQa()); searchResults.addAll(myExperimentSearch.searchCc()); } catch (PlanningServiceException e) { facesMessages.addError("Failed to retrieve components, registry unavailable."); LOG.error("Failed to retrieve components, registry unavailable.", e); } serviceInfoData = new ServiceInfoDataModel(new ArrayList<IServiceInfo>(searchResults), serviceLoaders); } /** * Adds a component for the selected alternative and leaf. * * @param serviceInfo * the component info to add */ public void addComponent(IServiceInfo serviceInfo) { if (selectedLeaf.isMapped()) { String currentMeasure = selectedLeaf.getMeasure().getUri(); if (!openMeasures.contains(currentMeasure)) { openMeasures.add(currentMeasure); } RecommendedComponent recommendedComponent = MyExperimentExecutablePlanGenerator.recommendComponent(serviceInfo, openMeasures, targetMimetypes.get(selectedAlternative)); if (recommendedComponent != null) { removeMeasureRecommendation(currentMeasure); recommendedComponents.add(recommendedComponent); openMeasures.removeAll(recommendedComponent.measures); } } } /** * Builds an experiment workflow from the recommended components. */ public void buildExperimentWorkflow() { MyExperimentExecutablePlanGenerator planGenerator = new MyExperimentExecutablePlanGenerator( selectedAlternative.getName(), user.getFullName()); // Parameters Map<String, String> parameters = new HashMap<String, String>(); for (Parameter p : selectedAlternative.getAction().getParams()) { parameters.put(p.getName(), p.getValue()); } try { planGenerator.setMigrationAction(actionInfos.get(selectedAlternative), parameters); planGenerator.addQaComponent(recommendedComponents); DigitalObject workflow = planGenerator.generateExecutablePlan(); developExperiments.setAlternativeWorkflow(selectedAlternative, workflow); facesMessages.addInfo("Experiment workflow built."); } catch (PlanningException e) { facesMessages.addError("Could not generate workflow from the selected components: " + e.getMessage()); } } /** * Remove a measure from the commended components. * * @param measure * the measure URI to remove */ private void removeMeasureRecommendation(String measure) { for (RecommendedComponent c : recommendedComponents) { c.measures.remove(measure); } } /** * Checks if the target mimetype of the alternative is valid. * * @param alternative * the alternative to check * @return true if it is valid, false otherwise */ private boolean targetMimetypeValid(Alternative alternative) { String targetMimetype = targetMimetypes.get(alternative); return targetMimetype != null && !targetMimetype.isEmpty(); } // --------------- getter/setter --------------- @Override protected AbstractWorkflowStep getWfStep() { return developExperiments; } public List<Alternative> getAlternatives() { return alternatives; } public void setAlternatives(List<Alternative> alternatives) { this.alternatives = alternatives; } public MyExperimentServices getMyExperimentServices() { return myExperimentServices; } public HashMap<Alternative, ActionInfo> getActionInfos() { return actionInfos; } public List<Leaf> getMappedLeaves() { return mappedLeaves; } public String getSourceMimetype() { return sourceMimetype; } public HashMap<Alternative, String> getTargetMimetypes() { return targetMimetypes; } public Alternative getSelectedAlternative() { return selectedAlternative; } public Leaf getSelectedLeaf() { return selectedLeaf; } public MyExperimentSearch getMyExperimentSearch() { return myExperimentSearch; } public ServiceInfoDataModel getServiceInfoData() { return serviceInfoData; } public List<String> getOpenMeasures() { return openMeasures; } public List<TreeNode> getTreeRoot() { return treeRoot; } public TreeHelperBean getTreeHelper() { return treeHelper; } }