001/* 002 * Copyright (c) 2003-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2015-08-24 22:48:48 +0000 (Mon, 24 Aug 2015) $' 007 * '$Revision: 33634 $' 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.sms.actors; 031 032import java.awt.event.ActionEvent; 033import java.util.Iterator; 034import java.util.Vector; 035 036import diva.graph.GraphController; 037import ptolemy.actor.IOPort; 038import ptolemy.actor.TypeEvent; 039import ptolemy.actor.TypeListener; 040import ptolemy.actor.TypedAtomicActor; 041import ptolemy.actor.TypedIOPort; 042import ptolemy.data.IntToken; 043import ptolemy.data.Token; 044import ptolemy.data.expr.Parameter; 045import ptolemy.data.type.BaseType; 046import ptolemy.data.type.Type; 047import ptolemy.graph.InequalityTerm; 048import ptolemy.kernel.ComponentEntity; 049import ptolemy.kernel.CompositeEntity; 050import ptolemy.kernel.Relation; 051import ptolemy.kernel.util.ChangeRequest; 052import ptolemy.kernel.util.IllegalActionException; 053import ptolemy.kernel.util.NameDuplicationException; 054import ptolemy.kernel.util.NamedObj; 055import ptolemy.kernel.util.Workspace; 056import ptolemy.vergil.actor.ActorInstanceController; 057import ptolemy.vergil.basic.NamedObjController; 058import ptolemy.vergil.basic.NodeControllerFactory; 059import ptolemy.vergil.toolbox.FigureAction; 060import ptolemy.vergil.toolbox.MenuActionFactory; 061 062/* 063 064 OPERATIONS: 065 066 067 Vector getActors() // the actors connected to merge actor 068 Iterator getTargetPorts(IOPort inputPort) // target (output) i/o ports for inputPort 069 Iterator getInputPortMappings(IOPort port) // get mappings for input port 070 void removeOutputPort(IOPort port) // removes the given output port 071 Vector getActorPorts(NamedObj actor) // output ports of source actor 072 Iterator getMappings() // all merge actor mappings 073 void setProductionRate() 074 075 void _computeTargetTypes() // sets target (output) types 076 Vector _getActorPortChannels(NamedObj actor) // return the ports for the connected actor 077 void _applyMerge() // applies the merge mapping 078 PortChannel _getPortChannel(IOPort inputPort) // input ports as port channels 079 Iterator _getInputPorts() // input i/o ports 080 void _initInputPorts() // reset input ports (and listeners) 081 void _removeMappings() 082 083 084 */ 085 086/** 087 * This is a first-cut, dumbed-down, and simple version of a generic merge 088 * function based on semantic annotations. 089 */ 090public class MergeActor extends TypedAtomicActor implements TypeListener { 091 092 public MergeInputPort mergeInputPort; // single multiport for inputs to be 093 // merged 094 095 /** 096 * Constructor 097 */ 098 public MergeActor(CompositeEntity container, String name) 099 throws NameDuplicationException, IllegalActionException { 100 super(container, name); 101 init(); 102 } 103 104 /** 105 * Constructor 106 */ 107 public MergeActor(Workspace workspace) throws NameDuplicationException, 108 IllegalActionException { 109 super(workspace); 110 init(); 111 } 112 113 /** 114 * Initialize the actor 115 */ 116 private void init() throws IllegalActionException, NameDuplicationException { 117 // add the input port 118 mergeInputPort = new MergeInputPort(this, "input"); 119 120 // black, blue, cyan, darkgray, gray, green, lightgray, magenta, 121 // orange, pink, red, white, yellow 122 _attachText("_iconDescription", "<svg>\n" 123 + "<rect x=\"0\" y=\"0\" rx=\"10\" ry=\"10\" " 124 + "width=\"80\" height=\"40\" " + "style=\"fill:orange\"/>\n" 125 + "<text x=\"12.5\" y=\"25\" " 126 + "style=\"font-size:20; fill:darkgray; " 127 + "font-family:SansSerif\">" + "merge</text>\n" + "</svg>\n"); 128 129 // inPort.addTypeListener? 130 131 // Create a node controller to control the context menu 132 _nodeController = new MergeActorControllerFactory(this, 133 "_controllerFactory"); 134 } 135 136 public void typeChanged(TypeEvent event) { 137 _computeTargetTypes(); 138 } 139 140 public void preinitialize() throws IllegalActionException { 141 super.preinitialize(); 142 _initInputPorts(); 143 _computeTargetTypes(); 144 } 145 146 public void fire() throws IllegalActionException { 147 super.fire(); 148 149 Iterator actors = getActors().iterator(); 150 while (actors.hasNext()) { 151 NamedObj actor = (NamedObj) actors.next(); 152 _applyMerge(actor); 153 } 154 } 155 156 public void computeMerge() throws IllegalActionException, 157 NameDuplicationException { 158 _removeMappings(); 159 _initInputPorts(); 160 161 SimpleComputeMergeAlgorithm alg = new SimpleComputeMergeAlgorithm(this); 162 alg.computeMerge(); 163 164 // assign types to target outputs 165 _computeTargetTypes(); 166 setProductionRate(); 167 168 // refresh the canvas 169 ChangeRequest r = new EmptyChangeRequest(this, "update request"); 170 toplevel().requestChange(r); 171 } 172 173 public void computeMergeOld() throws IllegalActionException, 174 NameDuplicationException { 175 // check if any mappings already if so, warn that they will be 176 // removed then remove them 177 _removeMappings(); 178 _initInputPorts(); 179 180 // first step: add one output port per input port 181 Iterator iter = _getInputPorts(); 182 for (int i = 0; iter.hasNext(); i++) { 183 IOPort p = (IOPort) iter.next(); 184 String sourceActor = p.getContainer().getName(); 185 String sourcePort = p.getName(); 186 String targetPort = sourceActor + "_" + sourcePort; 187 TypedIOPort output = new TypedIOPort(this, targetPort); 188 output.setOutput(true); 189 output.setInput(false); 190 output.setMultiport(false); 191 // create a mapping 192 String mergeName = "merge_" + i; 193 SimpleMergeMapping m = new SimpleMergeMapping(this, mergeName, 194 sourceActor, sourcePort, targetPort); 195 }// end for 196 197 // assign types to target outputs 198 _computeTargetTypes(); 199 setProductionRate(); 200 201 // refresh the canvas 202 ChangeRequest r = new EmptyChangeRequest(this, "update request"); 203 toplevel().requestChange(r); 204 } 205 206 public void editMerge() throws IllegalActionException, 207 NameDuplicationException { 208 // open the dialog 209 MergeEditorDialog editor = new MergeEditorDialog(null, this); 210 editor.setVisible(true); 211 } 212 213 /** 214 * 215 */ 216 public Iterator<SimpleMergeMapping> getInputPortMappings(IOPort port) { 217 Vector<SimpleMergeMapping> results = new Vector<SimpleMergeMapping>(); 218 if (port == null) 219 return results.iterator(); 220 Iterator<SimpleMergeMapping> iter = attributeList(SimpleMergeMapping.class).iterator(); 221 while (iter.hasNext()) { 222 try { 223 SimpleMergeMapping m = iter.next(); 224 String actorName = port.getContainer().getName(); 225 String portName = port.getName(); 226 if (actorName.equals(m.getSourceActor())) { 227 if (portName.equals(m.getSourceActorPort())) 228 results.add(m); 229 } 230 } catch (Exception e) { 231 e.printStackTrace(); 232 } 233 } 234 return results.iterator(); 235 } 236 237 /** 238 * 239 */ 240 public Vector getMappings() { 241 return new Vector(attributeList(SimpleMergeMapping.class)); 242 } 243 244 /** 245 * removes the given output port 246 */ 247 public void removeOutputPort(IOPort port) { 248 try { 249 port.setContainer(null); 250 // refresh the canvas 251 ChangeRequest r = new EmptyChangeRequest(this, "update request"); 252 toplevel().requestChange(r); 253 } catch (Exception e) { 254 e.printStackTrace(); 255 } 256 } 257 258 /** 259 * Determine the output types based on the types of input port. 260 */ 261 private void _computeTargetTypes() { 262 Iterator iter = _getInputPorts(); 263 while (iter.hasNext()) { 264 IOPort p = (IOPort) iter.next(); 265 if (p instanceof TypedIOPort) { 266 Iterator<IOPort> targets = getTargetPorts(p); 267 while (targets.hasNext()) { 268 TypedIOPort target = (TypedIOPort) targets.next(); 269 Type targetType = target.getType(); 270 Type inputType = ((TypedIOPort) p).getType(); 271 if (targetType.equals(BaseType.UNKNOWN) 272 || inputType.isCompatible(targetType)) 273 target.setTypeEquals(inputType); 274 } 275 } 276 }// end while 277 } 278 279 /** 280 * A helper funtion that computes the port channel (port, channel) of the 281 * given port. 282 */ 283 private PortChannel _getPortChannel(IOPort inputPort) { 284 Iterator channels = _getInputPorts(); 285 for (int channel = 0; channels.hasNext(); channel++) { 286 IOPort p = (IOPort) channels.next(); 287 if (p == inputPort) 288 return new PortChannel(inputPort, channel); 289 }// end while 290 return null; 291 } 292 293 /** 294 * Calculates the set of actors that are connected to this merge actor via 295 * one or more input ports. 296 * 297 * @return An iterator containing actors connected to this merge actor. 298 */ 299 public Vector getActors() { 300 Vector results = new Vector(); 301 Iterator iter = _getInputPorts(); 302 while (iter.hasNext()) { 303 IOPort p = (IOPort) iter.next(); 304 NamedObj o = p.getContainer(); 305 if (!results.contains(o)) 306 results.add(o); 307 }// end while 308 return results; 309 } 310 311 /** 312 * For a connected actor, applies the merge rules producing data tokens. 313 */ 314 private void _applyMerge(NamedObj actor) { 315 Vector portChannels = _getActorPortChannels(actor); 316 while (_actorHasTokens(portChannels)) { 317 _passMergeTokens(portChannels); 318 _passNonMergeTokens(portChannels); 319 } 320 } 321 322 private void _passNonMergeTokens(Vector portChannels) { 323 Vector inputActorPorts = new Vector(); 324 // get all the input ports from portChannels (i.e., ports for 325 // current actor) 326 Iterator iter = portChannels.iterator(); 327 while (iter.hasNext()) { 328 PortChannel p = (PortChannel) iter.next(); 329 inputActorPorts.add(p.getPort()); 330 } 331 // get all the target output ports for ports in inputActorPorts 332 Vector<IOPort> targetOutputPorts = new Vector<IOPort>(); 333 iter = inputActorPorts.iterator(); 334 while (iter.hasNext()) { 335 IOPort p = (IOPort) iter.next(); 336 Iterator<IOPort> targets = getTargetPorts(p); 337 while (targets.hasNext()) { 338 IOPort target = targets.next(); 339 if (!targetOutputPorts.contains(target)) 340 targetOutputPorts.add(target); 341 } 342 } 343 // get all the output ports not in targetOutputPorts 344 Vector nonMergeOutputPorts = new Vector(); 345 iter = outputPortList().iterator(); 346 while (iter.hasNext()) { 347 IOPort p = (IOPort) iter.next(); 348 if (!targetOutputPorts.contains(p)) 349 nonMergeOutputPorts.add(p); 350 } 351 352 // send a "null" value to each of the nonMergeOutputPorts 353 iter = nonMergeOutputPorts.iterator(); 354 while (iter.hasNext()) { 355 TypedIOPort p = (TypedIOPort) iter.next(); 356 // get the type of the output port of p (FIXME: 357 // _computeType should set output port to "largest" of 358 // inputs that map to it) 359 Token t = null; 360 Type type = p.getType(); 361 Class cls = type.getTokenClass(); 362 try { 363 // FIXME: SHOULD BE TO t.null(), BUT null() UNIMPLEMENTED 364 t = (Token) cls.newInstance(); 365 p.send(0, t.zero()); 366 } catch (Exception e) { 367 e.printStackTrace(); 368 } 369 System.out.println("SENT " + p.getName() + " TOKEN " + t); 370 } 371 } 372 373 private void _passMergeTokens(Vector portChannels) { 374 Iterator iter = portChannels.iterator(); 375 while (iter.hasNext()) { 376 try { 377 PortChannel p = (PortChannel) iter.next(); 378 IOPort in = p.getPort(); 379 int channel = p.getChannel(); 380 System.out.println("PASS MERGE TOKENS \n ... PORT: '" 381 + in.getName() + "' CHANNEL: '" + channel + "'"); 382 Token t = mergeInputPort.get(channel); 383 Iterator<IOPort> ptargets = getTargetPorts(in); 384 while (ptargets.hasNext()) { 385 IOPort ptarget = ptargets.next(); 386 ptarget.send(0, t); 387 System.out.println("SENT " + ptarget.getName() + " TOKEN " 388 + t + " FROM " + in.getName()); 389 }// end while 390 } catch (IllegalActionException e) { 391 e.printStackTrace(); 392 } 393 } 394 } 395 396 /** 397 * Determines if there is a token on the port channels 398 */ 399 private boolean _actorHasTokens(Vector portChannels) { 400 Iterator iter = portChannels.iterator(); 401 while (iter.hasNext()) { 402 try { 403 PortChannel p = (PortChannel) iter.next(); 404 if (!mergeInputPort.hasToken(p.getChannel())) 405 return false; 406 } catch (IllegalActionException e) { 407 e.printStackTrace(); 408 } 409 } 410 return true; 411 } 412 413 /** 414 * Given the mappings, determines which ports of the given actor are to be 415 * used as well as their channel. 416 * 417 * @return The given source actor's ports and channels as PortChannels 418 */ 419 private Vector _getActorPortChannels(NamedObj actor) { 420 Vector results = new Vector(); 421 Iterator iter = _getInputPorts(); 422 for (int channel = 0; iter.hasNext(); channel++) { 423 IOPort p = (IOPort) iter.next(); 424 if (actor.equals(p.getContainer())) 425 results.add(new PortChannel(p, channel)); 426 } 427 return results; 428 } 429 430 /** 431 * @return The output ports of actor connected to the merge actor 432 */ 433 public Vector<IOPort> getActorPorts(NamedObj actor) { 434 Vector<IOPort> results = new Vector<IOPort>(); 435 Iterator iter = _getInputPorts(); 436 while (iter.hasNext()) { 437 IOPort p = (IOPort) iter.next(); 438 if (actor.equals(p.getContainer())) 439 results.add(p); 440 } 441 return results; 442 } 443 444 public Iterator<IOPort> getTargetPorts(IOPort inPort) { 445 Vector<IOPort> results = new Vector<IOPort>(); 446 String actorSource = inPort.getContainer().getName(); 447 String portName = inPort.getName(); 448 Iterator maps = attributeList(SimpleMergeMapping.class).iterator(); 449 while (maps.hasNext()) { 450 SimpleMergeMapping m = (SimpleMergeMapping) maps.next(); 451 if (actorSource.equals(m.getSourceActor()) 452 && portName.equals(m.getSourceActorPort())) { 453 String outName = m.getTargetPort(); 454 Iterator ports = outputPortList().iterator(); 455 while (ports.hasNext()) { 456 IOPort p = (IOPort) ports.next(); 457 if (outName.equals(p.getName())) 458 results.add(p); 459 } 460 } 461 } 462 return results.iterator(); 463 } 464 465 private void _initInputPorts() { 466 // remove old listeners 467 Iterator iter = _getInputPorts(); 468 while (iter.hasNext()) { 469 IOPort p = (IOPort) iter.next(); 470 if (p instanceof TypedIOPort) 471 ((TypedIOPort) p).removeTypeListener(this); 472 }// end while 473 474 // create new set of input ports 475 _inputPorts = new Vector(); 476 iter = mergeInputPort.connectedPortList().iterator(); 477 while (iter.hasNext()) { 478 IOPort p = (IOPort) iter.next(); 479 _inputPorts.add(p); 480 if (p instanceof TypedIOPort) 481 ((TypedIOPort) p).addTypeListener(this); 482 }// end while 483 } 484 485 private Iterator _getInputPorts() { 486 return mergeInputPort.connectedPortList().iterator(); 487 } 488 489 private void _removeMappings() throws IllegalActionException, 490 NameDuplicationException { 491 // remove the mapping attributes 492 Iterator iter = attributeList(SimpleMergeMapping.class).iterator(); 493 ; 494 while (iter.hasNext()) { 495 SimpleMergeMapping m = (SimpleMergeMapping) iter.next(); 496 m.setContainer(null); 497 } 498 // remove the output ports 499 iter = outputPortList().iterator(); 500 while (iter.hasNext()) { 501 IOPort p = (IOPort) iter.next(); 502 p.setContainer(null); 503 } 504 } 505 506 public void setProductionRate() { 507 // the number of production tokens is num(actors) 508 // production rate set on each output port 509 Vector actors = getActors(); 510 int rate = actors.size(); 511 Iterator iter = outputPortList().iterator(); 512 while (iter.hasNext()) { 513 try { 514 IOPort p = (IOPort) iter.next(); 515 Parameter tpr = (Parameter) p 516 .getAttribute("tokenProductionRate"); 517 if (tpr == null) { 518 tpr = new Parameter(this, "tokenProductionRate", 519 new IntToken(rate)); 520 tpr.setContainer(p); 521 } else { 522 tpr.setToken(new IntToken(rate)); 523 } 524 } catch (Exception e) { 525 e.printStackTrace(); 526 } 527 } 528 } 529 530 public void update() { 531 // refresh the canvas 532 ChangeRequest r = new EmptyChangeRequest(this, "update request"); 533 toplevel().requestChange(r); 534 } 535 536 // 537 // Inner classes 538 // 539 540 /** 541 * Specific input port 542 */ 543 class MergeInputPort extends TypedIOPort { 544 545 /** 546 * constructor 547 */ 548 public MergeInputPort(ComponentEntity container, String name) 549 throws IllegalActionException, NameDuplicationException { 550 super(container, name); 551 setInput(true); 552 setOutput(false); 553 setMultiport(true); 554 } 555 556 // not sure what needs to be overriden now 557 public void link(Relation relation) throws IllegalActionException { 558 super.link(relation); 559 } 560 561 /** 562 * Prevent types from being modified 563 */ 564 public Type getType() { 565 return BaseType.GENERAL; 566 } 567 568 /** 569 * Sabotage type resolution ... 570 */ 571 public InequalityTerm getTypeTerm() { 572 return new MergePortTypeTerm(); 573 } 574 575 private class MergePortTypeTerm implements InequalityTerm { 576 public Object getAssociatedObject() { 577 return MergeInputPort.this; 578 } 579 580 public Object getValue() { 581 return getType(); 582 } 583 584 public InequalityTerm[] getVariables() { 585 return (new InequalityTerm[0]); 586 } 587 588 public void initialize(Object type) throws IllegalActionException { 589 } 590 591 public boolean isSettable() { 592 return false; 593 } 594 595 public boolean isValueAcceptable() { 596 return true; 597 } 598 599 public void setValue(Object type) throws IllegalActionException { 600 } 601 } 602 }; 603 604 /** 605 * 606 */ 607 private class MergeActorControllerFactory extends NodeControllerFactory { 608 private MergeActor _mergeActor; 609 610 public MergeActorControllerFactory(MergeActor mergeActor, String name) 611 throws NameDuplicationException, IllegalActionException { 612 super(mergeActor, name); 613 _mergeActor = mergeActor; 614 } 615 616 public NamedObjController create(GraphController controller) { 617 return new MergeActorInstanceController(controller, _mergeActor); 618 } 619 }; 620 621 /** 622 * ... 623 */ 624 public class MergeActorInstanceController extends ActorInstanceController { 625 public MergeActorInstanceController(GraphController controller, 626 MergeActor mergeActor) { 627 this(controller, FULL, mergeActor); 628 } 629 630 public MergeActorInstanceController(GraphController controller, 631 Access access, MergeActor mergeActor) { 632 super(controller, access); 633 MenuActionFactory f1 = new MenuActionFactory(new MergeActorAction1( 634 mergeActor)); 635 _menuFactory.addMenuItemFactory(f1); 636 MenuActionFactory f2 = new MenuActionFactory(new MergeActorAction2( 637 mergeActor)); 638 _menuFactory.addMenuItemFactory(f2); 639 640 } 641 } 642 643 /** 644 * ... 645 */ 646 protected class MergeActorAction1 extends FigureAction { 647 private MergeActor _mergeActor; 648 649 public MergeActorAction1(MergeActor mergeActor) { 650 super("Compute Merge"); 651 _mergeActor = mergeActor; 652 } 653 654 public void actionPerformed(ActionEvent ev) { 655 try { 656 _mergeActor.computeMerge(); 657 } catch (Exception e) { 658 e.printStackTrace(); 659 } 660 } 661 }; 662 663 /** 664 * ... 665 */ 666 protected class MergeActorAction2 extends FigureAction { 667 private MergeActor _mergeActor; 668 669 public MergeActorAction2(MergeActor mergeActor) { 670 super("Edit Merge Mappings"); 671 _mergeActor = mergeActor; 672 } 673 674 public void actionPerformed(ActionEvent ev) { 675 try { 676 _mergeActor.editMerge(); 677 } catch (Exception e) { 678 e.printStackTrace(); 679 } 680 } 681 }; 682 683 private class EmptyChangeRequest extends ChangeRequest { 684 public EmptyChangeRequest(Object o, String s) { 685 super(o, s); 686 } 687 688 public void _execute() { 689 // do nothing 690 } 691 }; 692 693 /** 694 * A helper class that encapsulates a port and its channel 695 */ 696 private class PortChannel { 697 public PortChannel(IOPort port, int channel) { 698 _port = port; 699 _channel = channel; 700 } 701 702 public IOPort getPort() { 703 return _port; 704 } 705 706 public int getChannel() { 707 return _channel; 708 } 709 710 private IOPort _port; 711 private int _channel; 712 }; 713 714 /** 715 * Overriden from NamedObj ... 716 */ 717 public String uniqueName(String prefix) { 718 if (prefix == null) 719 prefix = "null"; 720 prefix = _stripNumericSuffix(prefix); 721 String candidate = prefix + "1"; 722 int uniqueNameIndex = 2; 723 while (_hasName(candidate)) 724 candidate = prefix + uniqueNameIndex++; 725 return candidate; 726 } 727 728 private boolean _hasName(String name) { 729 Iterator iter = containedObjectsIterator(); 730 while (iter.hasNext()) { 731 NamedObj obj = (NamedObj) iter.next(); 732 if (obj.getName().equals(name)) 733 return true; 734 } 735 return false; 736 } 737 738 // this needs to be a subclass of typed io port 739 private Vector _inputPorts = new Vector(); // the set of ports connected to 740 // the mergeInputPort 741 private MergeActorControllerFactory _nodeController = null; // for updating 742 // canvas 743 private Vector _indexPorts = new Vector(); 744 745}