Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [ice-dev] [triquetrum-dev] ice-triquetrum fork

Hi Jay, ICE team,

I'm trying to implement a "2-step"-form on an ICE Item, as explained below. I.e. :
1. the user should get a list of available workflows (the list is now mocked with 2 painfully simple in-memory constructed model instances)
2. the user picks one model and then
3. the Item form should be replaced/extended with a form that shows dynamically generated workflow configuration entries
(based on the parameters that the workflow has defined in its model)
4. the user can optionally change parameter values and then launch the workflow

So I'm trying to add a datacomponent with on-the-fly generation of a variable set of form entries after giving the user the opportunity to pick a workflow.
But I can not get this working, although I think I'm close...

It seems the form and the included datacomponents of an item must be created in setupForm() that is already invoked during the base-class constructor invocation?
And that it should be possible to add entries to one of those datacomponents dynamically later on?
I've tried that, cfr attached source. Is someone able to review that?

I also hit an NPE, e.g. when trying to save the form after selecting a workflow or when clicking Go! for an incomplete form and then returning a FormStatus.NeedsInfo from inside process().

It seems the Item base class has an action property that is null. Do I need to set that one at some point? I could not see that being done in those examples though...

E.g. when saving :




!ENTRY org.eclipse.ui 2 0 2016-02-25 22:13:38.071
!MESSAGE Save Failed
!STACK 0
java.lang.NullPointerException
    at org.eclipse.ice.item.Item.getForm(Item.java:795)
    at org.eclipse.ice.core.internal.itemmanager.ItemManager.retrieveItem(ItemManager.java:315)
    at org.eclipse.ice.core.internal.Core.getItem(Core.java:448)
    at org.eclipse.ice.client.internal.Client.formUpdated(Client.java:607)
    at org.eclipse.ice.client.widgets.ICEFormEditor.notifyUpdateListeners(ICEFormEditor.java:1069)
    at org.eclipse.ice.client.widgets.ICEFormEditor.doSave(ICEFormEditor.java:710)
    at org.eclipse.ui.internal.SaveableHelper$2.run(SaveableHelper.java:156)
    at org.eclipse.ui.internal.SaveableHelper$5.run(SaveableHelper.java:285)
    at org.eclipse.jface.operation.ModalContext.runInCurrentThread(ModalContext.java:463)
    at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:371)
    at org.eclipse.ui.internal.WorkbenchWindow$14.run(WorkbenchWindow.java:2156)
    at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
    at org.eclipse.ui.internal.WorkbenchWindow.run(WorkbenchWindow.java:2152)
    at org.eclipse.ui.internal.SaveableHelper.runProgressMonitorOperation(SaveableHelper.java:293)
    at org.eclipse.ui.internal.SaveableHelper.runProgressMonitorOperation(SaveableHelper.java:271)
    at org.eclipse.ui.internal.SaveableHelper.savePart(SaveableHelper.java:161)
    at org.eclipse.ui.internal.WorkbenchPage.saveSaveable(WorkbenchPage.java:3874)
    at org.eclipse.ui.internal.WorkbenchPage.saveEditor(WorkbenchPage.java:3888)


And when trying to Go! :

Exception in thread "Thread-73" java.lang.NullPointerException
    at org.eclipse.ice.item.Item.getForm(Item.java:795)
    at org.eclipse.ice.core.internal.itemmanager.ItemManager.retrieveItem(ItemManager.java:315)
    at org.eclipse.ice.core.internal.Core.getItem(Core.java:448)
    at org.eclipse.ice.client.internal.ItemProcessor.run(ItemProcessor.java:473)
    at java.lang.Thread.run(Thread.java:745)


