<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">/*
 * Copyright 2005-2008 Pentaho Corporation.  All rights reserved. 
 * This program is free software; you can redistribute it and/or modify it under the 
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software 
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this 
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 
 * or from the Free Software Foundation, Inc., 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * Copyright 2008 - 2009 Pentaho Corporation.  All rights reserved.
 *
 * Created  
 * @author Steven Barkdull
 */
package org.pentaho.pac.client.scheduler.ctlr;



import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.pentaho.gwt.widgets.client.controls.ProgressPopupPanel;
import org.pentaho.gwt.widgets.client.controls.schededitor.ScheduleEditor;
import org.pentaho.gwt.widgets.client.ui.ICallback;
import org.pentaho.gwt.widgets.client.utils.CronParseException;
import org.pentaho.gwt.widgets.client.utils.TimeUtil;
import org.pentaho.pac.client.ISchedulerServiceAsync;
import org.pentaho.pac.client.PacServiceFactory;
import org.pentaho.pac.client.PentahoAdminConsole;
import org.pentaho.pac.client.common.ui.IResponseCallback;
import org.pentaho.pac.client.common.ui.dialog.ConfirmDialog;
import org.pentaho.pac.client.common.ui.dialog.MessageDialog;
import org.pentaho.pac.client.i18n.PacLocalizedMessages;
import org.pentaho.pac.client.scheduler.model.Schedule;
import org.pentaho.pac.client.scheduler.model.SchedulesModel;
import org.pentaho.pac.client.scheduler.view.DualModeScheduleEditor;
import org.pentaho.pac.client.scheduler.view.ScheduleCreatorDialog;
import org.pentaho.pac.client.scheduler.view.SchedulerToolbar;
import org.pentaho.pac.client.scheduler.view.SchedulesListCtrl;
import org.pentaho.pac.client.scheduler.view.SolutionRepositoryActionSequenceListEditor;
import org.pentaho.pac.client.scheduler.view.ScheduleCreatorDialog.TabIndex;
import org.pentaho.pac.client.utils.ExceptionParser;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.ButtonBase;
import com.google.gwt.user.client.ui.Widget;


public class SchedulerToolbarController {
  
  private SchedulerToolbar schedulerToolbar;
  private SchedulesListCtrl schedulesListCtrl;
  private ScheduleCreatorDialog scheduleCreatorDialog = null;
  private SchedulesListController schedulesListController = null;
  private SolutionRepositoryActionSequenceListEditorController solRepActionSequenceEditorController = null;
  private SchedulesModel schedulesModel = null;
  private static final PacLocalizedMessages MSGS = PentahoAdminConsole.getLocalizedMessages();
  private static final int INVALID_SCROLL_POS = -1;
  private static final String DISABLED = "disabled"; //$NON-NLS-1$
  private boolean isInitialized = false;
  private boolean loadingInitialized = false;
  private static String SUSPENDED_SCHEDULER_STATE = "suspended"; //$NON-NLS-1$
  private static String NORMAL_SCHEDULER_STATE = "normal"; //$NON-NLS-1$
  
  public SchedulerToolbarController( ScheduleCreatorDialog pScheduleCreatorDialog,
      SchedulerToolbar schedulerToolbar, SchedulesListCtrl schedulesListCtrl ) {
    this.scheduleCreatorDialog = pScheduleCreatorDialog;
    this.schedulerToolbar = schedulerToolbar;
    this.schedulesListCtrl = schedulesListCtrl;
  }
  
  public void init( SchedulesListController pSchedulesListController,
      SolutionRepositoryActionSequenceListEditorController solRepActionSequenceEditorController ) {
    
    if ( !isInitialized ) {
      this.schedulesListController = pSchedulesListController;
      this.solRepActionSequenceEditorController = solRepActionSequenceEditorController;
      
      final SchedulerToolbarController localThis = this;
  
      schedulerToolbar.setOnCreateListener( new ICallback&lt;Widget&gt;() { 
        public void onHandle(Widget w) {
          localThis.handleCreateSchedule();
        }
      });
      
      schedulerToolbar.setOnUpdateListener( new ICallback&lt;Widget&gt;() { 
        public void onHandle(Widget w) {
          localThis.handleUpdateSchedule();
        }
      });
  
      schedulerToolbar.setOnDeleteListener( new ICallback&lt;Widget&gt;() {
        public void onHandle(Widget w) {
          localThis.handleDeleteSchedules();
        }
      });
      
      schedulerToolbar.setOnResumeListener( new ICallback&lt;Widget&gt;() { 
        public void onHandle(Widget w) {
          localThis.handleResumeSchedules();
        }
      });
      
      schedulerToolbar.setOnSuspendListener( new ICallback&lt;Widget&gt;() { 
        public void onHandle(Widget w) {
          localThis.handlePauseSchedules();
        }
      });
      
      schedulerToolbar.setOnRunNowListener( new ICallback&lt;Widget&gt;() { 
        public void onHandle(Widget w) {
          localThis.handleRunNowSchedules();
        }
      });
      
      schedulerToolbar.setOnRefreshListener( new ICallback&lt;Widget&gt;() { 
        public void onHandle(Widget w) {
          loadJobsTable();
          // TODO sbarkdull reload sol rep model/view
        }
      });
      
      schedulerToolbar.setOnFilterListChangeListener( new ICallback&lt;String&gt;() { 
        public void onHandle(String s) {
          updateSchedulesTable();
        }
      });  

      ICallback&lt;SolutionRepositoryActionSequenceListEditor&gt; loadingCompleteHandler = new ICallback&lt;SolutionRepositoryActionSequenceListEditor&gt;() {
        public void onHandle(SolutionRepositoryActionSequenceListEditor o) {
          localThis.handleLoadingComplete();
        }
      };
      scheduleCreatorDialog.getSolutionRepositoryActionSequenceEditor().setOnLoadingCompleteHandler( loadingCompleteHandler );
      
      loadJobsTable();  // TODO sbarkdull  belongs in SchedulesListController
      enableTools();
      
      isInitialized = true;
    }
  }
  
