001/**
002 * Copyright (c) 2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: tao $'
006 * '$Date: 2010-06-03 16:45:10 -0700 (Thu, 03 Jun 2010) $' 
007 * '$Revision: 24730 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029package org.kepler.workflowscheduler.gui.configurationwizard;
030
031import java.awt.BorderLayout;
032import java.awt.Cursor;
033import java.awt.Dimension;
034import java.awt.GridBagConstraints;
035import java.awt.GridBagLayout;
036import java.awt.Insets;
037import java.awt.event.ActionEvent;
038import java.awt.event.ActionListener;
039import java.awt.event.WindowAdapter;
040import java.awt.event.WindowEvent;
041import java.util.Vector;
042
043import javax.swing.BorderFactory;
044import javax.swing.Box;
045import javax.swing.BoxLayout;
046import javax.swing.JButton;
047import javax.swing.JDialog;
048import javax.swing.JLabel;
049import javax.swing.JOptionPane;
050import javax.swing.JPanel;
051import javax.swing.JTextField;
052import javax.swing.border.Border;
053import javax.swing.border.EtchedBorder;
054
055import org.kepler.configuration.ConfigurationManagerException;
056import org.kepler.configuration.ConfigurationProperty;
057import org.kepler.configuration.NamespaceException;
058import org.kepler.gui.state.StateChangeEvent;
059import org.kepler.gui.state.StateChangeMonitor;
060import org.kepler.module.workflowschedulergui.Initialize;
061import org.kepler.workflowscheduler.gui.WorkflowRunEngine;
062import org.kepler.workflowscheduler.gui.WorkflowSchedulerPanel;
063
064import ptolemy.actor.gui.TableauFrame;
065import ptolemy.kernel.util.NamedObj;
066
067
068/**
069 * A dialog to configure the workflow run engines.
070 * @author tao
071 *
072 */
073public class WorkflowRunEngineConfigurationDialog extends JDialog
074{
075  private static final String TITLE = "Workflow Run Engine Configuration";
076  private static final String DEFAULTNAME = "The Run Engine Name";
077  private static final String DEFAULTURL = "http://yourhostname/workflowrunengine/services/KeplerWebService";
078  public static final String URLAPPENDIX = "?wsdl";
079  private static final int WIDTH = 800;
080  private static final int HEIGHT = 500;
081  static final int LEADSPACESIZE = 50; // leading space of each row
082  static final int TEXTFIELDSIZE = 600;
083  private TableauFrame parent = null;
084  private GridBagConstraints textFieldConstraint = null;
085  private GridBagConstraints labelConstraint = null;
086  private GridBagConstraints lastConstraint = null;
087  private JTextField nameTextField = null;
088  private JTextField urlTextField = null;
089  private JPanel mainPanel = null;
090  private JPanel addingEnginePanel = null;
091  private KnownWorkflowRunEnginePanel knownRunEnginePanel = null;
092  //private CompletingConfigurationListenerInterface completeListener = null;
093  
094  /**
095   * Constructor
096   */
097  public WorkflowRunEngineConfigurationDialog(TableauFrame parent)
098  {
099    //super(parent);
100    this.parent = parent;
101    //this.completeListener = completeListener;
102    init();
103    this.pack();
104    this.setVisible(true);
105  }
106  
107  
108  /*
109   * Initialize the dialog
110   */
111  private void init()
112  {
113    setPreferredSize(new Dimension(WIDTH, HEIGHT));    
114    if(parent != null)
115    {
116      setLocation(parent.getLocation());
117    }
118    setTitle(TITLE);
119    setModal(true);
120    setLayout(new BorderLayout());
121    addWindowListener(new DialogWindowAdapter(this));
122    initializeGridBagLayout();
123    initMainPanel();
124    initCloseButtonPanel();
125  }
126  
127  /*
128   * Initialize the grid bag layout manager
129   */
130  private void initializeGridBagLayout()
131  {
132    textFieldConstraint = new GridBagConstraints();
133    textFieldConstraint.fill = GridBagConstraints.HORIZONTAL;
134    //lastConstraint.anchor = GridBagConstraints.NORTHWEST;
135    // Give the "last" component as much space as possible
136    textFieldConstraint.weightx = 1.0;
137    //textFieldConstraint.gridwidth = GridBagConstraints.RELATIVE;     
138    textFieldConstraint.insets = new Insets(4, 4, 4, 4);
139
140    lastConstraint = (GridBagConstraints) textFieldConstraint.clone();
141    //These still get as much space as possible, but do
142    //not close out a row
143    lastConstraint.gridwidth = GridBagConstraints.REMAINDER;
144
145    // first component (usually it is a label) on each row
146    labelConstraint = (GridBagConstraints) textFieldConstraint.clone();
147    // Give these as little space as necessary
148    labelConstraint.weightx = 0.0;
149    labelConstraint.gridwidth = 1;
150
151  }
152  
153  /*
154   * MainPanel will contain two parts:
155   * 1. AddingEnginePanel - contains text input fields and add button
156   * 2. KnownWorkflowRunEngine panle - displays the known engines.
157   */
158  private void initMainPanel()
159  {
160    mainPanel = new JPanel();
161    mainPanel.setLayout(new BorderLayout());
162    Border compound = BorderFactory.createCompoundBorder(
163        BorderFactory.createEtchedBorder(EtchedBorder.RAISED), 
164        BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
165    compound = BorderFactory.createCompoundBorder(
166        BorderFactory.createEmptyBorder(12, 5, 5, 5), compound);
167    mainPanel.setBorder(compound);
168    initAddingEnginePanel();
169    mainPanel.add(addingEnginePanel, BorderLayout.CENTER);
170    WorkflowRunEngine[] engineList = getWorkflowRunEngineArrayFromConfig();
171    knownRunEnginePanel =  new KnownWorkflowRunEnginePanel(engineList);
172    mainPanel.add(knownRunEnginePanel, BorderLayout.SOUTH);
173    add(mainPanel, BorderLayout.CENTER);
174  }
175  
176  /*
177   * Initialize the panel adding workflow run engine name and url.
178   * It has a panel for two text fields which user can input engine name and url.
179   * It also has a panel for the add button
180   */
181  private void initAddingEnginePanel()
182  {
183    addingEnginePanel = new JPanel();
184    addingEnginePanel.setLayout(new BorderLayout());
185    initNameAndURLInputPanel();
186    initAddButtonPanel();
187  }
188  
189  private void initNameAndURLInputPanel()
190  {
191    JPanel nameAndURLPanel = new JPanel();
192    GridBagLayout gridbag = new GridBagLayout();
193    nameAndURLPanel.setLayout(gridbag);
194    
195    //name row
196    WorkflowSchedulerURLConfigurationDialog.addLeadingSpace(nameAndURLPanel, gridbag, labelConstraint);
197    JLabel nameLabel = new JLabel("Name          ");
198    WorkflowSchedulerPanel.addComponent(nameAndURLPanel, nameLabel, gridbag, labelConstraint);
199    nameTextField = new JTextField();
200    nameTextField.setText(DEFAULTNAME);
201    WorkflowSchedulerPanel.addFixWidthComponent(nameAndURLPanel, nameTextField , gridbag, textFieldConstraint);
202    WorkflowSchedulerURLConfigurationDialog.addEndingSpace(nameAndURLPanel, gridbag,lastConstraint);
203    
204    //url row
205    WorkflowSchedulerURLConfigurationDialog.addLeadingSpace(nameAndURLPanel, gridbag, labelConstraint);
206    JLabel urlLabel = new JLabel("URL          ");
207    WorkflowSchedulerPanel.addComponent(nameAndURLPanel, urlLabel, gridbag, labelConstraint);
208    urlTextField = new JTextField();
209    urlTextField.setText(DEFAULTURL);
210    WorkflowSchedulerPanel.addFixWidthComponent(nameAndURLPanel, urlTextField , gridbag, textFieldConstraint);
211    WorkflowSchedulerURLConfigurationDialog.addEndingSpace(nameAndURLPanel, gridbag,lastConstraint);
212    
213    addingEnginePanel.add(nameAndURLPanel, BorderLayout.CENTER);
214  }
215  
216  /*
217   * Initialize the button panel which contains the add button.
218   * This button panel will be added to addingEnginePanel
219   */
220  private void initAddButtonPanel()
221  {
222    JPanel buttonPanel = new JPanel();
223    buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
224    buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
225    buttonPanel.add(Box.createHorizontalGlue());
226    JButton addButton = new JButton("Add");
227    addButton.setPreferredSize(new Dimension(100, 50));
228    addButton.addActionListener(new ActionListener()
229    {
230      public void actionPerformed(ActionEvent e)
231      {
232        try
233        {
234          String url = urlTextField.getText();
235          String name = nameTextField.getText();
236          String urlWithAppendix = url+URLAPPENDIX;
237          if(WorkflowSchedulerURLConfigurationDialog.openURL(urlWithAppendix))
238          {
239            if(name != null && !name.trim().equals(""))
240            {
241              WorkflowRunEngine engine = new WorkflowRunEngine(name);
242              engine.setURL(url);
243              addRunEngineToConfig(engine);
244              addEngineToKnownWorkflowRunEnginePanel(engine);
245             
246            }
247            else
248            {
249              JOptionPane.showMessageDialog(null, "Workflow Run Engine name couldn't be blank", "Error", JOptionPane.ERROR_MESSAGE);
250            }
251          }
252          
253        }
254        catch(Exception ee)
255        {
256          ee.printStackTrace();
257          JOptionPane.showMessageDialog(null, "Couldn't add the new Run Enginel - "+ee.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
258        }
259      }
260    });  
261    buttonPanel.add(addButton);
262    addingEnginePanel.add(buttonPanel, BorderLayout.SOUTH);
263  }
264  
265  /*
266   * Initialize the panel containing the close button which close the dialog(top level)
267   */
268  private void initCloseButtonPanel()
269  {
270    JPanel buttonPanel = new JPanel();
271    buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
272    buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
273    buttonPanel.add(Box.createHorizontalGlue());
274    JButton cancelButton = new JButton("Close");
275    cancelButton.setPreferredSize(new Dimension(100, 50));
276    cancelButton.addActionListener(new ActionListener()
277    {
278      public void actionPerformed(ActionEvent e)
279      {
280        /*if(completeListener != null)
281        {
282          //System.out.println("calling complete method .....");
283          completeListener.completeConfiguration();
284        }*/
285        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
286        fireConfigChangeEvent();
287        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
288        dispose();
289      }
290    });   
291    buttonPanel.add(cancelButton);
292    //buttonPanel.add(Box.createHorizontalStrut(10));
293    this.add(buttonPanel, BorderLayout.SOUTH);
294  }
295  
296  /*
297   * A method will add a workflow run engine to the configuration
298   */
299  private void addRunEngineToConfig(WorkflowRunEngine engine) throws ConfigurationManagerException, NamespaceException
300  {
301    String newURL = engine.getURL();
302    String name = engine.getName();
303    ConfigurationProperty rootProperty = Initialize.getCurrentModuleProperty();
304    ConfigurationProperty engineListProperty = rootProperty.getProperty(Initialize.WORKFLOWRUNENGINELIST);
305    if(engineListProperty == null)
306    {
307      //add a new engine property
308      engineListProperty =  new ConfigurationProperty(Initialize.getCurrentModule(), Initialize.WORKFLOWRUNENGINELIST);
309      rootProperty.addProperty(engineListProperty);
310      
311    }
312    ConfigurationProperty engineProperty = new ConfigurationProperty(Initialize.getCurrentModule(),Initialize.WORKFLOWRUNENGINE);
313    //add a new engine property to the engine list property
314    ConfigurationProperty urlProperty = new ConfigurationProperty(Initialize.getCurrentModule(), Initialize.URL, newURL);
315    ConfigurationProperty nameProperty = new ConfigurationProperty(Initialize.getCurrentModule(), Initialize.NAME, name);
316    engineProperty.addProperty(nameProperty);
317    engineProperty.addProperty(urlProperty);
318    engineListProperty.addProperty(engineProperty);
319  }
320  
321  /*
322   * Update the known workflow run engine panel after adding a new engine
323   */
324  private void addEngineToKnownWorkflowRunEnginePanel(WorkflowRunEngine engine)
325  {    
326    knownRunEnginePanel.add(engine);
327  }
328  
329  /*
330   * Get the array of workflow run engine from configuration.
331   * null will be return if we can't find one.
332   */
333  private WorkflowRunEngine[] getWorkflowRunEngineArrayFromConfig()
334  {
335    WorkflowRunEngine[] engineList = null;
336    Vector<WorkflowRunEngine> engineVector = Initialize.getWorkflowRunEngineList();
337    if(engineVector != null && engineVector.size() > 0)
338    {
339      engineList = new WorkflowRunEngine[engineVector.size()];
340      engineVector.toArray(engineList);
341    }
342    return engineList;
343  }
344  
345  /*
346   * Fire a configuration change event
347   */
348  private void fireConfigChangeEvent()
349  {
350    NamedObj reference = null;
351    StateChangeEvent event = new StateChangeEvent(this,WorkflowSchedulerConfigEvent.MODIFYCONFIGEVENT, reference);
352    StateChangeMonitor.getInstance().notifyStateChange(event);
353  }
354  
355  /*
356   * A customized window adapter: the dialog box will be set invisible
357   * when users close the dialog.
358   */
359  private class DialogWindowAdapter extends WindowAdapter
360  {
361    private JDialog dialog = null;
362    
363    /**
364     * Constructor
365     * @param dialog
366     */
367    public DialogWindowAdapter(JDialog dialog)
368    {
369      this.dialog = dialog;
370    }
371    
372    /**
373     * Set the dialog box invisible
374     */
375    public void windowClosing(WindowEvent e) 
376    {
377      /*if(completeListener != null)
378      {
379        //System.out.println("calling complete method .....");
380        completeListener.completeConfiguration();
381      }*/
382      fireConfigChangeEvent();
383      if(dialog != null)
384      {
385        dialog.dispose();
386      }
387      
388    }
389  }
390}