/******************************************************************************* * 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.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.enterprise.context.ConversationScoped; import javax.inject.Inject; import javax.inject.Named; import javax.validation.constraints.NotNull; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.URL; import org.slf4j.Logger; import eu.scape_project.planning.exception.PlanningException; import eu.scape_project.planning.model.Alternative; 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.PlatoException; import eu.scape_project.planning.model.PreservationActionDefinition; import eu.scape_project.planning.model.SampleObject; 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.wf.AbstractWorkflowStep; import eu.scape_project.planning.plato.wf.DefineAlternatives; 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.MyExperimentSearch; import eu.scape_project.planning.services.myexperiment.domain.Port; import eu.scape_project.planning.services.myexperiment.domain.WorkflowDescription; import eu.scape_project.planning.services.pa.PreservationActionRegistryDefinition; import eu.scape_project.planning.services.pa.taverna.MyExperimentActionInfo; import eu.scape_project.planning.utils.FacesMessages; import eu.scape_project.planning.validation.ValidationError; /** * Class used as backing-bean for the view definealternatives.xhtml. * * @author Markus Hamm */ @Named("defineAlternatives") @ConversationScoped public class DefineAlternativesView extends AbstractView { private static final long serialVersionUID = -8800780634335662691L; /** * Types of registries. */ private enum SelectedRegistry { PA, CUSTOM, MY_EXPERIMENT }; @Inject private Logger log; @Inject private FacesMessages facesMessages; @Inject private DefineAlternatives defineAlternatives; /** * Alternative that is currently being edited. */ private IServiceInfo editableAlternativeActionInfo; /** * Name of the editable alternative which cannot be set directly in the * editableAlternative because alternative renaming is a complex process. */ @NotNull @Length(min = 1, max = 30) private String editableAlternativeName; /** * Alternative currently editable. */ private Alternative editableAlternative; /** * Alternative that is newly created. */ private Alternative customAlternative; /** * URL of custom myExperiment service. */ @URL private String customMyExperimentServiceUri; /** * Workflow description of custom myExperiment service. */ private MyExperimentActionInfo customMyExperimentServiceInfo; /** * Cache for myExperiment service details. */ @Inject private MyExperimentServices myExperimentServices; /** * List of all currently defined preservation service registries. */ private List<PreservationActionRegistryDefinition> availableRegistries; /** * List of actions of the currently selected registry. */ private List<IServiceInfo> availableActions; /** * Data model for services. */ private ServiceInfoDataModel serviceInfoData; /** * Service identifiers and their loaders. */ private Map<String, IServiceLoader> serviceLoaders; private SelectedRegistry selectedRegistry = SelectedRegistry.CUSTOM; private MyExperimentSearch myExperimentSearch; /** * Creates a new view object. */ public DefineAlternativesView() { currentPlanState = PlanState.TREE_DEFINED; name = "Define Alternatives"; viewUrl = "/plan/definealternatives.jsf"; group = "menu.evaluateAlternatives"; editableAlternative = null; customAlternative = null; customMyExperimentServiceInfo = null; customMyExperimentServiceUri = null; availableRegistries = new ArrayList<PreservationActionRegistryDefinition>(); availableActions = new ArrayList<IServiceInfo>(); serviceLoaders = new HashMap<String, IServiceLoader>(); myExperimentSearch = new MyExperimentSearch(); myExperimentSearch.setProfile("http://purl.org/DP/components#MigrationAction"); } /** * Initialises the view with plan data. * * @param plan * plan used to initialize */ public void init(Plan plan) { super.init(plan); availableRegistries.clear(); availableActions.clear(); try { availableRegistries.addAll(defineAlternatives.getPreservationActionRegistries()); } catch (PlanningServiceException e) { log.error("Failed to retrieve registries", e); facesMessages.addError("Could not find any preservation action registries."); } serviceLoaders.put("myExperiment", myExperimentServices); serviceLoaders.put("myExperiment-plan", myExperimentServices); myExperimentServices.clear(); showCustomAlternatives(); } /** * Removes the provided alternative from the plan. * * @param alternative * alternative to delete */ public void removeAlternative(Alternative alternative) { if (plan.isGivenAlternativeTheCurrentRecommendation(alternative)) { facesMessages.addInfo("You have removed the action which was chosen as the recommended alternative."); } plan.removeAlternative(alternative); if (alternative == editableAlternative) { editableAlternative = null; } } /** * Method responsible for preparing and showing the edit alternatives * window. * * @param alternative * the alternative to show */ public void showEditAlternative(Alternative alternative) { editableAlternative = alternative; editableAlternativeName = alternative.getName(); if (alternative.getAction() != null) { editableAlternativeActionInfo = ActionInfoFactory.createActionInfo(alternative.getAction()); IServiceLoader serviceLoader = serviceLoaders.get(alternative.getAction().getActionIdentifier()); if (serviceLoader != null) { serviceLoader.load(editableAlternativeActionInfo); } } } /** * Method responsible for add/edit a new/existing alternative. */ public void editAlternative() { editableAlternative.touch(); editableAlternativeName = editableAlternativeName.trim(); try { plan.renameAlternative(editableAlternative, editableAlternativeName); } catch (PlanningException e) { facesMessages.addError(e.getMessage()); return; } editableAlternative = null; } /** * Method responsible for causing the add/edit-alternative window to close. */ public void closeEditArea() { editableAlternative = null; } /** * Adds the predefine alternative "do nothing" to the plan. */ public void addDoNothing() { try { defineAlternatives.addAlternative("Keep status quo", "Keep the objects as they are."); } catch (PlanningException e) { facesMessages.addError("Could not add the alternative: " + e.getMessage()); } } /** * Adds the custom alternative to the plan. */ public void addCustomAlternative() { try { defineAlternatives.addAlternative(customAlternative); customAlternative = Alternative.createAlternative(); } catch (PlanningException e) { facesMessages.addError("Could not add the alternative: " + e.getMessage()); } } /** * Determines if there is at least one sample with format info. * * @return true if a sample with format info is available */ public boolean isFormatInfoAvailable() { return plan.getSampleRecordsDefinition().getFirstSampleWithFormat() != null; } /** * Determines if there is at least one sample with format info. * * @return true if a sample with format info is available */ public boolean isMimetypeAvailable() { SampleObject sample = getSampleWithFormat(); return isFormatInfoAvailable() && sample.getFormatInfo().getMimeType() != null && !"".equals(sample.getFormatInfo().getMimeType()); } /** * Returns a sample with attached format info - at the moment this is the * first sample with format info found. * * @return a sample object with format info */ public SampleObject getSampleWithFormat() { return plan.getSampleRecordsDefinition().getFirstSampleWithFormat(); } /** * Clears the lists of available services. */ private void clearAvailableServices() { availableActions.clear(); myExperimentServices.clear(); selectedRegistry = null; } /** * Shows the custom alternative input. */ public void showCustomAlternatives() { clearAvailableServices(); selectedRegistry = SelectedRegistry.CUSTOM; customAlternative = Alternative.createAlternative(); customMyExperimentServiceInfo = null; customMyExperimentServiceUri = null; } /** * Shows myExperiment alternatives. */ public void showMyExperimentAlternatives() { if (!isMimetypeAvailable()) { facesMessages .addError("Could not find a sample with format information. Please add a mimetype to one of your samples."); return; } clearAvailableServices(); selectedRegistry = SelectedRegistry.MY_EXPERIMENT; myExperimentSearch.setSourceMimetype(getSampleWithFormat().getFormatInfo().getMimeType()); filterMyExperimentAlternatives(); } /** * Filters myExperiment alternatives. */ public void filterMyExperimentAlternatives() { try { availableActions.clear(); availableActions.addAll(myExperimentSearch.searchMigrationAction()); serviceInfoData = new ServiceInfoDataModel(availableActions, serviceLoaders); } catch (PlanningServiceException e) { facesMessages.addError("Failed to filter alternatives, registry unavailable."); log.error("Failed to filter alternatives, registry unavailable.", e); } } /** * Retrieves the list of services available in the given registry. * * @param registry * the registry to query */ public void showPreservationServices(PreservationActionRegistryDefinition registry) { if (!isFormatInfoAvailable()) { facesMessages .addError("Could not find a sample with format information. Please add format information to one of your samples."); return; } clearAvailableServices(); selectedRegistry = SelectedRegistry.PA; try { availableActions.addAll(defineAlternatives.queryRegistry(getSampleWithFormat().getFormatInfo(), registry)); serviceInfoData = new ServiceInfoDataModel(availableActions, serviceLoaders); } catch (PlatoException e) { facesMessages.addError("Failed to query the registry: " + registry.getShortname() + " - " + e.getMessage()); log.error("Failed to query the registry: " + registry.getShortname(), e); } } /** * Adds a preservation action to the plan, created from the custom * myExperiment service URI. */ public void loadCustomMyExperimentService() { if (customMyExperimentServiceUri == null || "".equals(customMyExperimentServiceUri)) { return; } customMyExperimentServiceInfo = new MyExperimentActionInfo(); customMyExperimentServiceInfo.setDescriptor(customMyExperimentServiceUri); customMyExperimentServiceInfo.setUrl(customMyExperimentServiceUri); customMyExperimentServiceInfo.setShortname(customMyExperimentServiceUri); customMyExperimentServiceInfo.setInfo(customMyExperimentServiceUri); WorkflowDescription wf = myExperimentServices.getWorkflowDescription(customMyExperimentServiceInfo); if (wf != null) { customMyExperimentServiceInfo.setUrl(wf.getContentUri()); customMyExperimentServiceInfo.setShortname(wf.getName()); customMyExperimentServiceInfo.setInfo(wf.getDescription()); customMyExperimentServiceInfo.setDescriptor(wf.getDescriptor()); customMyExperimentServiceInfo.setContentType(wf.getContentType()); myExperimentServices.load(customMyExperimentServiceInfo); } else { customMyExperimentServiceInfo = null; } } /** * Adds a preservation action to the plan, created from the provided service * info. * * @param serviceInfo * the action info */ public void addPreservationAction(IServiceInfo serviceInfo) { try { defineAlternatives.addAlternative(serviceInfo); } catch (PlanningException e) { facesMessages.addError("Could not create an alternative from the service you selected."); } } /** * Adds a preservation action to the plan, created from the provided service * info. * * @param serviceInfo * the action info */ public void addPreservationAction(MyExperimentActionInfo serviceInfo) { WorkflowDescription wf = myExperimentServices.getWorkflowDescription(serviceInfo); if (wf == null) { facesMessages.addError("Could not retrieve workflow description from myExeriment."); return; } try { PreservationActionDefinition actionDefinition = new PreservationActionDefinition(); actionDefinition.setActionIdentifier(serviceInfo.getServiceIdentifier()); actionDefinition.setShortname(serviceInfo.getShortname()); actionDefinition.setDescriptor(serviceInfo.getDescriptor()); actionDefinition.setUrl(serviceInfo.getUrl()); actionDefinition.setInfo(serviceInfo.getInfo()); for (Port p : wf.getInputPorts()) { if (p.isParameterPort()) { actionDefinition.getParams().add(new Parameter(p.getName(), "")); } } String uniqueName = plan.getAlternativesDefinition().createUniqueName(actionDefinition.getShortname()); Alternative a = Alternative.createAlternative(uniqueName, actionDefinition); defineAlternatives.addAlternative(a); } catch (PlanningException e) { facesMessages.addError("Could not create an alternative from the service you selected."); } } /** * Adds a preservation action to the plan, created from the provided action * info. * * @param serviceInfo * the action info */ public void addPreservationAction(ActionInfo serviceInfo) { try { defineAlternatives.addAlternative(serviceInfo); } catch (PlanningException e) { facesMessages.addError("Could not create an alternative from the service you selected."); } } @Override protected boolean tryProceed(List<ValidationError> errors) { // view-specific validation if (editableAlternative != null) { errors .add(new ValidationError( "You are currently editing an Alternative. Please finish editing first before you proceed to the next step.", editableAlternative)); } // general validation boolean result = defineAlternatives.proceed(errors); return result && errors.isEmpty(); } // --------------- getter/setter --------------- @Override protected AbstractWorkflowStep getWfStep() { return defineAlternatives; } public FacesMessages getFacesMessages() { return facesMessages; } public void setFacesMessages(FacesMessages facesMessages) { this.facesMessages = facesMessages; } public Alternative getEditableAlternative() { return editableAlternative; } public void setEditableAlternative(Alternative editableAlternative) { this.editableAlternative = editableAlternative; } public String getEditableAlternativeName() { return editableAlternativeName; } public void setEditableAlternativeName(String editableAlternativeName) { this.editableAlternativeName = editableAlternativeName; } public IServiceInfo getEditableAlternativeActionInfo() { return editableAlternativeActionInfo; } public Alternative getCustomAlternative() { return customAlternative; } public void setCustomAlternative(Alternative customAlternative) { this.customAlternative = customAlternative; } public String getCustomMyExperimentServiceUri() { return customMyExperimentServiceUri; } public void setCustomMyExperimentServiceUri(String customMyExperimentServiceUri) { this.customMyExperimentServiceUri = customMyExperimentServiceUri; } public IServiceInfo getCustomMyExperimentServiceInfo() { return customMyExperimentServiceInfo; } public List<PreservationActionRegistryDefinition> getAvailableRegistries() { return availableRegistries; } public List<IServiceInfo> getAvailableActions() { return availableActions; } public SelectedRegistry getSelectedRegistry() { return selectedRegistry; } public MyExperimentSearch getMyExperimentSearch() { return myExperimentSearch; } public ServiceInfoDataModel getServiceInfoData() { return serviceInfoData; } public MyExperimentServices getTavernaServices() { return myExperimentServices; } public void setLog(Logger log) { this.log = log; } }