JAL-715 dialog for interactively editing a new or existing rest service
authorjprocter <jprocter@compbio.dundee.ac.uk>
Wed, 24 Aug 2011 14:43:08 +0000 (15:43 +0100)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Wed, 24 Aug 2011 14:43:08 +0000 (15:43 +0100)
src/jalview/gui/RestServiceEditorPane.java [new file with mode: 0644]
src/jalview/jbgui/GRestServiceEditorPane.java [new file with mode: 0644]

diff --git a/src/jalview/gui/RestServiceEditorPane.java b/src/jalview/gui/RestServiceEditorPane.java
new file mode 100644 (file)
index 0000000..4572f6f
--- /dev/null
@@ -0,0 +1,320 @@
+package jalview.gui;
+
+import jalview.bin.Cache;
+import jalview.io.packed.DataProvider.JvDataType;
+import jalview.jbgui.*;
+import jalview.ws.rest.InputType;
+import jalview.ws.rest.RestServiceDescription;
+
+import java.awt.*;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.ContainerEvent;
+import java.awt.event.ContainerListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.event.WindowStateListener;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.*;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.GapContent;
+
+import org.apache.log4j.lf5.LogLevel;
+
+public class RestServiceEditorPane extends GRestServiceEditorPane
+{
+  /**
+   * the latest version of the service definition.
+   */
+  jalview.ws.rest.RestServiceDescription currentservice = null;
+
+  /**
+   * original service passed to editor if we are modifying an existing service
+   * definition
+   */
+  jalview.ws.rest.RestServiceDescription oldservice = null;
+
+  public RestServiceEditorPane()
+  {
+    super();
+    // begin with initial text description box enabled.
+    urldesc.addKeyListener(new KeyListener()
+    {
+      long lastWait;
+      boolean doUpdate;
+      Thread updater=null;
+      @Override
+      public void keyTyped(KeyEvent e)
+      {
+        refreshCutnPaste(true);
+      }
+      
+      @Override
+      public void keyReleased(KeyEvent e)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+      
+      @Override
+      public void keyPressed(KeyEvent e)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+    });
+    paste.addComponentListener(new ComponentListener()
+    {
+      
+      @Override
+      public void componentShown(ComponentEvent e)
+      {
+        updateServiceFromGui();
+        refreshCutnPaste(false);
+        
+      }
+      
+      @Override
+      public void componentResized(ComponentEvent e)
+      {        
+      }
+      
+      @Override
+      public void componentMoved(ComponentEvent e)
+      {
+        
+      }
+      
+      @Override
+      public void componentHidden(ComponentEvent e)
+      {
+        // TODO Auto-generated method stub
+        
+      }
+    });
+  }
+
+  public RestServiceEditorPane(RestServiceDescription toedit)
+  {
+    this();
+    oldservice = toedit;
+    currentservice = new RestServiceDescription(toedit);
+    initGuiWith(currentservice);
+    refreshCutnPaste(false);
+    updateButtons();
+  }
+
+  /**
+   * refresh the buttons based on model state
+   */
+  public void updateButtons()
+  {
+    cancelButton.setEnabled(oldservice != null);
+    okButton.setEnabled(currentservice != null && currentservice.isValid());
+
+  }
+
+  Vector<String> _iparam = new Vector<String>();
+
+  Vector<String> _rparam = new Vector<String>();
+
+  /**
+   * generate an editable URL service string and parameter list using the
+   * service
+   * 
+   * @param currentservice2
+   */
+  private void initGuiWith(RestServiceDescription currentservice)
+  {
+    name.setText(currentservice.getName());
+    descr.setText(currentservice.getDescription());
+    url.setText(currentservice.getPostUrl());
+    urlsuff.setText(currentservice.getUrlSuffix());
+    _iparam.clear();
+    _rparam.clear();
+    for (Map.Entry<String, InputType> inparam : currentservice
+            .getInputParams().entrySet())
+    {
+      _iparam.add(inparam.getKey() + " "
+              + inparam.getValue().getURLtokenPrefix() + ":"
+              + inparam.getValue().getURLEncodedParameter().toString());
+    }
+    for (JvDataType oparam : currentservice.getResultDataTypes())
+    {
+      _rparam.add((oparam.name()));
+    }
+    iprms.setListData(_iparam);
+    rdata.setListData(_rparam);
+
+    action.removeAllItems();
+    action.addItem("Alignment");
+    action.addItem("Analysis");
+    // action.addItem("Analysis");
+    action.setSelectedItem(currentservice.getAction());
+    revalidate();
+  }
+
+  private boolean updateServiceFromGui() {
+    boolean valid=true;
+    Map<String,InputType>inputTypes = new HashMap<String, InputType>();
+    StringBuffer warnings=new StringBuffer();
+    for (String its:_iparam)
+    {
+      Matcher mtch = Pattern.compile("(\\S+)\\s(\\S+):\\[(.+)]").matcher(its);
+      if (mtch.find()) {
+        if (!RestServiceDescription.parseTypeString(mtch.group(2)+":"+mtch.group(3), mtch.group(1), mtch.group(2),mtch.group(3), inputTypes, warnings))
+        {
+          System.err.println("IMPLEMENTATION PROBLEM: Cannot parse RestService input parameter string '"+its+"'"+"\n"+warnings);
+        }        
+      }
+    }
+    char gc = gapChar.getSelectedItem()==null ? ' ' : ((String)gapChar.getSelectedItem()).charAt(0);
+    RestServiceDescription newService = new RestServiceDescription((String) action.getSelectedItem(),
+          descr.getText().trim(), name.getText().trim(), url.getText().trim(), urlsuff.getText().trim(), inputTypes, hSeparable.isSelected(), vSeparable.isSelected(), gc);
+            
+    if (newService.isValid())
+    {
+      for (String its:_rparam)
+      {
+        JvDataType dtype;
+        try {
+          dtype = JvDataType.valueOf(its);
+          newService.addResultDatatype(dtype);
+        }
+        catch (Throwable x)
+        {
+
+          System.err.println("IMPLEMENTATION PROBLEM: Cannot parse RestService output parameter string '"+its+"'"+"\n"+warnings);
+        }
+      }
+      currentservice = newService;
+      return true;
+    } else {
+      System.err.println("IMPLEMENTATION PROBLEM: Restservice generated from GUI is invalid\n"+warnings);
+
+    }
+    return false;
+  }
+  protected void refreshCutnPaste(boolean reparse)
+  {
+    if (!reparse && currentservice.isValid())
+    {
+      urldesc.setText(currentservice.toString());
+      parseWarnings.setVisible(false);
+    }
+    else
+    {
+      if (reparse)
+      {
+        String txt = urldesc.getText().trim();
+        StringBuffer warnings;
+        if (txt.length() > 0)
+        {
+          RestServiceDescription rsd = null;
+          try
+          {
+            rsd = new RestServiceDescription(txt);
+            if (rsd.isValid())
+            {
+              parseWarnings.setVisible(false);
+              initGuiWith(currentservice=rsd);
+            }
+            else
+            {
+              parseRes.setText("Parsing failed. Syntax errors shown below\n"
+                      + rsd.getInvalidMessage());
+              parseWarnings.setVisible(true);
+            }
+          } catch (Throwable e)
+          {
+            parseRes.setText("\nParsing failed. An unrecoverable exception was thrown:\n"
+                    + e.toString());
+            parseWarnings.setVisible(true);
+          }
+        }
+      }
+    }
+
+  }
+
+  public static void main(String[] args)
+  {
+    if (args.length == 0)
+    {
+      new Thread(new Runnable()
+      {
+        boolean visible = true;
+
+        public void run()
+        {
+          while (visible)
+          {
+            final Thread runner = Thread.currentThread();
+            JFrame df = new JFrame();
+            df.getContentPane().setLayout(new BorderLayout());
+            df.getContentPane().add(
+                    new RestServiceEditorPane(jalview.ws.rest.RestClient
+                            .makeShmmrRestClient().getRestDescription()),
+                    BorderLayout.CENTER);
+            df.setBounds(100, 100, 400, 600);
+            df.addComponentListener(new ComponentListener()
+            {
+
+              @Override
+              public void componentShown(ComponentEvent e)
+              {
+                // TODO Auto-generated method stub
+
+              }
+
+              @Override
+              public void componentResized(ComponentEvent e)
+              {
+                // TODO Auto-generated method stub
+
+              }
+
+              @Override
+              public void componentMoved(ComponentEvent e)
+              {
+                // TODO Auto-generated method stub
+
+              }
+
+              @Override
+              public void componentHidden(ComponentEvent e)
+              {
+                visible = false;
+                runner.interrupt();
+
+              }
+            });
+            df.setVisible(true);
+            while (visible)
+            {
+              try
+              {
+                Thread.sleep(10000);
+              } catch (Exception x)
+              {
+              }
+              ;
+            }
+            visible = true;
+          }
+        }
+      }).start();
+
+    }
+  }
+}
diff --git a/src/jalview/jbgui/GRestServiceEditorPane.java b/src/jalview/jbgui/GRestServiceEditorPane.java
new file mode 100644 (file)
index 0000000..74b1463
--- /dev/null
@@ -0,0 +1,394 @@
+package jalview.jbgui;
+
+import jalview.gui.JvSwingUtils;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextArea;
+import javax.swing.JViewport;
+import javax.swing.UIManager;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import net.miginfocom.swing.MigLayout;
+
+public class GRestServiceEditorPane extends JPanel {
+
+  protected JTabbedPane panels;
+
+  protected JPanel details, inputs, paste;
+
+  protected JTextArea urldesc, url, urlsuff, name, descr, parseRes;
+
+  protected JComboBox action, gapChar;
+
+  JLabel acttype;
+
+  protected JButton okButton;
+
+  protected JButton cancelButton;
+
+  JPanel svcattribs;
+
+  JPanel status;
+
+  protected JList iprms;
+
+  protected JList rdata;
+
+  JScrollPane iprmVp, rdataVp, parseResVp, urlVp, descrVp, urldescVp;
+
+  JButton rdataAdd, rdataRem, rdataNdown, rdataNup;
+
+  JButton iprmsAdd, iprmsRem;
+
+  protected JCheckBox hSeparable;
+
+  protected JCheckBox vSeparable;
+
+  protected JPanel parseWarnings;
+
+  public GRestServiceEditorPane()
+  {
+    jbInit();
+  }
+
+  protected void jbInit()
+  {
+    details = new JPanel();
+    details.setName("Details");
+    details.setLayout(new MigLayout());
+    inputs = new JPanel();
+    inputs.setName("Input/Output");
+    inputs.setLayout(new MigLayout("","[grow 85,fill][]",""));
+    paste = new JPanel();
+    paste.setName("Cut'n'Paste");
+    paste.setLayout(new MigLayout());
+
+    panels = new JTabbedPane();
+    panels.addTab(details.getName(), details);
+    panels.addTab(inputs.getName(), inputs);
+    panels.addTab(paste.getName(), paste);
+
+    JPanel cpanel;
+
+    // Name and URL Panel
+    cpanel = details;
+    name = new JTextArea(1, 12);
+
+    JvSwingUtils
+            .mgAddtoLayout(cpanel, "Short descriptive name for service",
+                    new JLabel("Name:"), name,"wrap");
+    action = new JComboBox();
+    JvSwingUtils
+            .mgAddtoLayout(
+                    cpanel,
+                    "What kind of function the service performs (e.g. alignment, analysis, search, etc).",
+                    new JLabel("Service Action:"), action,"wrap");
+    descr = new JTextArea(4, 40);
+    descrVp = new JScrollPane();
+    descrVp.setViewportView(descr);
+    JvSwingUtils.mgAddtoLayout(cpanel, "Brief description of service",
+            new JLabel("Description:"), descrVp,"wrap");
+
+    url = new JTextArea(2, 20);
+    urlVp = new JScrollPane();
+    urlVp.setViewportView(url);
+    JvSwingUtils
+            .mgAddtoLayout(
+                    cpanel,
+                    "URL to post data to service. Include any special parameters needed here",
+                    new JLabel("POST URL:"), urlVp,"wrap");
+
+    urlsuff = new JTextArea();
+    urlsuff.setColumns(20);
+
+    JvSwingUtils
+            .mgAddtoLayout(
+                    cpanel,
+                    "Optional suffix added to URL when retrieving results from service",
+                    new JLabel("URL Suffix:"), urlsuff,"wrap");
+
+    // input options
+    // details.add(cpanel = new JPanel(), BorderLayout.CENTER);
+    // cpanel.setLayout(new FlowLayout());
+    hSeparable = new JCheckBox("per Sequence");
+    hSeparable
+            .setToolTipText("<html>"
+                    + JvSwingUtils
+                            .wrapTooltip("When checked, a job is created for every sequence in the current selection.")
+                    + "<html>");
+    hSeparable.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent arg0)
+      {
+        hSeparable_actionPerformed(arg0);
+
+      }
+    });
+    vSeparable = new JCheckBox("Results are vertically separable");
+    vSeparable
+            .setToolTipText("<html>"
+                    + JvSwingUtils
+                            .wrapTooltip("When checked, a single job is created for the visible region and results"
+                                    + " mapped back onto their location in the alignment. Otherwise, a job would be"
+                                    + " created for every contiguous region visible in the alignment or current"
+                                    + " selection (e.g. a multiple alignment).")
+                    + "</html>");
+    vSeparable.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent arg0)
+      {
+        vSeparable_actionPerformed(arg0);
+
+      }
+    });
+    gapChar = new JComboBox();
+    JvSwingUtils
+            .mgAddtoLayout(
+                    cpanel,
+                    "Which gap character does this service prefer ?",
+                    new JLabel("Gap Character:"), gapChar,"wrap");
+    
+
+    cpanel.add(hSeparable);
+    cpanel.add(vSeparable);
+
+    // Input and Output lists
+    // Inputparams
+    JPanel iprmsList = new JPanel();
+    iprmsList.setBorder(new TitledBorder("Data input parameters"));
+    iprmsList.setLayout(new MigLayout());
+    iprmVp = new JScrollPane();
+    iprmVp.getViewport().setView(iprms = new JList());
+    iprmsList.add(iprmVp);
+    JPanel iprmButs = new JPanel();
+    iprmButs.setLayout(new MigLayout());
+
+    iprmsAdd = JvSwingUtils.makeButton("+", "Add input parameter",
+            new ActionListener()
+            {
+
+              @Override
+              public void actionPerformed(ActionEvent e)
+              {
+                iprmsAdd_actionPerformed(e);
+
+              }
+            });
+    iprmsRem = JvSwingUtils.makeButton("-",
+            "Remove selected input parameter", new ActionListener()
+            {
+
+              @Override
+              public void actionPerformed(ActionEvent e)
+              {
+                iprmsRem_actionPerformed(e);
+
+              }
+            });
+
+    iprmButs.add(iprmsAdd,"wrap");
+    iprmButs.add(iprmsRem,"wrap");
+    iprmsList.add(iprmButs, "wrap");
+    inputs.add(iprmsList, "wrap");
+
+    // Return Parameters
+    
+    rdataAdd = JvSwingUtils.makeButton("+", "Add return datatype",
+            new ActionListener()
+            {
+
+              @Override
+              public void actionPerformed(ActionEvent e)
+              {
+                rdataAdd_actionPerformed(e);
+
+              }
+            });
+    rdataRem = JvSwingUtils.makeButton("-", "Remove return datatype",
+            new ActionListener()
+            {
+
+              @Override
+              public void actionPerformed(ActionEvent e)
+              {
+                rdataRem_actionPerformed(e);
+
+              }
+            });
+    rdataNup = JvSwingUtils.makeButton("Move Up",
+            "Move return type up order", new ActionListener()
+            {
+
+              @Override
+              public void actionPerformed(ActionEvent e)
+              {
+                rdataNup_actionPerformed(e);
+
+              }
+            });
+    rdataNdown = JvSwingUtils.makeButton("Move Down",
+            "Move return type down order", new ActionListener()
+            {
+
+              @Override
+              public void actionPerformed(ActionEvent e)
+              {
+                rdataNdown_actionPerformed(e);
+
+              }
+            });
+
+    JPanel rparamList = new JPanel();
+    rparamList.setBorder(new TitledBorder("Data returned by service"));
+    rparamList.setLayout(new MigLayout());
+    rdata = new JList();
+    rdataVp = new JScrollPane();
+    rdataVp.getViewport().setView(rdata);
+    rparamList.add(rdataVp);
+    JPanel rparamButs = new JPanel();
+    rparamButs.setLayout(new MigLayout());
+    rparamButs.add(rdataAdd,"wrap");
+    rparamButs.add(rdataRem,"wrap");
+    rparamButs.add(rdataNup,"wrap");
+    rparamButs.add(rdataNdown,"wrap");
+    rparamList.add(rparamButs,"wrap");
+    inputs.add(rparamList,"wrap");
+    // Parse flat-text to a service
+
+    
+    urldesc = new JTextArea(2,40);
+    urldesc.setEditable(true);
+    urldescVp = new JScrollPane();
+    urldescVp.setViewportView(urldesc);
+    JvSwingUtils.mgAddtoLayout(paste,"Flat file representation of this rest service using the Really Simple Bioinformatics Service formalism", new JLabel("RSBS Encoded Service:"), urldescVp,"wrap");
+
+    parseRes = new JTextArea(5,40);
+    parseResVp = new JScrollPane();
+    parseResVp.setViewportView(parseRes);
+    parseWarnings = new JPanel(new MigLayout());
+    parseWarnings.setBorder(new TitledBorder("Parsing errors"));
+    parseWarnings.setToolTipText("<html>"+JvSwingUtils.wrapTooltip("Results of parsing the RSBS representation")+"</html>");
+    parseWarnings.add(parseResVp, "wrap");
+    parseRes.setEditable(false);
+    
+    setLayout(new BorderLayout());
+    add(panels, BorderLayout.CENTER);
+    okButton = JvSwingUtils.makeButton("OK", "", new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        ok_actionPerformed();
+      }
+    });
+    cancelButton = JvSwingUtils.makeButton("Cancel", "",
+            new ActionListener()
+            {
+
+              @Override
+              public void actionPerformed(ActionEvent e)
+              {
+                cancel_actionPerformed();
+              }
+            });
+
+  }
+
+  protected void hSeparable_actionPerformed(ActionEvent arg0)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected void vSeparable_actionPerformed(ActionEvent arg0)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected void cancel_actionPerformed()
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected void ok_actionPerformed()
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected void iprmsAdd_actionPerformed(ActionEvent e)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected void iprmsRem_actionPerformed(ActionEvent e)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected void rdataAdd_actionPerformed(ActionEvent e)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected void rdataRem_actionPerformed(ActionEvent e)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected void rdataNup_actionPerformed(ActionEvent e)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected void rdataNdown_actionPerformed(ActionEvent e)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected void ok_actionPerformed(ActionEvent e)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  protected void cancel_actionPerformed(ActionEvent e)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+}