001/* 002 * Copyright (c) 2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2016-02-16 22:50:54 +0000 (Tue, 16 Feb 2016) $' 007 * '$Revision: 34438 $' 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 */ 029 030package org.kepler.workflow; 031 032import java.awt.event.WindowAdapter; 033import java.awt.event.WindowEvent; 034import java.lang.ref.WeakReference; 035import java.util.HashMap; 036import java.util.LinkedList; 037import java.util.List; 038import java.util.Map; 039 040import org.apache.commons.logging.Log; 041import org.apache.commons.logging.LogFactory; 042import org.kepler.gui.ModelToFrameManager; 043import org.kepler.moml.NamedObjId; 044import org.kepler.moml.NamedObjIdChangeRequest; 045import org.kepler.moml.NamedObjIdReferralList; 046import org.kepler.objectmanager.ObjectManager; 047import org.kepler.objectmanager.lsid.KeplerLSID; 048import org.kepler.reporting.roml.ReportLayout; 049 050import ptolemy.actor.gui.TableauFrame; 051import ptolemy.kernel.util.ChangeListener; 052import ptolemy.kernel.util.ChangeRequest; 053import ptolemy.kernel.util.NamedObj; 054 055/** 056 * This singleton class manages a list of workflows. 057 * TODO add more information about this class and comment all methods 058 */ 059public class WorkflowManager implements ChangeListener { 060 private static final Log log = LogFactory.getLog(WorkflowManager.class); 061 062 private static WorkflowManager instance; 063 private static TableauFrame _rankingTableauFrame = null; 064 065 public static WorkflowManager getInstance() { 066 if (instance == null) { 067 instance = new WorkflowManager(); 068 } 069 return instance; 070 } 071 072 private Map<String, Workflow> workflows = new HashMap<String, Workflow>(); 073 074 /** 075 * 076 * @param workflowId 077 * @return 078 */ 079 public Workflow getWorkflow(TableauFrame tableauFrame, KeplerLSID workflowId) { 080 intialize(tableauFrame, workflowId); 081 String key = workflowId.toStringWithoutRevision(); 082 Workflow wf = workflows.get(key); 083 return wf; 084 } 085 086 /** 087 * Return a List of LSIDS that are associated with the given TableauFrame. 088 * Because the map stores lsids without revisions the lsids returned here 089 * are always revision 1. 090 * 091 * @param tableauFrame 092 * @return 093 */ 094 public List<KeplerLSID> getKeplerLSID(TableauFrame tableauFrame) { 095 List<KeplerLSID> lsids = new LinkedList<KeplerLSID>(); 096 for(String lsid : workflows.keySet()) { 097 boolean found = false; 098 Workflow w = workflows.get(lsid); 099 Map<TableauFrame, ReportLayout> map = w.getReportLayouts(); 100 for(TableauFrame frame : map.keySet()) { 101 if (frame == tableauFrame) { 102 found = true; 103 } 104 } 105 if (found) { 106 try { 107 // need to add revision here, kludgy 108 String fullLsid = lsid+":1"; 109 KeplerLSID klsid = new KeplerLSID(fullLsid); 110 if (!lsids.contains(klsid)) { 111 lsids.add(klsid); 112 } 113 } catch (Exception e) { 114 e.printStackTrace(); 115 } 116 } 117 } 118 return lsids; 119 } 120 121 /** 122 * 123 * @param workflowId 124 * @return 125 */ 126 public Workflow removeWorkflow(KeplerLSID workflowId) { 127 String key = workflowId.toStringWithoutRevision(); 128 Workflow wf = workflows.remove(key); 129 if(wf != null) { 130 wf._model.removeChangeListener(this); 131 } else { 132 System.err.println("WARNING: workflow not found for LSID " + workflowId); 133 try { 134 ObjectManager om = ObjectManager.getInstance(); 135 NamedObj namedObj = om.getObjectRevision(workflowId); 136 if (namedObj != null) { 137 namedObj.removeChangeListener(this); 138 } 139 } catch (Exception e) { 140 e.printStackTrace(); 141 } 142 } 143 return wf; 144 } 145 146 147 /** 148 * 149 * @param workflowId 150 * @return 151 */ 152 public boolean workflowExists(KeplerLSID workflowId) { 153 String key = workflowId.toStringWithoutRevision(); 154 return workflows.containsKey(key); 155 } 156 157 /** 158 * 159 * @param tableauFrame 160 * @param lsid 161 */ 162 private void intialize(TableauFrame tableauFrame, KeplerLSID lsid) { 163 String key = lsid.toStringWithoutRevision(); 164 Workflow workflow = null; 165 if (workflows.get(key) == null) { 166 167 // add a listener so we can remove it when the frame closes 168 WorkflowClosingAdapter listener = new WorkflowClosingAdapter(tableauFrame); 169 // tableauFrame is null when running from command line 170 if(tableauFrame != null) { 171 tableauFrame.addWindowListener(listener); 172 } 173 174 workflow = new Workflow(tableauFrame, lsid); 175 workflows.put(key, workflow); 176 } 177 // make sure we listen to the obj 178 // NOTE: ObjectManager cares about revision, we do not 179 try { 180 ObjectManager om = ObjectManager.getInstance(); 181 NamedObj namedObj = om.getObjectRevision(lsid); 182 if (namedObj != null) { 183 namedObj.addChangeListener(this); 184 if (workflow != null){ 185 workflow.setModel(namedObj); 186 } 187 } 188 } catch (Exception e) { 189 e.printStackTrace(); 190 } 191 } 192 193 /** 194 * 195 */ 196 @Override 197 public void changeExecuted(ChangeRequest change) { 198 199 if (change instanceof NamedObjIdChangeRequest) { 200 NamedObjIdChangeRequest noicr = (NamedObjIdChangeRequest) change; 201 Object source = noicr.getSource(); 202 if (source != null && source instanceof NamedObjId){ 203 NamedObjId noid = (NamedObjId) source; 204 NamedObj parent = noid.getContainer(); 205 NamedObj toplevel = noid.toplevel(); 206 if (!parent.equals(toplevel)) { 207 return; 208 } 209 KeplerLSID newLsid = noid.getId(); 210 log.debug("Processing Id ChangeRequest for new lsid: " + newLsid); 211 // check if we are managing the lsid already (revision bump) 212 if (workflowExists(newLsid)) { 213 log.debug("no action needed for new lsid: " + newLsid); 214 return; 215 } 216 // otherwise we need to look back in the derivedFrom list 217 KeplerLSID oldLsid = null; 218 219 try { 220 NamedObjIdReferralList nObjIdList = NamedObjId.getIDListAttributeFor(parent); 221 List<KeplerLSID> referrals = nObjIdList.getReferrals(); 222 if (referrals != null && referrals.size() > 0) { 223 oldLsid = referrals.get(0); 224 } 225 } catch (Exception e) { 226 e.printStackTrace(); 227 } 228 229 //swap out the old with the new 230 if (oldLsid != null && newLsid != null) { 231 log.debug("using layout from old lsid: " + oldLsid); 232 ModelToFrameManager modelToFrameManager = ModelToFrameManager.getInstance(); 233 TableauFrame tf = modelToFrameManager.getFrame(toplevel); 234 ReportLayout oldLayout = WorkflowManager.getInstance().getWorkflow(tf, oldLsid).getReportLayout(tf); 235 236 ///we must now change the reportLayout's copy of the workflowLSID 237 oldLayout.setWorkflowLSID(newLsid); 238 239 WorkflowManager.getInstance().getWorkflow(tf, newLsid).addReportLayout(tf, oldLayout); 240 WorkflowManager.getInstance().getWorkflow(tf, newLsid).setModel(parent); 241 242 } 243 } 244 } 245 246 } 247 248 /** 249 * 250 */ 251 @Override 252 public void changeFailed(ChangeRequest change, Exception exception) { 253 // TODO Auto-generated method stub 254 255 } 256 257 /** 258 * 259 * @return "ranking" tableauFrame. This is either the tableauFrame associated with the window associated with a ReportDesignerPanel 260 * that last gained focus or the tableauFrame used in ReportDesignerPanel's initializeTab. 261 */ 262 public static TableauFrame getRankingTableauFrame(){ 263 return _rankingTableauFrame; 264 } 265 266 public static void setRankingTableauFrame(TableauFrame tableauFrame){ 267 _rankingTableauFrame = tableauFrame; 268 } 269 270 /** Listener for windowClosing action. */ 271 class WorkflowClosingAdapter extends WindowAdapter { 272 public WorkflowClosingAdapter(TableauFrame frame) { 273 _frame = new WeakReference<TableauFrame>(frame); 274 } 275 @Override 276 public void windowClosing(WindowEvent e) { 277 // do nothing if kepler is exiting 278 if(!org.kepler.module.workflowrunmanager.Shutdown.haveShutdown()) { 279 TableauFrame frame = _frame.get(); 280 if(frame != null) { 281 List<KeplerLSID> lsids = getKeplerLSID(frame); 282 for (KeplerLSID lsid : lsids) { 283 //System.out.println("Removing workflow for " + lsid.toString()); 284 removeWorkflow(lsid); 285 } 286 } 287 } 288 } 289 private WeakReference<TableauFrame> _frame; 290 } 291 292}