001/* A ComponentEntity is a vertex in a clustered graph. 002 003 Copyright (c) 1997-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.kernel; 029 030import java.lang.ref.WeakReference; 031import java.util.Iterator; 032import java.util.List; 033 034import ptolemy.kernel.util.ChangeRequest; 035import ptolemy.kernel.util.IllegalActionException; 036import ptolemy.kernel.util.Instantiable; 037import ptolemy.kernel.util.InternalErrorException; 038import ptolemy.kernel.util.NameDuplicationException; 039import ptolemy.kernel.util.NamedObj; 040import ptolemy.kernel.util.Workspace; 041 042/////////////////////////////////////////////////////////////////// 043//// ComponentEntity 044 045/** 046 A ComponentEntity is a component in a CompositeEntity. 047 It might itself be composite, but in this base class it is assumed to 048 be atomic (meaning that it cannot contain components). 049 <p> 050 Derived classes may further constrain the container to be 051 a subclass of CompositeEntity. To do this, they should override 052 the protected method _checkContainer() to throw an exception. 053 <p> 054 A ComponentEntity can contain instances of ComponentPort. Derived 055 classes may further constrain to a subclass of ComponentPort. 056 To do this, they should override the public method newPort() to create 057 a port of the appropriate subclass, and the protected method _addPort() 058 to throw an exception if its argument is a port that is not of the 059 appropriate subclass. 060 061 @author John S. Davis II, Edward A. Lee 062 @version $Id$ 063 @since Ptolemy II 0.2 064 @Pt.ProposedRating Green (eal) 065 @Pt.AcceptedRating Green (cxh) 066 */ 067public class ComponentEntity<T extends ComponentPort> extends Entity<T> { 068 /** Construct an entity in the default workspace with an empty string 069 * The object is added to the workspace directory. 070 * as its name. Increment the version number of the workspace. 071 */ 072 public ComponentEntity() { 073 super(); 074 _addIcon(); 075 } 076 077 /** Construct an entity in the specified workspace with an empty 078 * string as a name. You can then change the name with setName(). 079 * If the workspace argument is null, then use the default workspace. 080 * The object is added to the workspace directory. 081 * Increment the version number of the workspace. 082 * @param workspace The workspace that will list the entity. 083 */ 084 public ComponentEntity(Workspace workspace) { 085 super(workspace); 086 _addIcon(); 087 } 088 089 /** Construct an entity with the given name contained by the specified 090 * entity. The container argument must not be null, or a 091 * NullPointerException will be thrown. This entity will use the 092 * workspace of the container for synchronization and version counts. 093 * If the name argument is null, then the name is set to the empty string. 094 * Increment the version of the workspace. 095 * This constructor write-synchronizes on the workspace. 096 * @param container The container entity. 097 * @param name The name of the entity. 098 * @exception IllegalActionException If the entity cannot be contained 099 * by the proposed container. 100 * @exception NameDuplicationException If the name coincides with 101 * an entity already in the container. 102 */ 103 public ComponentEntity(CompositeEntity container, String name) 104 throws IllegalActionException, NameDuplicationException { 105 super(container.workspace(), name); 106 setContainer(container); 107 _addIcon(); 108 } 109 110 /////////////////////////////////////////////////////////////////// 111 //// public methods //// 112 113 /** Clone the object into the specified workspace. The new object is 114 * <i>not</i> added to the directory of that workspace (you must do this 115 * yourself if you want it there). 116 * The result is a new component entity that defers its definition to the 117 * same object as this one (or to none) that has no container. 118 * @param workspace The workspace for the cloned object. 119 * @exception CloneNotSupportedException If one of the attributes 120 * cannot be cloned. 121 * @return A new instance of ComponentEntity. 122 */ 123 @Override 124 public Object clone(Workspace workspace) throws CloneNotSupportedException { 125 ComponentEntity newObject = (ComponentEntity) super.clone(workspace); 126 newObject._container = null; 127 return newObject; 128 } 129 130 /** Get the container entity. 131 * @return The container, which is an instance of CompositeEntity. 132 * @see #setContainer(CompositeEntity) 133 */ 134 @Override 135 public NamedObj getContainer() { 136 return _container; 137 } 138 139 /** Create an instance by cloning this object and then adjusting 140 * the parent-child relationships between the clone and its parent. 141 * Specifically, the clone defers its definition to this object, 142 * which becomes its "parent." It inherits all the objects contained 143 * by this object. If this object is a composite, then this method 144 * adjusts any deferral relationships that are entirely contained 145 * within the clone. That is, for any parent-child relationship that 146 * is entirely contained within this object (i.e., both the parent 147 * and the child are deeply contained by this object), a corresponding 148 * parent-child relationship is created within the clone such that 149 * both the parent and the child are entirely contained within 150 * the clone. 151 * <p> 152 * The new object is not a class definition (it is by default an 153 * "instance" rather than a "class"). To make it a class 154 * definition (a "subclass"), call setClassDefinition(true). 155 * <p> 156 * This method overrides the base class to use setContainer() to 157 * specify the container. 158 * @see #setClassDefinition(boolean) 159 * @param container The container for the instance, or null 160 * to instantiate it at the top level. 161 * @param name The name for the clone. 162 * @return A new instance that is a clone of this object 163 * with adjusted deferral relationships. 164 * @exception CloneNotSupportedException If this object 165 * cannot be cloned. 166 * @exception IllegalActionException If this object is not a 167 * class definition 168 * or the proposed container is not acceptable. 169 * @exception NameDuplicationException If the name collides with 170 * an object already in the container. 171 */ 172 @Override 173 public Instantiable instantiate(NamedObj container, String name) 174 throws CloneNotSupportedException, IllegalActionException, 175 NameDuplicationException { 176 if (container != null && !(container instanceof CompositeEntity)) { 177 throw new IllegalActionException(this, 178 "Cannot instantiate into a container that is not an " 179 + "instance of CompositeEntity: " 180 + container.getFullName()); 181 } 182 183 ComponentEntity clone = (ComponentEntity) super.instantiate(container, 184 name); 185 // Derived classes like this one are responsible for setting the container. 186 clone.setContainer((CompositeEntity) container); 187 188 clone._adjustDeferrals(); 189 190 // Now that there is a new parent-child relationship, 191 // we need to propagate values from the parent to the child. 192 // Note that this isn't needed to get the 193 // right values, since the child has been cloned 194 // from the parent. However, this will set the override 195 // levels appropriately in the child. 196 // NOTE: This could be done by calling propagateValues(), 197 // but that would be extremely inefficient since it would 198 // propagate to all previously instantiated instances as 199 // well as to the one new clone. 200 clone._adjustOverride(0); 201 202 return clone; 203 } 204 205 /** Return true if the entity is atomic. 206 * An atomic entity is one that cannot have components. 207 * Instances of this base class are always atomic. 208 * Derived classes that return false are assumed to be instances of 209 * CompositeEntity or a class derived from that. 210 * @return True if the entity is atomic. 211 * @see ptolemy.kernel.CompositeEntity 212 */ 213 public boolean isAtomic() { 214 return true; 215 } 216 217 /** Return true if the entity is opaque. 218 * An opaque entity is one that either is atomic or hides 219 * its components behind opaque ports. 220 * Instances of this base class are always opaque. 221 * Derived classes may be transparent, in which case they return false 222 * to this method and to isAtomic(). 223 * @return True if the entity is opaque. 224 * @see ptolemy.kernel.CompositeEntity 225 */ 226 public boolean isOpaque() { 227 return true; 228 } 229 230 /** Move this object down by one in the list of entities of 231 * its container. If this object is already last, do nothing. 232 * Increment the version of the workspace. 233 * @return The index of the specified object prior to moving it, 234 * or -1 if it is not moved. 235 * @exception IllegalActionException If this object has 236 * no container. 237 */ 238 @Override 239 public int moveDown() throws IllegalActionException { 240 CompositeEntity container = (CompositeEntity) getContainer(); 241 242 if (container == null) { 243 throw new IllegalActionException(this, "Has no container."); 244 } 245 246 try { 247 _workspace.getWriteAccess(); 248 249 int result = container._containedEntities.moveDown(this); 250 251 // Propagate. 252 Iterator derivedObjects = getDerivedList().iterator(); 253 254 while (derivedObjects.hasNext()) { 255 NamedObj derived = (NamedObj) derivedObjects.next(); 256 container = (CompositeEntity) derived.getContainer(); 257 container._containedEntities.moveDown(derived); 258 } 259 260 return result; 261 } finally { 262 _workspace.doneWriting(); 263 } 264 } 265 266 /** Move this object to the first position in the list 267 * of entities of the container. If this object is already first, 268 * do nothing. Increment the version of the workspace. 269 * @return The index of the specified object prior to moving it, 270 * or -1 if it is not moved. 271 * @exception IllegalActionException If this object has 272 * no container. 273 */ 274 @Override 275 public int moveToFirst() throws IllegalActionException { 276 CompositeEntity container = (CompositeEntity) getContainer(); 277 278 if (container == null) { 279 throw new IllegalActionException(this, "Has no container."); 280 } 281 282 try { 283 _workspace.getWriteAccess(); 284 285 int result = container._containedEntities.moveToFirst(this); 286 287 // Propagate. 288 Iterator derivedObjects = getDerivedList().iterator(); 289 290 while (derivedObjects.hasNext()) { 291 NamedObj derived = (NamedObj) derivedObjects.next(); 292 container = (CompositeEntity) derived.getContainer(); 293 container._containedEntities.moveToFirst(derived); 294 } 295 296 return result; 297 } finally { 298 _workspace.doneWriting(); 299 } 300 } 301 302 /** Move this object to the specified position in the list 303 * of entities of the container. If this object is already at 304 * the specified position, do nothing. Increment the version 305 * of the workspace. 306 * @param index The position to move this object to. 307 * @return The index of the specified object prior to moving it, 308 * or -1 if it is not moved. 309 * @exception IllegalActionException If this object has 310 * no container or if the index is out of bounds. 311 */ 312 @Override 313 public int moveToIndex(int index) throws IllegalActionException { 314 CompositeEntity container = (CompositeEntity) getContainer(); 315 316 if (container == null) { 317 throw new IllegalActionException(this, "Has no container."); 318 } 319 320 try { 321 _workspace.getWriteAccess(); 322 323 int result = container._containedEntities.moveToIndex(this, index); 324 325 // Propagate. 326 Iterator derivedObjects = getDerivedList().iterator(); 327 328 while (derivedObjects.hasNext()) { 329 NamedObj derived = (NamedObj) derivedObjects.next(); 330 container = (CompositeEntity) derived.getContainer(); 331 container._containedEntities.moveToIndex(derived, index); 332 } 333 334 return result; 335 } finally { 336 _workspace.doneWriting(); 337 } 338 } 339 340 /** Move this object to the last position in the list 341 * of entities of the container. If this object is already last, 342 * do nothing. 343 * Increment the version of the workspace. 344 * @return The index of the specified object prior to moving it, 345 * or -1 if it is not moved. 346 * @exception IllegalActionException If this object has 347 * no container. 348 */ 349 @Override 350 public int moveToLast() throws IllegalActionException { 351 CompositeEntity container = (CompositeEntity) getContainer(); 352 353 if (container == null) { 354 throw new IllegalActionException(this, "Has no container."); 355 } 356 357 try { 358 _workspace.getWriteAccess(); 359 360 int result = container._containedEntities.moveToLast(this); 361 362 // Propagate. 363 Iterator derivedObjects = getDerivedList().iterator(); 364 365 while (derivedObjects.hasNext()) { 366 NamedObj derived = (NamedObj) derivedObjects.next(); 367 container = (CompositeEntity) derived.getContainer(); 368 container._containedEntities.moveToLast(derived); 369 } 370 371 return result; 372 } finally { 373 _workspace.doneWriting(); 374 } 375 } 376 377 /** Move this object up by one in the list of 378 * entities of the container. If this object is already first, do 379 * nothing. Increment the version of the workspace. 380 * @return The index of the specified object prior to moving it, 381 * or -1 if it is not moved. 382 * @exception IllegalActionException If this object has 383 * no container. 384 */ 385 @Override 386 public int moveUp() throws IllegalActionException { 387 CompositeEntity container = (CompositeEntity) getContainer(); 388 389 if (container == null) { 390 throw new IllegalActionException(this, "Has no container."); 391 } 392 393 try { 394 _workspace.getWriteAccess(); 395 396 int result = container._containedEntities.moveUp(this); 397 398 // Propagate. 399 Iterator derivedObjects = getDerivedList().iterator(); 400 401 while (derivedObjects.hasNext()) { 402 NamedObj derived = (NamedObj) derivedObjects.next(); 403 container = (CompositeEntity) derived.getContainer(); 404 container._containedEntities.moveUp(derived); 405 } 406 407 return result; 408 } finally { 409 _workspace.doneWriting(); 410 } 411 } 412 413 /** Create a new port with the specified name. 414 * The container of the port is set to this entity. 415 * This overrides the base class to create an instance of ComponentPort. 416 * Derived classes may override this to further constrain the ports. 417 * This method is write-synchronized on the workspace and increments 418 * its version number. 419 * @param name The new port name. 420 * @return The new port 421 * @exception IllegalActionException If the argument is null. 422 * @exception NameDuplicationException If this entity already has a 423 * port with the specified name. 424 */ 425 @Override 426 public Port newPort(String name) 427 throws IllegalActionException, NameDuplicationException { 428 try { 429 _workspace.getWriteAccess(); 430 431 Port port = new ComponentPort(this, name); 432 return port; 433 } finally { 434 _workspace.doneWriting(); 435 } 436 } 437 438 /** Propagate the existence of this object. 439 * If this object has a container, then ensure that all 440 * objects derived from the container contain an object 441 * with the same class and name as this one. Create that 442 * object when needed. Return the list of objects that are created. 443 * This overrides the base class to adjust deferrals within 444 * the objects that are created by cloning this one. 445 * @return A list of derived objects of the same class 446 * as this object that are created. 447 * @exception IllegalActionException If the object does 448 * not exists and cannot be created. 449 */ 450 @Override 451 public List propagateExistence() throws IllegalActionException { 452 // Otherwise, _override probably doesn't get set in the 453 // derived object that is created. 454 List result = super.propagateExistence(); 455 456 // Adjust deferrals in all the newly created objects. 457 Iterator clones = result.iterator(); 458 459 while (clones.hasNext()) { 460 ComponentEntity clone = (ComponentEntity) clones.next(); 461 clone._adjustDeferrals(); 462 } 463 464 return result; 465 } 466 467 /** Specify the container, adding the entity to the list 468 * of entities in the container. If the container already contains 469 * an entity with the same name, then throw an exception and do not make 470 * any changes. Similarly, if the container is not in the same 471 * workspace as this entity, throw an exception. If this entity is 472 * a class element and the proposed container does not match 473 * the current container, then also throw an exception. 474 * If the entity is already contained by the container, do nothing. 475 * If this entity already has a container, remove it 476 * from that container first. Otherwise, remove it from 477 * the directory of the workspace, if it is present. 478 * If the argument is null, then unlink the ports of the entity 479 * from any relations and remove it from its container. 480 * It is not added to the workspace directory, so this could result in 481 * this entity being garbage collected. 482 * <p>Note that for entities that are created by parsing MoML, 483 * it may be necessary to call MoMLParser.purgeModelRecord(). 484 * This is especially critical when the MoML file imports 485 * MoML classes. See Effigy.setContainer() for details. 486 * 487 * <p>Derived classes may further constrain the container 488 * to subclasses of CompositeEntity by overriding the protected 489 * method _checkContainer(). This method validates all 490 * deeply contained instances of Settable, since they may no longer 491 * be valid in the new context. This method is write-synchronized 492 * to the workspace and increments its version number. 493 * @param container The proposed container. 494 * @exception IllegalActionException If the action would result in a 495 * recursive containment structure, or if 496 * this entity and container are not in the same workspace, or 497 * if the protected method _checkContainer() throws it, or if 498 * a contained Settable becomes invalid and the error handler 499 * throws it. 500 * @exception NameDuplicationException If the name of this entity 501 * collides with a name already in the container. 502 * @see #getContainer() 503 */ 504 public void setContainer(CompositeEntity container) 505 throws IllegalActionException, NameDuplicationException { 506 if (container != null && _workspace != container.workspace()) { 507 throw new IllegalActionException(this, container, 508 "Cannot set container because workspaces are different."); 509 } 510 511 CompositeEntity previousContainer = (CompositeEntity) getContainer(); 512 513 if (previousContainer == container) { 514 return; 515 } 516 517 _notifyHierarchyListenersBeforeChange(); 518 519 try { 520 _workspace.getWriteAccess(); 521 _checkContainer(container); 522 523 // NOTE: The following code is quite tricky. It is very careful 524 // to leave a consistent state even in the face of unexpected 525 // exceptions. Be very careful if modifying it. 526 527 // Do this first, because it may throw an exception, and we have 528 // not yet changed any state. 529 if (container != null) { 530 // checkContainer() above ensures that this cast is valid. 531 container._addEntity(this); 532 533 if (previousContainer == null) { 534 _workspace.remove(this); 535 } 536 } 537 538 _container = container; 539 540 if (previousContainer != null) { 541 // This is safe now because it does not throw an exception. 542 previousContainer._removeEntity(this); 543 } 544 545 if (container == null) { 546 Iterator ports = portList().iterator(); 547 548 while (ports.hasNext()) { 549 Port port = (Port) ports.next(); 550 port.unlinkAll(); 551 } 552 553 // Since the new container is null, this object is being 554 // deleted. Break deferral references that it may have. 555 _setParent(null); 556 } else { 557 // checkContainer() above ensures that this cast is valid. 558 container._finishedAddEntity(this); 559 560 // Transfer any queued change requests to the 561 // new container. There could be queued change 562 // requests if this component is deferring change 563 // requests. 564 if (_changeRequests != null) { 565 Iterator requests = _changeRequests.iterator(); 566 567 while (requests.hasNext()) { 568 ChangeRequest request = (ChangeRequest) requests.next(); 569 container.requestChange(request); 570 } 571 572 _changeRequests = null; 573 } 574 } 575 576 // Validate all deeply contained settables, since 577 // they may no longer be valid in the new context. 578 // Optimization: During construction, the previous 579 // container will be null. It doesn't make sense 580 // to validate at this point, since there shouldn't 581 // actually be any contained settables. Moreover, 582 // if the container is being set to null, then the 583 // component is being discarded. It shouldn't be 584 // necessary to validate settables at this point 585 // since all dependents should be within this 586 // scope. EAL 9/6/06 587 if (previousContainer != null && container != null) { 588 // NOTE: This somehow prevents CompositeEntity.validateSettables 589 // from ever being called when a model is loaded. 590 validateSettables(); 591 } 592 } finally { 593 try { 594 // Since we definitely notified the listeners 595 // before the change, we must definitely notify 596 // them after the change, even if the change caused 597 // some exceptions. Note that this too may trigger 598 // exceptions. 599 _notifyHierarchyListenersAfterChange(); 600 } finally { 601 _workspace.doneWriting(); 602 } 603 } 604 } 605 606 /** Set the name of the ComponentEntity. If there is already 607 * a ComponentEntity of the container with the same name, throw an 608 * exception. 609 * @exception IllegalActionException If the name has a period. 610 * @exception NameDuplicationException If there already is an entity 611 * in the container with the same name. 612 */ 613 @Override 614 public void setName(String name) 615 throws IllegalActionException, NameDuplicationException { 616 if (name == null) { 617 name = ""; 618 } 619 620 CompositeEntity container = (CompositeEntity) getContainer(); 621 622 if (container != null) { 623 ComponentEntity another = container.getEntity(name); 624 625 if (another != null && another != this) { 626 throw new NameDuplicationException(container, 627 "Name duplication: " + name); 628 } 629 } 630 631 super.setName(name); 632 } 633 634 /////////////////////////////////////////////////////////////////// 635 //// protected methods //// 636 637 /** Adjust the deferrals in this object. This method should 638 * be called on any newly created object that is created by 639 * cloning. While cloning, parent relations are set to null. 640 * That is, no object in the clone has a parent. This method 641 * identifies the correct parent for any object in the clone. 642 * To do this, it uses the class name. Specifically, if this 643 * object has a class name that refers to a class in scope, 644 * then it replaces the current parent with that object. 645 * To look for a class in scope, we go up the hierarchy, but 646 * no more times than the return value of getDerivedLevel(). 647 * The reason for this is that if the class from which this 648 * object is defined is above that level, then we do not want 649 * to establish a parent relationship with that class. This 650 * object is implied, and the parent relationship of the object 651 * from which it is implied is sufficient. 652 * <p> 653 * Derived classes that contain other objects should recursively 654 * call this method on contained objects. 655 * @exception IllegalActionException If the class found in scope 656 * cannot be set. 657 */ 658 protected void _adjustDeferrals() throws IllegalActionException { 659 // Use the class name. 660 String className = getClassName(); 661 662 // Search upwards in the hierarchy. 663 NamedObj context = this; 664 int levelsToSearch = getDerivedLevel(); 665 int aboveLevel = 0; 666 ComponentEntity candidate = null; 667 668 // Make sure we get a real candidate, which is a 669 // class definition. The second term in the if will 670 // cause the search to continue up the hierarchy. 671 // NOTE: There is still an oddness, in that 672 // the class scoping results in a subtle (and 673 // maybe incomprehensible) identification of 674 // the base class, particularly when pasting 675 // an instance or subclass into a new context. 676 while (aboveLevel < levelsToSearch 677 && (candidate == null || !candidate.isClassDefinition()) 678 && context != null) { 679 context = context.getContainer(); 680 681 if (context instanceof CompositeEntity) { 682 candidate = ((CompositeEntity) context).getEntity(className); 683 } 684 685 aboveLevel += 1; 686 } 687 688 if (candidate != null) { 689 _setParent(candidate); 690 _markContentsDerived(0); 691 692 // For every object contained by the new parent, 693 // we need to make sure its value is propagated 694 // to this new child and that the override field 695 // gets set to reflect that. 696 candidate.propagateValues(); 697 } 698 } 699 700 /** Check the specified container. 701 * @param container The proposed container. 702 * @exception IllegalActionException If the container is not an 703 * instance of CompositeEntity, or if the proposed container is 704 * null and there are other objects that defer their definitions 705 * to this one. 706 */ 707 protected void _checkContainer(InstantiableNamedObj container) 708 throws IllegalActionException { 709 if (container != null && !(container instanceof CompositeEntity)) { 710 throw new IllegalActionException(this, container, 711 "Component entity can only be contained by " 712 + "a CompositeEntity"); 713 } 714 715 // NOTE: If we don't enforce this, then undo could fail, 716 // since deletions occur in the opposite order of the re-additions 717 // in undo. So being silent about this error will not do. 718 if (container == null) { 719 // If the class has objects that defer to it, then 720 // refuse to delete. 721 boolean hasDeferrals = false; 722 List deferred = getChildren(); 723 StringBuffer names = new StringBuffer(); 724 725 if (deferred != null) { 726 // List contains weak references, so it's not 727 // sufficient to just check the length. 728 Iterator deferrers = deferred.iterator(); 729 730 while (deferrers.hasNext()) { 731 WeakReference deferrer = (WeakReference) deferrers.next(); 732 NamedObj deferrerObject = (NamedObj) deferrer.get(); 733 734 if (deferrerObject != null) { 735 hasDeferrals = true; 736 737 if (names.length() > 0) { 738 names.append(", "); 739 } 740 741 names.append(deferrerObject.getFullName()); 742 } 743 } 744 } 745 746 if (hasDeferrals) { 747 throw new IllegalActionException(this, 748 "Cannot delete because " 749 + "there are instances and/or subclasses:\n" 750 + names.toString()); 751 } 752 } 753 } 754 755 /** Get an entity with the specified name in the specified container. 756 * The returned object is assured of being an 757 * instance of the same class as this object. 758 * @param relativeName The name relative to the container. 759 * @param container The container expected to contain the object, which 760 * must be an instance of CompositeEntity. 761 * @return An object of the same class as this object, or null if there 762 * is none. 763 * @exception IllegalActionException If the object exists 764 * and has the wrong class, or if the specified container is not 765 * an instance of CompositeEntity. 766 */ 767 @Override 768 protected NamedObj _getContainedObject(NamedObj container, 769 String relativeName) throws IllegalActionException { 770 if (!(container instanceof CompositeEntity)) { 771 throw new IllegalActionException(this, "Expected " 772 + container.getFullName() 773 + " to be an instance of ptolemy.kernel.CompositeEntity," 774 + " but it is " + container.getClass().getName()); 775 } 776 777 ComponentEntity candidate = ((CompositeEntity) container) 778 .getEntity(relativeName); 779 780 if (candidate != null && !getClass().isInstance(candidate)) { 781 throw new IllegalActionException(this, 782 "Expected " + candidate.getFullName() 783 + " to be an instance of " + getClass().getName() 784 + ", but it is " + candidate.getClass().getName()); 785 } 786 787 return candidate; 788 } 789 790 /** Propagate existence of this object to the 791 * specified object. This overrides the base class 792 * to set the container. 793 * @param container Object to contain the new object. 794 * @exception IllegalActionException If the object 795 * cannot be cloned. 796 * @return A new object of the same class and name 797 * as this one. 798 */ 799 @Override 800 protected NamedObj _propagateExistence(NamedObj container) 801 throws IllegalActionException { 802 try { 803 ComponentEntity newObject = (ComponentEntity) super._propagateExistence( 804 container); 805 // FindBugs warns that the cast of container is 806 // unchecked. 807 if (!(container instanceof CompositeEntity)) { 808 throw new InternalErrorException( 809 container + " is not a CompositeEntity."); 810 } else { 811 newObject.setContainer((CompositeEntity) container); 812 } 813 return newObject; 814 } catch (NameDuplicationException e) { 815 throw new InternalErrorException(e); 816 } 817 } 818 819 /////////////////////////////////////////////////////////////////// 820 //// private methods //// 821 822 /** Define the icon. */ 823 private void _addIcon() { 824 _attachText("_iconDescription", _defaultIcon); 825 } 826 827 /////////////////////////////////////////////////////////////////// 828 //// private variables //// 829 830 /** The container. */ 831 private CompositeEntity _container; 832 833 /** The default value icon. This is static so that we avoid doing 834 * string concatenation each time we construct this object. 835 */ 836 private static String _defaultIcon = "<svg>\n" 837 + "<rect x=\"-30\" y=\"-20\" width=\"60\" " 838 + "height=\"40\" style=\"fill:white\"/>\n" 839 + "<polygon points=\"-20,-10 20,0 -20,10\" " 840 + "style=\"fill:blue\"/>\n" + "</svg>\n"; 841}