JAL-715 dialog for interactively editing a new or existing rest service
[jalview.git] / src / jalview / gui / RestServiceEditorPane.java
1 package jalview.gui;
2
3 import jalview.bin.Cache;
4 import jalview.io.packed.DataProvider.JvDataType;
5 import jalview.jbgui.*;
6 import jalview.ws.rest.InputType;
7 import jalview.ws.rest.RestServiceDescription;
8
9 import java.awt.*;
10 import java.awt.event.ComponentEvent;
11 import java.awt.event.ComponentListener;
12 import java.awt.event.ContainerEvent;
13 import java.awt.event.ContainerListener;
14 import java.awt.event.KeyEvent;
15 import java.awt.event.KeyListener;
16 import java.awt.event.WindowEvent;
17 import java.awt.event.WindowListener;
18 import java.awt.event.WindowStateListener;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.Vector;
23 import java.util.regex.Matcher;
24 import java.util.regex.Pattern;
25
26 import javax.swing.*;
27 import javax.swing.event.CaretEvent;
28 import javax.swing.event.DocumentEvent;
29 import javax.swing.event.DocumentListener;
30 import javax.swing.text.GapContent;
31
32 import org.apache.log4j.lf5.LogLevel;
33
34 public class RestServiceEditorPane extends GRestServiceEditorPane
35 {
36   /**
37    * the latest version of the service definition.
38    */
39   jalview.ws.rest.RestServiceDescription currentservice = null;
40
41   /**
42    * original service passed to editor if we are modifying an existing service
43    * definition
44    */
45   jalview.ws.rest.RestServiceDescription oldservice = null;
46
47   public RestServiceEditorPane()
48   {
49     super();
50     // begin with initial text description box enabled.
51     urldesc.addKeyListener(new KeyListener()
52     {
53       long lastWait;
54       boolean doUpdate;
55       Thread updater=null;
56       @Override
57       public void keyTyped(KeyEvent e)
58       {
59         refreshCutnPaste(true);
60       }
61       
62       @Override
63       public void keyReleased(KeyEvent e)
64       {
65         // TODO Auto-generated method stub
66         
67       }
68       
69       @Override
70       public void keyPressed(KeyEvent e)
71       {
72         // TODO Auto-generated method stub
73         
74       }
75     });
76     paste.addComponentListener(new ComponentListener()
77     {
78       
79       @Override
80       public void componentShown(ComponentEvent e)
81       {
82         updateServiceFromGui();
83         refreshCutnPaste(false);
84         
85       }
86       
87       @Override
88       public void componentResized(ComponentEvent e)
89       {        
90       }
91       
92       @Override
93       public void componentMoved(ComponentEvent e)
94       {
95         
96       }
97       
98       @Override
99       public void componentHidden(ComponentEvent e)
100       {
101         // TODO Auto-generated method stub
102         
103       }
104     });
105   }
106
107   public RestServiceEditorPane(RestServiceDescription toedit)
108   {
109     this();
110     oldservice = toedit;
111     currentservice = new RestServiceDescription(toedit);
112     initGuiWith(currentservice);
113     refreshCutnPaste(false);
114     updateButtons();
115   }
116
117   /**
118    * refresh the buttons based on model state
119    */
120   public void updateButtons()
121   {
122     cancelButton.setEnabled(oldservice != null);
123     okButton.setEnabled(currentservice != null && currentservice.isValid());
124
125   }
126
127   Vector<String> _iparam = new Vector<String>();
128
129   Vector<String> _rparam = new Vector<String>();
130
131   /**
132    * generate an editable URL service string and parameter list using the
133    * service
134    * 
135    * @param currentservice2
136    */
137   private void initGuiWith(RestServiceDescription currentservice)
138   {
139     name.setText(currentservice.getName());
140     descr.setText(currentservice.getDescription());
141     url.setText(currentservice.getPostUrl());
142     urlsuff.setText(currentservice.getUrlSuffix());
143     _iparam.clear();
144     _rparam.clear();
145     for (Map.Entry<String, InputType> inparam : currentservice
146             .getInputParams().entrySet())
147     {
148       _iparam.add(inparam.getKey() + " "
149               + inparam.getValue().getURLtokenPrefix() + ":"
150               + inparam.getValue().getURLEncodedParameter().toString());
151     }
152     for (JvDataType oparam : currentservice.getResultDataTypes())
153     {
154       _rparam.add((oparam.name()));
155     }
156     iprms.setListData(_iparam);
157     rdata.setListData(_rparam);
158
159     action.removeAllItems();
160     action.addItem("Alignment");
161     action.addItem("Analysis");
162     // action.addItem("Analysis");
163     action.setSelectedItem(currentservice.getAction());
164     revalidate();
165   }
166
167   private boolean updateServiceFromGui() {
168     boolean valid=true;
169     Map<String,InputType>inputTypes = new HashMap<String, InputType>();
170     StringBuffer warnings=new StringBuffer();
171     for (String its:_iparam)
172     {
173       Matcher mtch = Pattern.compile("(\\S+)\\s(\\S+):\\[(.+)]").matcher(its);
174       if (mtch.find()) {
175         if (!RestServiceDescription.parseTypeString(mtch.group(2)+":"+mtch.group(3), mtch.group(1), mtch.group(2),mtch.group(3), inputTypes, warnings))
176         {
177           System.err.println("IMPLEMENTATION PROBLEM: Cannot parse RestService input parameter string '"+its+"'"+"\n"+warnings);
178         }        
179       }
180     }
181     char gc = gapChar.getSelectedItem()==null ? ' ' : ((String)gapChar.getSelectedItem()).charAt(0);
182     RestServiceDescription newService = new RestServiceDescription((String) action.getSelectedItem(),
183           descr.getText().trim(), name.getText().trim(), url.getText().trim(), urlsuff.getText().trim(), inputTypes, hSeparable.isSelected(), vSeparable.isSelected(), gc);
184             
185     if (newService.isValid())
186     {
187       for (String its:_rparam)
188       {
189         JvDataType dtype;
190         try {
191           dtype = JvDataType.valueOf(its);
192           newService.addResultDatatype(dtype);
193         }
194         catch (Throwable x)
195         {
196
197           System.err.println("IMPLEMENTATION PROBLEM: Cannot parse RestService output parameter string '"+its+"'"+"\n"+warnings);
198         }
199       }
200       currentservice = newService;
201       return true;
202     } else {
203       System.err.println("IMPLEMENTATION PROBLEM: Restservice generated from GUI is invalid\n"+warnings);
204
205     }
206     return false;
207   }
208   protected void refreshCutnPaste(boolean reparse)
209   {
210     if (!reparse && currentservice.isValid())
211     {
212       urldesc.setText(currentservice.toString());
213       parseWarnings.setVisible(false);
214     }
215     else
216     {
217       if (reparse)
218       {
219         String txt = urldesc.getText().trim();
220         StringBuffer warnings;
221         if (txt.length() > 0)
222         {
223           RestServiceDescription rsd = null;
224           try
225           {
226             rsd = new RestServiceDescription(txt);
227             if (rsd.isValid())
228             {
229               parseWarnings.setVisible(false);
230               initGuiWith(currentservice=rsd);
231             }
232             else
233             {
234               parseRes.setText("Parsing failed. Syntax errors shown below\n"
235                       + rsd.getInvalidMessage());
236               parseWarnings.setVisible(true);
237             }
238           } catch (Throwable e)
239           {
240             parseRes.setText("\nParsing failed. An unrecoverable exception was thrown:\n"
241                     + e.toString());
242             parseWarnings.setVisible(true);
243           }
244         }
245       }
246     }
247
248   }
249
250   public static void main(String[] args)
251   {
252     if (args.length == 0)
253     {
254       new Thread(new Runnable()
255       {
256         boolean visible = true;
257
258         public void run()
259         {
260           while (visible)
261           {
262             final Thread runner = Thread.currentThread();
263             JFrame df = new JFrame();
264             df.getContentPane().setLayout(new BorderLayout());
265             df.getContentPane().add(
266                     new RestServiceEditorPane(jalview.ws.rest.RestClient
267                             .makeShmmrRestClient().getRestDescription()),
268                     BorderLayout.CENTER);
269             df.setBounds(100, 100, 400, 600);
270             df.addComponentListener(new ComponentListener()
271             {
272
273               @Override
274               public void componentShown(ComponentEvent e)
275               {
276                 // TODO Auto-generated method stub
277
278               }
279
280               @Override
281               public void componentResized(ComponentEvent e)
282               {
283                 // TODO Auto-generated method stub
284
285               }
286
287               @Override
288               public void componentMoved(ComponentEvent e)
289               {
290                 // TODO Auto-generated method stub
291
292               }
293
294               @Override
295               public void componentHidden(ComponentEvent e)
296               {
297                 visible = false;
298                 runner.interrupt();
299
300               }
301             });
302             df.setVisible(true);
303             while (visible)
304             {
305               try
306               {
307                 Thread.sleep(10000);
308               } catch (Exception x)
309               {
310               }
311               ;
312             }
313             visible = true;
314           }
315         }
316       }).start();
317
318     }
319   }
320 }