001/* An IOPort for controllers and refinements in modal models. 002 003 Copyright (c) 2006-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 */ 028package ptolemy.actor.lib.hoc; 029 030import ptolemy.actor.IOPort; 031import ptolemy.actor.IORelation; 032import ptolemy.actor.TypedIOPort; 033import ptolemy.kernel.ComponentEntity; 034import ptolemy.kernel.Entity; 035import ptolemy.kernel.Port; 036import ptolemy.kernel.Relation; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.NameDuplicationException; 039import ptolemy.kernel.util.Nameable; 040import ptolemy.kernel.util.NamedObj; 041import ptolemy.kernel.util.Workspace; 042 043/////////////////////////////////////////////////////////////////// 044//// RefinementPort 045 046/** 047 A port for controllers and refinements in modal models. This port 048 mirrors certain changes to it in the ports of the container of the container. 049 That container in turn mirrors those changes in other refinements and/or 050 controllers. This class is designed to work closely with ModalPort, 051 since changes to the ports can be initiated from either class. 052 053 @author Edward A. Lee 054 @version $Id$ 055 @since Ptolemy II 5.2 056 @Pt.ProposedRating Red (eal) 057 @Pt.AcceptedRating Red (liuxj) 058 */ 059public class RefinementPort extends TypedIOPort { 060 /** Construct a port in the given workspace. 061 * @param workspace The workspace. 062 * @exception IllegalActionException If the port is not of an acceptable 063 * class for the container, or if the container does not implement the 064 * TypedActor interface. 065 */ 066 public RefinementPort(Workspace workspace) throws IllegalActionException { 067 super(workspace); 068 _checkWhetherMirrorIsInput(); 069 } 070 071 /** Construct a port with a containing actor and a name 072 * that is neither an input nor an output. The specified container 073 * must implement the TypedActor interface, or an exception will be 074 * thrown. 075 * @param container The container actor. 076 * @param name The name of the port. 077 * @exception IllegalActionException If the port is not of an acceptable 078 * class for the container, or if the container does not implement the 079 * TypedActor interface. 080 * @exception NameDuplicationException If the name coincides with 081 * a port already in the container. 082 */ 083 public RefinementPort(ComponentEntity container, String name) 084 throws IllegalActionException, NameDuplicationException { 085 super(container, name); 086 _checkWhetherMirrorIsInput(); 087 } 088 089 /////////////////////////////////////////////////////////////////// 090 //// public methods //// 091 092 /** Override the super class method to allow UNKNOWN type if this 093 * port does not have any inside links. 094 * @return True if this port does not have any inside links, 095 * or the super class method returns true. 096 */ 097 @Override 098 public boolean isTypeAcceptable() { 099 if (numInsideLinks() == 0) { 100 return true; 101 } else { 102 return super.isTypeAcceptable(); 103 } 104 } 105 106 /** Set the connected relation to a bus if this port is a multiport. 107 */ 108 @Override 109 public void link(Relation relation) throws IllegalActionException { 110 super.link(relation); 111 112 if (isMultiport()) { 113 ((IORelation) relation).setWidth(IORelation.WIDTH_TO_INFER); 114 } 115 } 116 117 /** Move this object down by one in the list of attributes of 118 * its container. If this object is already last, do nothing. 119 * This method overrides the base class to mirror the change 120 * in any mirror ports. 121 * Increment the version of the workspace. 122 * @return The index of the specified object prior to moving it, 123 * or -1 if it is not moved. 124 * @exception IllegalActionException If this object has 125 * no container. 126 */ 127 @Override 128 public int moveDown() throws IllegalActionException { 129 boolean disableStatus = _mirrorDisable; 130 131 try { 132 _workspace.getWriteAccess(); 133 134 int result = -1; 135 136 if (_mirrorDisable || getContainer() == null) { 137 result = super.moveDown(); 138 } else { 139 _mirrorDisable = true; 140 141 boolean success = false; 142 Nameable container = getContainer(); 143 144 if (container != null) { 145 Nameable modal = container.getContainer(); 146 147 if (modal instanceof MultiCompositeActor) { 148 Port port = ((MultiCompositeActor) modal) 149 .getPort(getName()); 150 151 if (port instanceof IOPort) { 152 ((IOPort) port).moveDown(); 153 success = true; 154 } 155 } 156 } 157 158 // The mirror port(s), if there are any, 159 // will have called this method and achieved 160 // the moveDown. But if there are no mirror 161 // ports, we need to do it here. 162 if (!success) { 163 result = super.moveDown(); 164 } 165 } 166 167 return result; 168 } finally { 169 _mirrorDisable = disableStatus; 170 _workspace.doneWriting(); 171 } 172 } 173 174 /** Move this object to the first position in the list 175 * of attributes of the container. If this object is already first, 176 * do nothing. Increment the version of the workspace. 177 * This method overrides the base class to mirror the change 178 * in any mirror ports. 179 * @return The index of the specified object prior to moving it, 180 * or -1 if it is not moved. 181 * @exception IllegalActionException If this object has 182 * no container. 183 */ 184 @Override 185 public int moveToFirst() throws IllegalActionException { 186 boolean disableStatus = _mirrorDisable; 187 188 try { 189 _workspace.getWriteAccess(); 190 191 int result = -1; 192 193 if (_mirrorDisable || getContainer() == null) { 194 result = super.moveToFirst(); 195 } else { 196 _mirrorDisable = true; 197 198 boolean success = false; 199 Nameable container = getContainer(); 200 201 if (container != null) { 202 Nameable modal = container.getContainer(); 203 204 if (modal instanceof MultiCompositeActor) { 205 Port port = ((MultiCompositeActor) modal) 206 .getPort(getName()); 207 208 if (port instanceof IOPort) { 209 ((IOPort) port).moveToFirst(); 210 success = true; 211 } 212 } 213 } 214 215 // The mirror port(s), if there are any, 216 // will have called this method and achieved 217 // the moveToFirst. But if there are no mirror 218 // ports, we need to do it here. 219 if (!success) { 220 result = super.moveToFirst(); 221 } 222 } 223 224 return result; 225 } finally { 226 _mirrorDisable = disableStatus; 227 _workspace.doneWriting(); 228 } 229 } 230 231 /** Move this object to the specified position in the list 232 * of attributes of the container. If this object is already at the 233 * specified position, do nothing. 234 * This method overrides the base class to mirror the change 235 * in any mirror ports. 236 * Increment the version of the workspace. 237 * @param index The position to move this object to. 238 * @return The index of the specified object prior to moving it, 239 * or -1 if it is not moved. 240 * @exception IllegalActionException If this object has 241 * no container or if the index is out of bounds. 242 */ 243 @Override 244 public int moveToIndex(int index) throws IllegalActionException { 245 boolean disableStatus = _mirrorDisable; 246 247 try { 248 _workspace.getWriteAccess(); 249 250 int result = -1; 251 252 if (_mirrorDisable || getContainer() == null) { 253 result = super.moveToIndex(index); 254 } else { 255 _mirrorDisable = true; 256 257 boolean success = false; 258 Nameable container = getContainer(); 259 260 if (container != null) { 261 Nameable modal = container.getContainer(); 262 263 if (modal instanceof MultiCompositeActor) { 264 Port port = ((MultiCompositeActor) modal) 265 .getPort(getName()); 266 267 if (port instanceof IOPort) { 268 ((IOPort) port).moveToIndex(index); 269 success = true; 270 } 271 } 272 } 273 274 // The mirror port(s), if there are any, 275 // will have called this method and achieved 276 // the moveToIndex. But if there are no mirror 277 // ports, we need to do it here. 278 if (!success) { 279 result = super.moveToIndex(index); 280 } 281 } 282 283 return result; 284 } finally { 285 _mirrorDisable = disableStatus; 286 _workspace.doneWriting(); 287 } 288 } 289 290 /** Move this object to the last position in the list 291 * of attributes of the container. If this object is already last, 292 * do nothing. This method overrides the base class to mirror the change 293 * in any mirror ports. 294 * Increment the version of the workspace. 295 * @return The index of the specified object prior to moving it, 296 * or -1 if it is not moved. 297 * @exception IllegalActionException If this object has 298 * no container. 299 */ 300 @Override 301 public int moveToLast() throws IllegalActionException { 302 boolean disableStatus = _mirrorDisable; 303 304 try { 305 _workspace.getWriteAccess(); 306 307 int result = -1; 308 309 if (_mirrorDisable || getContainer() == null) { 310 result = super.moveToLast(); 311 } else { 312 _mirrorDisable = true; 313 314 boolean success = false; 315 Nameable container = getContainer(); 316 317 if (container != null) { 318 Nameable modal = container.getContainer(); 319 320 if (modal instanceof MultiCompositeActor) { 321 Port port = ((MultiCompositeActor) modal) 322 .getPort(getName()); 323 324 if (port instanceof IOPort) { 325 ((IOPort) port).moveToLast(); 326 success = true; 327 } 328 } 329 } 330 331 if (!success) { 332 result = super.moveToLast(); 333 } 334 } 335 336 return result; 337 } finally { 338 _mirrorDisable = disableStatus; 339 _workspace.doneWriting(); 340 } 341 } 342 343 /** Move this object up by one in the list of 344 * attributes of the container. If this object is already first, do 345 * nothing. 346 * This method overrides the base class to mirror the change 347 * in any mirror ports. 348 * Increment the version of the workspace. 349 * @return The index of the specified object prior to moving it, 350 * or -1 if it is not moved. 351 * @exception IllegalActionException If this object has 352 * no container. 353 */ 354 @Override 355 public int moveUp() throws IllegalActionException { 356 boolean disableStatus = _mirrorDisable; 357 358 try { 359 _workspace.getWriteAccess(); 360 361 int result = -1; 362 363 if (_mirrorDisable || getContainer() == null) { 364 result = super.moveUp(); 365 } else { 366 _mirrorDisable = true; 367 368 boolean success = false; 369 Nameable container = getContainer(); 370 371 if (container != null) { 372 Nameable modal = container.getContainer(); 373 374 if (modal instanceof MultiCompositeActor) { 375 Port port = ((MultiCompositeActor) modal) 376 .getPort(getName()); 377 378 if (port instanceof IOPort) { 379 ((IOPort) port).moveUp(); 380 success = true; 381 } 382 } 383 } 384 385 // The mirror port(s), if there are any, 386 // will have called this method and achieved 387 // the moveUp. But if there are no mirror 388 // ports, we need to do it here. 389 if (!success) { 390 result = super.moveUp(); 391 } 392 } 393 394 return result; 395 } finally { 396 _mirrorDisable = disableStatus; 397 _workspace.doneWriting(); 398 } 399 } 400 401 /** Override the base class so that if the port is being removed 402 * from the current container, then it is also removed from the 403 * controller and from each of the refinements. 404 * @param container The proposed container. 405 * @exception IllegalActionException If the proposed container is not a 406 * ComponentEntity, doesn't implement Actor, or has no name, 407 * or the port and container are not in the same workspace. Or 408 * it's not null 409 * @exception NameDuplicationException If the container already has 410 * a port with the name of this port. 411 */ 412 @Override 413 public void setContainer(Entity container) 414 throws IllegalActionException, NameDuplicationException { 415 NamedObj oldContainer = getContainer(); 416 417 if (container == oldContainer) { 418 // Nothing to do. 419 return; 420 } 421 422 boolean disableStatus = _mirrorDisable; 423 424 try { 425 _workspace.getWriteAccess(); 426 427 if (_mirrorDisable || getContainer() == null) { 428 // Have already called the super class. 429 // This time, process the request. 430 super.setContainer(container); 431 } else { 432 _mirrorDisable = true; 433 434 boolean success = false; 435 436 if (oldContainer != null) { 437 Nameable modal = oldContainer.getContainer(); 438 439 if (modal instanceof MultiCompositeActor) { 440 Port port = ((MultiCompositeActor) modal) 441 .getPort(getName()); 442 443 if (port != null) { 444 port.setContainer(null); 445 success = true; 446 } 447 } 448 } 449 450 if (!success) { 451 super.setContainer(container); 452 } 453 } 454 } finally { 455 _mirrorDisable = disableStatus; 456 _workspace.doneWriting(); 457 } 458 } 459 460 /** If the argument is true, make the port an input port. 461 * If the argument is false, make the port not an input port. 462 * This method overrides the base class to make the same 463 * change on the mirror ports in the controller and state refinments. 464 * This method invalidates the schedule and resolved types of the 465 * director of the container, if there is one. 466 * It is write-synchronized on the workspace, and increments 467 * the version of the workspace. 468 * @param isInput True to make the port an input. 469 * @exception IllegalActionException If changing the port status is 470 * not permitted. 471 */ 472 @Override 473 public void setInput(boolean isInput) throws IllegalActionException { 474 boolean disableStatus = _mirrorDisable; 475 476 try { 477 _workspace.getWriteAccess(); 478 479 if (_mirrorDisable || getContainer() == null 480 || _automaticallyInput) { 481 // Do not mirror. 482 super.setInput(isInput); 483 } else { 484 _mirrorDisable = true; 485 486 boolean success = false; 487 Nameable container = getContainer(); 488 489 if (container != null) { 490 Nameable modal = container.getContainer(); 491 492 if (modal instanceof MultiCompositeActor) { 493 Port port = ((MultiCompositeActor) modal) 494 .getPort(getName()); 495 496 if (port instanceof IOPort) { 497 ((IOPort) port).setInput(isInput); 498 success = true; 499 } 500 } 501 } 502 503 if (!success) { 504 super.setInput(isInput); 505 } 506 } 507 } finally { 508 _mirrorDisable = disableStatus; 509 _workspace.doneWriting(); 510 } 511 } 512 513 /** Control whether any change should be mirrored in the modal 514 * model, mode controller, and refinements. 515 * This is added to allow control by the UI. 516 * @param disable True if mirroring should not occur. 517 */ 518 public void setMirrorDisable(boolean disable) { 519 _mirrorDisable = disable; 520 } 521 522 /** If the argument is true, make the port a multiport. 523 * If the argument is false, make the port not a multiport. 524 * This method overrides the base class to make the same 525 * change on the mirror ports in the controller and state refinments. 526 * This method invalidates the schedule and resolved types of the 527 * director of the container, if there is one. 528 * It is write-synchronized on the workspace, and increments 529 * the version of the workspace. 530 * @param isMultiport True to make the port a multiport. 531 * @exception IllegalActionException If changing the port status is 532 * not permitted. 533 */ 534 @Override 535 public void setMultiport(boolean isMultiport) 536 throws IllegalActionException { 537 boolean disableStatus = _mirrorDisable; 538 539 try { 540 _workspace.getWriteAccess(); 541 542 if (_mirrorDisable || getContainer() == null) { 543 // Do not mirror. 544 super.setMultiport(isMultiport); 545 } else { 546 _mirrorDisable = true; 547 548 boolean success = false; 549 Nameable container = getContainer(); 550 551 if (container != null) { 552 Nameable modal = container.getContainer(); 553 554 if (modal instanceof MultiCompositeActor) { 555 Port port = ((MultiCompositeActor) modal) 556 .getPort(getName()); 557 558 if (port instanceof IOPort) { 559 ((IOPort) port).setMultiport(isMultiport); 560 success = true; 561 } 562 } 563 } 564 565 if (!success) { 566 super.setMultiport(isMultiport); 567 } 568 } 569 } finally { 570 _mirrorDisable = disableStatus; 571 _workspace.doneWriting(); 572 } 573 } 574 575 /** Set the name of the port, and mirror the change in all the 576 * mirror ports. 577 * This method is write-synchronized on the workspace, and increments 578 * the version of the workspace. 579 * @exception IllegalActionException If the name has a period. 580 * @exception NameDuplicationException If there is already a port 581 * with the same name in the container. 582 */ 583 @Override 584 public void setName(String name) 585 throws IllegalActionException, NameDuplicationException { 586 boolean disableStatus = _mirrorDisable; 587 588 try { 589 _workspace.getWriteAccess(); 590 591 if (_mirrorDisable || getContainer() == null) { 592 // Do not mirror. 593 super.setName(name); 594 } else { 595 _mirrorDisable = true; 596 597 boolean success = false; 598 Nameable container = getContainer(); 599 600 if (container != null) { 601 Nameable modal = container.getContainer(); 602 603 if (modal instanceof MultiCompositeActor) { 604 Port port = ((MultiCompositeActor) modal) 605 .getPort(getName()); 606 607 if (port != null) { 608 port.setName(name); 609 success = true; 610 } 611 } 612 } 613 614 if (!success) { 615 super.setName(name); 616 } 617 } 618 } finally { 619 _mirrorDisable = disableStatus; 620 _workspace.doneWriting(); 621 } 622 } 623 624 /** If the argument is true, make the port an output port. 625 * If the argument is false, make the port not an output port. 626 * In addition, if the container is an instance of Refinement, 627 * and the argument is true, find the corresponding port of the 628 * controller and make it an input and not an output. This makes 629 * it possible for the controller to see the outputs of the refinements. 630 * This method overrides the base class to make the same 631 * change on the mirror ports in the controller and state refinments. 632 * This method invalidates the schedule and resolved types of the 633 * director of the container, if there is one. 634 * It is write-synchronized on the workspace, and increments 635 * the version of the workspace. 636 * @param isOutput True to make the port an output. 637 * @exception IllegalActionException If changing the port status is 638 * not permitted. 639 */ 640 @Override 641 public void setOutput(boolean isOutput) throws IllegalActionException { 642 boolean disableStatus = _mirrorDisable; 643 644 try { 645 _workspace.getWriteAccess(); 646 647 if (_mirrorDisable || getContainer() == null) { 648 // Do not mirror. 649 super.setOutput(isOutput); 650 } else { 651 _mirrorDisable = true; 652 653 boolean success = false; 654 Nameable container = getContainer(); 655 656 if (container != null) { 657 Nameable modal = container.getContainer(); 658 659 if (modal instanceof MultiCompositeActor) { 660 Port port = ((MultiCompositeActor) modal) 661 .getPort(getName()); 662 663 if (port instanceof IOPort) { 664 ((IOPort) port).setOutput(isOutput); 665 success = true; 666 } 667 } 668 } 669 670 if (!success) { 671 super.setOutput(isOutput); 672 } 673 } 674 } finally { 675 _mirrorDisable = disableStatus; 676 _workspace.doneWriting(); 677 } 678 } 679 680 /////////////////////////////////////////////////////////////////// 681 //// protected variables //// 682 683 /** Indicator that the port is automatically an input port 684 * because it was set to be an output port. This automatic change 685 * is made in output ports of the ModalController so that if 686 * a refinement writes to its output port, then that data is 687 * available in scope for the guard expressions. 688 */ 689 protected boolean _automaticallyInput = false; 690 691 // This is protected to be accessible to ModalPort. 692 693 /** If false, then changes the port are mirrored in the container's 694 * container. This is false by default. 695 */ 696 protected boolean _mirrorDisable = false; 697 698 /////////////////////////////////////////////////////////////////// 699 //// private methods //// 700 701 /** If the container is a MultiCompositeActor and has a mirror port to this 702 * one that is not an input and is an output, then mark this port 703 * so that if it becomes an input, that input property is not 704 * reflected to the mirror port. 705 */ 706 private void _checkWhetherMirrorIsInput() { 707 // Need to check whether there is a containing MultiCompositeActor, 708 // and whether its mirror port is also an input. 709 Nameable container = getContainer(); 710 711 if (container != null) { 712 Nameable modal = container.getContainer(); 713 714 if (modal instanceof MultiCompositeActor) { 715 Port port = ((MultiCompositeActor) modal).getPort(getName()); 716 717 if (port instanceof IOPort) { 718 if (!((IOPort) port).isInput() 719 && ((IOPort) port).isOutput()) { 720 _automaticallyInput = true; 721 } 722 } 723 } 724 } 725 } 726}