  private List&lt;Schedule&gt; getSortedSchedulesList( List&lt;Schedule&gt; scheduleList ) {

    assert null != scheduleList : "getSortedSchedulesList(): Schedule list cannot be null."; //$NON-NLS-1$
    Collections.sort( scheduleList, new Comparator&lt;Schedule&gt;() {
      public int compare(Schedule s1, Schedule s2) {
        return s1.getJobName().compareToIgnoreCase( s2.getJobName() );
      }
    });
    return scheduleList;
  }
  
  private void updateSchedulesTable() {
    List&lt;Schedule&gt; scheduleList = schedulesModel.getScheduleList();
    schedulesListController.updateSchedulesTable( 
        getSortedSchedulesList( getFilteredSchedulesList( scheduleList ) ) );
  }

  private List&lt;Schedule&gt; getFilteredSchedulesList( List&lt;Schedule&gt; scheduleList ) {
    List&lt;Schedule&gt; filteredList = null;
    String filterVal = schedulerToolbar.getFilterValue();
    if ( !SchedulerToolbar.ALL_GROUPS_FILTER.equals( filterVal ) ) {
      filteredList = new ArrayList&lt;Schedule&gt;();
      for ( int ii=0; ii&lt;scheduleList.size(); ++ii ) {
        Schedule s = scheduleList.get( ii );
        if ( s.getJobGroup().equals( filterVal ) ) {
          filteredList.add( s );
        }
      }
    } else {
      filteredList = scheduleList;
    }
    return filteredList;
  }
  