regards
erwin
Op 25/02/2016 om 18:26 schreef Jay Jay Billings:
Ah. I see. There are several ways you could do that. One way is to use our MasterDetailsComponent, but that can be pretty complicated to get working. It would give you a really nice Master-Details pair view of the list of workflows and the parameters. 
Personally, I would just keep it simple. You can create a second DataComponent in setupForm() that shows the parameters for the workflow. Leave it empty or fill it with common, default values to start. Then, override reviewEntries() and once they pick the workflow and hit 'Save' you can just add/overwrite entries in the second DataComponent. This is what we do most of the time for problems like this and it is very scalable. 
Nek5000 is a good example of this, which you can see if you check out org.eclipse.ice.nek5000.Nek5000Model.java:250. In this case, users pick which example problem they want to run in a data component on the left, and the remaining data components (of which there are 5-10) are repopulated based on that choice. 
Jay
On Thu, Feb 25, 2016 at 12:17 PM, Erwin de Ley <erwin.de.ley@xxxxxxxxxx> wrote:
OK, but what should I do to add a second step/form in the specification of the Item, before launching the workflow? I.e. step/form 1 would show a list of available workflows. Then the user selects 1 and then I would want to show a second form that shows the parameters available for that particular workflow. Then the user sets some values and launches the workflow. erwin
Op 25/02/2016 om 17:39 schreef Jay Jay Billings:
Erwin,
Great!
The simplest way that you can get the list to update is to just update the Entry on the Form. The Entry will post an update that will be used to notify the UI. You can do that asynchronously or override submitForm().
Jay
On Thu, Feb 25, 2016 at 10:23 AM, erwindl0 <erwindl0@xxxxxxxxx> wrote:
Jay, The first basic step is done and working locally. I have added the necessary Triquetrum features to the ICE mars.target, and added minimal code to what you prepared to launch a trivial (fixed) workflow from the TriquetrumWorkflowItemModel. Next steps : 1. add a simple implementation of triquetrum's WorkflowRepositoryService. (done) 2. then the workflow editor can save models in there and... 3. the Triq...Item can browse the repo and provide a selection to the user in its form 4. ideally I would like to be able to dynamically redefine & rerender the form, based on available settable parameters in the selected workflow. I guess I can get that done by returning a NeedsInfo FormStatus after the first step? I.e. can an ICE Item iterate through completely different form definitions? Is there an example available for that? 5. then I can read the user-defined parameter values and launch the parameterized workflow 6. get that working for you as well : this would imply that you can also use the extended target. Whereas the Triq features now refer to a local feature export location on my machine, that would mean that I should have a Triquetrum p2 available for you. So ICE #128 will be really timely for that! regards erwin Op 24/02/2016 om 14:47 schreef Jay Jay Billings:

Erwin,

You can just push back to my fork. This is just a demo for EclipseCon, so we can commit it however we want.

I still need to add you as a collaborator on the fork. What is your github username again? (Hard for me to look up while sitting in a traffic jam. ;))

Jay

On Feb 24, 2016 8:39 AM, "erwindl0" <erwindl0@xxxxxxxxx> wrote:
Thanks Jay. So I assume that I just clone from your fork, create some triquetrum branch from the next branch, and then push my commits there? Or do I fork again myself and then do pull requests to your repo? cheers erwin Op 23/02/2016 om 23:07 schreef Jay Jay Billings:
Erwin and Christopher,
CC'ed ice-dev for completeness.
I started putting together a plugin for ICE that will run Triquetrum workflows. It was easiest to do this with a fork of the main ICE repo so that I can give Erwin commit privileges to push his changes back.
The way that I am doing this for now is to create an ICE plugin using our project generator. This will be sufficient to demonstrate for the talk that ICE and Triquetrum can talk to each other. However, it is not the way that I want to do it long term. The really sustainable way to do this will leverage some upcoming workflow engine updates that we are working on which will make it possible to create compositions of whole workflow engines.
Here are the instructions to get the fork and run ICE from it:
1.) Create an empty workspace
3.) Switch to the next branch and import all projects
4.) Go to org.eclipse.ice.target.mars and set mars.target as your target (unless you are doing this with ICE, which already has all of the required bundles set).
5.) Go to the org.eclipse.ice.repository project and right-click and run the launch configuration product.* for your OS. If you are using Windows or Mac, you will need to add org.eclipse.ice.triquetrum to that configuration.
6.) Go to the ICE perspective and in the ItemViewer at the left create the Triquetrum Item by clicking on the green plus button. The Triquetrum Item is currently at the bottom of the list that appears with an ugly name at the moment. (See attached picture.)
You can edit the code for Triquetrum by modifying the contents of the org.eclipse.ice.triquetrum bundle. I suggest that we do everything in the Model Item for the moment and don't mess with the launcher (no need really).
I think the way that this should work is that someone creates a workflow in Triquetrum with the graphical tools. Then, they open this Triquetrum model in ICE and they have a list of Triquetrum workflows from which they can choose. Once they pick one, the can choose something like "Launch Triquetrum Workflow" from the process bar at the top, hit Go! and the process() operation executes the workflow.
I have attached a data file that contains reflectivity data. The x axis is the angle Q and the y axis is the specular reflectivity. I don't know the units off-hand.
This is all I have time to do with this today and probably until Friday, but I should still be able to answer questions. If you can get ICE calling Triquetrum from TriquetrumWorkflowItemModel.setupForm(), then the rest should be very easy.
Jay
--
Jay Jay Billings
Oak Ridge National Laboratory
Twitter Handle: @jayjaybillings
_______________________________________________
triquetrum-dev mailing list
triquetrum-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/triquetrum-dev
--
Jay Jay Billings
Oak Ridge National Laboratory
Twitter Handle: @jayjaybillings
_______________________________________________
triquetrum-dev mailing list
triquetrum-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/triquetrum-dev
_______________________________________________ triquetrum-dev mailing list triquetrum-dev@xxxxxxxxxxx To change your delivery options, retrieve your password, or unsubscribe from this list, visit https://dev.eclipse.org/mailman/listinfo/triquetrum-dev
--
Jay Jay Billings
Oak Ridge National Laboratory
Twitter Handle: @jayjaybillings
_______________________________________________
triquetrum-dev mailing list
triquetrum-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/triquetrum-dev
package org.eclipse.ice.triquetrum.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.annotation.XmlRootElement;

