001/* 002 * $RCSfile$ 003 * 004 * $Author: crawl $ 005 * $Date: 2015-08-24 22:44:14 +0000 (Mon, 24 Aug 2015) $ 006 * $Revision: 33630 $ 007 * 008 * For Details: http://kepler-project.org 009 * 010 * Copyright (c) 2007 The Regents of the University of California. 011 * All rights reserved. 012 * 013 * Permission is hereby granted, without written agreement and without 014 * license or royalty fees, to use, copy, modify, and distribute this 015 * software and its documentation for any purpose, provided that the 016 * above copyright notice and the following two paragraphs appear in 017 * all copies of this software. 018 * 019 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 020 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 021 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 022 * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY 023 * OF SUCH DAMAGE. 024 * 025 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 026 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 027 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 028 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY 029 * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, 030 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 031 */ 032package org.kepler.monitor; 033 034import java.awt.Shape; 035import java.awt.geom.Rectangle2D; 036import java.util.ArrayList; 037import java.util.Arrays; 038import java.util.HashMap; 039import java.util.Iterator; 040import java.util.List; 041import java.util.Map; 042 043import javax.swing.JFrame; 044import javax.swing.Timer; 045 046import org.apache.commons.logging.Log; 047import org.apache.commons.logging.LogFactory; 048import org.kepler.monitor.MonitoredStatus.State; 049import org.kepler.monitor.figure.TrafficLightFigure; 050 051import diva.canvas.CompositeFigure; 052import diva.canvas.Figure; 053import diva.graph.GraphController; 054import diva.graph.GraphPane; 055import diva.graph.GraphViewEvent; 056import diva.graph.GraphViewListener; 057import diva.graph.JGraph; 058import ptolemy.actor.CompositeActor; 059import ptolemy.actor.ExecutionListener; 060import ptolemy.actor.IOPort; 061import ptolemy.actor.IOPortEvent; 062import ptolemy.actor.IOPortEventListener; 063import ptolemy.actor.Initializable; 064import ptolemy.actor.Manager; 065import ptolemy.actor.gui.Configuration; 066import ptolemy.actor.gui.Effigy; 067import ptolemy.actor.gui.Tableau; 068import ptolemy.actor.gui.TableauFactory; 069import ptolemy.data.BooleanToken; 070import ptolemy.data.StringToken; 071import ptolemy.data.Token; 072import ptolemy.data.expr.Parameter; 073import ptolemy.data.expr.SingletonParameter; 074import ptolemy.data.expr.StringParameter; 075import ptolemy.data.type.BaseType; 076import ptolemy.kernel.ComponentEntity; 077import ptolemy.kernel.CompositeEntity; 078import ptolemy.kernel.Port; 079import ptolemy.kernel.util.Attribute; 080import ptolemy.kernel.util.ChangeRequest; 081import ptolemy.kernel.util.IllegalActionException; 082import ptolemy.kernel.util.Location; 083import ptolemy.kernel.util.NameDuplicationException; 084import ptolemy.kernel.util.NamedObj; 085import ptolemy.kernel.util.Settable; 086import ptolemy.kernel.util.SingletonAttribute; 087import ptolemy.moml.MoMLChangeRequest; 088import ptolemy.vergil.actor.ActorController; 089import ptolemy.vergil.actor.ActorGraphFrame; 090import ptolemy.vergil.icon.EditorIcon; 091 092/** 093 * The monitor manager. 094 * <p> 095 * An instance of this attribute can be inserted in a workflow to dynamically 096 * associate activity icons to the existing entities ( 097 * {@link ptolemy.kernel.ComponentEntity}). 098 * 099 * <p> 100 * Demo workflows are under $KEPLER/workflows/test/monitor/ 101 * 102 * <p> 103 * Note: Configuration is very limited in this preliminary version. 104 * 105 * @author Carlos Rueda 106 * @version $Id: MonitorManager.java 33630 2015-08-24 22:44:14Z crawl $ 107 */ 108public class MonitorManager extends SingletonAttribute implements Initializable { 109 110 /** 111 * The icon type for all created monitor attributes 112 */ 113 public StringParameter iconType; 114 115 /** Delay for the timer */ 116 public StringParameter timerDelay; 117 118 /** 119 * Add monitor attributes for input ports? 120 */ 121 public Parameter addInputPortCounters; 122 123 /** 124 * Add monitor attributes for output ports? 125 */ 126 public Parameter addOutputPortCounters; 127 128 /** 129 * Creates a monitor manager. 130 * 131 * @see ptolemy.kernel.util.SingletonAttribute#SingletonAttribute(NamedObj, 132 * String) 133 */ 134 public MonitorManager(NamedObj container, String name) 135 throws IllegalActionException, NameDuplicationException { 136 super(container, name); 137 138 // set up my own icon and figure: 139 _managerIcon = new MonitorIcon(this, "_icon"); 140 _managerIcon.setText("MonitorManager"); 141 _managerFigure = new TrafficLightFigure(1, new Rectangle2D.Double(3, 8, 142 7, 7)); 143 _managerIcon.setFigure(_managerFigure); 144 145 // Parameters: 146 iconType = new StringParameter(this, "iconType"); 147 String none = ICON_TYPE_NONE; 148 String[] iconTypes = MonitorAttribute.iconTypes(); 149 iconType.setExpression(none); 150 iconType.addChoice(none); 151 for (int i = 0; i < iconTypes.length; i++) { 152 // don't show the COUNTER style: 153 if (!iconTypes[i].equals(MonitorAttribute.COUNTER)) { 154 iconType.addChoice(iconTypes[i]); 155 } 156 } 157 iconType.setDisplayName("Monitor icon type for entities"); 158 159 timerDelay = new StringParameter(this, "timerDelay"); 160 timerDelay.setExpression("1000"); 161 timerDelay.setDisplayName("Timer delay for created indicators (ms)"); 162 163 addInputPortCounters = new Parameter(this, "addInputPortCounters"); 164 addInputPortCounters.setTypeEquals(BaseType.BOOLEAN); 165 addInputPortCounters.setExpression("false"); 166 addInputPortCounters.setDisplayName("Add counters for input ports?"); 167 168 addOutputPortCounters = new Parameter(this, "addOutputPortCounters"); 169 addOutputPortCounters.setTypeEquals(BaseType.BOOLEAN); 170 addOutputPortCounters.setExpression("false"); 171 addOutputPortCounters.setDisplayName("Add counters for output ports?"); 172 173 if (isDebugging) { 174 log.debug("<" + getFullName() + "> container=" + container 175 + " name=" + name); 176 } 177 178 // Hide the name. 179 SingletonParameter hideName = new SingletonParameter(this, "_hideName"); 180 hideName.setToken(BooleanToken.TRUE); 181 hideName.setVisibility(Settable.EXPERT); 182 } 183 184 /** 185 * Sets the icon type and timer delay according to the changed attribute. 186 */ 187 @Override 188 public void attributeChanged(Attribute attribute) 189 throws IllegalActionException { 190 if (attribute == iconType) { 191 String iconTypeValue = iconType.stringValue(); 192 if (iconTypeValue.equals(ICON_TYPE_NONE) 193 || Arrays.asList(MonitorAttribute.iconTypes()).contains( 194 iconTypeValue)) { 195 _iconType = iconTypeValue; 196 } else { 197 throw new IllegalActionException("Unexpected iconType: " 198 + iconTypeValue); 199 } 200 } else if (attribute == timerDelay) { 201 try { 202 _timerDelay = Integer.parseInt(timerDelay.stringValue()); 203 } catch (NumberFormatException e) { 204 throw new IllegalActionException("NumberFormatException: " + e); 205 } 206 } else if (attribute == addInputPortCounters) { 207 Token token = addInputPortCounters.getToken(); 208 boolean newValue = ((BooleanToken) token).booleanValue(); 209 if (newValue != _addInputPortCounters) { 210 _addInputPortCounters = newValue; 211 } 212 } else if (attribute == addOutputPortCounters) { 213 Token token = addOutputPortCounters.getToken(); 214 boolean newValue = ((BooleanToken) token).booleanValue(); 215 if (newValue != _addOutputPortCounters) { 216 _addOutputPortCounters = newValue; 217 } 218 } else { 219 super.attributeChanged(attribute); 220 } 221 } 222 223 /** 224 * Finishes the monitors. 225 */ 226 @Override 227 public void wrapup() throws IllegalActionException { 228 if (isDebugging) { 229 log.debug("<" + getFullName() + "> #wrapup"); 230 } 231 Manager manager = ((CompositeActor) getContainer()).getManager(); 232 if (manager != null) { 233 manager.removeExecutionListener(_executionListener); 234 } 235 _executionFinished(); 236 } 237 238 /** 239 * If container is null, it finishes monitoring 240 */ 241 @Override 242 public void setContainer(NamedObj container) throws IllegalActionException, 243 NameDuplicationException { 244 245 if (isDebugging) { 246 log.debug("<" + getFullName() + "> new container=" + container); 247 } 248 249 NamedObj previousContainer = getContainer(); 250 super.setContainer(container); 251 252 if (previousContainer != null) { 253 if (previousContainer instanceof Initializable) { 254 ((Initializable) previousContainer).removeInitializable(this); 255 } 256 } 257 258 if (container != null) { 259 // Try to add this as an initialible object to the toplevel 260 // container: 261 262 NamedObj toplevel = toplevel(); 263 264 if (toplevel instanceof Initializable) { 265 // make sure we don't add ourselves multiple times: 266 ((Initializable) toplevel).removeInitializable(this); 267 ((Initializable) toplevel).addInitializable(this); 268 if (isDebugging) { 269 log.debug("<" + getFullName() 270 + "> added initializable to toplevel=" + toplevel); 271 } 272 } 273 } else { 274 _executionFinished(); 275 _removeMIcons(); 276 } 277 } 278 279 /** 280 * Creates the MI attributes for the existing component entities in the 281 * container and activates the MI icons. 282 */ 283 @Override 284 public void initialize() throws IllegalActionException { 285 if (isDebugging) { 286 log.debug("<" + getFullName() + "> #initialize()"); 287 } 288 289 _getGraphController(); 290 291 _initialize(); 292 293 Manager manager = ((CompositeActor) getContainer()).getManager(); 294 if (manager != null) { 295 manager.addExecutionListener(_executionListener); 296 } 297 298 for (MonitoredEntity item : _monitoredEntities.values()) { 299 item.startFigureUpdater(); 300 } 301 302 _managerFigure.setState(State.RUNNING); 303 304 if (isDebugging && _graphController != null) { 305 for (MonitoredEntity item : _monitoredEntities.values()) { 306 item._showPortLocations(_graphController); 307 } 308 } 309 310 _registerGraphViewListener(true); 311 312 } 313 314 /** Does nothing. */ 315 @Override 316 public void addInitializable(Initializable initializable) { 317 } 318 319 /** Does nothing. */ 320 @Override 321 public void preinitialize() throws IllegalActionException { 322 } 323 324 /** Does nothing. */ 325 @Override 326 public void removeInitializable(Initializable initializable) { 327 } 328 329 // ///////////////////////////////////////////////////////////////// 330 // // private members //// 331 332 /** 333 * Calls _relocate(item) when a monitored entity changes its location, so 334 * the corresponding MI attribute is relocated accordingly. 335 * 336 * <p> 337 * Note: it seems nodeMoved(e) is never called, so the action is done in 338 * nodeDrawn(e). 339 */ 340 private class MyGraphViewListener implements GraphViewListener { 341 @Override 342 public void edgeDrawn(GraphViewEvent e) { 343 // Ignore. 344 } 345 346 @Override 347 public void edgeRouted(GraphViewEvent e) { 348 // Ignore. 349 } 350 351 @Override 352 public void nodeDrawn(GraphViewEvent e) { 353 Object source = e.getSource(); 354 Object target = e.getTarget(); 355 if (source instanceof ActorController && target instanceof Location) { 356 Location loc = (Location) target; 357 NamedObj container = loc.getContainer(); 358 359 if (container instanceof ComponentEntity) { 360 ComponentEntity<?> entity = (ComponentEntity<?>) container; 361 MonitoredEntity item = _monitoredEntities.get(entity 362 .getName()); 363 if (item != null) { 364 for (MonitorAttribute attr : item.attrs) { 365 _relocate(item, attr); 366 } 367 } 368 } 369 } 370 } 371 372 @Override 373 public void nodeMoved(GraphViewEvent e) { 374 // NOTE haven't seen this method being called -- why? 375 log.debug("nodeMoved e=" + e); 376 } 377 } 378 379 private void _getGraphController() { 380 Effigy effigy = Configuration.findEffigy(this.toplevel()); 381 if (effigy == null) { 382 if (isDebugging) { 383 log.debug("<" + getFullName() + "> No top effigy"); 384 } 385 return; 386 } 387 effigy = effigy.topEffigy(); 388 TableauFactory tf = effigy.getTableauFactory(); 389 if (isDebugging) { 390 log.debug("<" + getFullName() + "> top effigy class = " 391 + effigy.getClass() + "\n" + "tableau factory = " + tf); 392 } 393 try { 394 Tableau tableau = tf.createTableau(effigy); 395 JFrame frame = tableau.getFrame(); 396 397 if (frame instanceof ActorGraphFrame) { 398 ActorGraphFrame agf = (ActorGraphFrame) frame; 399 JGraph jgraph = agf.getJGraph(); 400 GraphPane graphPane = jgraph.getGraphPane(); 401 _graphController = (GraphController) graphPane 402 .getGraphController(); 403 } 404 } catch (Exception e) { 405 log.debug("error in _getGraphController", e); 406 } 407 } 408 409 /** 410 * Registers/Unregisters our GraphViewListener so we can react to changes in 411 * location of entities. 412 * 413 * @param register 414 * true to call controller.addGraphViewListener(gvl), false to 415 * call controller.removeGraphViewListener(gvl), where controller 416 * is the GraphController obtained through the top effigy 417 * associated with this.toplevel(). 418 * 419 * @return true iff the {add|remove}GraphViewListener call was done. 420 */ 421 private boolean _registerGraphViewListener(boolean register) { 422 Effigy effigy = Configuration.findEffigy(this.toplevel()); 423 if (effigy == null) { 424 if (isDebugging) { 425 log.debug("<" + getFullName() + "> No top effigy"); 426 } 427 return false; 428 } 429 effigy = effigy.topEffigy(); 430 TableauFactory tf = effigy.getTableauFactory(); 431 if (isDebugging) { 432 log.debug("<" + getFullName() + "> top effigy class = " 433 + effigy.getClass() + "\n" + "tableau factory = " + tf); 434 } 435 try { 436 Tableau tableau = tf.createTableau(effigy); 437 JFrame frame = tableau.getFrame(); 438 439 if (frame instanceof ActorGraphFrame) { 440 ActorGraphFrame agf = (ActorGraphFrame) frame; 441 JGraph jgraph = agf.getJGraph(); 442 GraphPane graphPane = jgraph.getGraphPane(); 443 _graphController = (GraphController) graphPane 444 .getGraphController(); 445 446 if (register) { 447 _graphController.addGraphViewListener(gvl); 448 log 449 .debug("<" + getFullName() 450 + "> GraphViewListener added"); 451 } else { 452 _graphController.removeGraphViewListener(gvl); 453 log.debug("<" + getFullName() 454 + "> GraphViewListener removed"); 455 } 456 return true; 457 } 458 } catch (Exception e) { 459 log.debug("<" + getFullName() 460 + "> error in _registerGraphViewListener", e); 461 } 462 return false; 463 } 464 465 /** 466 * Creates and initialize the monitors to the entities in my container. 467 * 468 * @throws IllegalActionException 469 */ 470 private/* synchronized */void _initialize() throws IllegalActionException { 471 if (getContainer() == null) { 472 log.debug("<" + getFullName() + "> NO container!"); 473 return; 474 } 475 476 boolean wasDeferringChangeRequests = isDeferringChangeRequests(); 477 478 if (isDebugging) { 479 log.debug("<" + getFullName() + "> isDeferringChangeRequests = " 480 + wasDeferringChangeRequests); 481 } 482 483 if (wasDeferringChangeRequests) { 484 setDeferringChangeRequests(false); 485 } 486 487 List<ComponentEntity> entityList = ((CompositeEntity) getContainer()) 488 .entityList(ComponentEntity.class); 489 for (Iterator<ComponentEntity> it = entityList.iterator(); it.hasNext();) { 490 ComponentEntity<?> entity = (ComponentEntity<?>) it.next(); 491 _monitor(entity); 492 } 493 494 setDeferringChangeRequests(wasDeferringChangeRequests); 495 496 for (MonitoredEntity item : _monitoredEntities.values()) { 497 item.update(); 498 } 499 } 500 501 /** 502 * Creates the monitors for a given entity. 503 * 504 * @param entity 505 */ 506 private void _monitor(final ComponentEntity<?> entity) { 507 // We need the icon to get the location of the entity 508 Attribute attr = entity.getAttribute("_icon"); 509 if (attr == null) { 510 log.error(" Unexpected: No attribute by name '_icon' in entity " 511 + entity); 512 return; 513 } 514 if (!(attr instanceof EditorIcon)) { 515 log 516 .error(" Unexpected: '_icon' attribute is not an EditorIcon in entity " 517 + entity); 518 return; 519 } 520 521 log.debug("<" + getFullName() + "> _icon attribute class = " 522 + attr.getClass().getName()); 523 524 // If the entity already uses a MonitorIcon, then do nothing: 525 if (attr instanceof MonitorIcon) { 526 log.debug("<" + getFullName() 527 + "> Entity already uses a MonitorIcon."); 528 return; 529 } 530 531 // first, create a MonitoredEntity for the entity. 532 // This will be initialized with only the associated MonitoredStatus 533 // object: 534 MonitoredEntity item = new MonitoredEntity(entity); 535 _monitoredEntities.put(entity.getName(), item); 536 537 // now, create and associate a visual attribute for the entity as a 538 // whole: 539 if (!ICON_TYPE_NONE.equalsIgnoreCase(_iconType)) { 540 _addMonitorAttributeForEntity(item); 541 } 542 543 // now, create and associate visual attributes for the ports: 544 List<?> ports = item.entity.portList(); 545 for (Object obj : ports) { 546 Port port = (Port) obj; 547 if (port instanceof IOPort) { 548 IOPort ioport = (IOPort) port; 549 if ((ioport.isInput() && _addInputPortCounters) 550 || (ioport.isOutput() && _addOutputPortCounters)) { 551 _addMonitorAttributeForPort(item, ioport); 552 } 553 } 554 } 555 } 556 557 /** 558 * Adds a new MI attribute with the given name. 559 */ 560 private void _addMonitorAttributeForEntity(final MonitoredEntity item) { 561 final String name = _getMonitorAttributeNameForEntity(item.entity); 562 563 double[] loc = _getEntityAttributeLocation(item, null); 564 double x = loc[0], y = loc[1]; 565 566 String moml = _getMonitorAttributeMoml(name, x, y, _iconType, 567 _timerDelay); 568 569 ChangeRequest request = new MoMLChangeRequest(this, getContainer(), 570 moml) { 571 @Override 572 protected void _execute() throws Exception { 573 try { 574 super._execute(); 575 576 // ok, we now have our MonitorAttribute: 577 MonitorAttribute attr = (MonitorAttribute) getContainer() 578 .getAttribute(name); 579 580 // associate the MonitorAttribute: 581 item.addMonitorAttribute(attr); 582 583 attr.setMonitoredStatus(item.status); 584 585 FigureUpdater figUpdater = new FigureUpdater(); 586 figUpdater.setFigure(attr.getIcon().getFigure()); 587 588 attr.setFigureUpdater(figUpdater); 589 590 // and start the figure updater: 591 figUpdater.start(); 592 593 item.status.addPropertyChangeListener(figUpdater); 594 } catch (Exception e) { 595 e.printStackTrace(); 596 } 597 } 598 }; 599 600 if (isDebugging) { 601 log.debug("<" + getFullName() 602 + "> Request to add monitor with name " + name); 603 } 604 request.setPersistent(false); 605 requestChange(request); 606 } 607 608 /** 609 * Adds a new MI attribute with the given name. 610 */ 611 private void _addMonitorAttributeForPort(final MonitoredEntity item, 612 final IOPort ioport) { 613 final String name = _getMonitorAttributeNameForPort(item.entity, ioport); 614 615 double[] loc = _getPortAttributeLocation(item, ioport, null); 616 617 if (loc == null) { 618 // but we need the location; so, cannot add monitor: 619 return; 620 } 621 622 double x = loc[0], y = loc[1]; 623 624 String moml = _getMonitorAttributeMoml(name, x, y, 625 MonitorAttribute.COUNTER, _timerDelay); 626 627 ChangeRequest request = new MoMLChangeRequest(this, getContainer(), 628 moml) { 629 @Override 630 protected void _execute() throws Exception { 631 try { 632 super._execute(); 633 634 // ok, we now have our MonitorAttribute: 635 MonitorAttribute attr = (MonitorAttribute) getContainer() 636 .getAttribute(name); 637 638 // associate the ioport with the attribute: 639 attr.setPort(ioport); 640 641 // associate the MonitorAttribute: 642 item.addMonitorAttribute(attr); 643 644 attr.setMonitoredStatus(item.status); 645 646 FigureUpdater figUpdater = new FigureUpdater(); 647 figUpdater.setFigure(attr.getIcon().getFigure()); 648 649 attr.setFigureUpdater(figUpdater); 650 651 // set property for the updates 652 String portName = ioport.getName(); 653 String propName = "portEvent:" + portName; 654 figUpdater.setPropertyNameForLabel(propName); 655 656 // and start the figure updater: 657 figUpdater.start(); 658 659 item.status.addPropertyChangeListener(figUpdater); 660 } catch (Exception e) { 661 e.printStackTrace(); 662 } 663 } 664 }; 665 666 if (isDebugging) { 667 log.debug("<" + getFullName() 668 + "> Request to add monitor with name " + name); 669 } 670 request.setPersistent(false); 671 requestChange(request); 672 } 673 674 /** 675 * Gets the location for an entity's monitor attribute. 676 */ 677 private double[] _getEntityAttributeLocation(final MonitoredEntity item, 678 double[] loc) { 679 if (loc == null) { 680 loc = new double[2]; 681 } 682 683 Location entityLocation = (Location) item.entity 684 .getAttribute("_location"); 685 loc[0] = entityLocation.getLocation()[0]; 686 loc[1] = entityLocation.getLocation()[1]; 687 688 loc[0] += 12; 689 loc[1] += 6 + item.entityBounds.getY() + item.entityBounds.getHeight(); 690 691 return loc; 692 } 693 694 /** 695 * Gets the location for a port's monitor attribute. 696 */ 697 private double[] _getPortAttributeLocation(final MonitoredEntity item, 698 final IOPort ioport, double[] loc) { 699 boolean ok = false; 700 double x, y; 701 Location portLocation = (Location) ioport.getAttribute("_location"); 702 if (portLocation == null) { 703 Location entityLocation = (Location) item.entity 704 .getAttribute("_location"); 705 x = entityLocation.getLocation()[0]; 706 y = entityLocation.getLocation()[1]; 707 Figure portFigure = _graphController.getFigure(ioport); 708 if (portFigure == null) { 709 710 } else { 711 Rectangle2D portBounds = portFigure.getBounds(); 712 if (portBounds == null) { 713 714 } else { 715 if (isDebugging) { 716 log.debug("<" + getFullName() + "> " + ioport.getName() 717 + " no _location. portBounds=" + portBounds); 718 } 719 x += portBounds.getX(); 720 y += portBounds.getY(); 721 ok = true; 722 } 723 } 724 } else { 725 x = portLocation.getLocation()[0]; 726 y = portLocation.getLocation()[1]; 727 ok = true; 728 if (isDebugging) { 729 log.debug("<" + getFullName() + "> " + ioport.getName() 730 + " port location: " + portLocation); 731 } 732 } 733 734 if (ok) { 735 x += (ioport.isInput() ? -8 : +12); 736 y -= 6; 737 738 if (loc == null) { 739 loc = new double[2]; 740 } 741 loc[0] = x; 742 loc[1] = y; 743 return loc; 744 } else { 745 return null; 746 } 747 } 748 749 /** 750 * Relocates the MI attribute according to the location of its monitored 751 * object. 752 */ 753 private void _relocate(final MonitoredEntity item, 754 final MonitorAttribute attr) { 755 Location attrLocation = (Location) attr.getAttribute("_location"); 756 double[] attrLoc = attrLocation.getLocation(); 757 758 double[] newAttrLoc; 759 IOPort ioport = attr.getPort(); 760 if (ioport == null) { 761 newAttrLoc = _getEntityAttributeLocation(item, null); 762 } else { 763 newAttrLoc = _getPortAttributeLocation(item, ioport, null); 764 } 765 766 if (newAttrLoc == null) { 767 return; 768 } 769 770 if (attrLoc[0] == newAttrLoc[0] && attrLoc[1] == newAttrLoc[1]) { 771 return; 772 } 773 774 final double[] dLoc = newAttrLoc; 775 ChangeRequest request = new ChangeRequest(this, "update location") { 776 @Override 777 protected void _execute() throws Exception { 778 Location newLoc; 779 try { 780 newLoc = new Location(attr, "_location"); 781 newLoc.setLocation(dLoc); 782 } catch (IllegalActionException e) { 783 log.debug("<" + getFullName() + "> error setting location", 784 e); 785 } catch (NameDuplicationException e) { 786 log.debug("<" + getFullName() + "> error setting location", 787 e); 788 } 789 } 790 }; 791 if (isDebugging) { 792 log.debug("<" + getFullName() + "> MI relocation for entity " 793 + item.entity); 794 } 795 request.setPersistent(false); 796 requestChange(request); 797 } 798 799 /** Unregisters the GraphViewListener and removes all MI attributes */ 800 private/* synchronized */void _executionFinished() { 801 if (isDebugging) { 802 log.debug("<" + getFullName() + "> #_executionFinished()"); 803 } 804 805 try { 806 _registerGraphViewListener(false); 807 808 for (MonitoredEntity item : _monitoredEntities.values()) { 809 item.stopFigureUpdater(); 810 } 811 _removeMIcons(); 812 } finally { 813 _managerFigure.setState(State.IDLE); 814 } 815 } 816 817 /** 818 * Removes all MI attributes from the container. 819 */ 820 private/* synchronized */void _removeMIcons() { 821 final ChangeRequest request = new ChangeRequest(this, 822 "remove all monitor icons") { 823 @Override 824 protected void _execute() throws Exception { 825 for (MonitoredEntity item : _monitoredEntities.values()) { 826 item.status.getPropertyTimer().stop(); 827 item.releaseIOPortEventListeners(); 828 for (MonitorAttribute attr : item.attrs) { 829 _removeProperty(attr.getName()); 830 } 831 } 832 _monitoredEntities.clear(); 833 834 } 835 }; 836 if (isDebugging) { 837 log.debug("<" + getFullName() + "> Calling requestChange"); 838 } 839 request.setPersistent(false); 840 requestChange(request); 841 } 842 843 /** 844 * Gets the name for the MI attribute associated with an entity. 845 */ 846 private static String _getMonitorAttributeNameForEntity( 847 ComponentEntity<?> entity) { 848 String entityName = entity.getName(); 849 return entityName + "__monIcon"; 850 } 851 852 /** 853 * Gets the name for the MI attribute associated with an entity's port. 854 */ 855 private static String _getMonitorAttributeNameForPort( 856 ComponentEntity<?> entity, IOPort ioport) { 857 String entityName = entity.getName(); 858 return entityName + "_PORT_" + ioport.getName() + "__monIcon"; 859 } 860 861 /** Removes a property with the given name */ 862 private void _removeProperty(final String attrName) { 863 if (isDebugging) { 864 log.debug("<" + getFullName() + "> removing property with name " 865 + attrName + " ..."); 866 } 867 String moml = "<deleteProperty name=\"" + attrName + "\"/>"; 868 ChangeRequest request = new MoMLChangeRequest(this, getContainer(), 869 moml) { 870 @Override 871 protected void _execute() throws Exception { 872 try { 873 super._execute(); 874 } catch (Exception e) { 875 log.debug("<" + getFullName() 876 + "> exception executing MoMLChangeRequest", e); 877 } 878 } 879 }; 880 request.setPersistent(false); 881 requestChange(request); 882 } 883 884 /** 885 * Monitored entity. Association (ComponentEntity, MonitoredStatus, 886 * MonitorAttribute*). 887 */ 888 private static class MonitoredEntity { 889 ComponentEntity<?> entity; 890 Rectangle2D entityBounds; 891 MonitoredStatus status; 892 893 /** monitor attributes associated to the entity. */ 894 List<MonitorAttribute> attrs = new ArrayList<MonitorAttribute>(); 895 896 // just to be able to remove them from the ports: 897 Map<String, IOPortEventListener> portEventListeners = new HashMap<String, IOPortEventListener>(); 898 899 /** 900 * Creates the MonitorStatus member for the given entity. Internal 901 * listeners are registered to update the properties in the status 902 * object according to activity in the entity. 903 */ 904 MonitoredEntity(ComponentEntity<?> entity) { 905 this.entity = entity; 906 entityBounds = _getEntityBounds(entity); 907 908 status = new MonitoredStatus(); 909 //entity.getAttribute(name) 910 // the entity as a whole has a state 911 status.setProperty(State.STATE, State.IDLE); 912 913 status.getPropertyTimer().start(); 914 915 List<?> ports = entity.portList(); 916 for (Object obj : ports) { 917 Port port = (Port) obj; 918 if (port instanceof IOPort) { 919 IOPort ioport = (IOPort) port; 920 String portName = ioport.getName(); 921 final String propName = "portEvent:" + portName; 922 status.setProperty(propName, "0"); 923 924 IOPortEventListener portEventListener = new IOPortEventListener() { 925 long counter = 0; 926 927 @Override 928 public void portEvent(IOPortEvent event) { 929 status.setProperty(State.STATE, State.RUNNING); 930 931 /** Determine whether user specified a quality field*/ 932 String quality_field_value = null; 933 Parameter quality_field = (Parameter)event.getPort().getContainer().getAttribute("quality_field"); 934 935 /** If user specified a quality_field, get the value of the field to obtain which port to take 936 * the quality score from */ 937 if (quality_field != null) { 938 Token token = null; 939 try { 940 token = quality_field.getToken(); 941 } catch (IllegalActionException e) { 942 // TODO Auto-generated catch block 943 e.printStackTrace(); 944 } 945 946 if(token != null) { 947 if(token instanceof StringToken) { 948 quality_field_value = ((StringToken)token).stringValue(); 949 } else { 950 quality_field_value = token.toString(); 951 } 952 } 953 } 954 955 /** Initialize parameter attributes to determine 956 * whether user specified quality fields for quality thresholds*/ 957 Parameter quality_high_param = (Parameter)event.getPort().getContainer().getAttribute("high_quality"); 958 Parameter quality_low_param = (Parameter)event.getPort().getContainer().getAttribute("low_quality"); 959 960 /** Initialize quality scores and thresholds*/ 961 Token quality_high_value; 962 Token quality_low_value; 963 964 /** Check whether user specified a port in the quality field and verify 965 * if the port the event is coming from is the port the user specified 966 * in the quality field*/ 967 if (quality_field_value != null && 968 event.getPort().getDisplayName().equals(quality_field_value)) { 969 970 /** Check whether user specified fields for quality thresholds*/ 971 if (quality_high_param != null && quality_low_param != null) { 972 try { 973 974 /** Retrieve quality threshold values */ 975 quality_high_value = quality_high_param.getToken(); 976 quality_low_value = quality_low_param.getToken(); 977 978 /** Store values in quality states*/ 979 status.setProperty(State.HIGH_QUALITY, quality_high_value); 980 status.setProperty(State.LOW_QUALITY, quality_low_value); 981 982 } catch (IllegalActionException e) { 983 // TODO Auto-generated catch block 984 e.printStackTrace(); 985 } 986 } 987 988 if(event.getToken() != null) { 989 status.setProperty(State.QUALITY_SCORE, event.getToken()); 990 } else { 991 Token[] tokens = event.getTokenArray(); 992 if(tokens != null) { 993 for(Token token : tokens) { 994 status.setProperty(State.QUALITY_SCORE, token); 995 } 996 } 997 } 998 } 999 else { 1000 //status.setProperty(State.STATE, event.getToken()); 1001 status.setProperty(State.QUALITY_SCORE, State.NO_QUALITY_SCORE); 1002 } 1003 1004 int eventType = event.getEventType(); 1005 if (eventType == IOPortEvent.GET_END 1006 || eventType == IOPortEvent.SEND_END) { 1007 ++counter; 1008 status.setProperty(propName, String 1009 .valueOf(counter)); 1010 } 1011 } 1012 }; 1013 portEventListeners.put(portName, portEventListener); 1014 1015 ioport.addIOPortEventListener(portEventListener); 1016 } 1017 } 1018 } 1019 1020 private void addMonitorAttribute(MonitorAttribute attr) { 1021 attrs.add(attr); 1022 } 1023 1024 private void startFigureUpdater() { 1025 for (MonitorAttribute attr : attrs) { 1026 FigureUpdater figUpdater = attr.getFigureUpdater(); 1027 if (figUpdater != null) { 1028 figUpdater.start(); 1029 } 1030 } 1031 } 1032 1033 private void stopFigureUpdater() { 1034 for (MonitorAttribute attr : attrs) { 1035 FigureUpdater figUpdater = attr.getFigureUpdater(); 1036 if (figUpdater != null) { 1037 figUpdater.stop(); 1038 } 1039 } 1040 } 1041 1042 private void update() { 1043 for (MonitorAttribute attr : attrs) { 1044 FigureUpdater fu = attr.getFigureUpdater(); 1045 if (fu != null) { 1046 fu.update(); 1047 } 1048 } 1049 } 1050 1051 /** Removes the registered port event listeners */ 1052 void releaseIOPortEventListeners() { 1053 List<?> ports = entity.portList(); 1054 for (Object obj : ports) { 1055 Port port = (Port) obj; 1056 if (port instanceof IOPort) { 1057 IOPort ioport = (IOPort) port; 1058 String portName = ioport.getName(); 1059 ioport.removeIOPortEventListener(portEventListeners 1060 .get(portName)); 1061 } 1062 } 1063 } 1064 1065 /** debug utility */ 1066 void _showPortLocations(GraphController gc) { 1067 log.debug("ENTITY: " + entity); 1068 List<?> ports = entity.portList(); 1069 for (Object obj : ports) { 1070 Port port = (Port) obj; 1071 if (port instanceof IOPort) { 1072 IOPort ioport = (IOPort) port; 1073 String portName = ioport.getName(); 1074 1075 Location loc = (Location) ioport.getAttribute("_location"); 1076 if (loc == null) { 1077 log.debug(portName + " no _location. Attr list: " 1078 + ioport.attributeList()); 1079 1080 // see ActorController._placePortFigures() 1081 Figure portFigure = gc.getFigure(port); 1082 if (portFigure == null) { 1083 log.debug("portFigure is null"); 1084 } else { 1085 Shape shape = portFigure.getShape(); 1086 if (shape == null) { 1087 log.debug("shape is null"); 1088 } else { 1089 Rectangle2D portBounds = shape.getBounds2D(); 1090 log.debug("portBounds=" + portBounds); 1091 } 1092 } 1093 } else { 1094 log.debug(portName + " port location: " + loc); 1095 } 1096 } 1097 } 1098 } 1099 } 1100 1101 /** For now, intended to detect exceptions and then finish the handling */ 1102 private ExecutionListener _executionListener = new ExecutionListener() { 1103 @Override 1104 public void executionError(Manager manager, Throwable throwable) { 1105 _executionFinished(); 1106 } 1107 1108 @Override 1109 public void executionFinished(Manager manager) { 1110 _executionFinished(); 1111 } 1112 1113 @Override 1114 public void managerStateChanged(Manager manager) { 1115 } 1116 }; 1117 1118 /** @return the entity bounds. */ 1119 private static Rectangle2D _getEntityBounds(ComponentEntity<?> entity) { 1120 EditorIcon entityIcon = (EditorIcon) entity.getAttribute("_icon"); 1121 CompositeFigure entityFigure = (CompositeFigure) entityIcon 1122 .createFigure(); 1123 return entityFigure.getBounds(); 1124 } 1125 1126 private static String _getMonitorAttributeMoml(String name, double x, 1127 double y, String iconType, int timerDelay) { 1128 return "<property name=\"" + name + "\" " + "class=\"" 1129 + MonitorAttribute.class.getName() + "\">\n" 1130 + "<property name=\"_location\" " 1131 + "class=\"ptolemy.kernel.util.Location\" " + "value=\"[" + x 1132 + ", " + y + "]\">\n" + "</property>\n" 1133 + "<property name=\"iconType\" " 1134 + "class=\"ptolemy.data.expr.StringParameter\" " + "value=\"" 1135 + iconType + "\">\n" + "</property>\n" 1136 + "<property name=\"timerDelay\" " 1137 + "class=\"ptolemy.data.expr.StringParameter\" " + "value=\"" 1138 + timerDelay + "\">\n" + "</property>\n" 1139 + "<property name=\"_hideName\" " 1140 + "class=\"ptolemy.data.expr.SingletonParameter\" " 1141 + "value=\"true\">\n" + "</property>" + "\n" + "</property>"; 1142 } 1143 1144 /** My own icon */ 1145 private MonitorIcon _managerIcon; 1146 1147 /** My own figure */ 1148 private TrafficLightFigure _managerFigure; 1149 1150 private String _iconType; 1151 1152 private int _timerDelay; 1153 1154 /** Cache of the value of addInputPortCounters. */ 1155 boolean _addInputPortCounters = false; 1156 1157 /** Cache of the value of addOutputPortCounters. */ 1158 boolean _addOutputPortCounters = false; 1159 1160 /** Name -> MEntity map of current monitored entities. */ 1161 private Map<String, MonitoredEntity> _monitoredEntities = new HashMap<String, MonitoredEntity>(); 1162 1163 private GraphController _graphController; 1164 1165 /** The GraphViewListener instance for this MI manager. */ 1166 private final GraphViewListener gvl = new MyGraphViewListener(); 1167 1168 private static final String ICON_TYPE_NONE = "None"; 1169 1170 private static final Log log = LogFactory.getLog(MonitorManager.class); 1171 1172 private static final boolean isDebugging = log.isDebugEnabled(); 1173 1174 static { 1175 // this helps in debugging the destruction of the created timers 1176 Log logTimers = LogFactory.getLog(MonitorManager.class.getPackage() 1177 .getName() 1178 + ".logTimers"); 1179 if (logTimers.isDebugEnabled()) { 1180 logTimers.debug("setting Timer.setLogTimers(true)"); 1181 Timer.setLogTimers(true); 1182 } 1183 } 1184 1185 private static final long serialVersionUID = 1L; 1186}