001/* 002 * Copyright (c) 2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: barseghian $' 006 * '$Date: 2013-01-15 21:38:31 +0000 (Tue, 15 Jan 2013) $' 007 * '$Revision: 31329 $' 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 030/** 031 * 032 */ 033package org.kepler.kar.handlers; 034 035import java.io.ByteArrayInputStream; 036import java.io.File; 037import java.io.FileInputStream; 038import java.io.InputStream; 039import java.util.HashMap; 040import java.util.Hashtable; 041import java.util.List; 042import java.util.Map; 043import java.util.Vector; 044 045import javax.swing.JLabel; 046 047import org.apache.commons.logging.Log; 048import org.apache.commons.logging.LogFactory; 049import org.kepler.gui.state.ReportingStateChangeEvent; 050import org.kepler.gui.state.StateChangeMonitor; 051import org.kepler.kar.KAREntry; 052import org.kepler.kar.KAREntryHandler; 053import org.kepler.kar.KAREntryHandlerFactory; 054import org.kepler.kar.KARFile; 055import org.kepler.moml.NamedObjId; 056import org.kepler.moml.NamedObjIdReferralList; 057import org.kepler.objectmanager.ObjectManager; 058import org.kepler.objectmanager.cache.CacheManager; 059import org.kepler.objectmanager.cache.CacheObject; 060import org.kepler.objectmanager.cache.ReportLayoutCacheObject; 061import org.kepler.objectmanager.lsid.KeplerLSID; 062import org.kepler.provenance.Queryable; 063import org.kepler.reporting.rio.ReportInstance; 064import org.kepler.reporting.rio.fop.ReportRenderer; 065import org.kepler.reporting.rio.util.ProvenanceUtil; 066import org.kepler.reporting.roml.ReportLayout; 067import org.kepler.util.WorkflowRun; 068import org.kepler.workflow.WorkflowManager; 069import org.kepler.workflowrunmanager.WorkflowRunManager; 070import org.kepler.workflowrunmanager.WorkflowRunManagerManager; 071 072import ptolemy.actor.gui.TableauFrame; 073import ptolemy.kernel.CompositeEntity; 074import ptolemy.kernel.util.IllegalActionException; 075import ptolemy.kernel.util.NameDuplicationException; 076import ptolemy.kernel.util.NamedObj; 077 078/** 079 * @author Ben Leinfelder 080 * 081 */ 082public class ReportLayoutKAREntryHandler implements KAREntryHandler { 083 084 private static final Log log = LogFactory.getLog(ReportLayoutKAREntryHandler.class.getName()); 085 private static final boolean isDebugging = log.isDebugEnabled(); 086 087 088 public ReportLayoutKAREntryHandler() { 089 } 090 091 /** 092 * Method for backwards compatibility with KAR version 1.0 KAR version 2.0 093 * uses the binary class name as the type. 094 * 095 * @see org.kepler.kar.KAREntryHandler#getTypeName() 096 */ 097 public String getTypeName() { 098 return ReportLayout.class.getName(); 099 } 100 101 public boolean handlesType(String typeName) { 102 103 //try string based comparison 104 if (typeName.equals(ReportLayout.class.getName())) { 105 return true; 106 } 107 if (typeName.equals(ReportInstance.class.getName())) { 108 return true; 109 } 110// if (typeName.equals(WorkflowRun.class.getName())) { 111// return true; 112// } 113 return false; 114 } 115 116 /* 117 * (non-Javadoc) 118 * 119 * @see org.kepler.kar.KAREntryHandler#initialize() 120 */ 121 public void initialize() { 122 if (isDebugging) { 123 log.debug("initialize()"); 124 } 125 } 126 127 public boolean open(KARFile karFile, KAREntry entry, TableauFrame tableauFrame) throws Exception { 128 // look up the LSID for the entry, do we need it? 129 KeplerLSID reportLsid = entry.getLSID(); 130 CacheManager cm = CacheManager.getInstance(); 131 ReportLayoutCacheObject rlco = (ReportLayoutCacheObject) cm.getObject(reportLsid); 132 ReportLayout rl = null; 133 rlco = null; // force the read from the karfile BRL, 2009/12/14 134 if (rlco == null){ // try to get it out of the karFile 135 rl = ReportRenderer.convertXML2Report(karFile.getInputStream(entry)); 136 } 137 else{ 138 rl = (ReportLayout) rlco.getObject(); 139 } 140 141 KeplerLSID workflowLsid = rl.getWorkflowLSID(); 142 143 // the tableauFrame passed in is the old window - the one from 144 // which the open action was invoked. We want the newest 145 TableauFrame tf = WorkflowManager.getRankingTableauFrame(); 146 WorkflowManager.getInstance().getWorkflow(tf, workflowLsid).addReportLayout(tf, rl); 147 148 //try to refresh the UI 149 NamedObj namedObj = ObjectManager.getInstance().getObjectRevision(workflowLsid); 150 JLabel dummyComponent = new JLabel(); 151 ReportingStateChangeEvent event = new ReportingStateChangeEvent(dummyComponent, ReportingStateChangeEvent.REPORT_LAYOUT_CHANGED, namedObj); 152 StateChangeMonitor.getInstance().notifyStateChange(event); 153 dummyComponent = null; 154 155 return true; 156 } 157 158 /* 159 * (non-Javadoc) 160 * 161 * @see org.kepler.kar.KAREntryHandler#open(java.util.jar.JarEntry) 162 */ 163 public CacheObject cache(KARFile karFile, KAREntry entry) throws Exception { 164 if (isDebugging) { 165 log.debug("cache(" + karFile.toString() + "," + entry.toString() + ")"); 166 } 167 168 // look up the LSID for the entry, do we need it? 169 KeplerLSID reportLsid = entry.getLSID(); 170 171 // reportLsid.getRevision() 172 173 //create the reportLayout object 174 InputStream is = karFile.getInputStream(entry); 175 ReportLayout rl = ReportRenderer.convertXML2Report(is); 176 177 // giving both e.g. RIO.1.xml and Unnamed1_ROML.xml name "roml" like below 178 // seems to cause bug#4969. instead use entry.getName() so they're different. 179 //ReportLayoutCacheObject rlco = new ReportLayoutCacheObject("roml", reportLsid); 180 ReportLayoutCacheObject rlco = new ReportLayoutCacheObject(entry.getName(), reportLsid); 181 rlco.setReportLayout(rl); 182 //rlco.write(); 183 if (rlco == null) { 184 log.error("ReportLayoutCacheObject is null"); 185 } 186 187 //set in the manager 188 ///KeplerLSID workflowLsid = rl.getWorkflowLSID(); 189 190// WorkflowManager wm = WorkflowManager.getInstance(); 191// Workflow wf = wm.getWorkflow(workflowLsid); 192// List<ReportLayout> layouts = wf.getReportLayouts(); 193// layouts.clear(); 194// layouts.add(rl); 195 196 // cache object for reporting 197 return rlco; 198 199 } 200 201 /* 202 * (non-Javadoc) 203 * 204 * @see 205 * org.kepler.kar.KAREntryHandler#save(org.kepler.objectmanager.lsid.KeplerLSID 206 * ) 207 */ 208 public Hashtable<KAREntry, InputStream> save(Vector<KeplerLSID> lsids, KeplerLSID karLsid, 209 TableauFrame tableauFrame) 210 throws Exception { 211 if (isDebugging) log.debug("save("+lsids.toString()+", karLSID:" +karLsid.toString()+")"); 212 213 WorkflowRunManagerManager wrmm = WorkflowRunManagerManager.getInstance(); 214 WorkflowRunManager wrm = wrmm.getWRM(tableauFrame); 215 216 Hashtable<KAREntry, InputStream> items = new Hashtable<KAREntry, InputStream>(); 217 218 for ( KeplerLSID lsid : lsids ) { 219 // determine what we are saving, and call the appropriate method 220 // no longer using OM to get the run here, Nov 03, 2010. 221 NamedObj nObj = wrm.getRun(lsid); 222 if (nObj == null){ 223 //log.debug("current status of ObjectManager"); 224 //ObjectManager.getInstance().printDebugInfo(); 225 log.debug("WorkflowRunManager.getRun("+lsid+") returned null, try to get from ObjectManager.getInstance().getObjectRevision("+lsid+")"); 226 nObj = ObjectManager.getInstance().getObjectRevision(lsid); 227 } 228 if (nObj == null){ 229 log.debug("nObj == null"); 230 } 231 if (nObj instanceof WorkflowRun) { 232 log.debug("nObj instanceof WorkflowRun"); 233 WorkflowRun run = (WorkflowRun) nObj; 234 Hashtable<KAREntry,InputStream> wfRunLayouts = saveWorkflowRun(run, karLsid, tableauFrame); 235 items.putAll(wfRunLayouts); 236 } else if (nObj instanceof CompositeEntity) { 237 log.debug("nObj instanceof CompositeEntity"); 238 // Must avoid putting both ROMLs into the KAR when it's a run-KAR since they 239 // (atm - r24489) both have the same LSID, and can therefore otherwise end 240 // up with the ROML that does not dependsOn the run in the KAR. 241 if (wrm.getSelectedRunsForSave() == null || wrm.getSelectedRunsForSave().isEmpty()){ 242 log.debug("calling saveReportLayout("+lsid+")"); 243 Hashtable<KAREntry,InputStream> workflowLayouts = saveReportLayout(lsid); 244 items.putAll(workflowLayouts); 245 } 246 } 247 } 248 return items; 249 250 } 251 252 /** 253 * This method is intended for serializing Layouts that have been saved 254 * with a particular workflow execution. It DOES use provenance for looking it up 255 * @param run 256 * @return 257 * @throws Exception 258 */ 259 private Hashtable<KAREntry, InputStream> saveWorkflowRun(WorkflowRun run, KeplerLSID karLsid, 260 TableauFrame tableauFrame) throws Exception { 261 262 Hashtable<KAREntry, InputStream> items = new Hashtable<KAREntry, InputStream>(); 263 264 if (run == null) { 265 log.debug("WorkflowRun is null"); 266 return null; 267 } 268 269 // Get the layout item[s] for the run 270 Hashtable<KAREntry, InputStream> layoutItems = this.getReportLayoutForWorkflowRun(run, tableauFrame); 271 items.putAll(layoutItems); 272 273 return items; 274 } 275 276 277 /** 278 * This is intended to be used when serializing a ROML along with its MOML 279 * This method does NOT use provenance to retrieve any information 280 * @param lsid for the Workflow (not the report layout) 281 * @return 282 * @throws Exception 283 */ 284 private Hashtable<KAREntry, InputStream> saveReportLayout(KeplerLSID lsid) 285 throws Exception { 286 287 log.debug("saveReportLayout(" + lsid + ")"); 288 289 Hashtable<KAREntry, InputStream> items = new Hashtable<KAREntry, InputStream>(); 290 291 // Get the workflow from the object manager 292 NamedObj nObj = ObjectManager.getInstance().getObjectRevision(lsid); 293 if (nObj == null) { 294 // there is no guarantee that ObjectManager will return an object for an lsid 295 throw new Exception("Object not found."); 296 } 297 298 String workflowName = nObj.getName(); 299 300 ReportLayout reportLayout = null; 301 KeplerLSID reportLayoutLsid = null; 302 303 try { 304 // if we don't have a layout for this current LSID, 305 // then we need to look up the last LSID used to link them up 306 if (!WorkflowManager.getInstance().workflowExists(lsid)) { 307 log.debug("workflow/layout does not exist for LSID=" + lsid); 308 // use the last entry in the derived from list to find the most recent one 309 NamedObjIdReferralList nObjIdList = NamedObjId.getIDListAttributeFor(nObj); 310 List<KeplerLSID> referrals = nObjIdList.getReferrals(); 311 if (referrals != null && referrals.size() > 0) { 312 KeplerLSID oldLsid = referrals.get(0); 313 log.debug("looking up layout using older revision, oldLSID=" + oldLsid); 314 315 // look up the report layout - using old LSID 316 //TODO change to just passing in tableauFrame? 317 TableauFrame tf = WorkflowManager.getRankingTableauFrame(); 318 reportLayout = WorkflowManager.getInstance().getWorkflow(tf, oldLsid).getReportLayout(tf); 319 } 320 } else { 321 // look up the report layout - lsid should be golden now 322 TableauFrame tf = WorkflowManager.getRankingTableauFrame(); 323 reportLayout = WorkflowManager.getInstance().getWorkflow(tf, lsid).getReportLayout(tf); 324 } 325 326 // if reportLayout is null just return 327 if (reportLayout == null || reportLayout.isBlank()){ 328 log.warn("reportLayout is null or blank, not saving an entry to KAR"); 329 return items; 330 } 331 332 // synch the LSID on the layout before saving 333 reportLayout.setWorkflowLSID(lsid); 334 } 335 336 337 catch (Exception e) { 338 log.error("Could not set LSID for ReportLayout: " + e.getMessage()); 339 } 340 341 // Get the ROML as xml 342 File xml = File.createTempFile("roml", ".xml"); 343 xml.deleteOnExit(); 344 ReportRenderer.convertReport2XML(reportLayout, xml); 345 346 // make an entry for the roml 347 String entryName = workflowName + "_ROML.xml"; 348 log.debug(entryName); 349 350 // Make an entry for the layout 351 KAREntry entry = new KAREntry(entryName); 352 353 // Set the LSID/type for the reportLayout entry 354 entry.setLSID(reportLayout.getLsid()); 355 // reportLayout.getClass().getName() can return a ReportInstance on KAR open, refer to class 356 // instead of object 357 //entry.setType(reportLayout.getClass().getName()); 358 entry.setType(ReportLayout.class.getName()); 359 entry.addLsidDependency(reportLayout.getWorkflowLSID()); 360 361 log.debug("adding entry to KAR: " + entryName); 362 363 items.put( 364 entry, 365 new FileInputStream(xml)); 366 367 return items; 368 369 } 370 371 private Hashtable<KAREntry, InputStream> getReportLayoutForWorkflowRun(WorkflowRun run, 372 TableauFrame tableauFrame) { 373 374 Hashtable<KAREntry, InputStream> items = new Hashtable<KAREntry, InputStream>(); 375 376 // Get a queryable for the workflow that ran 377 Queryable queryable = null; 378 try { 379 queryable = ProvenanceUtil.getQueryable(run.getWorkflowLSID(), tableauFrame); 380 } catch (Exception e3) { 381 log.error("could not find queryable for the workflow: " + run.getWorkflowLSID()); 382 e3.printStackTrace(); 383 } 384 385 // Get the report layout from provenance 386 ReportLayout reportLayout = null; 387 byte[] romlXML = null; 388 Map<String, String> metadataMap = new HashMap<String, String>(); 389 metadataMap.put("type", ReportLayout.class.getName()); 390 List<byte[]> dataList = null; 391 try { 392 dataList = queryable.getAssociatedDataForExecution( 393 run.getExecId(), 394 metadataMap, 395 false); 396 if (dataList != null && !dataList.isEmpty()) { 397 romlXML = dataList.get(0); 398 // only constructing this to get the layout LSID 399 reportLayout = ReportRenderer.convertXML2Report(new ByteArrayInputStream(romlXML)); 400 } 401 else { 402 log.warn("no data file found for reportLayout, run= " + run.getExecId()); 403 } 404 } catch (Exception e2) { 405 log.error("error looking up report layout XML: " + e2.getMessage()); 406 e2.printStackTrace(); 407 } 408 409 if (reportLayout == null) { 410 return items; 411 } 412 413 // Add the ROML XML 414 log.debug("Adding ReportLayout: " + reportLayout); 415 KAREntry entryROML= new KAREntry("ROML." + run.getExecId() + ".xml"); 416 try { 417 entryROML.setLSID( reportLayout.getLsid() ); 418 entryROML.setType( ReportLayout.class.getName() ); 419 entryROML.addLsidDependency( reportLayout.getWorkflowLSID() ); 420 entryROML.addLsidDependency( run.getExecLSID() ); 421 items.put(entryROML, new ByteArrayInputStream(romlXML)); 422 } catch (Exception e1) { 423 log.error("error adding ROML XML entry: " + e1.getMessage()); 424 e1.printStackTrace(); 425 } 426 427 return items; 428 } 429 430 /** 431 * A factory that creates a KAREntryHandler object. 432 * 433 *@author aaron 434 */ 435 public static class Factory extends KAREntryHandlerFactory { 436 /** 437 * Create a factory with the given name and container. 438 * 439 *@param container 440 * The container. 441 *@param name 442 * The name of the entity. 443 *@exception IllegalActionException 444 * If the container is incompatible with this attribute. 445 *@exception NameDuplicationException 446 * If the name coincides with an attribute already in the 447 * container. 448 */ 449 public Factory(NamedObj container, String name) 450 throws IllegalActionException, NameDuplicationException { 451 super(container, name); 452 } 453 454 /** 455 * Create a library pane that displays the given library of actors. 456 * 457 * @return A new LibraryPaneTab that displays the library 458 */ 459 public KAREntryHandler createKAREntryHandler() { 460 if (isDebugging) 461 log.debug("createKAREntryHandler()"); 462 ReportLayoutKAREntryHandler rlkeh = new ReportLayoutKAREntryHandler(); 463 return rlkeh; 464 } 465 } 466 467}