import org.eclipse.core.resources.IProject;
import org.eclipse.ice.datastructures.entry.DiscreteEntry;
import org.eclipse.ice.datastructures.entry.IEntry;
import org.eclipse.ice.datastructures.entry.StringEntry;
import org.eclipse.ice.datastructures.form.DataComponent;
import org.eclipse.ice.datastructures.form.Form;
import org.eclipse.ice.datastructures.form.FormStatus;
import org.eclipse.ice.item.model.Model;
import org.eclipse.ice.triquetrum.WorkflowServiceTracker;
import org.eclipse.triquetrum.workflow.ModelHandle;
import org.eclipse.triquetrum.workflow.WorkflowExecutionService;
import org.eclipse.triquetrum.workflow.WorkflowExecutionService.StartMode;

import ptolemy.actor.CompositeActor;
import ptolemy.actor.TypedCompositeActor;
import ptolemy.actor.lib.Const;
import ptolemy.actor.lib.gui.Display;
import ptolemy.data.expr.Parameter;
import ptolemy.data.expr.StringParameter;
import ptolemy.domains.sdf.kernel.SDFDirector;

@XmlRootElement(name = "TriquetrumWorkflowItemModel")
public class TriquetrumWorkflowItemModel extends Model {

  private static final String AVAILABLE_WORKFLOWS = "Available workflows";
  private Map<String, CompositeActor> models;
  private DiscreteEntry workflowSelectionEntry;
  private DataComponent workflowCfgComp;

  private boolean workflowSelected = false;

  public TriquetrumWorkflowItemModel() {
    this(null);
  }

  public TriquetrumWorkflowItemModel(IProject project) {
    // Setup the form and everything
    super(project);
  }

