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;
030
031import java.awt.event.ActionEvent;
032import java.util.Hashtable;
033import java.util.concurrent.atomic.AtomicBoolean;
034
035import javax.swing.AbstractAction;
036import javax.swing.JOptionPane;
037
038import org.apache.commons.logging.Log;
039import org.apache.commons.logging.LogFactory;
040import org.kepler.authentication.AuthenticationListener;
041import org.kepler.authentication.AuthenticationManager;
042import org.kepler.authentication.Domain;
043import org.kepler.gui.AuthenticationWithDomainNameAction;
044import org.kepler.module.workflowschedulergui.Initialize;
045import org.kepler.objectmanager.repository.Repository;
046import org.kepler.objectmanager.repository.RepositoryManager;
047
048import ptolemy.actor.gui.TableauFrame;
049
050/**
051 * Represent an abstract actions which operates a workflow scheduler server. The subclasses
052 * include ScheduleWorkflowAction, RemoveScheduleAction, EnableScheduleAction and
053 * DisableScheduleAction
054 */
055public class SchedulerAbstractAction extends AbstractAction implements  AuthenticationListener
056{
057  private static final Log log = LogFactory.getLog(SchedulerAbstractAction.class
058      .getName());
059  protected static final String SCHEDULER = "scheduler";
060  protected static final String URL = "url";
061  protected static final String ERROR = "Error";
062  protected static String SLASHCONNECTOR = "://";
063  public static final String NOREPORTWARNING ="The selected workflow's KAR doesn't contain "+
064  "a report design, and so no run KAR will be created as a result of execution.\n"+
065  "Continue?";
066  
067  protected static Hashtable <String, String>domainSessionHash = new Hashtable<String, String>();
068  protected static String authenDomainForSourceKar = null;
069  //protected static String sessionId = null; //all subclass will share this session id
070  protected static String authenticationServiceURLForSourceKar = null;
071  protected static String sourceRepositoryName = null;
072  protected static Repository source = null;
073  protected String schedulerURL = null;
074  protected Schedule schedule = null;
075  protected TableauFrame parent = null;
076  //protected AuthenticateAction authAction = null;
077  protected ScheduleChangeController scheduleChangeController = null;
078  protected WorkflowSchedulerParentPanel schedulerParentPanel = null;
079  protected static volatile AtomicBoolean  isActionWithAuthenticationDone = new AtomicBoolean(true);
080  protected static boolean hasReportLayout = true;
081  
082  
083  
084  
085  /**
086   * Constructor
087   * @param parent the parent frame of this action
088   * @param scheduleChangeController the GUI controller to handle the schedule change.
089   */
090  public SchedulerAbstractAction(TableauFrame parent, WorkflowSchedulerParentPanel schedulerParentPanel, 
091      ScheduleChangeController scheduleChangeController)
092  {
093    this.parent = parent;
094    this.schedulerParentPanel = schedulerParentPanel;
095    this.scheduleChangeController = scheduleChangeController;
096    schedulerURL = Initialize.getSchedulerURL();
097    //this.authenDomainForSourceKar = authenDomainForSourceKar;
098  }
099  
100  /**
101   * Perform an action to a workflow
102   */
103  public void actionPerformed(ActionEvent e) 
104  {
105    //check scheduler url is available.
106    if(schedulerURL == null || schedulerURL.trim().equals(""))
107    {
108      JOptionPane.showMessageDialog(parent, 
109          "Kepler couldn't find the workflow scheduler url in the configuration file.", 
110          "Error", JOptionPane.ERROR_MESSAGE);
111      return;
112    }  
113    
114    //check if a search process is done
115    if(schedulerParentPanel != null && !schedulerParentPanel.isSelectingRemoteWorkflowDone())
116    {
117      String message = "Kepler hasn't finished the search on existing schedules from the remote scheduler.\n  Please click the button later.";
118      JOptionPane.showMessageDialog(parent, 
119         message, "Warning", JOptionPane.WARNING_MESSAGE);
120      return;
121    }
122    
123    int choice = JOptionPane.YES_OPTION;                
124    if(!hasReportLayout && this instanceof ScheduleWorkflowAction &&
125        scheduleChangeController != null && scheduleChangeController.showWarningMessageOnNoReporting())
126    {
127      choice = JOptionPane.showConfirmDialog(parent, 
128         NOREPORTWARNING, "Warning", JOptionPane.YES_NO_OPTION);
129    }
130    
131    if(choice == JOptionPane.NO_OPTION)
132    {
133      //System.out.println("Choosing no=============== ");
134      return;
135    }
136    
137    try
138    {
139      //check Action with authentication(we login only once) is done
140      checkActionWithAuthentication();
141    }
142    catch(Exception ee)
143    {
144      log.warn(ee.getMessage());
145      return;
146    }
147    
148    if(scheduleChangeController != null)
149    {
150      scheduleChangeController.startProgressBar();
151    }
152    boolean success = getAuthenticationService();
153    if(!success)
154    {
155      return;
156    }
157    String sessionID = null;
158    if(authenDomainForSourceKar != null)
159    {
160      sessionID = domainSessionHash.get(authenDomainForSourceKar);
161    }  
162    
163    //check if the cached sessionID is still valid
164    if(sessionID != null)
165    {
166      boolean existing = AuthenticationManager.getManager().proxyExists(sessionID, authenDomainForSourceKar);
167      if(!existing)
168      {
169        //not existing any more, set it to null
170        sessionID = null;
171      }
172    }
173   
174    if (sessionID == null)
175    {
176      //login first
177      try
178      {
179        authenticate();
180      }
181      catch(Exception ee)
182      {
183        log.warn(ee.getMessage());
184      }
185    }
186    else
187    {
188      try
189      {
190        doAction();
191      }
192      catch(Exception ee)
193      {
194        log.warn(ee.getMessage());
195      }
196      if(scheduleChangeController != null)
197      {
198        scheduleChangeController.stopProgressBar();
199      }
200    }
201   
202  }
203  
204  /**
205   *Do the real action. Every subclass should implement this method
206   */
207  protected void doAction() throws Exception
208  {
209    String error = "Couldn't do schedule-related action to the workflow since the source repository is unknown";
210    if(source == null)
211    {
212      JOptionPane.showMessageDialog(parent, error, ERROR, JOptionPane.ERROR_MESSAGE);
213      throw new Exception(error);
214    }
215   
216  }
217  
218  /**
219   * Check if an action with authentication process is done
220   * @throws Exception
221   */
222  public  void checkActionWithAuthentication() throws Exception
223  {
224  //check if the the authentication process is done.
225    if(isActionWithAuthenticationDone.get()== false)
226    {
227      String message = "Login and a schedule-related action are being processed right now. Please wait, then click the button later.";
228      JOptionPane.showMessageDialog(parent, 
229         message, "Warning", JOptionPane.WARNING_MESSAGE);
230       throw new Exception(message);
231    }
232  }
233  
234  /*
235   * Get the authentication service url
236   */
237  private boolean getAuthenticationService()
238  {
239    boolean success = true;   
240    Repository repository = null;
241    try
242    {
243      repository= RepositoryManager.getInstance().getRepository(sourceRepositoryName);
244      if(repository == null)
245      {
246        throw new Exception("Kepler couldn't find the reposiotry in its configuration file for the name "+sourceRepositoryName);
247      }
248    }
249    catch(Exception e)
250    {
251      JOptionPane.showMessageDialog(parent, "Kepler couldn't get the repository information for "+sourceRepositoryName
252          + " and so you couldn't continue to do a schedule-related action -"+e.getMessage(), ERROR, JOptionPane.ERROR_MESSAGE);
253      success = false;
254      return success;
255    }
256    authenDomainForSourceKar = repository.getAuthDomain();
257    try
258    {
259      Domain domain = AuthenticationManager.getManager().getDomain(authenDomainForSourceKar);
260      if(domain == null)
261      {
262        throw new Exception("The authentication domain couldn't be found for the name"+authenDomainForSourceKar);
263      }
264      else
265      {
266        authenticationServiceURLForSourceKar = domain.getServiceURL();
267        //System.out.println("Get the NEW!!! authentication service url is ======  "+authenticationServiceURL);
268      }
269    }
270    catch(Exception e)
271    {
272      JOptionPane.showMessageDialog(parent, "Couldn't get the authentication domanin and you could NOT continue to do a schedule-related action - \n"+e.getMessage(), ERROR, JOptionPane.ERROR_MESSAGE);
273      success = false;
274    }
275    
276    //System.out.println("The authentication service url is ======  "+authenticationServiceURL);
277    return success;
278  }
279  
280
281  /**
282   * Set the sourceRepositoryName associated with the action
283   * @param name
284   */
285  public static void setSourceRespositoryName(String name) throws Exception
286  {
287    sourceRepositoryName = name;
288    source = RepositoryManager.getInstance().getRepository(sourceRepositoryName);
289  }
290  
291  /*
292   * Fire authentication command
293   */
294  private void authenticate() throws Exception
295  {
296    isActionWithAuthenticationDone.set(false);
297    if(scheduleChangeController != null)
298    {
299      scheduleChangeController.disableTreeSelection();
300    }
301    AuthenticationWithDomainNameAction authAction = 
302       new AuthenticationWithDomainNameAction(parent, this, authenDomainForSourceKar);
303    ActionEvent event = new ActionEvent(this, 100, "command");
304    authAction.actionPerformed(event);
305  }
306  /**
307   * Call back method of AuthenticatListener.
308   * 
309   */
310  public void authenticationComplete(int status, String sessionId, String domainName)
311  {
312     if(status == AuthenticationListener.FAILURE)
313     {
314       //System.out.println("failure ============== in authenticationCompleted");
315       JOptionPane.showMessageDialog(parent, "Authentication failed and you could NOT do a schedule-related action.", ERROR, JOptionPane.ERROR_MESSAGE);
316     }
317     else if(status == AuthenticationListener.CANCEL)
318     {
319       //System.out.println("cancel ============== in authenticationCompleted");
320     }
321     else if(status == AuthenticationListener.SUCCESS)
322     {
323       //System.out.println("sccuess ============== in authenticationCompleted");
324       //this.sessionID = sessionId;
325       //System.out.println("===============put the session id "+sessionId+ " and domain name "+domainName+" into the hashtable");
326       domainSessionHash.put(domainName, sessionId);
327       try
328       {
329         doAction();
330       }
331       catch(Exception ee)
332       {
333         log.error(ee.getMessage());
334       }
335     }
336     isActionWithAuthenticationDone.set(true);
337     if(scheduleChangeController != null)
338     {
339       scheduleChangeController.enableTreeSelection();
340       scheduleChangeController.stopProgressBar();      
341     }
342     //System.out.println("authentication is done ============== in authenticationCompleted");
343  }
344  
345  /**
346   * Set the schedule object
347   * @param schedule
348   */
349  public void setSchedule(Schedule schedule)
350  {
351    this.schedule = schedule;
352  }
353
354  /**
355   * Set true if the workflow associated with action has a report layout. 
356   * @param hasReportingLayout
357   */
358  public static void setHasReportLayout(boolean hasReportingLayout)
359  {
360    hasReportLayout = hasReportingLayout;
361  }
362}