  private void updateSchedule() {

    AsyncCallback&lt;Object&gt; updateScheduleResponseCallback = new AsyncCallback&lt;Object&gt;() {
      public void onSuccess( Object o ) {
        scheduleCreatorDialog.hide();
        loadJobsTable();
      }

      public void onFailure(Throwable caught) {
        MessageDialog messageDialog = new MessageDialog();
        messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
        messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(),caught.getMessage() ));          
      }
    };
    final List&lt;Schedule&gt; scheduleList = schedulesListCtrl.getSelectedSchedules();
    Schedule oldSchedule = scheduleList.get( 0 );
    DualModeScheduleEditor scheduleEditor = scheduleCreatorDialog.getScheduleEditor();
    
    ISchedulerServiceAsync schedSvc = scheduleEditor.isSubscriptionSchedule()
      ? PacServiceFactory.getSubscriptionService()
      : PacServiceFactory.getSchedulerService();
    
    String cronStr = scheduleEditor.getCronString();
    Date startDate = scheduleEditor.getStartDate();
    Date endDate = scheduleEditor.getEndDate();
    
    if ( null == cronStr ) {  // must be a repeating schedule
      String startTime = scheduleEditor.getStartTime(); // format of string should be: HH:MM:SS AM/PM, e.g. 7:12:28 PM
      startDate = TimeUtil.getDateTime( startTime, startDate );
      endDate = (null != endDate) ? TimeUtil.getDateTime( startTime, endDate ) : null;
    }
    
    ScheduleEditor.ScheduleType rt = scheduleEditor.getScheduleType(); 
    switch ( rt ) {
      case RUN_ONCE:
        schedSvc.updateRepeatSchedule(
            oldSchedule.getJobName(),
            oldSchedule.getJobGroup(),
            oldSchedule.getSchedId(),
            scheduleEditor.getName().trim(), 
            scheduleEditor.getGroupName().trim(), 
            scheduleEditor.getDescription().trim(), 
            startDate,
            endDate,
            "0" /*repeat count*/, //$NON-NLS-1$
            "0" /*repeat time*/,  //$NON-NLS-1$
            scheduleCreatorDialog.getSolutionRepositoryActionSequenceEditor().getActionsAsString().trim(),
            updateScheduleResponseCallback
          );
        break;
      case SECONDS: // fall through
      case MINUTES: // fall through
      case HOURS: // fall through
      case DAILY: // fall through
      case WEEKLY: // fall through
      case MONTHLY: // fall through
      case YEARLY:
        if ( null == cronStr ) {
          String repeatInterval = Long.toString( TimeUtil.secsToMillisecs( 
                scheduleEditor.getRepeatInSecs() ) );
          schedSvc.updateRepeatSchedule(
              oldSchedule.getJobName(),
              oldSchedule.getJobGroup(),
              oldSchedule.getSchedId(),
              scheduleEditor.getName().trim(), 
              scheduleEditor.getGroupName().trim(), 
              scheduleEditor.getDescription().trim(), 
              startDate,
              endDate,
              null /*repeat count*/,
              repeatInterval.trim(), 
              scheduleCreatorDialog.getSolutionRepositoryActionSequenceEditor().getActionsAsString().trim(),
              updateScheduleResponseCallback
            );
          break;
        } else {
          // fall through to case CRON
        }
      case CRON:
        schedSvc.updateCronSchedule(
            oldSchedule.getJobName(),
            oldSchedule.getJobGroup(),
            oldSchedule.getSchedId(),
            scheduleEditor.getName().trim(), 
            scheduleEditor.getGroupName().trim(), 
            scheduleEditor.getDescription().trim(), 
            startDate,
            endDate,
            cronStr.trim(), 
            scheduleCreatorDialog.getSolutionRepositoryActionSequenceEditor().getActionsAsString().trim(),
            updateScheduleResponseCallback
          );
        break;
      default:
        throw new RuntimeException( MSGS.invalidRunType( rt.toString() ) );
    }
  }
  
  /**
   * 
   */
  @SuppressWarnings("fallthrough")
  private void updateScheduleWithNewScheduleType() {
    
    final List&lt;Schedule&gt; scheduleList = schedulesListCtrl.getSelectedSchedules();
    Schedule oldSchedule = scheduleList.get( 0 );

    AsyncCallback&lt;Object&gt; deleteScheduleCallback = new AsyncCallback&lt;Object&gt;() {
      public void onSuccess( Object o ) {
        createSchedule();
      }

      public void onFailure(Throwable caught) {
        MessageDialog messageDialog = new MessageDialog();
        messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
        messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(), caught.getMessage()));           
      }
    };
    
    // TODO sbarkdull scheduleCreatorDialog -&gt; scheduleEditorDialog
    DualModeScheduleEditor scheduleEditor = scheduleCreatorDialog.getScheduleEditor();

    ISchedulerServiceAsync schedSvc = null;
    if ( oldSchedule.isSubscriptionSchedule() != scheduleEditor.isSubscriptionSchedule() ) {
      // they are changing the schedule type, so delete it, and add a new one
      schedSvc = oldSchedule.isSubscriptionSchedule()  
        ? PacServiceFactory.getSubscriptionService()
        : PacServiceFactory.getSchedulerService();
      List&lt;Schedule&gt; deleteList = new ArrayList&lt;Schedule&gt;();
      deleteList.add( oldSchedule );
      schedSvc.deleteJobs(deleteList, deleteScheduleCallback );
    } else {
      // they are NOT changing the schedule type, so just update the existing schedule.
      updateSchedule();
    }
  }

  /**
   * Merge the two maps into one map. Add all key-values in the schedulerMap to
   * the mergedMap, unless the key is in both the schedulerMap and subscriptionMap.
   * If it is in both maps, add the one from the subscriptionMap.
   * NOTE: all elements in subscriptionMap should be in the schedulerMap, but not the
   * inverse.
   * 
   * @param schedulerMap
   * @param subscriptionMap
   * @return
   */
  private static List&lt;Schedule&gt; mergeSchedules( Map&lt;String,Schedule&gt; schedulerMap, 
      Map&lt;String,Schedule&gt; subscriptionMap ) {
    
    Schedule currentSched = null;
    List&lt;Schedule&gt; mergedList = new ArrayList&lt;Schedule&gt;();
    for ( Map.Entry&lt;String,Schedule&gt; me : schedulerMap.entrySet() ) {
      
      Schedule subscriptionSchedule = subscriptionMap.get( me.getKey() );
      if ( null != subscriptionSchedule ) {
        currentSched = subscriptionSchedule;
      } else {
        currentSched = me.getValue();
      }
      mergedList.add( currentSched );
    }
    return mergedList;
  }
  
  private void initFilterList() {
    String currentFilter = schedulerToolbar.getFilterValue();
    currentFilter = ( null == currentFilter ) ? SchedulerToolbar.ALL_GROUPS_FILTER : currentFilter;
    
    Set&lt;String&gt; groupNames = new HashSet&lt;String&gt;();
    List&lt;Schedule&gt; scheduleList = schedulesModel.getScheduleList();
    for ( int ii=0; ii&lt;scheduleList.size(); ++ii ) {
      Schedule s = scheduleList.get( ii );
      String groupName = s.getJobGroup();
      if ( !groupNames.contains( groupName ) ) {
        groupNames.add( groupName );
      }
    }
    schedulerToolbar.clearFilters();
    
    schedulerToolbar.addFilterItem( SchedulerToolbar.ALL_GROUPS_FILTER );
    for ( String name : groupNames ) {
      schedulerToolbar.addFilterItem(name );
    }
    schedulerToolbar.setFilterValue( currentFilter );
    
  }
  
  private void loadJobsTable() {

    final ProgressPopupPanel loadingPanel = new ProgressPopupPanel();
    loadingPanel.setLabelText( MSGS.loading() );
    loadingPanel.center();
    
    final int currScrollPos = schedulesListCtrl.getScrollPosition();
    final Map&lt;String,Schedule&gt; schedulesMap = new HashMap&lt;String,Schedule&gt;();
    
    AsyncCallback&lt;Map&lt;String,Schedule&gt;&gt; schedulerServiceCallback = new AsyncCallback&lt;Map&lt;String,Schedule&gt;&gt;() {
      public void onSuccess( Map&lt;String,Schedule&gt; pSchedulesMap ) {
        schedulesMap.putAll( pSchedulesMap );
        enableTools();
        
        AsyncCallback&lt;Map&lt;String,Schedule&gt;&gt; subscriptionServiceCallback = new AsyncCallback&lt;Map&lt;String,Schedule&gt;&gt;() {
          public void onSuccess( Map&lt;String,Schedule&gt; subscriptionSchedulesMap ) {
            List&lt;Schedule&gt; schedulesList = mergeSchedules( schedulesMap, subscriptionSchedulesMap );
            schedulesModel = new SchedulesModel();
            schedulesModel.add( schedulesList );
            initFilterList();
            updateSchedulesTable();
            if ( INVALID_SCROLL_POS != currScrollPos ) { 
              schedulesListCtrl.setScrollPosition( currScrollPos );
            }
            enableTools();
            loadingPanel.hide();
          } // end inner onSuccess

          public void onFailure(Throwable caught) {
            loadingPanel.hide();
            schedulesListCtrl.setTempMessage( MSGS.noSchedules() );
            MessageDialog messageDialog = new MessageDialog( MSGS.error(), 
                caught.getMessage() );
            messageDialog.center();
            enableTools();
          } // end inner onFailure
        }; // end subscriptionServiceCallback
        
        PacServiceFactory.getSubscriptionService().getJobNames( subscriptionServiceCallback );
      } // end outer onSuccess

      public void onFailure(Throwable caught) {
        loadingPanel.hide();
        schedulesListCtrl.setTempMessage( MSGS.noSchedules() );
        MessageDialog messageDialog = new MessageDialog();
        messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
        messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(), caught.getMessage()));
        messageDialog.center();
        messageDialog.show();
        enableTools();
      } // end outer onFailure
    }; // end schedulerServiceCallback
      
    PacServiceFactory.getSchedulerService().getJobNames( schedulerServiceCallback );
  }
  
  public void enableTools() {
    List&lt;Schedule&gt; scheduleList = schedulesListCtrl.getSelectedSchedules();
    
    boolean suspendEnabled = false, resumeEnabled = false;
    
    boolean resolvedSuspended = false, resolvedEnabled = false;
    
    for (Schedule schedule:scheduleList) {
    	if (!resolvedSuspended &amp;&amp; !schedule.getTriggerState().equalsIgnoreCase(SUSPENDED_SCHEDULER_STATE)){
    		suspendEnabled = true;
    		resolvedSuspended = true;
		}
    	
    	if (!resolvedEnabled &amp;&amp; !schedule.getTriggerState().equalsIgnoreCase(NORMAL_SCHEDULER_STATE)){
    		resumeEnabled = true;
    		resolvedEnabled = true;
		}
    }

    int numSelectedItems = scheduleList.size();
    
    enableWidget( schedulerToolbar.getCreateBtn(), true );
    enableWidget( schedulerToolbar.getUpdateBtn(), 1 == numSelectedItems );
    enableWidget( schedulerToolbar.getDeleteBtn(), numSelectedItems &gt; 0 );
    enableWidget( schedulerToolbar.getSuspendBtn(),  suspendEnabled );
    enableWidget( schedulerToolbar.getResumeBtn(), resumeEnabled );
    enableWidget( schedulerToolbar.getRunNowBtn(), numSelectedItems &gt; 0 );
    enableWidget( schedulerToolbar.getRefreshBtn(), true );
  }
  
  private static void enableWidget( ButtonBase btn, boolean isEnabled ) {
    btn.setEnabled( isEnabled );
    if ( isEnabled ) {
      btn.removeStyleDependentName( DISABLED );
    } else {
      btn.addStyleDependentName( DISABLED );
    }
  }
  
  /**
   * NOTE: this method is extremely similar to updateSchedule, when modifying this method,
   * consider modifying updateSchedule in a similar way.
   */
  @SuppressWarnings("fallthrough")
  private void createSchedule() {
    // TODO, List&lt;Schedule&gt; is probably not what we will get back
    AsyncCallback&lt;Object&gt; responseCallback = new AsyncCallback&lt;Object&gt;() {
      public void onSuccess( Object o ) {
        scheduleCreatorDialog.hide();
        loadJobsTable();
      }

      public void onFailure(Throwable caught) {
        MessageDialog messageDialog = new MessageDialog();
        messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
        messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(), caught.getMessage()));     
      }
    }; // end responseCallback
    
    // TODO sbarkdull scheduleCreatorDialog -&gt; scheduleEditorDialog
    DualModeScheduleEditor scheduleEditor = scheduleCreatorDialog.getScheduleEditor();

    String cronStr = scheduleEditor.getCronString();
    Date startDate = scheduleEditor.getStartDate();
    Date endDate = scheduleEditor.getEndDate();
    
    if ( null == cronStr ) {  // must be a repeating schedule
      String startTime = scheduleEditor.getStartTime(); // format of string should be: HH:MM:SS AM/PM, e.g. 7:12:28 PM
      startDate = TimeUtil.getDateTime( startTime, startDate );
      endDate = (null != endDate) ? TimeUtil.getDateTime( startTime, endDate ) : null;
    }
    
    ScheduleEditor.ScheduleType rt = scheduleEditor.getScheduleType();

    // TODO sbarkdull, if we want to support creation of scheduler schedules, we need to supply
 // a UI mechanism like a checkbox to allow user to identify scheduler vs subscription, 
 // and then test the value of the check box instead of the following "true".
    ISchedulerServiceAsync schedSvc = scheduleEditor.isSubscriptionSchedule()  
      ? PacServiceFactory.getSubscriptionService()
      : PacServiceFactory.getSchedulerService();
    
    switch ( rt ) {
      case RUN_ONCE:
        schedSvc.createRepeatSchedule(
            scheduleEditor.getName().trim(), 
            scheduleEditor.getGroupName().trim(), 
            scheduleEditor.getDescription().trim(), 
            startDate,
            endDate,
            "0" /*repeat count*/, //$NON-NLS-1$
            "0" /*repeat time*/,  //$NON-NLS-1$
            scheduleCreatorDialog.getSolutionRepositoryActionSequenceEditor().getActionsAsString().trim(),
            responseCallback
          );
        break;
      case SECONDS: // fall through
      case MINUTES: // fall through
      case HOURS: // fall through
      case DAILY: // fall through
      case WEEKLY: // fall through
      case MONTHLY: // fall through
      case YEARLY:
        if ( null == cronStr ) {
          String repeatInterval = Long.toString( TimeUtil.secsToMillisecs( 
                scheduleEditor.getRepeatInSecs() ) );
          schedSvc.createRepeatSchedule(
              scheduleEditor.getName().trim(), 
              scheduleEditor.getGroupName().trim(), 
              scheduleEditor.getDescription().trim(), 
              startDate,
              endDate,
              null /*repeat count*/,
              repeatInterval.trim(), 
              scheduleCreatorDialog.getSolutionRepositoryActionSequenceEditor().getActionsAsString().trim(),
              responseCallback
            );
          break;
        } else {
          // fall through to case CRON
        }
      case CRON:
        schedSvc.createCronSchedule(
            scheduleEditor.getName().trim(), 
            scheduleEditor.getGroupName().trim(), 
            scheduleEditor.getDescription().trim(), 
            startDate,
            endDate,
            cronStr.trim(), 
            scheduleCreatorDialog.getSolutionRepositoryActionSequenceEditor().getActionsAsString().trim(),
            responseCallback
          );
        break;
      default:
        throw new RuntimeException( MSGS.invalidRunType( rt.toString() ) );
    }
  }
  
  private void deleteSelectedSchedules() {
    final List&lt;Schedule&gt; selectedScheduleList = schedulesListCtrl.getSelectedSchedules();
    
    AsyncCallback&lt;Object&gt; outerCallback = new AsyncCallback&lt;Object&gt;() {
      
      public void onSuccess(Object result) {
        AsyncCallback&lt;Object&gt; innerCallback = new AsyncCallback&lt;Object&gt;() {
          public void onSuccess(Object pResult) {
            loadJobsTable();
          }
          public void onFailure(Throwable caught) {
            MessageDialog messageDialog = new MessageDialog();
            messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
            messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(), caught.getMessage()));   
          }
        }; // end inner callback
        final List&lt;Schedule&gt; subscriptionSchedList = getSubscriptionSchedules( selectedScheduleList );
        PacServiceFactory.getSubscriptionService().deleteJobs( subscriptionSchedList, innerCallback );
      } // end onSuccess
      
      public void onFailure(Throwable caught) {
        MessageDialog messageDialog = new MessageDialog();
        messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
        messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(), caught.getMessage()));   
      }
    }; // end outer callback -----------

    List&lt;Schedule&gt; nonSubscriptionSchedList = getSchedules( selectedScheduleList );
    PacServiceFactory.getSchedulerService().deleteJobs( nonSubscriptionSchedList, outerCallback );
  }
  
  /**
   * initialize the &lt;code&gt;scheduleEditor&lt;/code&gt;'s user interface with 
   * the contents of the &lt;code&gt;sched&lt;/code&gt;.
   * 
   * @param scheduleEditor
   * @param sched
   * @throws CronParseException if sched has a non-empty CRON string, and the CRON string is not valid.
   */
  private void initScheduleCreatorDialog( Schedule sched ) throws CronParseException {

    scheduleCreatorDialog.reset( new Date() );
    initScheduleEditor( sched );
    initSolutionRepositoryActionSequenceEditor( sched );
  }
  
  private void initScheduleEditor( Schedule sched ) throws CronParseException {
    DualModeScheduleEditor scheduleEditor = scheduleCreatorDialog.getScheduleEditor();

    scheduleEditor.setSubscriptionSchedule( sched.isSubscriptionSchedule() );
    scheduleEditor.setName( sched.getJobName() );
    scheduleEditor.setGroupName( sched.getJobGroup() );
    scheduleEditor.setDescription( sched.getDescription() );
    
    String repeatIntervalInMillisecs = sched.getRepeatInterval();
    if ( sched.isCronSchedule() ) {
      scheduleEditor.setCronString( sched.getCronString() );  // throws CronParseException
    } else if ( sched.isRepeatSchedule() ) {
      long repeatIntervalInSecs = TimeUtil.millsecondsToSecs( Long.parseLong( repeatIntervalInMillisecs ) );
      if ( 0 == repeatIntervalInSecs ) {
        // run once
        scheduleEditor.setScheduleType( ScheduleEditor.ScheduleType.RUN_ONCE );
      } else {
        // run multiple
        scheduleEditor.setRepeatInSecs( (int) repeatIntervalInSecs );
      }
    } else {
      throw new RuntimeException( MSGS.illegalStateMissingCronAndRepeat() );
    }

    String timePart = null;
    String strDate = sched.getStartDate();
    if ( null != strDate ) {
      Date startDate = TimeUtil.getDate( strDate );
      if ( sched.isRepeatSchedule() ) {
        timePart = TimeUtil.getTimePart( startDate );
        scheduleEditor.setStartTime( timePart );
        startDate = TimeUtil.zeroTimePart( startDate );
      }
      scheduleEditor.setStartDate( startDate );
    }
//    scheduleEditor.getRunOnceEditor().setStartTime(strTime)
//    scheduleEditor.getRunOnceEditor().setStartDate(strTime)
    
    strDate = sched.getEndDate();
    if ( null != strDate ) {
      scheduleEditor.setEndBy();
      Date endDate = TimeUtil.getDate( strDate );
      if ( sched.isRepeatSchedule() ) {
        endDate = TimeUtil.zeroTimePart( endDate );
      }
      scheduleEditor.setEndDate(endDate);
    } else {
      scheduleEditor.setNoEndDate();
    }
    
  }
  
  private void initSolutionRepositoryActionSequenceEditor( Schedule sched ) {
    solRepActionSequenceEditorController.init( sched.getActionsList() );
    
  }
  
  private boolean isNewScheduleCreatorDialogValid() {
    ScheduleEditor schedEd = scheduleCreatorDialog.getScheduleEditor();
    ScheduleEditorValidator schedEdValidator = new NewScheduleEditorValidator( schedEd, schedulesModel );
    return isScheduleCreatorDialogValid( schedEdValidator );
  }

  private boolean isUpdateScheduleCreatorDialogValid() {
    ScheduleEditor schedEd = scheduleCreatorDialog.getScheduleEditor();
    ScheduleEditorValidator schedEdValidator = new ScheduleEditorValidator( schedEd, schedulesModel );
    return isScheduleCreatorDialogValid( schedEdValidator );
  }
  
  private void handleCreateSchedule() {
    final SchedulerToolbarController localThis = this;
    
    scheduleCreatorDialog.setTitle( MSGS.scheduleCreator() );
    scheduleCreatorDialog.reset( new Date() );
    if(!loadingInitialized) {
      scheduleCreatorDialog.setOkBtnEnabled( false );  
    }
    scheduleCreatorDialog.setOnOkHandler( new ICallback&lt;MessageDialog&gt;() {
      public void onHandle(MessageDialog d) {
        localThis.createSchedule();
      }
    });

    this.scheduleCreatorDialog.setOnValidateHandler( new IResponseCallback&lt;MessageDialog, Boolean&gt;() {
      public Boolean onHandle( MessageDialog schedDlg ) {
        return isNewScheduleCreatorDialogValid();
      }
    });
    
    scheduleCreatorDialog.center();
    solRepActionSequenceEditorController.init( null );
    scheduleCreatorDialog.getScheduleEditor().setFocus();
  }
  
  private void handleUpdateSchedule() {
    final SchedulerToolbarController localThis = this;

    scheduleCreatorDialog.setTitle( MSGS.scheduleEditor() );
    final List&lt;Schedule&gt; scheduleList = schedulesListCtrl.getSelectedSchedules();
    if(!loadingInitialized) {
      scheduleCreatorDialog.setOkBtnEnabled( false );  
    }
    scheduleCreatorDialog.setOnOkHandler( new ICallback&lt;MessageDialog&gt;() {
      public void onHandle(MessageDialog d) {
        localThis.updateScheduleWithNewScheduleType();
      }
    });
    this.scheduleCreatorDialog.setOnValidateHandler( new IResponseCallback&lt;MessageDialog, Boolean&gt;() {
      public Boolean onHandle( MessageDialog schedDlg ) {
        return isUpdateScheduleCreatorDialogValid();
      }
    });
    // the update button should be enabled/disabled to guarantee that one and only one schedule is selected
    assert scheduleList.size() == 1 : "When clicking update, exactly one schedule should be selected."; //$NON-NLS-1$
    
    Schedule sched = scheduleList.get( 0 );
    try {
      initScheduleCreatorDialog( sched );
      scheduleCreatorDialog.center();
      scheduleCreatorDialog.getScheduleEditor().setFocus();
    } catch (CronParseException e) {
      final MessageDialog errorDialog = new MessageDialog( MSGS.error(),
          MSGS.invalidCronInInitOfRecurrenceDialog( sched.getCronString(), e.getMessage() ) );
      errorDialog.setOnOkHandler( new ICallback&lt;MessageDialog&gt;() {
        public void onHandle(MessageDialog messageDialog ) {
          errorDialog.hide();
          scheduleCreatorDialog.center();
        }
      });
      errorDialog.center();
    }
  }

  private void handleLoadingComplete() {
    scheduleCreatorDialog.setOkBtnEnabled( true );
    loadingInitialized = true;
  }
  
  private void handleDeleteSchedules() {
    final SchedulerToolbarController localThis = this;
    
    final ConfirmDialog confirm = new ConfirmDialog( MSGS.confirmDelete(),
        MSGS.confirmDeleteQuestion( Integer.toString( getNumSubscribers() ) ) );
    confirm.setOnOkHandler( new ICallback&lt;MessageDialog&gt;() {
      public void onHandle( MessageDialog d ) {
        confirm.hide();
        localThis.deleteSelectedSchedules();
      }
    });
    confirm.center();
  }
  
  private int getNumSubscribers() {
    List&lt;Schedule&gt; schedList = schedulesListCtrl.getSelectedSchedules();
    int numSubscribers = 0;
    for ( Schedule sched: schedList ) {
      try {
        numSubscribers += Integer.parseInt( sched.getSubscriberCount() );
      } catch (NumberFormatException ex) {
        // Do nothing, we'll return 0.
      }
    }
    return numSubscribers;
  }
  
  private void handleResumeSchedules() {
    final List&lt;Schedule&gt; selectedScheduleList = schedulesListCtrl.getSelectedSchedules();
    
    AsyncCallback&lt;Object&gt; outerCallback = new AsyncCallback&lt;Object&gt;() {
      
      public void onSuccess(Object result) {
        AsyncCallback&lt;Object&gt; innerCallback = new AsyncCallback&lt;Object&gt;() {
          public void onSuccess(Object pResult) {
            loadJobsTable();
          }
          public void onFailure(Throwable caught) {
            MessageDialog messageDialog = new MessageDialog();
            messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
            messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(), caught.getMessage()));     
          }
        }; // end inner callback
        final List&lt;Schedule&gt; subscriptionSchedList = getSubscriptionSchedules( selectedScheduleList );
        PacServiceFactory.getSubscriptionService().resumeJobs( subscriptionSchedList, innerCallback );
      } // end onSuccess
      
      public void onFailure(Throwable caught) {
        MessageDialog messageDialog = new MessageDialog();
        messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
        messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(), caught.getMessage()));     
      }
    }; // end outer callback -----------

    List&lt;Schedule&gt; nonSubscriptionSchedList = getSchedules( selectedScheduleList );
    PacServiceFactory.getSchedulerService().resumeJobs( nonSubscriptionSchedList, outerCallback );
  }
  
  private void handlePauseSchedules() {
    final List&lt;Schedule&gt; selectedScheduleList = schedulesListCtrl.getSelectedSchedules();
    
    AsyncCallback&lt;Object&gt; outerCallback = new AsyncCallback&lt;Object&gt;() {
      
      public void onSuccess(Object result) {
        AsyncCallback&lt;Object&gt; innerCallback = new AsyncCallback&lt;Object&gt;() {
          public void onSuccess(Object pResult) {
            loadJobsTable();
          }
          public void onFailure(Throwable caught) {
            MessageDialog messageDialog = new MessageDialog();
            messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
            messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(), caught.getMessage()));    
          }
        }; // end inner callback
        final List&lt;Schedule&gt; subscriptionSchedList = getSubscriptionSchedules( selectedScheduleList );
        PacServiceFactory.getSubscriptionService().pauseJobs( subscriptionSchedList, innerCallback );
      } // end onSuccess
      
      public void onFailure(Throwable caught) {
        MessageDialog messageDialog = new MessageDialog();
        messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
        messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(), caught.getMessage()));    
      }
    }; // end outer callback -----------

    List&lt;Schedule&gt; nonSubscriptionSchedList = getSchedules( selectedScheduleList );
    PacServiceFactory.getSchedulerService().pauseJobs( nonSubscriptionSchedList, outerCallback );
  }
  
  private void handleRunNowSchedules() {
    final List&lt;Schedule&gt; selectedScheduleList = schedulesListCtrl.getSelectedSchedules();
    
    AsyncCallback&lt;Object&gt; outerCallback = new AsyncCallback&lt;Object&gt;() {
      
      public void onSuccess(Object result) {
        AsyncCallback&lt;Object&gt; innerCallback = new AsyncCallback&lt;Object&gt;() {
          public void onSuccess(Object pResult) {
            loadJobsTable();
          }
          public void onFailure(Throwable caught) {
            MessageDialog messageDialog = new MessageDialog();
            messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
            messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(), caught.getMessage()));     
          }
        }; // end inner callback
        final List&lt;Schedule&gt; subscriptionSchedList = getSubscriptionSchedules( selectedScheduleList );
        PacServiceFactory.getSubscriptionService().executeJobs( subscriptionSchedList, innerCallback );
      } // end onSuccess
      
      public void onFailure(Throwable caught) {
        MessageDialog messageDialog = new MessageDialog();
        messageDialog.setText(ExceptionParser.getErrorHeader(caught.getMessage()));
        messageDialog.setMessage(ExceptionParser.getErrorMessage(caught.getMessage(), caught.getMessage()));    
      }
    }; // end outer callback -----------

    List&lt;Schedule&gt; nonSubscriptionSchedList = getSchedules( selectedScheduleList );
    PacServiceFactory.getSchedulerService().executeJobs( nonSubscriptionSchedList, outerCallback );
  }

  
  private static List&lt;Schedule&gt; getSchedules( List&lt;Schedule&gt; schedList ) {
    List&lt;Schedule&gt; list = new ArrayList&lt;Schedule&gt;();
    for ( Schedule sched : schedList ) {
      if ( !sched.isSubscriptionSchedule() ) {
        list.add( sched);
      }
    }
    return list;
  }
  
  private static List&lt;Schedule&gt; getSubscriptionSchedules( List&lt;Schedule&gt; schedList ) {
    List&lt;Schedule&gt; list = new ArrayList&lt;Schedule&gt;();
    for ( Schedule sched : schedList ) {
      if ( sched.isSubscriptionSchedule() ) {
        list.add( sched);
      }
    }
    return list;
    
  }
  
  /**
   * NOTE: This method should not be called directly except by isNewScheduleCreatorDialogValid and isUpdateScheduleCreatorDialogValid
   * NOTE: code in this method must stay in sync with isScheduleEditorValid(), i.e. all error msgs
   * that may be cleared in clearScheduleEditorValidationMsgs(), must be set-able here.
   */
  private boolean isScheduleCreatorDialogValid( ScheduleEditorValidator schedEdValidator ) {

    boolean isValid = true;

    boolean isSubscriptionSched = scheduleCreatorDialog.getScheduleEditor().isSubscriptionSchedule();
    SolutionRepositoryActionSequenceListEditor solRepPicker = scheduleCreatorDialog.getSolutionRepositoryActionSequenceEditor();
    SolutionRepositoryActionSequenceListEditorValidator solRepValidator = new SolutionRepositoryActionSequenceListEditorValidator( solRepPicker, isSubscriptionSched );

    scheduleCreatorDialog.clearTabError();
    schedEdValidator.clear();
    solRepValidator.clear();
    
    /*
     * If a tab's controls have errors, change the tab's appearance so that
     * the tab-label displays in an error-color (red). If the current tab 
     * does not have an error, find the first tab that does have an error,
     * and set it to the current tab.
     */
    TabIndex firstTabWithError = null;
    boolean doesSelectedTabHaveError = false;
    TabIndex selectedIdx = scheduleCreatorDialog.getSelectedTab();
    
    if ( !schedEdValidator.isValid() ) {
      isValid = false ;
      scheduleCreatorDialog.setTabError( TabIndex.SCHEDULE );
      if ( null == firstTabWithError ) {
        firstTabWithError = TabIndex.SCHEDULE;
      }
      if ( TabIndex.SCHEDULE == selectedIdx ) {
        doesSelectedTabHaveError = true;
      }
    }    
    if ( !solRepValidator.isValid() ) {
      isValid = false ;
      scheduleCreatorDialog.setTabError( TabIndex.SCHEDULE_ACTION );
      if ( null == firstTabWithError ) {
        firstTabWithError = TabIndex.SCHEDULE_ACTION;
      }
      if ( TabIndex.SCHEDULE_ACTION == selectedIdx ) {
        doesSelectedTabHaveError = true;
      }
    }
    if ( false == doesSelectedTabHaveError &amp;&amp; firstTabWithError != null ) {
      scheduleCreatorDialog.setSelectedTab( firstTabWithError );
    }
    
    return isValid;
  }

  public SchedulesModel getSchedulesModel() {
    return schedulesModel;
  }
}
</pre></body></html>