From e74c1be398cd4ebe5f420c13be6143464100bb52 Mon Sep 17 00:00:00 2001 From: jprocter Date: Wed, 24 Aug 2011 15:43:08 +0100 Subject: [PATCH 1/1] JAL-715 dialog for interactively editing a new or existing rest service --- src/jalview/gui/RestServiceEditorPane.java | 320 ++++++++++++++++++++ src/jalview/jbgui/GRestServiceEditorPane.java | 394 +++++++++++++++++++++++++ 2 files changed, 714 insertions(+) create mode 100644 src/jalview/gui/RestServiceEditorPane.java create mode 100644 src/jalview/jbgui/GRestServiceEditorPane.java diff --git a/src/jalview/gui/RestServiceEditorPane.java b/src/jalview/gui/RestServiceEditorPane.java new file mode 100644 index 0000000..4572f6f --- /dev/null +++ b/src/jalview/gui/RestServiceEditorPane.java @@ -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 _iparam = new Vector(); + + Vector _rparam = new Vector(); + + /** + * 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 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; + MapinputTypes = new HashMap(); + 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 index 0000000..74b1463 --- /dev/null +++ b/src/jalview/jbgui/GRestServiceEditorPane.java @@ -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("" + + JvSwingUtils + .wrapTooltip("When checked, a job is created for every sequence in the current selection.") + + ""); + hSeparable.addActionListener(new ActionListener() + { + + @Override + public void actionPerformed(ActionEvent arg0) + { + hSeparable_actionPerformed(arg0); + + } + }); + vSeparable = new JCheckBox("Results are vertically separable"); + vSeparable + .setToolTipText("" + + 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).") + + ""); + 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(""+JvSwingUtils.wrapTooltip("Results of parsing the RSBS representation")+""); + 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 + + } + +} -- 1.7.10.2