001/** A tab pane to display properties of a server workflow.
002 * 
003 * Copyright (c) 2010 The Regents of the University of California.
004 * All rights reserved.
005 *
006 * '$Author: crawl $'
007 * '$Date: 2010-06-03 16:45:10 -0700 (Thu, 03 Jun 2010) $' 
008 * '$Revision: 24730 $'
009 * 
010 * Permission is hereby granted, without written agreement and without
011 * license or royalty fees, to use, copy, modify, and distribute this
012 * software and its documentation for any purpose, provided that the above
013 * copyright notice and the following two paragraphs appear in all copies
014 * of this software.
015 *
016 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
017 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
018 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
019 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
020 * SUCH DAMAGE.
021 *
022 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
023 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
025 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
026 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
027 * ENHANCEMENTS, OR MODIFICATIONS.
028 *
029 */
030 
031package org.kepler.workflowscheduler.gui;
032
033import java.awt.BorderLayout;
034import java.awt.Cursor;
035import java.awt.Dimension;
036import java.awt.GridBagConstraints;
037import java.awt.GridBagLayout;
038import java.awt.Insets;
039import java.awt.event.ActionEvent;
040import java.awt.event.ItemEvent;
041import java.awt.event.ItemListener;
042import java.io.File;
043import java.io.FileInputStream;
044import java.io.FileOutputStream;
045import java.io.ObjectInputStream;
046import java.io.ObjectOutputStream;
047import java.io.StringReader;
048import java.text.ParseException;
049import java.text.SimpleDateFormat;
050import java.util.Collections;
051import java.util.Date;
052import java.util.HashMap;
053import java.util.TimeZone;
054import java.util.Vector;
055import java.util.concurrent.locks.Lock;
056import java.util.concurrent.locks.ReentrantLock;
057
058import javax.swing.AbstractAction;
059import javax.swing.BorderFactory;
060import javax.swing.Box;
061import javax.swing.BoxLayout;
062import javax.swing.JButton;
063import javax.swing.JComboBox;
064import javax.swing.JComponent;
065import javax.swing.JLabel;
066import javax.swing.JOptionPane;
067import javax.swing.JPanel;
068import javax.swing.JTextArea;
069import javax.swing.JTextField;
070
071import org.apache.commons.logging.Log;
072import org.apache.commons.logging.LogFactory;
073import org.kepler.gui.TabManager;
074import org.kepler.module.workflowschedulergui.Initialize;
075import org.kepler.objectmanager.repository.Repository;
076import org.kepler.objectmanager.repository.RepositoryManager;
077import org.kepler.util.DotKeplerManager;
078import org.xml.sax.ContentHandler;
079import org.xml.sax.ErrorHandler;
080import org.xml.sax.InputSource;
081import org.xml.sax.XMLReader;
082import org.xml.sax.helpers.XMLReaderFactory;
083
084import edu.ucsb.nceas.schedulerclient.WorkflowSchedulerClient;
085import ptolemy.actor.gui.TableauFrame;
086
087
088/** A tab pane to display a scheduler of a server workflow.
089 * 
090 * @author Daniel Crawl
091 * @version $Id: ServerWorkflowPropertiesPanel.java 24730 2010-06-03 23:45:10Z crawl $
092 */
093public class WorkflowSchedulerPanel extends JPanel 
094{
095  private static final Log log = LogFactory.getLog(WorkflowSchedulerPanel.class
096      .getName());
097    private static final int LEADSPACESIZE = 50; // leading space of each row
098    private static final int TEXTFIELDSIZE = 400;
099    public static final String[] INTERVALUNITLABEL = {"hours", "days", "weeks", "months"};
100    public static final String[] INTERVALUNITVALUE = {Schedule.HOUR, Schedule.DAY, Schedule.WEEK, Schedule.MONTH};
101    public static final String WORKFLOWRUNENGINECOMBOBOX = "workflowRunEngineCombo";
102    public static final String DESTINATIONSERVERCOMBOBOX = "destinationServerCombo";
103    public static final String TIMEEXAMPLE = "MM/dd/yyyy hh:mm:ss";
104    private static final int UINTCOMBOXWIDTH = 100;
105    private static final String WARNING = "Warning";
106    public static final String TIMESTAMPFORMAT = "MM/dd/yyyy HH:mm:ss";
107    public static final String TIMESTAMPFORMATWITHTIMEZONE =  TIMESTAMPFORMAT+" zzzz";
108    private static final String URL = "url";
109    private static final String NOTE = "Schedule the selected workflow by filling in "+
110                                    "the fields below, choosing an execution engine, and the "+
111                                     "destination repository for the workflow result archive:";
112    private static final String UNKNOWN = "Unknown";
113    private static final String SOURCEKARLOCATION = "Location     ";
114    private static final int TIMEZONESTYLE = TimeZone.LONG;
115    private static final String TIMEZONEIDCACHEFILENAME = "time_zone_ids_cache_";
116    private TableauFrame parent;
117    private JPanel schedulerPanel = null;
118    private JPanel parameterPanel = null;
119    private JPanel buttonPanel = null;
120    private ExistingSchedulePanel existingSchedulePanel = null;
121    private GridBagConstraints textFieldConstraint = null;
122    private GridBagConstraints labelConstraint = null;
123    private GridBagConstraints lastConstraint = null;
124    private JLabel nameTextLabel = null;
125    private JLabel karSourceLocationLabel = null;
126    private JTextField intervalTextField = null;
127    private JTextField startTimeTextField = null;
128    private JTextField endTimeTextField = null;
129    private String startTime = null;
130    private String endTime = null;
131    private String interval = null;
132    private JComboBox intervalUnitComboBox = null;
133    private JComboBox startTimeZoneComboBox = null;
134    private JComboBox endTimeZoneComboBox = null;
135    //private String intervalUnit = INTERVALUNITVALUE[0];
136    private String workflowId = null;
137    private String workflowName = null;
138    private String karLSID = null;
139    private String karSourceRepositoryName = null;
140    private String runKarDestinationRepositoryName = null;
141    private String workflowRunEngineURL = null;
142    //private String schedulerURL = "http://fakeurl";
143    //private String returnedWorkflowJobName = null;
144    private Schedule[] existingScheduleList = null;
145    private ScheduleWorkflowAction scheduleAction = null;
146    private ScheduleChangeController scheduleChangeController = null;
147    private JComboBox workflowRunEngineBox = null;
148    private JComboBox resultDestinationBox = null;
149    private Vector<WorkflowRunEngine> workflowRunEngineList = new Vector<WorkflowRunEngine>();
150    private Vector <Repository> repositoryList = null;
151    private SearchScheduleSwingWorker searchWorker = null;
152    private Vector<String> availableTimeZoneIDsInServer = new Vector<String>();
153    private static String[] availableTimeZoneIDsInLocal = null;
154    private Vector <String> availableTimeZoneNames = new Vector<String>();
155    //private SearchSchedulesWorkerListenerInterface searchWorkerListener = null;
156    WorkflowSchedulerParentPanel schedulerParentPanel = null;
157    private final Lock existingScheduleTablelock = new ReentrantLock();
158    private IntervalUnitComboBoxAction intervalUnitSelectionaction = new IntervalUnitComboBoxAction();
159    private HashMap<String, TimeZone> timeZoneDisplayHash = new HashMap <String, TimeZone>();
160    private String startTimeZoneID = null;
161    private String startTimeZoneName = null;
162    private String startTimeLabel = null;
163    private String endTimeZoneID = null;
164    private String endTimeZoneName = null;
165    private String endTimeLabel = null;
166    private File  timeZoneIDsCacheFile = null;
167    private String schedulerURL = Initialize.getSchedulerURL();
168  
169
170    /** Construct a new ServerWorkflowSchedulePanel in a frame with a specific title. */
171    public WorkflowSchedulerPanel(TableauFrame parent, WorkflowSchedulerParentPanel schedulerParentPanel,
172                                ScheduleChangeController scheduleChangeController) throws Exception 
173    {
174        super();
175        this.parent = parent;
176        this.schedulerParentPanel = schedulerParentPanel;
177        this.scheduleChangeController = scheduleChangeController;
178        try
179        {
180          initialize();
181        }
182        catch (Exception e)
183        {
184          throw new Exception("\nWorkflowSchedulerPanel -- couldn't initialize the workflow scheduler panel -- "+e.getMessage());
185        }
186
187        setBackground(TabManager.BGCOLOR);
188    }
189    
190   
191    /**
192     * This method must return the TableauFrame this tab is associated with.
193     */
194    public TableauFrame getParentFrame()
195    {
196      return parent;
197    }
198
199    
200    /* Initialize the contents of the panel. */
201    private void initialize() throws Exception
202    {
203      //getSchedulerURL();
204      initializeTimeZones();
205      initializeGridBagLayout();
206      initializeSchedulerPanel();
207      //initializeParameterPanel();
208      initializeButtonPanel();
209      initializeExistingSchedulePanel();
210     
211      //whole panel will be box layout
212      this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
213      this.add(Box.createVerticalStrut(10));      
214      Box box = Box.createHorizontalBox();
215      //JLabel noteLabel = new JLabel(NOTE, JLabel.LEFT);
216      //noteLabel.setForeground(Color.blue);
217      //noteLabel.setOpaque(true);
218      //noteLabel.setBackground(Color.blue);
219      JTextArea noteTextArea = new JTextArea(NOTE);
220      noteTextArea.setEditable(false);
221      noteTextArea.setLineWrap(true);
222      noteTextArea.setWrapStyleWord(true);
223      //descriptionTextArea.setPreferredSize(new Dimension(400, 400));
224      noteTextArea.setBackground(TabManager.BGCOLOR);
225      box.add(noteTextArea);
226      box.add(Box.createHorizontalGlue());
227      this.add(box);
228      
229      this.add(Box.createVerticalStrut(15));
230      
231      this.add(schedulerPanel);
232      //this.add(parameterPanel);
233      this.add(buttonPanel);
234      //this.add(Box.createVerticalStrut(60));
235      this.add(existingSchedulePanel);
236          
237      
238    }
239    
240    
241    /*
242     * Initialize the available time zones
243     */
244    private void initializeTimeZones() throws Exception
245    {
246      
247      if(schedulerURL != null && !schedulerURL.trim().equals(""))
248      {
249        String newURL = schedulerURL.replaceAll("/", "_");
250        newURL = newURL.replaceAll(":", "_");
251        timeZoneIDsCacheFile = new File(DotKeplerManager.getInstance().getTransientModuleDirectory(Initialize.MODULENAME),
252            TIMEZONEIDCACHEFILENAME+newURL);
253        //System.out.println("The cache file path is "+timeZoneIDsCacheFile.getAbsolutePath());
254      }
255      
256      //System.out.println("start !!!!!!!!!!!!!!!!!!!!!!!!!!!11 initialize time zone");
257      availableTimeZoneIDsInLocal = TimeZone.getAvailableIDs();
258      initializeSchedulerServerAvailableTimeZoneIDs();
259      for( String id : availableTimeZoneIDsInServer)
260      {
261        //only display the ids found in both server and local
262        if(localContainsTimeZoneID(id))
263        {
264          //add standard time zone name
265          Boolean notDayLight = false;
266          TimeZone zone = TimeZone.getTimeZone(id);
267          String standName = zone.getDisplayName(notDayLight, TIMEZONESTYLE);
268          if(!availableTimeZoneNames.contains(standName))
269          {
270            availableTimeZoneNames.add(standName);  
271            timeZoneDisplayHash.put(standName, zone);
272          }
273          //add day light time zone name if it is available
274          Boolean useDayLight = zone.useDaylightTime();
275          if(useDayLight) 
276          {
277            String dayLightName = zone.getDisplayName(useDayLight, TIMEZONESTYLE);
278            if (!availableTimeZoneNames.contains(dayLightName))
279            {
280              availableTimeZoneNames.add(dayLightName);
281              timeZoneDisplayHash.put(dayLightName, zone);
282            }
283          }
284        }
285        
286      }
287      Collections.sort(availableTimeZoneNames);
288      //System.out.println("end !!!!!!!!!!!!!!!!!!!!!!!!!!!11 initialize time zone");
289    }
290    
291    
292    private void initializeSchedulerServerAvailableTimeZoneIDs() throws Exception 
293    {
294      if(timeZoneIDsCacheFile != null && timeZoneIDsCacheFile.exists())
295      {
296        //try to get the available ids from the cache
297        try
298        {
299          getAvailableServerTimeZoneIDFromCache();
300          if(availableTimeZoneIDsInServer == null || availableTimeZoneIDsInServer.isEmpty())
301          {
302            getAvailableServerTimeZoneIDFromServer();
303          }
304        }
305        catch(Exception e)
306        {
307          log.warn("WorkflowSchedulerPanel.initializeSchedulerServerAvailableTimeZoneIDs - Failed to get the available time zone from the cache.\n"+
308                        "Try to get the time zone ids from server again");
309          getAvailableServerTimeZoneIDFromServer();
310        }
311      }
312      else
313      {
314        //try to get the available ids from the server
315        getAvailableServerTimeZoneIDFromServer();
316      }
317      
318    }
319    
320    /*
321     * Get the available server time zone id from a cache file
322     */
323    private void getAvailableServerTimeZoneIDFromCache() throws Exception
324    {
325      if(timeZoneIDsCacheFile != null)
326     {
327        //System.out.println("===== get ids from cache ");
328        FileInputStream fileInput = new FileInputStream(timeZoneIDsCacheFile);
329        ObjectInputStream objectInput = new ObjectInputStream(fileInput);
330        availableTimeZoneIDsInServer = (Vector<String>)objectInput.readObject();
331     }
332    }
333    
334    /*
335     * Gets the available server time zone id from the workflow scheduler server
336     */
337    private void getAvailableServerTimeZoneIDFromServer() throws Exception
338    {
339      //System.out.println("===== get ids from sever ");
340      String sessionID = "blank";
341      String authURL = "blank";
342      WorkflowSchedulerClient client = new WorkflowSchedulerClient(schedulerURL, sessionID, authURL); 
343      String result = null;
344      try
345      {
346        parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
347        result = client.getAvailableTimeZoneIDs();
348        parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
349      }
350      catch(Exception e)
351      {
352        parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
353        throw new Exception("\nCouldn't contact the scheduler -- "+schedulerURL+" to get its available time zone ids --\n "+e.getMessage());
354      }
355      if(result != null && !result.trim().equals(""))
356      {
357        StringReader xmlReader = new StringReader(result);
358        try
359        {
360          XMLReader parser = null;
361          parser = XMLReaderFactory.createXMLReader(SearchScheduleSwingWorker.PARSERNAME);
362          ServerTimeZoneIDParser handler = new ServerTimeZoneIDParser();
363          parser.setContentHandler((ContentHandler) handler);
364          parser.setErrorHandler((ErrorHandler) handler);
365          parser.parse(new InputSource(xmlReader));
366          availableTimeZoneIDsInServer = handler.getValaibleTimeZoneIDs();
367          saveAvailableServerTimeZoneIDToCache();
368        }
369        catch(Exception e)
370        {
371         throw new Exception("\nCouldn't parse the information about the server available time zone ids  in "+
372           schedulerURL+" - "+e.getMessage());
373        }
374      }
375    }
376    
377    
378    /*
379     * Save the time zone ids from the server into a cache file
380     */
381    private void saveAvailableServerTimeZoneIDToCache()
382    {
383      if(availableTimeZoneIDsInServer != null) {
384        try
385        {
386          if(timeZoneIDsCacheFile != null)
387          {
388            timeZoneIDsCacheFile.delete();
389          }
390          FileOutputStream fileOutput = new FileOutputStream(timeZoneIDsCacheFile);
391          ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput);
392          objectOutput.writeObject(availableTimeZoneIDsInServer);
393        }
394        catch(Exception e)
395        {
396          log.error("WorkflowSchedulerPanel.saveAvailableServerTimeZoneIDToCache - Can't save the server time zone ids into a cache file :"+e.getMessage());
397        }
398      }
399    }
400    /*
401     * Initialize the grid bag layout manager
402     */
403    private void initializeGridBagLayout()
404    {
405      textFieldConstraint = new GridBagConstraints();
406      textFieldConstraint.fill = GridBagConstraints.HORIZONTAL;
407      //lastConstraint.anchor = GridBagConstraints.NORTHWEST;
408      // Give the "last" component as much space as possible
409      textFieldConstraint.weightx = 1.0;
410      //textFieldConstraint.gridwidth = GridBagConstraints.RELATIVE;     
411      textFieldConstraint.insets = new Insets(4, 4, 4, 4);
412
413      lastConstraint = (GridBagConstraints) textFieldConstraint.clone();
414      //These still get as much space as possible, but do
415      //not close out a row
416      lastConstraint.gridwidth = GridBagConstraints.REMAINDER;
417  
418      // first component (usually it is a label) on each row
419      labelConstraint = (GridBagConstraints) textFieldConstraint.clone();
420      // Give these as little space as necessary
421      labelConstraint.weightx = 0.0;
422      labelConstraint.gridwidth = 1;
423
424    }
425    
426    /*
427     * Initialize the scheduler panel. This panel contains
428     * workflow name, start time, end time and interval.
429     */
430    private void initializeSchedulerPanel()
431    {
432      schedulerPanel = new JPanel();
433      GridBagLayout gridbag = new GridBagLayout();
434      schedulerPanel.setLayout(gridbag);
435      // Name row
436      addLeadingSpace(schedulerPanel, gridbag);
437      JLabel nameLabel = new JLabel("Workflow          ");
438      addComponent(schedulerPanel, nameLabel, gridbag, labelConstraint);
439      nameTextLabel = new JLabel(UNKNOWN);
440      addFixWidthComponent(schedulerPanel, nameTextLabel, gridbag, textFieldConstraint);
441      addEndingSpace(schedulerPanel, gridbag);
442      
443      //source kar file location row
444      addLeadingSpace(schedulerPanel, gridbag);
445      JLabel karSourceLocation = new JLabel(SOURCEKARLOCATION);
446      addComponent(schedulerPanel, karSourceLocation, gridbag, labelConstraint);
447      karSourceLocationLabel = new JLabel(UNKNOWN);
448      addFixWidthComponent(schedulerPanel, karSourceLocationLabel, gridbag, textFieldConstraint);
449      addEndingSpace(schedulerPanel, gridbag);
450      
451      //start time row
452      addLeadingSpace(schedulerPanel, gridbag);
453      JLabel startTimeLabel = new JLabel("Start Time          ");
454      addComponent(schedulerPanel, startTimeLabel, gridbag, labelConstraint);
455      startTimeTextField = new JTextField();
456      startTimeTextField.setText(TIMEEXAMPLE);
457      addFixWidthComponent(schedulerPanel, startTimeTextField , gridbag, textFieldConstraint);
458      startTimeZoneComboBox = new JComboBox(availableTimeZoneNames);
459      startTimeZoneComboBox.addItemListener(new StartTimeZoneItemListener());
460      startTimeZoneComboBox.setSelectedItem(getDefaultTimeZoneName());
461      addComponent(schedulerPanel, startTimeZoneComboBox, gridbag, labelConstraint);
462      addEndingSpace(schedulerPanel, gridbag);
463    
464      //end time row
465      addLeadingSpace(schedulerPanel, gridbag);
466      JLabel endTimeLabel = new JLabel("End Time          ");
467      addComponent(schedulerPanel, endTimeLabel, gridbag, labelConstraint);
468      endTimeTextField = new JTextField();
469      endTimeTextField.setText(TIMEEXAMPLE);
470      addFixWidthComponent(schedulerPanel, endTimeTextField, gridbag, textFieldConstraint);
471      endTimeZoneComboBox = new JComboBox(availableTimeZoneNames);
472      endTimeZoneComboBox.addItemListener(new EndTimeZoneItemListener());
473      endTimeZoneComboBox.setSelectedItem(getDefaultTimeZoneName());
474      addComponent(schedulerPanel, endTimeZoneComboBox, gridbag, labelConstraint);
475      addEndingSpace(schedulerPanel, gridbag);
476     
477      //interval row
478      addLeadingSpace(schedulerPanel, gridbag);
479      JLabel intervalLabel = new JLabel("Interval          ");
480      addComponent(schedulerPanel, intervalLabel, gridbag, labelConstraint);
481      intervalTextField = new JTextField();
482      addFixWidthComponent(schedulerPanel, intervalTextField, gridbag, textFieldConstraint);
483      intervalUnitComboBox = new JComboBox(INTERVALUNITLABEL);
484     
485      intervalUnitComboBox.addActionListener(intervalUnitSelectionaction);
486      Dimension size = intervalUnitComboBox.getPreferredSize();
487      size.width = UINTCOMBOXWIDTH;
488      addComponent(schedulerPanel, intervalUnitComboBox, gridbag, labelConstraint);
489      addEndingSpace(schedulerPanel, gridbag);     
490      
491      //workflow run engine combobox row
492      addLeadingSpace(schedulerPanel, gridbag);
493      JLabel workflowRunEngineLabel = new JLabel("Workflow Run Engine      ");
494      addComponent(schedulerPanel, workflowRunEngineLabel, gridbag, labelConstraint);
495      workflowRunEngineList = Initialize.getWorkflowRunEngineList();
496      workflowRunEngineBox = new JComboBox(workflowRunEngineList);
497      workflowRunEngineBox.setRenderer(new RepositoryAndRunEngineComboBoxRenderer(WORKFLOWRUNENGINECOMBOBOX));
498      addFixWidthComponent(schedulerPanel, workflowRunEngineBox, gridbag, textFieldConstraint);
499      addEndingSpace(schedulerPanel, gridbag);
500      
501      //result destination combobox row
502      addLeadingSpace(schedulerPanel, gridbag);
503      JLabel resultDestinationLabel = new JLabel("Result Destination    ");
504      addComponent(schedulerPanel, resultDestinationLabel, gridbag, labelConstraint);
505      try
506      {
507        repositoryList= RepositoryManager.getInstance().getRepositories();
508      }
509      catch(Exception e)
510      {
511        log.warn("ServerWorkflowSchedulePanel.initializeSchedulerPane - couldn't get repository list "+e.getMessage());
512      }
513      
514      if(repositoryList == null)
515      {
516        repositoryList = new Vector<Repository>();
517      }
518      resultDestinationBox = new JComboBox(repositoryList);
519      resultDestinationBox.setRenderer(new RepositoryAndRunEngineComboBoxRenderer(DESTINATIONSERVERCOMBOBOX));
520      addFixWidthComponent(schedulerPanel, resultDestinationBox, gridbag, textFieldConstraint);
521      addEndingSpace(schedulerPanel, gridbag);
522      
523      
524    }
525    
526   
527    
528    /*
529     * Initialize button panel. The panel contains "Schedule" button.
530     */
531    private void initializeButtonPanel()
532    {
533      scheduleAction = new ScheduleWorkflowAction(parent, schedulerParentPanel,scheduleChangeController);
534      buttonPanel = new JPanel();
535      buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
536      buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
537      buttonPanel.add(Box.createHorizontalGlue());
538      JButton scheduleButton = new JButton("Schedule");
539      scheduleButton.setPreferredSize(new Dimension(100, 50));
540      scheduleButton.addActionListener(new AbstractAction()
541      {
542        public void actionPerformed(ActionEvent e) 
543        {
544          setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
545          boolean valid = validateInputField();
546          if (valid == true)
547          {
548             Schedule schedule = new Schedule();
549             schedule.setWorkflowId(workflowId);
550             schedule.setKarLSID(karLSID);
551             schedule.setWorkflowName(workflowName);
552             
553             //appendTimeZoneToTimeString();
554             //System.out.println("The start time is "+startTime);
555             //System.out.println("The end time is "+endTime);
556             schedule.setStartTime(startTime);
557             schedule.setStartTimeLabel(startTime+" "+startTimeZoneName);
558             schedule.setStartTimeZoneID(startTimeZoneID);
559             schedule.setStartTimeFormat(TIMESTAMPFORMAT);
560             schedule.setEndTime(endTime);
561             schedule.setEndTimeLabel(endTime+" "+endTimeZoneName);
562             schedule.setEndTimeZoneID(endTimeZoneID);
563             schedule.setEndTimeFormat(TIMESTAMPFORMAT);
564             schedule.setInterval(interval);
565             
566             schedule.setWorkflowRunEngine(
567                 (WorkflowRunEngine)workflowRunEngineBox.getSelectedItem());
568             schedule.setWorkflowRunDestination(
569                 (Repository)resultDestinationBox.getSelectedItem());
570             try
571             {
572               String intervalUnit = intervalUnitSelectionaction.getIntervalUnit();
573               schedule.setIntervalUnit(intervalUnit);
574             }
575             catch(Exception ee)
576             {
577               JOptionPane.showMessageDialog(parent, ee.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
578               return;
579             }
580             scheduleAction.setSchedule(schedule);
581             scheduleAction.actionPerformed(e);
582          }
583          setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
584        }
585      });
586      buttonPanel.add(scheduleButton);
587
588    }
589    
590    /*
591     * Initialize the existing schedule panel
592     */
593    private void initializeExistingSchedulePanel()
594    {
595      existingSchedulePanel = new ExistingSchedulePanel(existingScheduleList, parent, schedulerParentPanel, scheduleChangeController);
596      scheduleChangeController.addListener(existingSchedulePanel);
597    }
598    
599   
600    
601   
602    /*
603     *Add leading space in each row of a panel 
604     */
605    private void addLeadingSpace(JPanel panel, GridBagLayout layout)
606    {
607      String space = "       ";
608      JLabel leadingLabel = new JLabel(space);
609      Dimension size = leadingLabel.getPreferredSize();
610      size.width = LEADSPACESIZE;
611      leadingLabel.setPreferredSize(size);
612      addComponent(panel, leadingLabel, layout, labelConstraint);
613    }
614    
615    /*
616     *Add ending space in each row of a panel 
617     */
618    private void addEndingSpace(JPanel panel, GridBagLayout layout)
619    {
620      String space = "       ";
621      JLabel leadingLabel = new JLabel(space);
622      addComponent(panel, leadingLabel, layout, lastConstraint);
623    }
624    
625    private String getDefaultTimeZoneName()
626    {
627      String name = null;
628      TimeZone timeZone = TimeZone.getDefault();
629      boolean daylight = timeZone.inDaylightTime(new Date());
630      name = timeZone.getDisplayName(daylight, TIMEZONESTYLE);
631      return name;
632    }
633    
634    /*
635     * Create a blank "last field" component gets us to a new line.
636     */
637    /*private void addNewLine(JPanel panel, GridBagLayout layout)
638    {
639      String space = " ";
640      JLabel leadingLabel = new JLabel(space);
641      addComponentWithGridBagLayout(panel, leadingLabel, layout, lastConstraint);
642    }*/
643    
644    /*
645     * Add a component with specified layout to the given panel
646     */
647    public static void addComponent(JPanel panel, JComponent component, GridBagLayout layout, GridBagConstraints constraint)
648    {
649      if(component != null  && panel != null && layout != null)
650      {
651        layout.setConstraints(component, constraint);
652        panel.add(component);
653      }
654
655    }
656    
657    /*
658     * Add a component with specified layout to the given panel
659     */
660    public static void addFixWidthComponent(JPanel panel, JComponent component, GridBagLayout layout, GridBagConstraints constraint)
661    {
662      if(component != null  && panel != null && layout != null)
663      {
664        Dimension size = component.getPreferredSize();
665        size.width = TEXTFIELDSIZE;
666        layout.setConstraints(component, constraint);
667        panel.add(component);
668      }
669
670    }
671    
672    /*
673     * Validate the input fields on the schedule panel
674     */
675    private boolean validateInputField()
676    {
677      boolean success = true;
678      startTime = startTimeTextField.getText();
679      endTime = endTimeTextField.getText();
680      interval = intervalTextField.getText();
681      //validate startTime
682      if(startTime== null || startTime.trim().equals(""))
683      {
684        JOptionPane.showMessageDialog(parent, "\"Start Time\" field can't be blank!", WARNING, JOptionPane.WARNING_MESSAGE);
685        success = false;
686        return success;
687      }
688      else
689      {
690         success = validateTimeString(startTime, TIMESTAMPFORMAT);
691         if(success == false)
692         {
693           JOptionPane.showMessageDialog(parent, "\"Start Time\" field should be the format \"MM/dd/yyyy hh:mm:ss\"!", WARNING, JOptionPane.WARNING_MESSAGE);
694           return success;
695         }
696      }
697      //validate endTime
698      if(endTime== null || endTime.trim().equals(""))
699      {
700        JOptionPane.showMessageDialog(parent, "\"End Time\" field can't be blank!", WARNING, JOptionPane.WARNING_MESSAGE);
701        success = false;
702        return success;
703      }
704      else
705      {
706         success = validateTimeString(endTime, TIMESTAMPFORMAT);
707         if(success == false)
708         {
709           JOptionPane.showMessageDialog(parent, "\"End Time\" field should be the format \"MM/dd/yyyy hh:mm:ss\"!", WARNING, JOptionPane.WARNING_MESSAGE);
710           return success;
711         }
712      }
713      //validate interval
714      if(interval == null || interval.trim().equals(""))
715      {
716        JOptionPane.showMessageDialog(parent, "\"Interval\" field can't be blank!", WARNING, JOptionPane.WARNING_MESSAGE);
717        success = false;
718        return success;
719      }
720      else
721      {
722         try
723         {
724           int intValue = Integer.parseInt(interval);
725           if(intValue < 1)
726           {
727             JOptionPane.showMessageDialog(parent, "\"Interval\"  should be greater than zero!", WARNING, JOptionPane.WARNING_MESSAGE);
728             success = false;
729             return success;
730           }
731         }
732         catch(NumberFormatException e)
733         {
734           JOptionPane.showMessageDialog(parent, "\"Interval\" field should be an integer!", WARNING, JOptionPane.WARNING_MESSAGE);
735           success = false;
736           return success;
737         }
738      }     
739      return success;
740    }
741    
742    /*
743     * Validate the time string with specified format
744     */
745      private boolean validateTimeString(String dateString, String format)  
746      {
747        boolean valid = true;
748      
749        try 
750        {
751          SimpleDateFormat dateFormat = new SimpleDateFormat(format);
752          dateFormat.setLenient(false);
753          Date startDate = dateFormat.parse(dateString);         
754        } 
755        catch (ParseException pe) 
756        {
757          valid = false;
758        }
759      
760        return valid;
761      }
762    
763  
764    
765   /*
766    * Set the kar source eporsitory name.
767    * @param name
768    */
769   private void setKarSourceRepositoryName(String name)
770   {
771     this.karSourceRepositoryName = name;
772   }
773    /**
774     * Get the id of the workflow (LSID format)
775     * @return the id
776     */
777    public String getWorkflowId()
778    {
779      return workflowId;
780    }
781    
782    /**
783     * Set the workflow id (LSID format)
784     * @param workflowId the id will be set
785     */
786    public void setWorkflowId(String workflowId)
787    {
788      this.workflowId = workflowId;
789    }
790
791    /**
792     * Get the name of the workflow
793     * @return the name
794     */
795    public String getWorkflowName()
796    {
797      return workflowName;
798    }
799
800    /*
801     * Set the name of the workflow. It will update the workflow name label
802     * on the gui as well
803     * @param workflowName the name will be set
804     */
805    private void setWorkflowName(String workflowName)
806    {
807      if(workflowName == null || workflowName.trim().equals(""))
808      {
809        this.workflowName = UNKNOWN;
810      }
811      else
812      {
813        this.workflowName = workflowName;
814      }
815      //updateWorkflowNameLabel();
816    }
817    
818    /*
819     * Update workflow name text label
820     */
821    private void updateWorkflowNameLabel()
822    {
823      nameTextLabel.setText(workflowName);
824      nameTextLabel.repaint();
825      nameTextLabel.validate();
826    }
827    
828    /*
829     * Update the source kar file location
830     */
831    private void updateSourceKarFileLocationLabel()
832    {
833      if(karSourceRepositoryName != null && 
834          !karSourceRepositoryName.trim().equals(""))
835      {
836        karSourceLocationLabel.setText(karSourceRepositoryName);
837        karSourceLocationLabel.repaint();
838        karSourceLocationLabel.validate();
839      }
840    }
841
842    /**
843     * Get the kar file id associated with the workflow.
844     * @return the id fo the kar file
845     */
846    public String getKarLSID()
847    {
848      return karLSID;
849    }
850
851    /**
852     * Set the id of the kar file
853     * @param karId id will be set
854     */
855    public void setKarLSID(String karId)
856    {
857      this.karLSID = karId;
858    }
859    
860    /**
861     * Pass a workflow information to the scheulder. The scheduler will update
862     * its gui as well.
863     * @param workflowName name of the workflow
864     * @param workflowLSID lsid of the workflow 
865     * @param karSourceRepositoryName name of the repository where the kar file stays
866     * @param karLSID lsid of the kar file which the workflow stays
867     */
868    public void setWorkflowForScheduling(String workflowName, String workflowLSID, 
869                                      String karSourceRepositoryName, String karLSID, boolean hasReportLayout)
870    {
871      
872      schedulerParentPanel.removeAll();
873      schedulerParentPanel.add(this, BorderLayout.CENTER);
874      setWorkflowId(workflowLSID);
875      setKarSourceRepositoryName(karSourceRepositoryName);
876      updateSourceKarFileLocationLabel();
877      try
878      {
879        SchedulerAbstractAction.setSourceRespositoryName(karSourceRepositoryName);
880        SchedulerAbstractAction.setHasReportLayout(hasReportLayout);
881      }
882      catch(Exception e)
883      {
884        JOptionPane.showMessageDialog(parent, "User will NOT do any schedule-related action since kepler couldn't find the repository named "+
885            karSourceRepositoryName+" - "+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
886      }
887      setKarLSID(karLSID);
888      setWorkflowName(workflowName);
889      updateWorkflowNameLabel();
890      addExistingSchedules();
891    }
892    
893    /*
894     * Search the scheudler to find the existing schedules for the workflow,
895     * and add those schedules to the existing workflow panel.
896     */
897    private void addExistingSchedules()
898    {
899      if(searchWorker != null)
900      {
901        //System.out.println("interrupt====");
902        searchWorker.cancel(true);
903        searchWorker = null;
904        
905      }
906      try
907      {
908        searchWorker = new SearchScheduleSwingWorker(scheduleChangeController,
909                                                      workflowId, karLSID, existingScheduleTablelock);
910        //searchWorker.setSearchWorkerListener(searchWorkerListener);
911        searchWorker.execute();
912      }
913      catch(Exception e)
914      {
915        if(scheduleChangeController != null)
916        {
917          scheduleChangeController.stopProgressBar();
918        }
919        JOptionPane.showMessageDialog(parent, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
920      }
921    }
922    
923  
924    /**
925     * Look for couterpart of interval unit for a specified unit label
926     * @param unitLabel the specified unit label
927     * @return the actual unit for the label. Null will be returned if no match was found
928     */
929    public static String lookupIntervalUnit(String unitLabel)
930    {
931      String unit = null;
932      if(unitLabel != null)
933      {
934        for(int i=0; i< INTERVALUNITLABEL.length; i++)
935        {
936          String label = INTERVALUNITLABEL[i];
937          if(label != null && label.equals(unitLabel))
938          {
939            unit = INTERVALUNITVALUE[i];
940            break;
941          }
942        }
943      }
944      return unit;
945    }
946   
947    
948    /**
949     * Look for counterpart of interval unit label for a specified unit
950     * @param unit the specified unit 
951     * @return the unit label for the unit. Null will be returned if no match was found
952     */
953    public static String lookupIntervalUnitLabel(String unit)
954    {
955      String unitLabel = null;
956      if(unit != null)
957      {
958        for(int i=0; i< INTERVALUNITVALUE.length; i++)
959        {
960          String unitValue =  INTERVALUNITVALUE[i];
961          if(unitValue != null && unitValue.equals(unit))
962          {
963            unitLabel =INTERVALUNITLABEL[i];
964            break;
965          }
966        }
967      }
968      return unitLabel;
969    }
970    
971    /*
972     * Append time zone to the time string.
973     */
974    /*private void appendTimeZoneToTimeString()
975    {
976      //TimeZone timeZone = Calendar.getInstance().getTimeZone();
977      //String name = timeZone.getDisplayName(true, TimeZone.LONG);
978      String selectedStartTimeZone = (String)startTimeZoneComboBox.getSelectedItem();
979      //System.out.println("The selected start time zone is "+selectedStartTimeZone);
980      startTime = startTime+" "+selectedStartTimeZone;
981      //System.out.println("The start time is "+startTime);
982      String selectedEndTimeZone = (String)endTimeZoneComboBox.getSelectedItem();
983      //System.out.println("The selected end time zone is "+selectedEndTimeZone);
984      endTime = endTime+" "+selectedEndTimeZone;
985      //System.out.println("The end time is "+endTime);
986      
987    }*/
988    
989    public static boolean localContainsTimeZoneID(String id)
990    {
991      boolean contains = false;
992      if(id != null && !id.trim().equals(""))
993      {
994        for(String timeZoneId : availableTimeZoneIDsInLocal)
995        {
996          if(timeZoneId != null && !timeZoneId.trim().equals("") && timeZoneId.equals(id))
997          {
998            //System.out.println("local time zone cotains the id "+id);
999            contains = true;
1000            break;
1001          }
1002        }
1003      }
1004      return contains;
1005    }
1006    
1007    /*
1008     * A listener to handle a selection on the start time zone drop-down box.
1009     * It decides the start time zone id.
1010     * It also sets the end time zone as same as the start time zone when user
1011     * change the start time zone.
1012     */
1013    private class StartTimeZoneItemListener implements ItemListener
1014    {
1015       public void itemStateChanged(ItemEvent e)
1016       {
1017         //System.out.println("====== event: selec"+e.getItem());
1018         startTimeZoneName = (String) e.getItem();
1019         //System.out.println("The selected start time name is "+startTimeZoneName);
1020         TimeZone zone = timeZoneDisplayHash.get(startTimeZoneName);
1021         startTimeZoneID = zone.getID();
1022         //System.out.println("selected this id in start time zone"+startTimeZoneID);
1023         if(endTimeZoneComboBox != null) 
1024         {
1025           endTimeZoneComboBox.setSelectedItem(e.getItem());
1026         }
1027       }
1028    }
1029    
1030    
1031    /*
1032     * A listener to handle a selection on the end time zone drop-down box.
1033     * It decides the end time zone id.
1034     */
1035    private class EndTimeZoneItemListener implements ItemListener
1036    {
1037       public void itemStateChanged(ItemEvent e)
1038       {
1039         //System.out.println("====== event: selec"+e.getItem());
1040         endTimeZoneName = (String) e.getItem();
1041         //System.out.println("The selected end time name is "+endTimeZoneName);
1042         TimeZone zone = timeZoneDisplayHash.get(endTimeZoneName);
1043         endTimeZoneID = zone.getID();
1044         //System.out.println("selected this id in end time zone "+endTimeZoneID);
1045
1046       }
1047    }
1048    
1049}