http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreationDialog.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreationDialog.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreationDialog.java new file mode 100644 index 0000000..3a467fd --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreationDialog.java @@ -0,0 +1,666 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu; + +import static java.awt.BorderLayout.CENTER; +import static java.awt.BorderLayout.NORTH; +import static java.awt.BorderLayout.SOUTH; +import static java.util.Collections.sort; +import static javax.swing.JOptionPane.WARNING_MESSAGE; +import static javax.swing.JOptionPane.showMessageDialog; +import static org.apache.log4j.Logger.getLogger; +import static io.github.taverna_extras.component.ui.util.Utils.uniqueName; +import static org.apache.taverna.scufl2.api.common.Scufl2Tools.NESTED_WORKFLOW; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.AbstractAction; +import javax.swing.DefaultComboBoxModel; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.ListCellRenderer; + +//import net.sf.taverna.t2.lang.ui.DeselectingButton; +//import net.sf.taverna.t2.workbench.edits.CompoundEdit; +//import net.sf.taverna.t2.workbench.edits.Edit; +//import net.sf.taverna.t2.workbench.edits.EditException; +//import net.sf.taverna.t2.workbench.edits.EditManager; +//import net.sf.taverna.t2.workbench.helper.HelpEnabledDialog; +//import net.sf.taverna.t2.workbench.models.graph.GraphController; +//import net.sf.taverna.t2.workbench.views.graph.GraphViewComponent; +//import net.sf.taverna.t2.workflow.edits.AddActivityEdit; +//import net.sf.taverna.t2.workflow.edits.AddActivityInputPortMappingEdit; +//import net.sf.taverna.t2.workflow.edits.AddActivityOutputPortMappingEdit; +//import net.sf.taverna.t2.workflow.edits.AddChildEdit; +//import net.sf.taverna.t2.workflow.edits.AddDataLinkEdit; +//import net.sf.taverna.t2.workflow.edits.AddProcessorInputPortEdit; +//import net.sf.taverna.t2.workflow.edits.AddProcessorOutputPortEdit; +//import net.sf.taverna.t2.workflow.edits.AddWorkflowInputPortEdit; +//import net.sf.taverna.t2.workflow.edits.AddWorkflowOutputPortEdit; +//import net.sf.taverna.t2.workflow.edits.RemoveChildEdit; +//import net.sf.taverna.t2.workflow.edits.RemoveDataLinkEdit; +//import net.sf.taverna.t2.workflow.edits.SetIterationStrategyStackEdit; + +import org.apache.log4j.Logger; +import org.apache.taverna.annotation.annotationbeans.DescriptiveTitle; +import org.apache.taverna.lang.ui.DeselectingButton; + +import org.apache.taverna.scufl2.api.activity.Activity; +import org.apache.taverna.scufl2.api.annotation.Annotation; +import org.apache.taverna.scufl2.api.common.Named; +import org.apache.taverna.scufl2.api.common.NamedSet; +import org.apache.taverna.scufl2.api.common.Scufl2Tools; +import org.apache.taverna.scufl2.api.container.WorkflowBundle; +import org.apache.taverna.scufl2.api.core.BlockingControlLink; +import org.apache.taverna.scufl2.api.core.ControlLink; +import org.apache.taverna.scufl2.api.core.DataLink; +import org.apache.taverna.scufl2.api.core.Processor; +import org.apache.taverna.scufl2.api.core.Workflow; +import org.apache.taverna.scufl2.api.port.InputActivityPort; +import org.apache.taverna.scufl2.api.port.InputProcessorPort; +import org.apache.taverna.scufl2.api.port.InputWorkflowPort; +import org.apache.taverna.scufl2.api.port.OutputActivityPort; +import org.apache.taverna.scufl2.api.port.OutputProcessorPort; +import org.apache.taverna.scufl2.api.port.OutputWorkflowPort; +import org.apache.taverna.scufl2.api.port.ProcessorPort; +import org.apache.taverna.scufl2.api.port.ReceiverPort; +import org.apache.taverna.scufl2.api.port.SenderPort; +import org.apache.taverna.scufl2.api.profiles.Profile; +import org.apache.taverna.workbench.edits.CompoundEdit; +import org.apache.taverna.workbench.edits.Edit; +import org.apache.taverna.workbench.edits.EditException; +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.helper.HelpEnabledDialog; +import org.apache.taverna.workbench.models.graph.GraphController; +import org.apache.taverna.workbench.views.graph.GraphViewComponent; +import org.apache.taverna.workflow.edits.AddActivityEdit; +import org.apache.taverna.workflow.edits.AddActivityInputPortMappingEdit; +import org.apache.taverna.workflow.edits.AddActivityOutputPortMappingEdit; +import org.apache.taverna.workflow.edits.AddChildEdit; +import org.apache.taverna.workflow.edits.AddDataLinkEdit; +import org.apache.taverna.workflow.edits.AddProcessorInputPortEdit; +import org.apache.taverna.workflow.edits.AddProcessorOutputPortEdit; +import org.apache.taverna.workflow.edits.AddWorkflowInputPortEdit; +import org.apache.taverna.workflow.edits.AddWorkflowOutputPortEdit; +import org.apache.taverna.workflow.edits.RemoveChildEdit; +import org.apache.taverna.workflow.edits.RemoveDataLinkEdit; +import org.apache.taverna.workflow.edits.SetIterationStrategyStackEdit; +import org.apache.taverna.workflowmodel.utils.AnnotationTools; + +/** + * @author alanrw + */ +public class NestedWorkflowCreationDialog extends HelpEnabledDialog { + private static final long serialVersionUID = 727059218457420449L; + private static final Logger logger = getLogger(NestedWorkflowCreationDialog.class); + private static final Comparator<Processor> processorComparator = new Comparator<Processor>() { + @Override + public int compare(Processor o1, Processor o2) { + return o1.getName().compareTo(o2.getName()); + } + }; + private static final ListCellRenderer<Object> defaultRenderer = new DefaultListCellRenderer(); + private static final ListCellRenderer<Processor> processorRenderer = new ListCellRenderer<Processor>() { + @Override + public Component getListCellRendererComponent( + JList<? extends Processor> list, + Processor value, int index, boolean isSelected, + boolean cellHasFocus) { + return defaultRenderer.getListCellRendererComponent(list, + value.getName(), index, isSelected, cellHasFocus); + } + }; + + private final EditManager em; + private final GraphViewComponent graphView; + private final List<Processor> includedProcessors = new ArrayList<>(); + private List<Processor> allProcessors; + private final List<Processor> includableProcessors = new ArrayList<>(); + + private JList<Processor> includableList = new JList<>(); + private JList<Processor> includedList = new JList<>(); + private final Workflow currentDataflow; + private JButton excludeButton; + private JButton includeButton; + private JButton okButton; + private JButton resetButton; + private JTextField nameField = new JTextField(30); + + public NestedWorkflowCreationDialog(Frame owner, Object o, + Workflow dataflow, EditManager em, GraphViewComponent graphView) { + super(owner, "Nested workflow creation", true, null); + this.em = em; + this.graphView = graphView; + + if (o instanceof Processor) + includedProcessors.add((Processor) o); + this.currentDataflow = dataflow; + + allProcessors = new ArrayList<>(dataflow.getProcessors()); + + this.setLayout(new BorderLayout()); + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout()); + + okButton = new DeselectingButton(new OKAction(this)); + buttonPanel.add(okButton); + + resetButton = new DeselectingButton(new ResetAction(this)); + buttonPanel.add(resetButton); + + JButton cancelButton = new DeselectingButton(new CancelAction(this)); + buttonPanel.add(cancelButton); + + JPanel innerPanel = new JPanel(new BorderLayout()); + JPanel processorChoice = createProcessorChoicePanel(dataflow); + innerPanel.add(processorChoice, CENTER); + + JPanel namePanel = new JPanel(new FlowLayout()); + namePanel.add(new JLabel("Workflow name: ")); + nameField.setText("nested"); + namePanel.add(nameField); + innerPanel.add(namePanel, SOUTH); + + this.add(innerPanel, CENTER); + + this.add(buttonPanel, SOUTH); + this.pack(); + this.setSize(new Dimension(500, 800)); + } + + private JPanel createProcessorChoicePanel(Workflow dataflow) { + JPanel result = new JPanel(); + result.setLayout(new GridLayout(0, 2)); + + JPanel includedProcessorsPanel = createIncludedProcessorsPanel(); + JPanel includableProcessorsPanel = createIncludableProcessorsPanel(); + result.add(includableProcessorsPanel); + result.add(includedProcessorsPanel); + updateLists(); + return result; + } + + private JPanel createIncludableProcessorsPanel() { + JPanel result = new JPanel(); + result.setLayout(new BorderLayout()); + result.add(new JLabel("Possible services"), NORTH); + includableList.setModel(new DefaultComboBoxModel<>(new Vector<>( + includableProcessors))); + includableList.setCellRenderer(processorRenderer); + result.add(new JScrollPane(includableList), CENTER); + + includeButton = new DeselectingButton("Include", new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + includedProcessors.addAll(includableList + .getSelectedValuesList()); + calculateIncludableProcessors(); + updateLists(); + } + }); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout()); + buttonPanel.add(includeButton); + result.add(buttonPanel, SOUTH); + return result; + } + + private void resetLists() { + includedProcessors.clear(); + updateLists(); + } + + private JPanel createIncludedProcessorsPanel() { + JPanel result = new JPanel(); + result.setLayout(new BorderLayout()); + result.add(new JLabel("Included services"), NORTH); + includedList.setModel(new DefaultComboBoxModel<>(new Vector<>( + includedProcessors))); + includedList.setCellRenderer(processorRenderer); + result.add(new JScrollPane(includedList), CENTER); + + excludeButton = new DeselectingButton("Exclude", new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + includedProcessors.removeAll(includedList + .getSelectedValuesList()); + calculateIncludableProcessors(); + updateLists(); + } + }); + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout()); + buttonPanel.add(excludeButton); + + result.add(buttonPanel, SOUTH); + return result; + } + + private void updateLists() { + calculateIncludableProcessors(); + sort(includedProcessors, processorComparator); + sort(includableProcessors, processorComparator); + includedList.setModel(new DefaultComboBoxModel<>(new Vector<>( + includedProcessors))); + includableList.setModel(new DefaultComboBoxModel<>(new Vector<>( + includableProcessors))); + boolean someIncludedProcessors = includedProcessors.size() > 0; + excludeButton.setEnabled(someIncludedProcessors); + okButton.setEnabled(someIncludedProcessors); + resetButton.setEnabled(someIncludedProcessors); + boolean someIncludableProcessors = includableProcessors.size() > 0; + includeButton.setEnabled(someIncludableProcessors); + } + + public void calculateIncludableProcessors() { + includableProcessors.clear(); + if (includedProcessors.isEmpty()) + includableProcessors.addAll(allProcessors); + else + for (Processor p : includedProcessors) { + considerNearestUpstream(p); + considerNearestDownstream(p); + } + sort(includableProcessors, processorComparator); + } + + private void considerNearestDownstream(Processor investigate) { + for (BlockingControlLink condition : investigate.controlLinksWaitingFor()) + considerInclusion(condition.getBlock()); + + for (OutputProcessorPort outputPort : investigate.getOutputPorts()) + for (DataLink datalink : outputPort.getDatalinksFrom()) { + ReceiverPort sink = datalink.getSendsTo(); + if (sink instanceof InputProcessorPort) + considerInclusion(((InputProcessorPort) sink).getParent()); + } + } + + private void considerNearestUpstream(Processor investigate) { + for (BlockingControlLink condition : investigate.controlLinksBlocking()) + considerInclusion(condition.getUntilFinished()); + for (InputProcessorPort inputPort : investigate.getInputPorts()) + for (DataLink incomingLink : inputPort.getDatalinksTo()) { + if (incomingLink == null) + continue; + SenderPort source = incomingLink.getReceivesFrom(); + if (source instanceof OutputProcessorPort) + considerInclusion(((OutputProcessorPort) source).getParent()); + } + } + + private void considerInclusion(Processor p) { + if (!includedProcessors.contains(p) + && !includableProcessors.contains(p)) + includableProcessors.add(p); + } + + private void createNestedWorkflow() { + final List<Edit<?>> currentWorkflowEditList = new ArrayList<>(); + Map<Object, Object> oldNewMapping = new HashMap<>(); + Map<DataLink, String> linkProcessorPortMapping = new HashMap<>(); + Map<SenderPort, OutputWorkflowPort> outputPortMap = new HashMap<>(); + Map<ReceiverPort, InputWorkflowPort> inputPortMap = new HashMap<>(); + + Profile profile;//FIXME + Processor nestingProcessor = createNestingProcessor(currentWorkflowEditList); + Workflow nestedDataflow = createNestedDataflow(); + + transferProcessors(currentWorkflowEditList, oldNewMapping, + nestedDataflow); + transferDatalinks(oldNewMapping, linkProcessorPortMapping, + outputPortMap, inputPortMap, nestedDataflow); + transferConditions(currentWorkflowEditList, oldNewMapping, + nestingProcessor); + addDataflowToNestingProcessor(nestingProcessor, nestedDataflow, profile); + currentWorkflowEditList.add(new AddChildEdit<>(currentDataflow, + nestingProcessor)); + createDatalinkEdits(currentWorkflowEditList, oldNewMapping, + linkProcessorPortMapping, nestingProcessor); + + try { + GraphController gc = graphView.getGraphController(currentDataflow); + gc.setExpandNestedDataflow(nestingProcessor.getActivity(profile), true); + em.doDataflowEdit(currentDataflow.getParent(), new CompoundEdit( + currentWorkflowEditList)); + gc.redraw(); + } catch (EditException e1) { + logger.error("failed to manufacture nested workflow", e1); + } + } + + private void addDataflowToNestingProcessor(Processor nestingProcessor, + Workflow nestedDataflow, Profile profile) { + Activity da = new Activity(); + da.setParent(profile); + da.createConfiguration(NESTED_WORKFLOW).getJsonAsObjectNode() + .put("nestedWorkflow", nestedDataflow.getName()); + try { + new AddActivityEdit(nestingProcessor, da).doEdit(); + new SetIterationStrategyStackEdit(nestingProcessor, null/*FIXME*/).doEdit(); + for (InputActivityPort aip : da.getInputPorts()) { + InputProcessorPort pip = new InputProcessorPort(); + pip.setName(aip.getName()); + pip.setDepth(aip.getDepth()); + new AddProcessorInputPortEdit(nestingProcessor, pip).doEdit(); + new AddActivityInputPortMappingEdit(da, pip, aip).doEdit(); + } + for (OutputActivityPort aop : da.getOutputPorts()) { + OutputProcessorPort pop = new OutputProcessorPort(); + pop.setName(aop.getName()); + pop.setDepth(aop.getDepth()); + pop.setGranularDepth(aop.getGranularDepth()); + new AddProcessorOutputPortEdit(nestingProcessor, pop).doEdit(); + new AddActivityOutputPortMappingEdit(da, pop, aop).doEdit(); + } + } catch (EditException e1) { + logger.error("failed to add ports to processor", e1); + } + } + + private void createDatalinkEdits(List<Edit<?>> editList, + Map<Object, Object> oldNewMapping, + Map<DataLink, String> linkProcessorPortMapping, + Processor nestingProcessor) { + for (DataLink dl : currentDataflow.getDataLinks()) + if (oldNewMapping.containsKey(dl.getReceivesFrom()) + && oldNewMapping.containsKey(dl.getSendsTo())) + // Internal to nested workflow + editList.add(new RemoveDataLinkEdit(dl.getParent(), dl)); + else if (oldNewMapping.containsKey(dl.getReceivesFrom())) { + // Coming out of nested workflow + OutputProcessorPort nestedPort = nestingProcessor + .getOutputPorts().getByName( + linkProcessorPortMapping.get(dl)); + if (nestedPort != null) { + DataLink replacementDatalink = new DataLink(nestedPort + .getParent().getParent(), nestedPort, + dl.getSendsTo()); + editList.add(new RemoveDataLinkEdit(dl.getParent(), dl)); + editList.add(new AddDataLinkEdit(nestedPort.getParent() + .getParent(), replacementDatalink)); + } + } else if (oldNewMapping.containsKey(dl.getSendsTo())) { + // Coming into nested workflow + InputProcessorPort nestedPort = nestingProcessor + .getInputPorts().getByName( + linkProcessorPortMapping.get(dl)); + if (nestedPort != null) { + DataLink replacementDatalink = new DataLink(nestedPort + .getParent().getParent(), dl.getReceivesFrom(), + nestedPort); + editList.add(new RemoveDataLinkEdit(dl.getParent(), dl)); + editList.add(new AddDataLinkEdit(nestedPort.getParent() + .getParent(), replacementDatalink)); + } + } + } + + private void transferConditions(List<Edit<?>> editList, + Map<Object, Object> oldNewMapping, Processor nestingProcessor) { + for (Processor p : currentDataflow.getProcessors()) { + boolean isTargetMoved = oldNewMapping.containsKey(p); + for (BlockingControlLink c : p.controlLinksWaitingFor()) { + Processor pre = c.getUntilFinished(); + boolean isControlMoved = oldNewMapping.containsKey(pre); + if (isTargetMoved && isControlMoved) { + // Add in new condition + new BlockingControlLink( + (Processor) oldNewMapping.get(pre), + (Processor) oldNewMapping.get(p)); + } else if (isTargetMoved) { + editList.add(new RemoveChildEdit<>(c.getParent(),c)); + editList.add(new AddChildEdit<>(c.getParent(), + new BlockingControlLink(pre, nestingProcessor))); + } else if (isControlMoved) { + editList.add(new RemoveChildEdit<>(c.getParent(), c)); + editList.add(new AddChildEdit<>(c.getParent(), + new BlockingControlLink(nestingProcessor, p))); + } + } + } + } + + private void transferDatalinks(Map<Object, Object> oldNewMapping, + Map<DataLink, String> linkProcessorPortMapping, + Map<SenderPort, OutputWorkflowPort> outputPortMap, + Map<ReceiverPort, InputWorkflowPort> inputPortMap, + Workflow nestedDataflow) { + NamedSet<InputWorkflowPort> inputPorts = new NamedSet<>(); + NamedSet<OutputWorkflowPort> outputPorts = new NamedSet<>(); + + for (DataLink dl : currentDataflow.getDataLinks()) { + final SenderPort datalinkSource = dl.getReceivesFrom(); + final ReceiverPort datalinkSink = dl.getSendsTo(); + if (oldNewMapping.containsKey(datalinkSource) + && oldNewMapping.containsKey(datalinkSink)) { + // Internal to nested workflow + DataLink newDatalink = new DataLink(null, + (SenderPort) oldNewMapping.get(datalinkSource), + (ReceiverPort) oldNewMapping.get(datalinkSink)); + try { + new AddDataLinkEdit(nestedDataflow, newDatalink).doEdit(); + } catch (EditException e1) { + logger.error("failed to connect datalink", e1); + } + } else if (oldNewMapping.containsKey(datalinkSource)) { + OutputWorkflowPort dop = null; + if (!outputPortMap.containsKey(datalinkSource)) { + dop = new OutputWorkflowPort(nestedDataflow, uniqueName( + datalinkSource.getName(), outputPorts)); + outputPorts.add(dop); + outputPortMap.put(datalinkSource, dop); + } else + dop = outputPortMap.get(datalinkSource); + String portName = dop.getName(); + // Coming out of nested workflow + linkProcessorPortMapping.put(dl, portName); + try { + new AddWorkflowOutputPortEdit(nestedDataflow, dop).doEdit(); + DataLink newDatalink = new DataLink( + (SenderPort) oldNewMapping.get(datalinkSource), + dop.getInternalInputPort()); + new AddDataLinkEdit(nestedDataflow, newDatalink).doEdit(); + } catch (EditException e1) { + logger.error("failed to add dataflow output", e1); + } + } else if (oldNewMapping.containsKey(datalinkSink)) { + InputWorkflowPort dip = null; + if (!inputPortMap.containsKey(datalinkSink)) { + dip = new InputWorkflowPort(nestedDataflow, uniqueName( + datalinkSink.getName(), inputPorts)); + inputPorts.add(dip); + dip.setDepth(dl.getResolvedDepth()); + inputPortMap.put(datalinkSink, dip); + } else + dip = inputPortMap.get(datalinkSink); + String portName = dip.getName(); + // Coming into nested workflow + linkProcessorPortMapping.put(dl, portName); + try { + new AddWorkflowInputPortEdit(nestedDataflow, dip).doEdit(); + DataLink newDatalink = new DataLink( + dip.getInternalOutputPort(), + (ReceiverPort) oldNewMapping.get(datalinkSink)); + new AddDataLinkEdit(nestedDataflow, newDatalink).doEdit(); + } catch (EditException e1) { + logger.error("failed to add dataflow input", e1); + } + } + } + } + + private void transferProcessors(List<Edit<?>> editList, + Map<Object, Object> oldNewMapping, Workflow nestedDataflow) { + for (Processor entity : includedProcessors) + try { + if (entity instanceof Processor) + transferProcessor(editList, oldNewMapping, nestedDataflow, + (Processor) entity); + /*else if (entity instanceof Merge) + //FIXME what to do here? Anything? + transferMerge(editList, oldNewMapping, nestedDataflow, + (Merge) entity);*/ + } catch (Exception e1) { + logger.error("failed to transfer processor", e1); + } + } + + /*private void transferMerge(List<Edit<?>> editList, + Map<Object, Object> oldNewMapping, Workflow nestedDataflow, + Merge merge) throws EditException { + editList.add(edits.getRemoveMergeEdit(currentDataflow, merge)); + Merge newMerge = edits.createMerge(nestedDataflow); + edits.getAddMergeEdit(nestedDataflow, newMerge).doEdit(); + oldNewMapping.put(merge, newMerge); + for (MergeInputPort mip : merge.getInputPorts()) { + MergeInputPort newMip = edits.createMergeInputPort(newMerge, + mip.getName(), mip.getDepth()); + edits.getAddMergeInputPortEdit(newMerge, newMip).doEdit(); + oldNewMapping.put(mip, newMip); + } + oldNewMapping.put(merge.getOutputPort(), newMerge.getOutputPort()); + }*/ + + private void transferProcessor(List<Edit<?>> editList, + Map<Object, Object> oldNewMapping, Workflow nestedDataflow, + Processor p) throws Exception { + editList.add(new RemoveChildEdit<>(currentDataflow, p)); + Processor newProcessor = (Processor) p.clone(); + newProcessor.setParent(nestedDataflow); + oldNewMapping.put(p, newProcessor); + for (InputProcessorPort pip : p.getInputPorts()) + for (InputProcessorPort newPip : newProcessor.getInputPorts()) + if (pip.getName().equals(newPip.getName())) { + oldNewMapping.put(pip, newPip); + break; + } + for (OutputProcessorPort pop : p.getOutputPorts()) + for (OutputProcessorPort newPop : newProcessor.getOutputPorts()) + if (pop.getName().equals(newPop.getName())) { + oldNewMapping.put(pop, newPop); + break; + } + } + + private Processor createNestingProcessor(List<Edit<?>> editList) { + //TODO check what workflow the new processor is going into + Processor nestingProcessor = new Processor(currentDataflow, uniqueName( + nameField.getText(), currentDataflow.getProcessors())); + if (includedProcessors.size() != 1) + return nestingProcessor; + Processor includedProcessor = includedProcessors.get(0); + for (Annotation a: includedProcessor.getAnnotations()) { + Annotation newAnn = (Annotation) a.clone(); + newAnn.setTarget(nestingProcessor); + editList.add(new AddChildEdit<>(a.getParent(), newAnn)); + } + return nestingProcessor; + } + + private Workflow createNestedDataflow() { + Workflow nestedDataflow = new Workflow(uniqueName(nameField.getText(), + currentDataflow.getParent().getWorkflows())); + // Set the title of the nested workflow to the name suggested by the user + try { + new AnnotationTools().setAnnotationString(nestedDataflow, + DescriptiveTitle.class, nameField.getText()).doEdit(); + } catch (EditException ex) { + logger.error("failed to put annotation on nested dataflow", ex); + } + return nestedDataflow; + } + + private final class OKAction extends AbstractAction { + private static final long serialVersionUID = 6516891432445682857L; + private final JDialog dialog; + + private OKAction(JDialog dialog) { + super("OK"); + this.dialog = dialog; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (includedProcessors.isEmpty()) { + showMessageDialog( + null, + "At least one service must be included in the nested workflow", + "Nested workflow creation", WARNING_MESSAGE); + return; + } + + createNestedWorkflow(); + dialog.setVisible(false); + } + } + + private final class ResetAction extends AbstractAction { + private static final long serialVersionUID = 7296742769289881218L; + + private ResetAction(JDialog dialog) { + super("Reset"); + } + + @Override + public void actionPerformed(ActionEvent e) { + resetLists(); + } + } + + private final class CancelAction extends AbstractAction { + private static final long serialVersionUID = -7842176979437027091L; + private final JDialog dialog; + + private CancelAction(JDialog dialog) { + super("Cancel"); + this.dialog = dialog; + } + + @Override + public void actionPerformed(ActionEvent e) { + dialog.setVisible(false); + } + } +}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreatorMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreatorMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreatorMenuAction.java new file mode 100644 index 0000000..0cdb2ba --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreatorMenuAction.java @@ -0,0 +1,94 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu; + +import java.awt.Dialog; +import java.awt.event.ActionEvent; +import java.net.URI; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import org.apache.taverna.activities.dataflow.servicedescriptions.DataflowActivityIcon; + +import org.apache.taverna.scufl2.api.core.Processor; +import org.apache.taverna.scufl2.api.core.Workflow; +import org.apache.taverna.ui.menu.AbstractContextualMenuAction; +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.selection.SelectionManager; +import org.apache.taverna.workbench.views.graph.GraphViewComponent; + +/** + * @author alanrw + */ +public class NestedWorkflowCreatorMenuAction extends + AbstractContextualMenuAction { + private static final URI configureSection = URI + .create("http://taverna.sf.net/2009/contextMenu/configure"); + + private SelectionManager sm; + private EditManager em; + private GraphViewComponent gv; + + public NestedWorkflowCreatorMenuAction() { + super(configureSection, 70); + } + + public void setEditManager(EditManager editManager) { + em = editManager; + } + public void setGraphView(GraphViewComponent graphView) { + gv = graphView; + } + public void setSelectionManager(SelectionManager selectionManager) { + sm = selectionManager; + } + + @Override + public boolean isEnabled() { + Object selection = getContextualSelection().getSelection(); + if (!super.isEnabled() || selection == null) + return false; + if (selection instanceof Processor) + return true; + if (!(selection instanceof Workflow)) + return false; + return !((Workflow) selection).getProcessors().isEmpty(); + } + + @Override + protected Action createAction() { + return new AbstractAction("Create nested workflow...", + DataflowActivityIcon.getDataflowIcon()) { + private static final long serialVersionUID = -3121307982540205215L; + + @Override + public void actionPerformed(ActionEvent e) { + createNestedWorkflow(); + } + }; + } + + private void createNestedWorkflow() { + Dialog dialog = new NestedWorkflowCreationDialog(null, + getContextualSelection().getSelection(), + sm.getSelectedWorkflow(), em, gv); + dialog.setVisible(true); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityAction.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityAction.java new file mode 100644 index 0000000..2bce63a --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityAction.java @@ -0,0 +1,81 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu; + +import static org.apache.log4j.Logger.getLogger; + +import java.awt.event.ActionEvent; +import java.net.MalformedURLException; + +import org.apache.log4j.Logger; +import io.github.taverna_extras.component.api.ComponentFactory; +import io.github.taverna_extras.component.api.Version; +import io.github.taverna_extras.component.ui.ComponentAction; +import io.github.taverna_extras.component.ui.ComponentActivityConfigurationBean; +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon; + +import org.apache.taverna.scufl2.api.activity.Activity; +import org.apache.taverna.scufl2.api.container.WorkflowBundle; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.workbench.file.FileType; +import org.apache.taverna.workbench.file.exceptions.OpenException; +import org.apache.taverna.workbench.views.graph.GraphViewComponent; + +/** + * @author alanrw + */ +@SuppressWarnings("serial") +public class OpenComponentFromComponentActivityAction extends ComponentAction { + private static Logger logger = getLogger(OpenComponentFromComponentActivityAction.class); + + private final FileManager fileManager; + private final ComponentFactory factory; + private final FileType fileType; + + public OpenComponentFromComponentActivityAction(FileManager fileManager, + ComponentFactory factory, FileType ft, + GraphViewComponent graphView, ComponentServiceIcon icon) { + super("Open component...", graphView); + this.fileManager = fileManager; + this.factory = factory; + this.fileType = ft; + setIcon(icon); + } + + private Activity selection; + + @Override + public void actionPerformed(ActionEvent ev) { + try { + Version.ID ident = new ComponentActivityConfigurationBean( + selection.getConfiguration(), factory); + WorkflowBundle d = fileManager.openDataflow(fileType, ident); + markGraphAsBelongingToComponent(d); + } catch (OpenException e) { + logger.error("failed to open component", e); + } catch (MalformedURLException e) { + logger.error("bad URL in component description", e); + } + } + + public void setSelection(Activity selection) { + this.selection = selection; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityMenuAction.java new file mode 100644 index 0000000..6f28816 --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityMenuAction.java @@ -0,0 +1,104 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu; + +import java.net.URI; + +import javax.swing.Action; + +import io.github.taverna_extras.component.api.ComponentFactory; +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon; + +import org.apache.taverna.scufl2.api.activity.Activity; +import org.apache.taverna.scufl2.api.core.Processor; +import org.apache.taverna.ui.menu.AbstractContextualMenuAction; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.workbench.file.FileType; +import org.apache.taverna.workbench.selection.SelectionManager; +import org.apache.taverna.workbench.views.graph.GraphViewComponent; + +/** + * @author alanrw + */ +public class OpenComponentFromComponentActivityMenuAction extends + AbstractContextualMenuAction { + private static final URI configureSection = URI + .create("http://taverna.sf.net/2009/contextMenu/configure"); + + private SelectionManager sm; + private FileManager fileManager; + private ComponentFactory factory; + private FileType fileType; + private GraphViewComponent graphView; + private ComponentServiceIcon icon; + + public OpenComponentFromComponentActivityMenuAction() { + super(configureSection, 75); + } + + public void setSelectionManager(SelectionManager sm) { + this.sm = sm; + } + + public void setFileManager(FileManager fileManager) { + this.fileManager = fileManager; + } + + public void setComponentFactory(ComponentFactory factory) { + this.factory = factory; + } + + public void setFileType(FileType fileType) { + this.fileType = fileType; + } + + public void setGraphView(GraphViewComponent graphView) { + this.graphView = graphView; + } + + public void setIcon(ComponentServiceIcon icon) { + this.icon = icon; + } + + @Override + public boolean isEnabled() { + return getSelectedActivity() != null; + } + + @Override + protected Action createAction() { + OpenComponentFromComponentActivityAction action = new OpenComponentFromComponentActivityAction( + fileManager, factory, fileType, graphView, icon); + action.setSelection(getSelectedActivity()); + return action; + } + + private Activity getSelectedActivity() { + Object selection = getContextualSelection().getSelection(); + if (!super.isEnabled() || !(selection instanceof Processor)) + return null; + + try { + return ((Processor) selection).getActivity(sm.getSelectedProfile()); + } catch (RuntimeException e) { + return null; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentAction.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentAction.java new file mode 100644 index 0000000..ebb51a8 --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentAction.java @@ -0,0 +1,275 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu; + +import static java.awt.BorderLayout.CENTER; +import static java.awt.BorderLayout.SOUTH; +import static javax.swing.JOptionPane.ERROR_MESSAGE; +import static javax.swing.JOptionPane.OK_CANCEL_OPTION; +import static javax.swing.JOptionPane.OK_OPTION; +import static javax.swing.JOptionPane.showConfirmDialog; +import static javax.swing.JOptionPane.showMessageDialog; +import static io.github.taverna_extras.component.api.config.ComponentPropertyNames.COMPONENT_NAME; +import static io.github.taverna_extras.component.ui.ComponentActivityConfigurationBean.ignorableNames; +import static io.github.taverna_extras.component.ui.util.Utils.uniqueName; +import static org.apache.taverna.scufl2.api.common.Scufl2Tools.NESTED_WORKFLOW; + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.JCheckBox; +import javax.swing.JPanel; +import javax.swing.JSeparator; + +import io.github.taverna_extras.component.api.Component; +import io.github.taverna_extras.component.api.ComponentFactory; +import io.github.taverna_extras.component.api.Family; +import io.github.taverna_extras.component.api.Registry; +import io.github.taverna_extras.component.api.Version; +import io.github.taverna_extras.component.ui.ComponentActivityConfigurationBean; +import io.github.taverna_extras.component.ui.panel.ComponentChooserPanel; +import io.github.taverna_extras.component.ui.preference.ComponentPreference; +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon; +import io.github.taverna_extras.component.ui.util.Utils; + +import org.apache.taverna.scufl2.api.activity.Activity; +import org.apache.taverna.scufl2.api.common.Scufl2Tools; +import org.apache.taverna.scufl2.api.core.Processor; +import org.apache.taverna.scufl2.api.core.Workflow; +import org.apache.taverna.scufl2.api.port.InputActivityPort; +import org.apache.taverna.scufl2.api.port.InputProcessorPort; +import org.apache.taverna.scufl2.api.port.OutputActivityPort; +import org.apache.taverna.scufl2.api.port.OutputProcessorPort; +import org.apache.taverna.workbench.edits.CompoundEdit; +import org.apache.taverna.workbench.edits.Edit; +import org.apache.taverna.workbench.edits.EditException; +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.selection.SelectionManager; +import org.apache.taverna.workflow.edits.AddActivityEdit; +import org.apache.taverna.workflow.edits.AddActivityInputPortMappingEdit; +import org.apache.taverna.workflow.edits.AddActivityOutputPortMappingEdit; +import org.apache.taverna.workflow.edits.RemoveActivityEdit; +import org.apache.taverna.workflow.edits.RenameEdit; + +/** + * @author alanrw + */ +public class ReplaceByComponentAction extends AbstractAction { + private static final long serialVersionUID = 7364648399658711574L; + + private final EditManager em; + private final ComponentPreference prefs; + private final SelectionManager sm; + private final ComponentFactory factory; + private final Scufl2Tools tools = new Scufl2Tools(); + + private Processor selection; + + public ReplaceByComponentAction(ComponentPreference prefs, + ComponentFactory factory, EditManager em, SelectionManager sm, + ComponentServiceIcon icon) { + super("Replace by component...", icon.getIcon()); + this.prefs = prefs; + this.em = em; + this.sm = sm; + this.factory = factory; + } + + @Override + public void actionPerformed(ActionEvent e) { + JPanel overallPanel = new JPanel(new BorderLayout()); + ComponentChooserPanel panel = new ComponentChooserPanel(prefs); + overallPanel.add(panel, CENTER); + JPanel checkBoxPanel = new JPanel(new FlowLayout()); + JCheckBox replaceAllCheckBox = new JCheckBox( + "Replace all matching services"); + checkBoxPanel.add(replaceAllCheckBox); + checkBoxPanel.add(new JSeparator()); + JCheckBox renameServicesCheckBox = new JCheckBox("Rename service(s)"); + checkBoxPanel.add(renameServicesCheckBox); + renameServicesCheckBox.setSelected(true); + overallPanel.add(checkBoxPanel, SOUTH); + int answer = showConfirmDialog(null, overallPanel, "Component choice", + OK_CANCEL_OPTION); + if (answer == OK_OPTION) + doReplace(panel.getChosenRegistry(), panel.getChosenFamily(), + replaceAllCheckBox.isSelected(), + renameServicesCheckBox.isSelected(), + panel.getChosenComponent()); + } + + private void doReplace(Registry chosenRegistry, Family chosenFamily, + boolean replaceAll, boolean rename, Component chosenComponent) { + Version chosenVersion = chosenComponent.getComponentVersionMap().get( + chosenComponent.getComponentVersionMap().lastKey()); + Version.ID ident = new Version.Identifier( + chosenRegistry.getRegistryBase(), chosenFamily.getName(), + chosenComponent.getName(), chosenVersion.getVersionNumber()); + + ComponentActivityConfigurationBean cacb = new ComponentActivityConfigurationBean( + ident, factory); + + try { + if (replaceAll) { + Activity baseActivity = selection.getActivity(sm + .getSelectedProfile()); + URI activityType = baseActivity.getType(); + String configString = getConfigString(baseActivity); + + replaceAllMatchingActivities(activityType, cacb, configString, + rename, sm.getSelectedWorkflow()); + } else + replaceActivity(cacb, selection, rename, + sm.getSelectedWorkflow()); + } catch (Exception e) { + showMessageDialog( + null, + "Failed to replace nested workflow with component: " + + e.getMessage(), "Component Problem", + ERROR_MESSAGE); + } + } + + private String getConfigString(Activity baseActivity) { + return baseActivity.getConfiguration().getJsonAsString(); + } + + private void replaceAllMatchingActivities(URI activityType, + ComponentActivityConfigurationBean cacb, String configString, + boolean rename, Workflow d) throws IntermediateException { + for (Processor p : d.getProcessors()) { + Activity a = p.getActivity(sm.getSelectedProfile()); + if (a.getType().equals(activityType) + && getConfigString(a).equals(configString)) + replaceActivity(cacb, p, rename, d); + else if (a.getType().equals(NESTED_WORKFLOW)) + replaceAllMatchingActivities(activityType, cacb, configString, + rename, + tools.nestedWorkflowForProcessor(p, a.getParent())); + } + } + + private void replaceActivity(ComponentActivityConfigurationBean cacb, + Processor p, boolean rename, Workflow d) throws IntermediateException { + final Activity originalActivity = p.getActivity(sm.getSelectedProfile()); + final List<Edit<?>> currentWorkflowEditList = new ArrayList<>(); + + Activity replacementActivity = new Activity(); + try { + URI configType; + replacementActivity.createConfiguration(configType); + + replacementActivity.configure(cacb); + //FIXME + } catch (Exception e) { + throw new IntermediateException( + "Unable to configure component", e); + } + if (originalActivity.getInputPorts().size() != replacementActivity + .getInputPorts().size()) + throw new IntermediateException( + "Component does not have matching ports", null); + + int replacementOutputSize = replacementActivity.getOutputPorts().size(); + int originalOutputSize = originalActivity.getOutputPorts().size(); + for (String name : ignorableNames) { + if (originalActivity.getOutputPorts().getByName(name) != null) + originalOutputSize--; + if (replacementActivity.getOutputPorts().getByName(name) != null) + replacementOutputSize--; + } + + int sizeDifference = replacementOutputSize - originalOutputSize; + if (sizeDifference != 0) + throw new IntermediateException( + "Component does not have matching ports", null); + + for (InputActivityPort aip : originalActivity.getInputPorts()) { + String aipName = aip.getName(); + int aipDepth = aip.getDepth(); + InputActivityPort caip = replacementActivity.getInputPorts().getByName(aipName); + if ((caip == null) || (caip.getDepth() != aipDepth)) + throw new RuntimeException("Original input port " + + aipName + " is not matched"); + } + for (OutputActivityPort aop : originalActivity.getOutputPorts()) { + String aopName = aop.getName(); + int aopDepth = aop.getDepth(); + OutputActivityPort caop = replacementActivity.getOutputPorts().getByName(aopName); + if ((caop == null || aopDepth != caop.getDepth()) + && !ignorableNames.contains(aopName)) + throw new IntermediateException( + "Original output port " + aopName + " is not matched", null); + } + + for (InputProcessorPort pip : p.getInputPorts()) { + InputActivityPort iap = replacementActivity.getInputPorts() + .getByName(pip.getName()); + if (iap == null) + iap = new InputActivityPort(replacementActivity, pip.getName()); + currentWorkflowEditList.add(new AddActivityInputPortMappingEdit( + replacementActivity, pip, iap)); + } + + for (OutputProcessorPort pop : p.getOutputPorts()) { + OutputActivityPort oap = replacementActivity.getOutputPorts() + .getByName(pop.getName()); + if (oap == null) + oap = new OutputActivityPort(replacementActivity, pop.getName()); + currentWorkflowEditList.add(new AddActivityOutputPortMappingEdit( + replacementActivity, pop, oap)); + } + + currentWorkflowEditList + .add(new AddActivityEdit(p, replacementActivity)); + currentWorkflowEditList + .add(new RemoveActivityEdit(p, originalActivity)); + + if (rename) { + String possibleName = replacementActivity.getConfiguration() + .getJsonAsObjectNode().get(COMPONENT_NAME).textValue(); + currentWorkflowEditList.add(new RenameEdit<>(p, uniqueName( + possibleName, d.getProcessors()))); + } + try { + em.doDataflowEdit(d.getParent(), new CompoundEdit( + currentWorkflowEditList)); + } catch (EditException e) { + throw new IntermediateException( + "Unable to replace with component", e); + } + } + + public void setSelection(Processor selection) { + this.selection = selection; + } + + @SuppressWarnings("serial") + private static class IntermediateException extends Exception { + IntermediateException(String msg, Throwable cause) { + super(msg, cause); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentMenuAction.java new file mode 100644 index 0000000..470ad40 --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentMenuAction.java @@ -0,0 +1,87 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu; + +import java.net.URI; + +import javax.swing.Action; + +import io.github.taverna_extras.component.api.ComponentFactory; +import io.github.taverna_extras.component.ui.preference.ComponentPreference; +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon; + +import org.apache.taverna.scufl2.api.core.Processor; +import org.apache.taverna.ui.menu.AbstractContextualMenuAction; +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.selection.SelectionManager; + +/** + * @author alanrw + */ +public class ReplaceByComponentMenuAction extends AbstractContextualMenuAction { + private static final URI configureSection = URI + .create("http://taverna.sf.net/2009/contextMenu/configure"); + + private ComponentPreference preferences; + private EditManager editManager; + private SelectionManager selectionManager; + private ComponentFactory factory; + private ComponentServiceIcon icon; + + public ReplaceByComponentMenuAction() { + super(configureSection, 75); + } + + public void setPreferences(ComponentPreference preferences) { + this.preferences = preferences; + } + + public void setEditManager(EditManager editManager) { + this.editManager = editManager; + } + + public void setSelectionManager(SelectionManager selectionManager) { + this.selectionManager = selectionManager; + } + + public void setComponentFactory(ComponentFactory factory) { + this.factory = factory; + } + + public void setIcon(ComponentServiceIcon icon) { + this.icon = icon; + } + + @Override + public boolean isEnabled() { + Object selection = getContextualSelection().getSelection(); + if (!super.isEnabled()) + return false; + return (selection instanceof Processor); + } + + @Override + protected Action createAction() { + ReplaceByComponentAction action = new ReplaceByComponentAction( + preferences, factory, editManager, selectionManager, icon); + action.setSelection((Processor) getContextualSelection().getSelection()); + return action; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/AbstractComponentMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/AbstractComponentMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/AbstractComponentMenuAction.java new file mode 100644 index 0000000..671e190 --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/AbstractComponentMenuAction.java @@ -0,0 +1,31 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu.component; + +import static io.github.taverna_extras.component.ui.menu.component.ComponentMenuSection.COMPONENT_SECTION; + +import java.net.URI; +import org.apache.taverna.ui.menu.AbstractMenuAction; + +abstract class AbstractComponentMenuAction extends AbstractMenuAction { + public AbstractComponentMenuAction(int positionHint, URI id) { + super(COMPONENT_SECTION, positionHint, id); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseAction.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseAction.java new file mode 100644 index 0000000..da22a60 --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseAction.java @@ -0,0 +1,73 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu.component; + +import static org.apache.log4j.Logger.getLogger; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.Action; + +import org.apache.log4j.Logger; +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon; +import io.github.taverna_extras.component.ui.util.Utils; +import org.apache.taverna.lang.observer.Observable; +import org.apache.taverna.lang.observer.Observer; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.workbench.file.events.FileManagerEvent; + +/** + * @author alanrw + */ +public class ComponentCloseAction extends AbstractAction implements + Observer<FileManagerEvent> { + private static final long serialVersionUID = -153986599735293879L; + private static final String CLOSE_COMPONENT = "Close component"; + @SuppressWarnings("unused") + private static Logger logger = getLogger(ComponentCloseAction.class); + + private Action closeAction; + private final Utils utils; + + public ComponentCloseAction(Action closeWorkflowAction, FileManager fm, + ComponentServiceIcon icon, Utils utils) { + super(CLOSE_COMPONENT, icon.getIcon()); + closeAction = closeWorkflowAction; + this.utils = utils; + fm.addObserver(this); + } + + @Override + public void actionPerformed(ActionEvent arg0) { + closeAction.actionPerformed(arg0); + } + + @Override + public boolean isEnabled() { + return utils.currentDataflowIsComponent(); + } + + @Override + public void notify(Observable<FileManagerEvent> sender, + FileManagerEvent message) throws Exception { + setEnabled(utils.currentDataflowIsComponent()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseMenuAction.java new file mode 100644 index 0000000..6c40a5f --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseMenuAction.java @@ -0,0 +1,66 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu.component; + +import java.net.URI; + +import javax.swing.Action; + +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon; +import io.github.taverna_extras.component.ui.util.Utils; +import org.apache.taverna.workbench.file.FileManager; + +/** + * @author alanrw + */ +public class ComponentCloseMenuAction extends AbstractComponentMenuAction { + private static final URI CLOSE_COMPONENT_URI = URI + .create("http://taverna.sf.net/2008/t2workbench/menu#componentClose"); + + private Action action; + private FileManager fm; + private ComponentServiceIcon icon; + private Utils utils; + + public ComponentCloseMenuAction() { + super(1000, CLOSE_COMPONENT_URI); + } + + public void setCloseWorkflowAction(Action action) { + this.action = action; + } + + public void setFileManager(FileManager fm) { + this.fm = fm; + } + + public void setIcon(ComponentServiceIcon icon) { + this.icon = icon; + } + + public void setUtils(Utils utils) { + this.utils = utils; + } + + @Override + protected Action createAction() { + return new ComponentCloseAction(action, fm, icon, utils); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyAction.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyAction.java new file mode 100644 index 0000000..676a6c9 --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyAction.java @@ -0,0 +1,164 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu.component; + +import static java.awt.GridBagConstraints.BOTH; +import static java.awt.GridBagConstraints.WEST; +import static javax.swing.JOptionPane.ERROR_MESSAGE; +import static javax.swing.JOptionPane.OK_CANCEL_OPTION; +import static javax.swing.JOptionPane.OK_OPTION; +import static javax.swing.JOptionPane.showConfirmDialog; +import static javax.swing.JOptionPane.showMessageDialog; +import static org.apache.log4j.Logger.getLogger; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; +import javax.swing.JPanel; +import javax.swing.border.TitledBorder; + +import org.apache.log4j.Logger; +import io.github.taverna_extras.component.api.Component; +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.api.Family; +import io.github.taverna_extras.component.api.Version; +import io.github.taverna_extras.component.api.profile.Profile; +import io.github.taverna_extras.component.ui.panel.ComponentChoiceMessage; +import io.github.taverna_extras.component.ui.panel.ComponentChooserPanel; +import io.github.taverna_extras.component.ui.panel.ProfileChoiceMessage; +import io.github.taverna_extras.component.ui.panel.RegistryAndFamilyChooserPanel; +import io.github.taverna_extras.component.ui.preference.ComponentPreference; +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon; +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceProviderConfig; +import io.github.taverna_extras.component.ui.util.Utils; +import org.apache.taverna.lang.observer.Observable; +import org.apache.taverna.lang.observer.Observer; + +/** + * @author alanrw + */ +public class ComponentCopyAction extends AbstractAction { + private static final long serialVersionUID = -4440978712410081685L; + private static final Logger logger = getLogger(ComponentCopyAction.class); + private static final String COPY_COMPONENT = "Copy component..."; + + private final ComponentPreference prefs; + private final Utils utils; + + public ComponentCopyAction(ComponentPreference pref, ComponentServiceIcon icon, Utils utils) { + super(COPY_COMPONENT, icon.getIcon()); + this.prefs = pref; + this.utils = utils; + } + + @Override + public void actionPerformed(ActionEvent arg0) { + JPanel overallPanel = new JPanel(); + overallPanel.setLayout(new GridBagLayout()); + + GridBagConstraints gbc = new GridBagConstraints(); + + ComponentChooserPanel source = new ComponentChooserPanel(prefs); + source.setBorder(new TitledBorder("Source component")); + + gbc.insets = new Insets(0, 5, 0, 5); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.anchor = WEST; + gbc.fill = BOTH; + gbc.gridwidth = 2; + gbc.weightx = 1; + overallPanel.add(source, gbc); + + final RegistryAndFamilyChooserPanel target = new RegistryAndFamilyChooserPanel(prefs); + target.setBorder(new TitledBorder("Target family")); + gbc.gridy++; + overallPanel.add(target, gbc); + + source.addObserver(new Observer<ComponentChoiceMessage>() { + @Override + public void notify(Observable<ComponentChoiceMessage> sender, + ComponentChoiceMessage message) throws Exception { + Profile componentProfile = null; + Family componentFamily = message.getComponentFamily(); + if (componentFamily != null) + componentProfile = componentFamily.getComponentProfile(); + ProfileChoiceMessage profileMessage = new ProfileChoiceMessage( + componentProfile); + target.notify(null, profileMessage); + } + }); + + int answer = showConfirmDialog(null, overallPanel, "Copy Component", + OK_CANCEL_OPTION); + if (answer == OK_OPTION) + doCopy(source.getChosenComponent(), target.getChosenFamily()); + } + + private void doCopy(Component sourceComponent, Family targetFamily) { + if (sourceComponent == null) { + showMessageDialog(null, "Unable to determine source component", + "Component Copy Problem", ERROR_MESSAGE); + return; + } else if (targetFamily == null) { + showMessageDialog(null, "Unable to determine target family", + "Component Copy Problem", ERROR_MESSAGE); + return; + } + + try { + String componentName = sourceComponent.getName(); + boolean alreadyUsed = targetFamily.getComponent(componentName) != null; + if (alreadyUsed) + showMessageDialog(null, componentName + " is already used", + "Duplicate component name", ERROR_MESSAGE); + else { + Version targetVersion = doCopy(sourceComponent, targetFamily, + componentName); + try { + utils.refreshComponentServiceProvider(new ComponentServiceProviderConfig( + targetVersion.getID()).getConfiguration()); + } catch (Exception e) { + logger.error(e); + } + } + } catch (ComponentException e) { + logger.error("failed to copy component", e); + showMessageDialog(null, + "Unable to create component: " + e.getMessage(), + "Component Copy Problem", ERROR_MESSAGE); + } + } + + private Version doCopy(Component sourceComponent, Family targetFamily, + String componentName) throws ComponentException { + return targetFamily + .createComponentBasedOn( + componentName, + sourceComponent.getDescription(), + sourceComponent + .getComponentVersionMap() + .get(sourceComponent.getComponentVersionMap() + .lastKey()).getImplementation()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyMenuAction.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyMenuAction.java new file mode 100644 index 0000000..3c6db63 --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyMenuAction.java @@ -0,0 +1,61 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu.component; + +import java.net.URI; + +import javax.swing.Action; + +import io.github.taverna_extras.component.ui.preference.ComponentPreference; +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon; +import io.github.taverna_extras.component.ui.util.Utils; + +/** + * @author alanrw + */ +public class ComponentCopyMenuAction extends AbstractComponentMenuAction { + private static final URI COPY_COMPONENT_URI = URI + .create("http://taverna.sf.net/2008/t2workbench/menu#componentCopy"); + + private ComponentPreference prefs; + private ComponentServiceIcon icon; + private Utils utils; + + public ComponentCopyMenuAction() { + super(800, COPY_COMPONENT_URI); + } + + public void setIcon(ComponentServiceIcon icon) { + this.icon = icon; + } + + public void setPreferences(ComponentPreference prefs) {//FIXME beaninject + this.prefs = prefs; + } + + public void setUtils(Utils utils) { + this.utils = utils; + } + + @Override + protected Action createAction() { + return new ComponentCopyAction(prefs, icon, utils); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCreatorSupport.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCreatorSupport.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCreatorSupport.java new file mode 100644 index 0000000..ffe26d8 --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCreatorSupport.java @@ -0,0 +1,257 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu.component; + +import static javax.swing.JOptionPane.ERROR_MESSAGE; +import static javax.swing.JOptionPane.OK_CANCEL_OPTION; +import static javax.swing.JOptionPane.OK_OPTION; +import static javax.swing.JOptionPane.showConfirmDialog; +import static javax.swing.JOptionPane.showMessageDialog; +import static org.apache.log4j.Logger.getLogger; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import io.github.taverna_extras.component.api.Component; +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.api.ComponentFactory; +import io.github.taverna_extras.component.api.Version; +import io.github.taverna_extras.component.ui.ComponentActivityConfigurationBean; +import io.github.taverna_extras.component.ui.panel.RegistryAndFamilyChooserComponentEntryPanel; +import io.github.taverna_extras.component.ui.preference.ComponentPreference; +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceProviderConfig; +import io.github.taverna_extras.component.ui.util.Utils; + +import org.apache.taverna.scufl2.api.activity.Activity; +import org.apache.taverna.scufl2.api.container.WorkflowBundle; +import org.apache.taverna.scufl2.api.core.DataLink; +import org.apache.taverna.scufl2.api.core.Processor; +import org.apache.taverna.scufl2.api.core.Workflow; +import org.apache.taverna.scufl2.api.port.InputProcessorPort; +import org.apache.taverna.scufl2.api.port.InputWorkflowPort; +import org.apache.taverna.scufl2.api.port.OutputProcessorPort; +import org.apache.taverna.scufl2.api.port.OutputWorkflowPort; +import org.apache.taverna.workbench.edits.CompoundEdit; +import org.apache.taverna.workbench.edits.Edit; +import org.apache.taverna.workbench.edits.EditException; +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.file.FileManager; +import org.apache.taverna.workbench.file.FileType; +import org.apache.taverna.workbench.file.exceptions.SaveException; +import org.apache.taverna.workbench.selection.SelectionManager; +import org.apache.taverna.workflow.edits.AddActivityEdit; +import org.apache.taverna.workflow.edits.AddActivityInputPortMappingEdit; +import org.apache.taverna.workflow.edits.AddActivityOutputPortMappingEdit; +import org.apache.taverna.workflow.edits.AddDataLinkEdit; +import org.apache.taverna.workflow.edits.AddProcessorEdit; +import org.apache.taverna.workflow.edits.AddWorkflowInputPortEdit; +import org.apache.taverna.workflow.edits.AddWorkflowOutputPortEdit; +import org.apache.taverna.workflow.edits.RemoveActivityEdit; +import org.apache.taverna.workflow.edits.RenameEdit; +import org.apache.taverna.workflowmodel.processor.activity.NestedDataflow; +import org.apache.taverna.workflowmodel.utils.Tools; + +public class ComponentCreatorSupport { + private static final Logger logger = getLogger(ComponentCreatorSupport.class); + + private ComponentFactory factory; + private FileManager fm; + private EditManager em; + private ComponentPreference prefs; + private FileType ft; + private SelectionManager sm; + + public void setComponentFactory(ComponentFactory factory) { + this.factory = factory; + } + + public void setPreferences(ComponentPreference pref) { + this.prefs = pref; + } + + public void setFileManager(FileManager fm) { + this.fm = fm; + } + + public void setEditManager(EditManager em) { + this.em = em; + } + + public void setFileType(FileType ft) { + this.ft = ft; + } + + public void setSelectionManager(SelectionManager sm) { + this.sm = sm; + } + + public class CopiedProcessor { + Processor processor; + Map<String,Workflow> requiredSubworkflows; + } + + void moveComponentActivityIntoPlace(Activity toReplace, Processor contextProcessor, + Activity replacingActivity) throws EditException { + List<Edit<?>> editsToDo = new ArrayList<>(); + for (InputProcessorPort pip : contextProcessor.getInputPorts()) + editsToDo.add(new AddActivityInputPortMappingEdit(toReplace, pip, null/*FIXME*/)); + for (OutputProcessorPort pop : contextProcessor.getOutputPorts()) + editsToDo.add(new AddActivityOutputPortMappingEdit(toReplace, pop, null/*FIXME*/)); + editsToDo.add(new RemoveActivityEdit(contextProcessor, toReplace)); + editsToDo.add(new AddActivityEdit(contextProcessor, replacingActivity)); + em.doDataflowEdit(contextProcessor.getParent().getParent(), + new CompoundEdit(editsToDo)); + } + + void connectNewProcessor(Workflow d, Processor newProcessor) + throws EditException { + List<Edit<?>> editsToDo = new ArrayList<>(); + + for (InputProcessorPort pip : newProcessor.getInputPorts()) { + InputWorkflowPort dip = new InputWorkflowPort(d, pip.getName()); + // FIXME How to set depth? + editsToDo.add(new AddWorkflowInputPortEdit(d, dip)); + editsToDo.add(new AddDataLinkEdit(d, new DataLink(d, dip, pip))); + } + + for (OutputProcessorPort pop : newProcessor.getOutputPorts()) { + OutputWorkflowPort dop = new OutputWorkflowPort(d, pop.getName()); + // TODO How to indicate depth? + editsToDo.add(new AddWorkflowOutputPortEdit(d, dop)); + editsToDo.add(new AddDataLinkEdit(d, new DataLink(d, pop, dop))); + } + em.doDataflowEdit(d.getParent(), new CompoundEdit(editsToDo)); + } + + public ComponentActivityConfigurationBean saveWorkflowAsComponent( + WorkflowBundle d, Version.ID ident) throws SaveException, IOException, + ComponentException { + if (ident == null) + return null; + + createInitialComponent(d, ident); + + Utils.refreshComponentServiceProvider(new ComponentServiceProviderConfig( + ident)); + return new ComponentActivityConfigurationBean(ident, factory); + } + + public ComponentActivityConfigurationBean saveWorkflowAsComponent( + Workflow d, Version.ID ident) throws SaveException, IOException, + ComponentException { + WorkflowBundle b = new WorkflowBundle(); + ((Workflow)d.clone()).setParent(b); + //FIXME also must copy profile parts! + return saveWorkflowAsComponent(b, ident); + } + + Version.ID getNewComponentIdentification(String defaultName) { + RegistryAndFamilyChooserComponentEntryPanel panel = new RegistryAndFamilyChooserComponentEntryPanel(prefs); + panel.setComponentName(defaultName); + int result = showConfirmDialog(null, panel, "Component location", + OK_CANCEL_OPTION); + if (result != OK_OPTION) + return null; + + Version.ID ident = panel.getComponentVersionIdentification(); + if (ident == null) { + showMessageDialog(null, + "Not enough information to create component", + "Component creation problem", ERROR_MESSAGE); + return null; + } + + try { + Component existingComponent = factory.getComponent(ident); + if (existingComponent != null) { + showMessageDialog(null, + "Component with this name already exists", + "Component creation problem", ERROR_MESSAGE); + return null; + } + } catch (ComponentException e) { + logger.error("failed to search registry", e); + showMessageDialog(null, + "Problem searching registry: " + e.getMessage(), + "Component creation problem", ERROR_MESSAGE); + return null; + } + return ident; + } + + CopiedProcessor copyProcessor(Processor p) throws IOException { + CopiedProcessor copy = new CopiedProcessor(); + copy.processor = ProcessorXMLSerializer.getInstance().processorToXML(p); + copy.requiredSubworkflows = new HashMap<>(); + rememberSubworkflows(p, copy); + return copy; + } + + void rememberSubworkflows(Processor p, CopiedProcessor copy) { + for (Activity a : p.getActivity(sm.getSelectedProfile())) + if (a instanceof NestedDataflow) { + NestedDataflow da = (NestedDataflow) a; + Workflow df = da.getNestedDataflow(); + if (!copy.requiredSubworkflows.containsKey(df.getIdentifier())) { + copy.requiredSubworkflows.put(df.getIdentifier(), + DataflowXMLSerializer.getInstance() + .serializeDataflow(df)); + for (Processor sp : df.getProcessors()) + rememberSubworkflows(sp, copy); + } + } + } + + public Processor pasteProcessor(CopiedProcessor copy, Workflow d) + throws + ClassNotFoundException, InstantiationException, + IllegalAccessException, EditException { + Processor result = ProcessorXMLDeserializer.getInstance() + .deserializeProcessor(copy.processor, copy.requiredSubworkflows); + if (result == null) + return null; + + String newName = Tools.uniqueProcessorName(result.getName(), d); + + List<Edit<?>> editList = new ArrayList<>(); + if (!newName.equals(result.getName())) + editList.add(new RenameEdit<>(result, newName)); + editList.add(new AddProcessorEdit(d, result)); + em.doDataflowEdit(d.getParent(), new CompoundEdit(editList)); + + return result; + } + + public Version.ID createInitialComponent(WorkflowBundle d, Version.ID ident) + throws ComponentException { + try { + fm.saveDataflow(d, ft, ident, false); + + em.doDataflowEdit(d, new RenameEdit<>(d, d.getName())); + } catch (SaveException | IllegalStateException | EditException e) { + throw new ComponentException(e); + } + return ident; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteAction.java ---------------------------------------------------------------------- diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteAction.java new file mode 100644 index 0000000..72141c9 --- /dev/null +++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteAction.java @@ -0,0 +1,143 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 io.github.taverna_extras.component.ui.menu.component; + +import static java.lang.String.format; +import static javax.swing.JOptionPane.ERROR_MESSAGE; +import static javax.swing.JOptionPane.OK_CANCEL_OPTION; +import static javax.swing.JOptionPane.OK_OPTION; +import static javax.swing.JOptionPane.YES_NO_OPTION; +import static javax.swing.JOptionPane.YES_OPTION; +import static javax.swing.JOptionPane.showConfirmDialog; +import static javax.swing.JOptionPane.showMessageDialog; +import static org.apache.log4j.Logger.getLogger; + +import java.awt.event.ActionEvent; +import java.util.concurrent.ExecutionException; + +import javax.swing.AbstractAction; +import javax.swing.SwingWorker; + +import org.apache.log4j.Logger; +import io.github.taverna_extras.component.api.Component; +import io.github.taverna_extras.component.api.ComponentException; +import io.github.taverna_extras.component.api.Version; +import io.github.taverna_extras.component.ui.panel.ComponentChooserPanel; +import io.github.taverna_extras.component.ui.preference.ComponentPreference; +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon; +import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceProviderConfig; +import io.github.taverna_extras.component.ui.util.Utils; + +import org.apache.taverna.scufl2.api.configurations.Configuration; +import org.apache.taverna.scufl2.api.container.WorkflowBundle; +import org.apache.taverna.workbench.file.FileManager; + +/** + * @author alanrw + */ +public class ComponentDeleteAction extends AbstractAction { + private static final String COMPONENT_PROBLEM_TITLE = "Component Problem"; + private static final String CONFIRM_MSG = "Are you sure you want to delete %s?"; + private static final String CONFIRM_TITLE = "Delete Component Confirmation"; + private static final String DELETE_COMPONENT_LABEL = "Delete component..."; + private static final String DELETE_FAILED_TITLE = "Component Deletion Error"; + private static final String FAILED_MSG = "Unable to delete %s: %s"; + private static final String OPEN_COMPONENT_MSG = "The component is open"; + private static final String TITLE = "Component choice"; + private static final String WHAT_COMPONENT_MSG = "Unable to determine component"; + private static final long serialVersionUID = -2992743162132614936L; + private static final Logger logger = getLogger(ComponentDeleteAction.class); + + private final FileManager fm; + private final ComponentPreference prefs; + private final Utils utils; + + public ComponentDeleteAction(FileManager fm, ComponentPreference prefs, + ComponentServiceIcon icon, Utils utils) { + super(DELETE_COMPONENT_LABEL, icon.getIcon()); + this.fm = fm; + this.prefs = prefs; + this.utils = utils; + } + + @Override + public void actionPerformed(ActionEvent evt) { + ComponentChooserPanel panel = new ComponentChooserPanel(prefs); + int answer = showConfirmDialog(null, panel, TITLE, OK_CANCEL_OPTION); + if (answer == OK_OPTION) + doDelete(panel.getChosenComponent()); + } + + private void doDelete(final Component chosenComponent) { + if (chosenComponent == null) { + showMessageDialog(null, WHAT_COMPONENT_MSG, + COMPONENT_PROBLEM_TITLE, ERROR_MESSAGE); + } else if (componentIsInUse(chosenComponent)) { + showMessageDialog(null, OPEN_COMPONENT_MSG, + COMPONENT_PROBLEM_TITLE, ERROR_MESSAGE); + } else if (showConfirmDialog(null, + format(CONFIRM_MSG, chosenComponent.getName()), CONFIRM_TITLE, + YES_NO_OPTION) == YES_OPTION) + new SwingWorker<Configuration, Object>() { + @Override + protected Configuration doInBackground() throws Exception { + return deleteComponent(chosenComponent); + } + + @Override + protected void done() { + refresh(chosenComponent, this); + } + }.execute(); + } + + private Configuration deleteComponent(Component component) + throws ComponentException { + ComponentServiceProviderConfig config = new ComponentServiceProviderConfig( + component.getFamily()); + component.delete(); + return config.getConfiguration(); + } + + protected void refresh(Component component, + SwingWorker<Configuration, Object> worker) { + try { + utils.refreshComponentServiceProvider(worker.get()); + } catch (ExecutionException e) { + logger.error("failed to delete component", e.getCause()); + showMessageDialog( + null, + format(FAILED_MSG, component.getName(), e.getCause() + .getMessage()), DELETE_FAILED_TITLE, ERROR_MESSAGE); + } catch (InterruptedException e) { + logger.warn("interrupted during component deletion", e); + } + } + + private boolean componentIsInUse(Component component) { + for (WorkflowBundle d : fm.getOpenDataflows()) { + Object dataflowSource = fm.getDataflowSource(d); + if (dataflowSource instanceof Version.ID + && ((Version.ID) dataflowSource).mostlyEqualTo(component)) + return true; + } + return false; + } +}
