001/* A composite that contain one actor and mirror the ports and parameters of that actor. 002 003 Copyright (c) 2007-2015 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 java.io.IOException; 031import java.io.Writer; 032import java.util.Iterator; 033import java.util.LinkedList; 034import java.util.List; 035 036import ptolemy.actor.IOPort; 037import ptolemy.actor.TypedCompositeActor; 038import ptolemy.actor.parameters.MirrorPortParameter; 039import ptolemy.actor.parameters.ParameterMirrorPort; 040import ptolemy.actor.parameters.PortParameter; 041import ptolemy.kernel.ComponentEntity; 042import ptolemy.kernel.ComponentPort; 043import ptolemy.kernel.ComponentRelation; 044import ptolemy.kernel.CompositeEntity; 045import ptolemy.kernel.Entity; 046import ptolemy.kernel.Port; 047import ptolemy.kernel.util.Attribute; 048import ptolemy.kernel.util.ChangeRequest; 049import ptolemy.kernel.util.IllegalActionException; 050import ptolemy.kernel.util.InternalErrorException; 051import ptolemy.kernel.util.KernelException; 052import ptolemy.kernel.util.NameDuplicationException; 053import ptolemy.kernel.util.NamedObj; 054import ptolemy.kernel.util.Workspace; 055import ptolemy.moml.HandlesInternalLinks; 056 057/////////////////////////////////////////////////////////////////// 058//// ReflectComposite 059 060/** 061 A composite that contains one actor and mirrors the ports and 062 parameters of that actor. In this base class, ports that are 063 not instances of MirrorPort are not mirrored. The subclass 064 MirrorComposite will mirror those ports. 065 066 @author Ilge Akkaya and Edward A. Lee 067 @version $Id$ 068 @since Ptolemy II 10.0 069 @Pt.ProposedRating Yellow (eal) 070 @Pt.AcceptedRating Red (neuendor) 071 */ 072public class ReflectComposite extends TypedCompositeActor 073 implements HandlesInternalLinks { 074 075 /** Create an actor with a name and a container. 076 * The container argument must not be null, or a 077 * NullPointerException will be thrown. This actor will use the 078 * workspace of the container for synchronization and version counts. 079 * If the name argument is null, then the name is set to the empty string. 080 * Increment the version of the workspace. 081 * @param container The container actor. 082 * @param name The name of this actor. 083 * @exception IllegalActionException If the container is incompatible 084 * with this actor. 085 * @exception NameDuplicationException If the name coincides with 086 * an actor already in the container. 087 */ 088 public ReflectComposite(CompositeEntity container, String name) 089 throws IllegalActionException, NameDuplicationException { 090 super(container, name); 091 _init(true); 092 } 093 094 /** Construct a ReflectComposite in the specified workspace with 095 * no container and an empty string as a name. You can then change 096 * the name with setName(). If the workspace argument is null, then 097 * use the default workspace. You should set the local director or 098 * executive director before attempting to send data to the actor 099 * or to execute it. Add the actor to the workspace directory. 100 * Increment the version number of the workspace. 101 * @param workspace The workspace that will list the actor. 102 */ 103 public ReflectComposite(Workspace workspace) { 104 super(workspace); 105 _init(true); 106 } 107 108 /** Create an actor with a name and a container that optionally 109 * mirrors the ports that are instances of ParameterPort. 110 * The container argument must not be null, or a 111 * NullPointerException will be thrown. This actor will use the 112 * workspace of the container for synchronization and version counts. 113 * If the name argument is null, then the name is set to the empty string. 114 * Increment the version of the workspace. 115 * @param container The container actor. 116 * @param name The name of this actor. 117 * @param mirrorParameterPorts If false, then ports that are instances of 118 * ParameterPort are not mirrored. 119 * @exception IllegalActionException If the container is incompatible 120 * with this actor. 121 * @exception NameDuplicationException If the name coincides with 122 * an actor already in the container. 123 */ 124 public ReflectComposite(CompositeEntity container, String name, 125 boolean mirrorParameterPorts) 126 throws IllegalActionException, NameDuplicationException { 127 super(container, name); 128 _init(mirrorParameterPorts); 129 } 130 131 /////////////////////////////////////////////////////////////////// 132 //// public methods //// 133 134 /** Clone the object into the specified workspace. This overrides 135 * the base class to set up the associations in the mirror ports 136 * and to set a flag indicating that cloning is complete. 137 * @param workspace The workspace for the new object. 138 * @return A new NamedObj. 139 * @exception CloneNotSupportedException If any of the attributes 140 * cannot be cloned. 141 * @see #exportMoML(Writer, int, String) 142 */ 143 @Override 144 public Object clone(Workspace workspace) throws CloneNotSupportedException { 145 ReflectComposite result = (ReflectComposite) super.clone(workspace); 146 147 // Fix port associations. 148 Iterator entities = result.entityList().iterator(); 149 150 while (entities.hasNext()) { 151 Entity insideEntity = (Entity) entities.next(); 152 Iterator ports = result.portList().iterator(); 153 154 while (ports.hasNext()) { 155 IOPort port = (IOPort) ports.next(); 156 Port insidePort = insideEntity.getPort(port.getName()); 157 158 if (insidePort instanceof MirrorPort) { 159 ((MirrorPort) port) 160 .setAssociatedPort((MirrorPort) insidePort); 161 } else if (insidePort instanceof ParameterMirrorPort) { 162 ((ParameterMirrorPort) port).setAssociatedPort( 163 (ParameterMirrorPort) insidePort); 164 } 165 } 166 } 167 return result; 168 } 169 170 /** Override the base class to return a specialized port. 171 * @param name The name of the port to create. 172 * @return A new instance of IteratePort, an inner class. 173 * @exception NameDuplicationException If the container already has a port 174 * with this name. 175 */ 176 @Override 177 public Port newPort(String name) throws NameDuplicationException { 178 try { 179 Port result = new MirrorPort(this, name); 180 181 // NOTE: We would like prevent deletion via MoML 182 // (or name changes, for that matter), but the following 183 // also prevents making it an input, which makes 184 // adding ports via the port dialog fail. 185 // result.setDerivedLevel(1); 186 // Force the port to be persistent despite being derived. 187 // result.setPersistent(true); 188 return result; 189 } catch (IllegalActionException ex) { 190 // This exception should not occur, so we throw a runtime 191 // exception. 192 throw new InternalErrorException(this, ex, null); 193 } 194 } 195 196 /** Create a new ParameterMirrorPort. 197 * @param name The name of the port to create. 198 * @return A new instance of PtidesMirrorPort, an inner class. 199 * @exception NameDuplicationException If the container already has a port 200 * with this name. 201 */ 202 public Port newParameterPort(String name) throws NameDuplicationException { 203 try { 204 PortParameter parameter = new MirrorPortParameter(this, name); 205 return parameter.getPort(); 206 } catch (IllegalActionException ex) { 207 // This exception should not occur, so we throw a runtime 208 // exception. 209 throw new InternalErrorException(this, ex, null); 210 } 211 } 212 213 /////////////////////////////////////////////////////////////////// 214 //// protected methods //// 215 216 /** Override the base class to queue a change request to remove 217 * any previously contained entity and its mirrored ports, and 218 * to mirror the ports of the added entity. 219 * @param entity Entity to contain. 220 * @exception IllegalActionException If the entity has no name, or the 221 * action would result in a recursive containment structure, or the 222 * argument does not implement the TypedActor interface. 223 * @exception NameDuplicationException If the name collides with a name 224 * already on the actor contents list, or if the added element is a 225 * class definition. 226 */ 227 @Override 228 protected void _addEntity(ComponentEntity entity) 229 throws IllegalActionException, NameDuplicationException { 230 if (entity.isClassDefinition()) { 231 throw new IllegalActionException(this, 232 "Cannot place a class definition in an " 233 + "ReflectComposite actor."); 234 } 235 236 super._addEntity(entity); 237 238 // Issue a change request to add the appropriate 239 // ports and connections to the new entity. 240 ChangeRequest request = new ChangeRequest(this, // originator 241 "Adjust contained entities, ports and parameters") { 242 // Override this to indicate that the change is localized. 243 // This keeps the EntityTreeModel from closing open libraries 244 // when notified of this change. 245 @Override 246 public NamedObj getLocality() { 247 return ReflectComposite.this; 248 } 249 250 @Override 251 protected void _execute() throws Exception { 252 // NOTE: We defer to a change request 253 // because only at this point can we be sure that the 254 // change request that triggered this has completed (i.e. that 255 // the entity being added has been added. 256 synchronized (ReflectComposite.this) { 257 try { 258 workspace().getWriteAccess(); 259 260 // Entity most recently added. 261 ComponentEntity entity = null; 262 263 // Delete any previously contained entities. 264 // The strategy here is a bit tricky if this ReflectComposite 265 // is within a class definition (that is, if it has derived objects). 266 // The key is that derived objects do not permit deletion (via 267 // MoML) of contained entities. They cannot because this would 268 // violate the invariant of classes where derived objects 269 // always contain the same objects as their parents. 270 // Thus, if this is derived, we _cannot_ delete contained 271 // entities. Thus, we should not generate entity removal 272 // commands. 273 List priorEntities = entityList(); 274 Iterator priors = priorEntities.iterator(); 275 276 while (priors.hasNext()) { 277 ComponentEntity prior = (ComponentEntity) priors 278 .next(); 279 280 // If there is at least one more contained object, 281 // then delete this one. 282 // NOTE: How do we prevent the user from attempting to 283 // override the contained object in a subclass? 284 // It doesn't work to not remove this if the object 285 // is derived, because then derived objects won't 286 // track the prototype. 287 if (priors.hasNext()) { 288 prior.setContainer(null); 289 } else { 290 // The last entity in the entityList is 291 // the one that we just added. 292 entity = prior; 293 } 294 } 295 296 if (entity == null) { 297 // Nothing to do. 298 return; 299 } 300 301 Iterator entityPorts = entity.portList().iterator(); 302 303 while (entityPorts.hasNext()) { 304 ComponentPort insidePort = (ComponentPort) entityPorts 305 .next(); 306 // Use a strategy pattern here so that subclasses can control 307 // which ports are mirrored. 308 if (!_mirrorPort(insidePort)) { 309 continue; 310 } 311 String name = insidePort.getName(); 312 313 // The outside port may already exist (e.g. 314 // as a consequence of cloning). 315 IOPort newPort = (IOPort) getPort(name); 316 317 if (newPort == null) { 318 newPort = (IOPort) newPort(name); 319 } 320 321 if (insidePort instanceof IOPort) { 322 IOPort castPort = (IOPort) insidePort; 323 newPort.setMultiport(castPort.isMultiport()); 324 newPort.setInput(castPort.isInput()); 325 newPort.setOutput(castPort.isOutput()); 326 } 327 328 // Set up inside connections. 329 // Do this only if they are not already connected. 330 List connectedPorts = insidePort 331 .connectedPortList(); 332 333 if (!connectedPorts.contains(newPort)) { 334 ComponentRelation relation = newRelation( 335 uniqueName("relation")); 336 newPort.link(relation); 337 insidePort.link(relation); 338 } 339 } 340 } finally { 341 workspace().doneWriting(); 342 } 343 } 344 } 345 }; 346 347 requestChange(request); 348 } 349 350 /** Add a port to this actor. This overrides the base class to 351 * mirror the new port, only if it is an instance of MirrorPort 352 * in the contained actor, if there is one, 353 * and to establish a connection to a port on the contained actor. 354 * @param port The TypedIOPort to add to this actor. 355 * @exception IllegalActionException If the port is not an instance 356 * of IteratePort, or the port has no name. 357 * @exception NameDuplicationException If the port name collides with a 358 * name already in the actor. 359 */ 360 @Override 361 protected void _addPort(Port port) 362 throws IllegalActionException, NameDuplicationException { 363 364 super._addPort(port); 365 366 if ((port instanceof MirrorPort 367 || port instanceof ParameterMirrorPort)) { 368 // Create and connect a matching inside port on contained entities. 369 // Do this as a change request to ensure that the action of 370 // creating the port passed in as an argument is complete by 371 // the time this executes. Do not use MoML here because it 372 // isn't necessary to generate any undo code. _removePort() 373 // takes care of the undo. 374 final IOPort castPort = (IOPort) port; 375 376 ChangeRequest request = new ChangeRequest(this, 377 "Add a port on the inside") { 378 // Override this to indicate that the change is localized. 379 // This keeps the EntityTreeModel from closing open libraries 380 // when notified of this change. 381 @Override 382 public NamedObj getLocality() { 383 return ReflectComposite.this; 384 } 385 386 @Override 387 protected void _execute() throws Exception { 388 // NOTE: We defer the construction of the MoML 389 // change request to here because only at this 390 // point can we be sure that the change request 391 // that triggered this has completed. 392 synchronized (ReflectComposite.this) { 393 // Create and connect a matching inside port 394 // on contained entities. 395 // NOTE: We assume this propagates to derived 396 // objects because _addPort is called when 397 // MoML is parsed to add a port to 398 // MirrorComposite. Even the MirrorCompositeContents 399 // uses MoML to add this port, so this will 400 // result in propagation. 401 try { 402 workspace().getWriteAccess(); 403 _inAddPort = true; 404 405 String portName = castPort.getName(); 406 Iterator entities = entityList().iterator(); 407 408 if (entities.hasNext()) { 409 Entity insideEntity = (Entity) entities.next(); 410 Port insidePort = insideEntity 411 .getPort(portName); 412 413 if (insidePort == null) { 414 if (castPort instanceof MirrorPort) { 415 insidePort = insideEntity 416 .newPort(portName); 417 } else if (castPort instanceof ParameterMirrorPort) { // ParameterMirrorPort 418 insidePort = ((MirrorComposite) insideEntity) 419 .newParameterPort(portName); 420 } 421 422 if (insidePort instanceof IOPort) { 423 IOPort castInsidePort = (IOPort) insidePort; 424 castInsidePort 425 .setInput(castPort.isInput()); 426 castInsidePort 427 .setOutput(castPort.isOutput()); 428 castInsidePort.setMultiport( 429 castPort.isMultiport()); 430 } 431 } 432 433 if (insidePort == null) { 434 // FindBugs was reporting that insidePort could still be null. 435 throw new InternalErrorException( 436 ReflectComposite.this, null, 437 "insidePort is null? castPort " 438 + castPort 439 + " is neither a MirrorPort nor a ParameterMirrorPort?"); 440 } 441 442 if (insidePort instanceof MirrorPort) { 443 ((MirrorPort) castPort).setAssociatedPort( 444 (MirrorPort) insidePort); 445 } else if (insidePort instanceof ParameterMirrorPort) { // ParameterMirrorPort 446 ((ParameterMirrorPort) castPort) 447 .setAssociatedPort( 448 (ParameterMirrorPort) insidePort); 449 } 450 451 // Create a link only if it doesn't already exist. 452 List connectedPorts = insidePort 453 .connectedPortList(); 454 455 // Check if inside port is already connected to a port with that name. 456 // Skipping this step causes duplicate link attempts between castPort and insidePort 457 // in the case that _addPort() is called during clone(), in which CompositeEntity.clone() 458 // will already have created a link between the two ports. 459 460 Iterator connectedPortsIterator = connectedPorts 461 .iterator(); 462 boolean alreadyConnected = false; 463 while (connectedPortsIterator.hasNext()) { 464 Port cp = (Port) connectedPortsIterator 465 .next(); 466 if (cp.getName().equals(portName)) { 467 // do not connect 468 alreadyConnected = true; 469 } 470 } 471 if (!alreadyConnected) { 472 // There is no connection. Create one. 473 ComponentRelation newRelation = newRelation( 474 uniqueName("relation")); 475 insidePort.link(newRelation); 476 castPort.link(newRelation); 477 } 478 } 479 } finally { 480 workspace().doneWriting(); 481 _inAddPort = false; 482 } 483 } 484 } 485 }; 486 487 requestChange(request); 488 } 489 } 490 491 /** Override the base class to describe contained entities, 492 * attributes, and ports, but not inside links or relations. 493 * The rest of the contents are generated automatically when a 494 * contained entity is inserted. 495 * @param output The output to write to. 496 * @param depth The depth in the hierarchy, to determine indenting. 497 * @exception IOException If an I/O error occurs. 498 */ 499 @Override 500 protected void _exportMoMLContents(Writer output, int depth) 501 throws IOException { 502 Iterator attributes = attributeList().iterator(); 503 504 while (attributes.hasNext()) { 505 Attribute attribute = (Attribute) attributes.next(); 506 attribute.exportMoML(output, depth); 507 } 508 509 Iterator ports = portList().iterator(); 510 511 while (ports.hasNext()) { 512 Port port = (Port) ports.next(); 513 port.exportMoML(output, depth); 514 } 515 516 Iterator entities = entityList().iterator(); 517 518 while (entities.hasNext()) { 519 ComponentEntity entity = (ComponentEntity) entities.next(); 520 entity.exportMoML(output, depth); 521 } 522 } 523 524 /** Return true if the specified inside port should be mirrored. 525 * This base class returns true if the inside port is an instance 526 * of MirrorPort. 527 * @param insidePort The port that may be mirrored. 528 * @return True if the inside port should be mirrored. 529 */ 530 protected boolean _mirrorPort(ComponentPort insidePort) { 531 // do not mirror ports that are not instances of MirrorPort 532 if (insidePort instanceof MirrorPort) { 533 return true; 534 } 535 return false; 536 } 537 538 /** Override the base class to remove the ports and inside relations 539 * of this actor. This method assumes the caller has write access 540 * on the workspace. 541 * @param entity The entity being removed from this entity. 542 */ 543 @Override 544 protected void _removeEntity(ComponentEntity entity) { 545 super._removeEntity(entity); 546 547 // Remove all inside relations. This will have the 548 // side effect of removing connections on the inside. 549 Iterator relations = relationList().iterator(); 550 551 while (relations.hasNext()) { 552 try { 553 ((ComponentRelation) relations.next()).setContainer(null); 554 } catch (KernelException e) { 555 throw new InternalErrorException(e); 556 } 557 } 558 559 // Have to copy the list to avoid a concurrent 560 // modification exception. 561 Iterator ports = new LinkedList(portList()).iterator(); 562 563 while (ports.hasNext()) { 564 Port port = (Port) ports.next(); 565 566 try { 567 _inRemoveEntity = true; 568 port.setContainer(null); 569 } catch (KernelException e) { 570 throw new InternalErrorException(e); 571 } finally { 572 _inRemoveEntity = false; 573 } 574 } 575 } 576 577 /** Override the base class to remove the associated port on the 578 * inside entity and the link to it, if there is one. 579 * This method assumes the caller has write access on the 580 * workspace. 581 * @param port The port being removed from this entity. 582 */ 583 @Override 584 protected void _removePort(final Port port) { 585 super._removePort(port); 586 587 // NOTE: Do not use MoML here because we do not want to generate 588 // undo actions to recreate the inside relation and port. 589 // This is because _addPort() will take care of that. 590 // The cast is safe because all my ports are instances of IOPort. 591 Iterator relations = ((IOPort) port).insideRelationList().iterator(); 592 593 while (relations.hasNext()) { 594 ComponentRelation relation = (ComponentRelation) relations.next(); 595 596 try { 597 relation.setContainer(null); 598 } catch (KernelException ex) { 599 throw new InternalErrorException(ex); 600 } 601 } 602 603 // Remove the ports from the inside entity only if this 604 // is not being called as a side effect of calling _removeEntity(). 605 if (_inRemoveEntity) { 606 return; 607 } 608 609 Iterator entities = entityList().iterator(); 610 611 while (entities.hasNext()) { 612 Entity insideEntity = (Entity) entities.next(); 613 Port insidePort = insideEntity.getPort(port.getName()); 614 615 if (insidePort != null) { 616 try { 617 insidePort.setContainer(null); 618 } catch (KernelException ex) { 619 throw new InternalErrorException(ex); 620 } 621 } 622 } 623 } 624 625 /////////////////////////////////////////////////////////////////// 626 //// private variables //// 627 628 /** Flag indicating that we are executing _addPort(). */ 629 protected boolean _inAddPort = false; 630 631 /** Flag indicating that we are executing _removeEntity(). */ 632 protected boolean _inRemoveEntity = false; 633 634 /** Flag indicating whether to mirror instances of ParameterPort. */ 635 protected boolean _mirrorParameterPorts = true; 636 637 /////////////////////////////////////////////////////////////////// 638 //// private methods //// 639 640 /** Initialize the class. 641 * @param mirrorParameterPorts If true, then mirror instances of ParameterPort. 642 */ 643 private void _init(boolean mirrorParameterPorts) { 644 setClassName("ptolemy.actor.lib.hoc.ReflectComposite"); 645 _attachText("_iconDescription", 646 "<svg>\n" + "<rect x=\"-30\" y=\"-20\" " 647 + "width=\"60\" height=\"40\" " 648 + "style=\"fill:white\"/>\n" + "<text x=\"-6\" y=\"10\"" 649 + "style=\"font-size:24\">?</text>\n" + "</svg>\n"); 650 _mirrorParameterPorts = mirrorParameterPorts; 651 } 652 653 /////////////////////////////////////////////////////////////////// 654 //// inner classes //// 655 656 /////////////////////////////////////////////////////////////////// 657 //// ReflectCompositeContents 658 659 /** This is a specialized composite actor for use in ReflectComposite. 660 * In particular, it ensures that if ports are added or deleted 661 * locally, then corresponding ports will be added or deleted 662 * in the container. That addition will result in appropriate 663 * connections being made. 664 */ 665 public static class ReflectCompositeContents extends TypedCompositeActor { 666 // NOTE: This has to be a static class so that MoML can 667 // instantiate it. 668 669 /** Construct an actor with a name and a container. 670 * @param container The container. 671 * @param name The name of this actor. 672 * @exception IllegalActionException If the container is incompatible 673 * with this actor. 674 * @exception NameDuplicationException If the name coincides with 675 * an actor already in the container. 676 */ 677 public ReflectCompositeContents(CompositeEntity container, String name) 678 throws IllegalActionException, NameDuplicationException { 679 super(container, name); 680 } 681 682 /** Override the base class to return a specialized port. 683 * @param name The name of the port to create. 684 * @return A new instance of MirrorPort. 685 * @exception NameDuplicationException If the container already has 686 * a port with this name. 687 */ 688 @Override 689 public Port newPort(String name) throws NameDuplicationException { 690 try { 691 return new MirrorPort(this, name); 692 } catch (IllegalActionException ex) { 693 // This exception should not occur, so we throw a runtime 694 // exception. 695 throw new InternalErrorException(this, ex, null); 696 } 697 } 698 699 /** Add a port to this actor. This overrides the base class to 700 * add a corresponding port to the container using a change 701 * request, if the port is an instance of MirrorPort and 702 * does not already exist. 703 * @param port The TypedIOPort to add to this actor. 704 * @exception IllegalActionException If the port is not an instance of 705 * MirrorPort, or the port has no name. 706 * @exception NameDuplicationException If the port name 707 * collides with a name already in the actor. 708 */ 709 @Override 710 protected void _addPort(final Port port) 711 throws IllegalActionException, NameDuplicationException { 712 713 super._addPort(port); 714 715 if ((port instanceof MirrorPort 716 || port instanceof ParameterMirrorPort)) { 717 718 final ReflectComposite container = (ReflectComposite) getContainer(); 719 720 if (container._inAddPort) { 721 return; 722 } 723 724 // Use a change request so we can be sure the port 725 // being added is fully constructed. 726 ChangeRequest request = new ChangeRequest(this, 727 "Add mirror port to the container.") { 728 // Override this to indicate that the change is localized. 729 // This keeps the EntityTreeModel from closing open libraries 730 // when notified of this change. 731 @Override 732 public NamedObj getLocality() { 733 return getContainer(); 734 } 735 736 @Override 737 protected void _execute() throws Exception { 738 try { 739 workspace().getWriteAccess(); 740 741 if (port instanceof ParameterMirrorPort) { 742 ParameterMirrorPort newPort = (ParameterMirrorPort) container 743 .getPort(port.getName()); 744 745 if (newPort == null) { 746 newPort = (ParameterMirrorPort) container 747 .newParameterPort(port.getName()); 748 } 749 } else { // MirrorPort 750 MirrorPort newPort = (MirrorPort) container 751 .getPort(port.getName()); 752 753 if (newPort == null) { 754 newPort = (MirrorPort) container 755 .newPort(port.getName()); 756 } 757 758 if (port instanceof IOPort) { 759 newPort.setInput(((IOPort) port).isInput()); 760 newPort.setOutput( 761 ((IOPort) port).isOutput()); 762 newPort.setMultiport( 763 ((IOPort) port).isMultiport()); 764 } 765 } 766 } finally { 767 workspace().doneWriting(); 768 } 769 } 770 }; 771 container.requestChange(request); 772 } 773 } 774 } 775}