  @Override
  public void setupForm() {
    if (form == null) {
      allowedActions = new ArrayList<String>();
      allowedActions.add("Launch the Workflow");

      form = new Form();
      form.setActionList(allowedActions);
      models = new HashMap<>();
      try {
        models.put("hello", buildTrivialCompositeActor("hello"));
        models.put("goodbye", buildTrivialCompositeActor("goodbye"));
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }

    // Create a data component for the workflow selection
    DataComponent workflowSelectionComp = new DataComponent();
    // not sure what this ID is for? I can not seem to find getters by ID on
    // the form or other ways in which the ID is used?
    workflowSelectionComp.setId(1);
    workflowSelectionComp.setName("Triquetrum Info");
    workflowSelectionComp.setDescription("Select a Triquetrum workflow from the list");

    workflowSelectionEntry = new DiscreteEntry();
    workflowSelectionEntry.setName(AVAILABLE_WORKFLOWS);
    workflowSelectionEntry.setAllowedValues(new ArrayList<String>(models.keySet()));
    workflowSelectionComp.addEntry(workflowSelectionEntry);
    form.addComponent(workflowSelectionComp);

     // Create a data component for configuring a selected workflow
     workflowCfgComp = new DataComponent();
     workflowCfgComp.setId(2);
     workflowCfgComp.setDescription("Configure the selected workflow");
     form.addComponent(workflowCfgComp);

    return;
  }

  @Override
  public void setupFormWithServices() {
    // TODO use workflow repository service here?
    super.setupFormWithServices();
  }

  @Override
  protected void setupItemInfo() {
    setName("Triquetrum workflow Model");
    setDescription("An item to launch a Triquetrum workflow");
  }

  @Override
  protected FormStatus reviewEntries(Form preparedForm) {

    String selectedWorkflowName = workflowSelectionEntry.getValue();

    if (selectedWorkflowName == null) {
      return FormStatus.NeedsInfo;
    } else if (!workflowSelected) {
      CompositeActor selectedWorkflow = models.get(selectedWorkflowName);
      // Create a data component for configuring a selected workflow
//      workflowCfgComp = new DataComponent();
//      workflowCfgComp.setId(2);
//      workflowCfgComp.setDescription("Configure the selected workflow");
//      form.addComponent(workflowCfgComp);

      for (Parameter p : selectedWorkflow.attributeList(Parameter.class)) {
        StringEntry newEntry = new StringEntry();
        newEntry.setName(p.getName());
        newEntry.setDefaultValue(p.getExpression());
        workflowCfgComp.addEntry(newEntry);
      }
      workflowSelected = true;
      return FormStatus.NeedsInfo;
    } else {
      // the workflow parameterization is optional, so we just check that the cfg panel was shown at least.
      // and if so, we're ready to process!
      return FormStatus.ReadyToProcess;
    }
  }

  @Override
  public FormStatus process(String actionName) {

    // Not sure if this might break something in ICE,
    // but I'd like to make sure that review is always done,
    // also when the user did not save the form.
    // Using getForm generates an NPE here, so let's try with using form directly.
    FormStatus processStatus = reviewEntries(form);

    if (FormStatus.ReadyToProcess.equals(processStatus)) {
      String selectedWorkflowName = workflowSelectionEntry.getValue();

      CompositeActor selectedWorkflow = models.get(selectedWorkflowName);
      try {
        WorkflowExecutionService workflowExecutionService = WorkflowServiceTracker.getWorkflowExecutionService();
        if (workflowExecutionService != null) {
          workflowExecutionService.start(StartMode.RUN, selectedWorkflow, null, getParameterOverrides(), null);
        } else {
          // figure out how to return error msgs to ICE
          // seems there's no FormStatus.ProcessError or so...
          System.err.println("No active WorkflowExecutionService found...");
        }
        status = FormStatus.Processed;
      } catch (Exception e) {
        e.printStackTrace();
        status = FormStatus.Processed;
      }

    } else {
      status = processStatus;
    }
    return status;
  }

  @Override
  public void loadInput(String name) {

    // Implement this if you want to enable imports for this Item

    // TODO: Add User Code Here
  }

  private Map<String, String> getParameterOverrides() {
    Map<String,String> parameterOverrides = new HashMap<>();

    for(IEntry entry : workflowCfgComp.retrieveAllEntries()) {
      if(entry.isModified()) {
        parameterOverrides.put(entry.getName(), entry.getValue());
      }
    }
    return parameterOverrides;
  }

  private CompositeActor buildTrivialCompositeActor(String wfName) throws Exception {
    CompositeActor compositeActor = new TypedCompositeActor();
    compositeActor.setName(wfName);
    compositeActor.setDirector(new SDFDirector(compositeActor, "director"));
    new StringParameter(compositeActor, "msg").setExpression(wfName);
    ;
    Const source = new Const(compositeActor, "const");
    Display sink = new Display(compositeActor, "sink");
    compositeActor.connect(source.output, sink.input);
    return compositeActor;
  }
}


Back to the top