JAL-715 dialog for interactively editing a new or existing rest service
[jalview.git] / src / jalview / gui / RestServiceEditorPane.java
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();
+
+    }
+  }
+}