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.io.File; 032import java.util.Stack; 033import java.util.concurrent.atomic.AtomicBoolean; 034 035import javax.swing.Box; 036import javax.swing.BoxLayout; 037import javax.swing.JLabel; 038import javax.swing.JOptionPane; 039import javax.swing.JPanel; 040 041import org.apache.commons.logging.Log; 042import org.apache.commons.logging.LogFactory; 043import org.ecoinformatics.ecogrid.client.IdentifierServiceClient; 044import org.kepler.gui.TabPane; 045import org.kepler.kar.KARFile; 046import org.kepler.objectmanager.lsid.KeplerLSID; 047import org.kepler.objectmanager.repository.Repository; 048import org.kepler.objectmanager.repository.RepositoryManager; 049 050import ptolemy.actor.gui.TableauFrame; 051 052/** 053 * This class represents the right panel of the scheduler dialog object. 054 * It can show one panel of the two options - a JLabel which ask user to 055 * select a remote workflow and a real scheduler panel. 056 * @author tao 057 * 058 */ 059public class WorkflowSchedulerParentPanel extends JPanel implements TabPane, 060 UploadingKARFileListenerInterface 061{ 062 private static final Log log = LogFactory.getLog(WorkflowSchedulerParentPanel.class 063 .getName()); 064 static final String SCHEDULER = "Scheduler"; 065 private static final int ITEM = 0; 066 067 private JLabel message = new JLabel("Select a workflow from the Components panel."); 068 private TableauFrame parent = null; 069 private WorkflowSchedulerPanel schedulerPanel = null; 070 //private boolean showedMessage = true; 071 private ScheduleChangeController scheduleChangeController; 072 //private volatile boolean doneSelectRemoteWorkflow = false; 073 private Stack trackSelectRemoteWorkflow = new Stack(); 074 private AtomicBoolean previousSelectionIsWorkflow = new AtomicBoolean(false); 075 076 /** 077 * Constructor 078 * @param parent 079 */ 080 public WorkflowSchedulerParentPanel(TableauFrame parent, ScheduleChangeController scheduleChangeController) 081 { 082 this.parent = parent; 083 this.scheduleChangeController = scheduleChangeController; 084 if(this.scheduleChangeController != null) 085 { 086 this.scheduleChangeController.addListener(this); 087 } 088 try 089 { 090 schedulerPanel = new WorkflowSchedulerPanel(parent,this, this.scheduleChangeController); 091 } 092 catch(Exception e) 093 { 094 JOptionPane.showMessageDialog(null, "Workflow scheduler couldn't function correctly -- "+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); 095 //log.error("Workflow scheduler couldn't function correctly -- "+e.getMessage()); 096 } 097 098 initialize(); 099 } 100 101 /* 102 * Initialize the panel 103 */ 104 private void initialize() 105 { 106 this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); 107 this.add(Box.createVerticalStrut(20)); 108 Box box = Box.createHorizontalBox(); 109 box.add(Box.createHorizontalStrut(250)); 110 box.add(message); 111 box.add(Box.createHorizontalGlue()); 112 this.add(box); 113 this.add(Box.createVerticalGlue()); 114 } 115 116 /** 117 * Return the parent frame 118 */ 119 public TableauFrame getParentFrame() 120 { 121 return parent; 122 } 123 124 /** 125 * This method should return the name of the tab which is used to label the 126 * tab in the TabbedPane 127 */ 128 public String getTabName() 129 { 130 return SCHEDULER; 131 } 132 133 /** 134 * Initialize the tab 135 */ 136 public void initializeTab() throws Exception 137 { 138 139 } 140 141 /** 142 * Set the parent frame of this panel 143 */ 144 public void setParentFrame(TableauFrame parent) 145 { 146 this.parent = parent; 147 } 148 149 /** 150 * Action for selecting a remote workflow on component search panel 151 * @param name name of the workflow 152 * @param lsid lsid of the workflow 153 * @param karSourceRepositoryName the name of repository storing the kar file 154 * @param karId the id of the kar file 155 * @param hasReporting if the workflow has a reporting module 156 */ 157 public synchronized void selectRemoteWorkflow(String workflowName, String workflowLsid, 158 String karSourceRepositoryName, String karId, boolean hasReportLayout) 159 { 160 //System.out.println("The workflow name is "+workflowName); 161 //System.out.println("The workflow lsid is "+workflowLsid); 162 //System.out.println("The repository name is "+karSourceRepositoryName); 163 //System.out.println("The kar id is "+karId); 164 //System.out.println("Choosing yes=============== "); 165 if(karId != null && workflowLsid != null && karSourceRepositoryName != null && schedulerPanel != null) 166 { 167 if(scheduleChangeController != null) 168 { 169 scheduleChangeController.startProgressBar(); 170 } 171 previousSelectionIsWorkflow.set(true); 172 trackSelectRemoteWorkflow.add(ITEM); 173 schedulerPanel.setWorkflowForScheduling(workflowName, workflowLsid, 174 karSourceRepositoryName, karId, hasReportLayout); 175 } 176 else 177 { 178 selectNonSchedulalbeItem(); 179 } 180 181 } 182 183 /** 184 * Set a local workflow on this panel for scheduling 185 * @param karFilePath the path of kar file which contains the workflow 186 * @param workflowName the name of the workflow 187 * @param workflowLSID the id of the workflow 188 */ 189 public synchronized void setLocalWorkflow(String karFilePath, String workflowName, String workflowLSID) 190 { 191 192 selectNonSchedulalbeItem();//set the background 193 Repository repository = null; 194 195 if(schedulerPanel == null) 196 { 197 return; 198 } 199 200 try 201 { 202 repository = RepositoryManager.getInstance().getSaveRepository(); 203 } 204 catch(Exception e) 205 { 206 log.warn("Couldn't find saving repository -"+e.getMessage()); 207 } 208 209 if(repository == null) 210 { 211 JOptionPane.showMessageDialog(parent, "To schedule this workflow, you must first choose a remote repository.\n" 212 +"Click the \"Sources\" button and mark \"Save\" next to a remote Source, and try again.","Warning" , JOptionPane.WARNING_MESSAGE); 213 return; 214 } 215 216 217 218 //check if the kar file already in LocalRemoteWorkflwoMappingController 219 String remoteKarFileLSID = getRemoteKarLSIDFromLocalRemoteWorkflowController(karFilePath, repository.getName()); 220 if(remoteKarFileLSID == null) 221 { 222 //LocalRemoteWorkflwoMappingController doesn't register it, 223 //check remote the server 224 if(scheduleChangeController != null) 225 { 226 scheduleChangeController.startProgressBar(); 227 } 228 KARFile karFile = getKarFile(karFilePath); 229 if(karFile == null) 230 { 231 if(scheduleChangeController != null) 232 { 233 scheduleChangeController.stopProgressBar(); 234 } 235 return; 236 } 237 //check the remote repository 238 boolean registered = isAlreadyRegistered(karFile.getLSID(), repository); 239 if(!registered) 240 { 241 // has not been uploaded, please upload the kar file 242 int choice = JOptionPane.showConfirmDialog(parent, 243 "To schedule this workflow on the "+repository.getName()+" repository, it must first" 244 +" be uploaded.\nUpload KAR?", "Warning", JOptionPane.YES_NO_OPTION); 245 246 if(choice == JOptionPane.NO_OPTION) 247 { 248 if(scheduleChangeController != null) 249 { 250 scheduleChangeController.stopProgressBar(); 251 } 252 return; 253 } 254 uploadKarFile(karFile,karFilePath, workflowName, workflowLSID, repository.getName()); 255 256 } 257 else 258 { 259 remoteKarFileLSID = karFile.getLSID().toString(); 260 boolean hasReportLayout = true;// we don't warn user again 261 // success upload and we have the remote kar file at hand. 262 selectRemoteWorkflow(workflowName, workflowLSID, 263 repository.getName(), remoteKarFileLSID, hasReportLayout); 264 } 265 } 266 else 267 { 268 boolean hasReportLayout = true;// we don't warn user again 269 // success upload and we have the remote kar file at hand. 270 selectRemoteWorkflow(workflowName, workflowLSID, 271 repository.getName(), remoteKarFileLSID, hasReportLayout); 272 } 273 } 274 275 /* 276 * Get the remote kar lsid for the local workflow kar file from LocalRemoteWorkflowController 277 * If null returned, this means the local kar file has not been uploaded to the 278 * remote repository 279 */ 280 private String getRemoteKarLSIDFromLocalRemoteWorkflowController(String localKarFilePath, String repositoryName) 281 { 282 String remoteKarLSID = null; 283 //first to see if the local-remote controller has the copy. This is memory checking. 284 LocalRemoteWorkflowMap map = LocalRemoteWorkflowMappingController.getMap(localKarFilePath, repositoryName); 285 if(map != null) 286 { 287 remoteKarLSID = map.getRemoteKarLSID(); 288 } 289 //System.out.println("=========== get kar lisd from the controller "+remoteKarLSID); 290 return remoteKarLSID; 291 } 292 293 /* 294 * Test if the kar lsid is already registered in the saving repository 295 */ 296 private boolean isAlreadyRegistered(KeplerLSID lsid, Repository saveRepository) 297 { 298 boolean registered = false; 299 try 300 { 301 IdentifierServiceClient identificationClient = new IdentifierServiceClient( 302 saveRepository.getLSIDServerURL()); 303 registered = identificationClient.isRegistered(lsid.toString()); 304 } 305 catch(Exception e) 306 { 307 log.warn("Couldn't determine if the kar lsid has been registered in the remote repository - "+e.getMessage()); 308 } 309 //System.out.println("=========== is already register for the lisd "+lsid.toString()+ " "+registered); 310 return registered; 311 } 312 313 /* 314 * Get KARFile object from the karFilePath. null will be returned if kepler 315 * can't create KARFile. 316 */ 317 private KARFile getKarFile(String karFilePath) 318 { 319 KARFile karFile = null; 320 try 321 { 322 karFile = new KARFile(new File(karFilePath)); 323 } 324 catch(Exception e) 325 { 326 JOptionPane.showMessageDialog(parent, 327 "Kepler couldn't create kar file for path "+karFilePath+ 328 " - "+e.getMessage(),"Error" , JOptionPane.ERROR_MESSAGE); 329 330 } 331 return karFile; 332 } 333 334 /* 335 * Upload the kar file and kar xml to remote repository. 336 * The lisd of kar file will be returned. If uploading failed, null will be returned. 337 */ 338 private void uploadKarFile( KARFile karFile,String karFilePath, 339 String workflowName, String workflowLSID, String repositoryName) 340 { 341 UploadingKARFileSwingWorker worker = new UploadingKARFileSwingWorker(karFile, karFilePath, 342 workflowName, workflowLSID, repositoryName, scheduleChangeController, parent); 343 worker.execute(); 344 } 345 346 /** 347 * SearchSchedulesListenerInterface calls back this method. 348 * It will update the gui. 349 */ 350 public void complete() 351 { 352 this.repaint(); 353 this.validate(); 354 trackSelectRemoteWorkflow.pop(); 355 if(scheduleChangeController != null) 356 { 357 scheduleChangeController.stopProgressBar(); 358 } 359 360 //System.out.println("search is done"); 361 } 362 363 /** 364 * Call back method when the uploading is done. 365 * It will put the kar file lsid into a map. Then select the remote copy of the kar file to 366 * scheduler gui. 367 * @param KARFileLSID the lisd of the uploaded kar file 368 * @param KARFilePath the path of the local kar file 369 * @param workflowName the name of the workflow 370 * @param workflowLSID the lsid of the workflow 371 * @param repositoryName the name of the remote repository 372 */ 373 public void completeUploading(String KARFileLSID, String KARFilePath, String workflowName, 374 String workflowLSID, String repositoryName) 375 { 376 if(scheduleChangeController != null) 377 { 378 scheduleChangeController.stopProgressBar(); 379 } 380 if(KARFileLSID != null) 381 { 382 LocalRemoteWorkflowMap map = new LocalRemoteWorkflowMap(KARFilePath, 383 workflowLSID, workflowName, KARFileLSID, repositoryName); 384 LocalRemoteWorkflowMappingController.add(map); 385 boolean hasReportLayout = true;// we don't warn user again 386 // success upload and we have the remote kar file at hand. 387 selectRemoteWorkflow(workflowName, workflowLSID, 388 repositoryName, KARFileLSID, hasReportLayout); 389 } 390 else 391 { 392 JOptionPane.showMessageDialog(parent, 393 "Failed to upload kar file to the repository.","Error" , JOptionPane.ERROR_MESSAGE); 394 } 395 396 397 } 398 399 /** 400 * Method for ScheduleChangeListener. Do nothing. 401 * Handle the event that a new schedule is added 402 * @param schedule the new schedule 403 * @throws Exception 404 */ 405 public void addSchedule(Schedule schedule) throws Exception 406 { 407 408 } 409 410 /** 411 * Method for ScheduleChangeListener. Do nothing. 412 * Handle the event that a schedule is removed 413 * @param schedule the schedule will be removed 414 * @throws Exception 415 */ 416 public void removeSchedule(Schedule schedule) throws Exception 417 { 418 419 } 420 421 /** 422 * Method for ScheduleChangeListener. Do nothing. 423 * Handle the event that a schedule will be enabled 424 * @param schedule the schedule will be enabled 425 * @throws Exception 426 */ 427 public void enableSchedule(Schedule schedule) throws Exception 428 { 429 430 } 431 432 /** 433 * Method for ScheduleChangeListener. Do nothing. 434 * Handle the event that a schedule will be disabled 435 * @param schedule the schedule will be disabled 436 * @throws Exception 437 */ 438 public void disableSchedule(Schedule schedule) throws Exception 439 { 440 441 } 442 443 /** 444 * Method for ScheduleChangeListener. Do nothing. 445 * Handle the event that new schedules will replace the old ones 446 * @param newSchedule new schedules 447 * @throws Exception 448 */ 449 public void update(Schedule[] newSchedules) throws Exception 450 { 451 452 } 453 454 /** 455 * Action for selecting a non remote workflow on component search panel 456 */ 457 public void selectNonSchedulalbeItem() 458 { 459 if(previousSelectionIsWorkflow.get() == true) 460 { 461 this.removeAll(); 462 initialize(); 463 this.repaint(); 464 this.validate(); 465 previousSelectionIsWorkflow.set(false); 466 } 467 468 469 } 470 471 /** 472 * Gets the status of selecting workflow being done 473 * @return true if the selecting is done 474 */ 475 public boolean isSelectingRemoteWorkflowDone() 476 { 477 return trackSelectRemoteWorkflow.isEmpty(); 478 } 479 480}