001/* An IOPort for multi composite actors. 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 java.util.Iterator; 031 032import ptolemy.actor.TypedIOPort; 033import ptolemy.kernel.ComponentEntity; 034import ptolemy.kernel.ComponentRelation; 035import ptolemy.kernel.Entity; 036import ptolemy.kernel.Port; 037import ptolemy.kernel.Relation; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.NameDuplicationException; 040import ptolemy.kernel.util.Workspace; 041 042/////////////////////////////////////////////////////////////////// 043//// MultiCompositePort 044 045/** 046 A port for multi-composite actors. This port mirrors certain changes to it in 047 the ports of the controller and refinements of the modal model. It is 048 designed to work closely with RefinementPort, since changes to the 049 ports can be initiated in either class. 050 051 @see RefinementPort 052 @see MultiCompositeActor 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 MultiCompositePort 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 MultiCompositePort(Workspace workspace) 067 throws IllegalActionException { 068 super(workspace); 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 MultiCompositePort(ComponentEntity container, String name) 084 throws IllegalActionException, NameDuplicationException { 085 super(container, name); 086 } 087 088 /////////////////////////////////////////////////////////////////// 089 //// public methods //// 090 091 /** Move this object down by one in the list of attributes of 092 * its container. If this object is already last, do nothing. 093 * This method overrides the base class to mirror the change 094 * in any mirror ports. 095 * Increment the version of the workspace. 096 * @return The index of the specified object prior to moving it, 097 * or -1 if it is not moved. 098 * @exception IllegalActionException If this object has 099 * no container. 100 */ 101 @Override 102 public int moveDown() throws IllegalActionException { 103 try { 104 _workspace.getWriteAccess(); 105 106 int result = super.moveDown(); 107 108 if (result != -1) { 109 // Mirror the change in mirror ports. 110 MultiCompositeActor container = (MultiCompositeActor) getContainer(); 111 Iterator entities = container.entityList().iterator(); 112 113 while (entities.hasNext()) { 114 Entity entity = (Entity) entities.next(); 115 Port mirrorPort = entity.getPort(getName()); 116 117 if (mirrorPort instanceof RefinementPort) { 118 RefinementPort castPort = (RefinementPort) mirrorPort; 119 boolean disableStatus = castPort._mirrorDisable; 120 121 try { 122 castPort._mirrorDisable = true; 123 castPort.moveDown(); 124 } finally { 125 castPort._mirrorDisable = disableStatus; 126 } 127 } 128 } 129 } 130 131 return result; 132 } finally { 133 _workspace.doneWriting(); 134 } 135 } 136 137 /** Move this object to the first position in the list 138 * of attributes of the container. If this object is already first, 139 * do nothing. Increment the version of the workspace. 140 * This method overrides the base class to mirror the change 141 * in any mirror ports. 142 * @return The index of the specified object prior to moving it, 143 * or -1 if it is not moved. 144 * @exception IllegalActionException If this object has 145 * no container. 146 */ 147 @Override 148 public int moveToFirst() throws IllegalActionException { 149 try { 150 _workspace.getWriteAccess(); 151 152 int result = super.moveToFirst(); 153 154 if (result != -1) { 155 // Mirror the change in mirror ports. 156 MultiCompositeActor container = (MultiCompositeActor) getContainer(); 157 Iterator entities = container.entityList().iterator(); 158 159 while (entities.hasNext()) { 160 Entity entity = (Entity) entities.next(); 161 Port mirrorPort = entity.getPort(getName()); 162 163 if (mirrorPort instanceof RefinementPort) { 164 RefinementPort castPort = (RefinementPort) mirrorPort; 165 boolean disableStatus = castPort._mirrorDisable; 166 167 try { 168 castPort._mirrorDisable = true; 169 castPort.moveToFirst(); 170 } finally { 171 castPort._mirrorDisable = disableStatus; 172 } 173 } 174 } 175 } 176 177 return result; 178 } finally { 179 _workspace.doneWriting(); 180 } 181 } 182 183 /** Move this object to the specified position in the list 184 * of attributes of the container. If this object is already at the 185 * specified position, do nothing. 186 * This method overrides the base class to mirror the change 187 * in any mirror ports. 188 * Increment the version of the workspace. 189 * @param index The position to move this object to. 190 * @return The index of the specified object prior to moving it, 191 * or -1 if it is not moved. 192 * @exception IllegalActionException If this object has 193 * no container or if the index is out of bounds. 194 */ 195 @Override 196 public int moveToIndex(int index) throws IllegalActionException { 197 try { 198 _workspace.getWriteAccess(); 199 200 int result = super.moveToIndex(index); 201 202 if (result != -1) { 203 // Mirror the change in mirror ports. 204 MultiCompositeActor container = (MultiCompositeActor) getContainer(); 205 Iterator entities = container.entityList().iterator(); 206 207 while (entities.hasNext()) { 208 Entity entity = (Entity) entities.next(); 209 Port mirrorPort = entity.getPort(getName()); 210 211 if (mirrorPort instanceof RefinementPort) { 212 RefinementPort castPort = (RefinementPort) mirrorPort; 213 boolean disableStatus = castPort._mirrorDisable; 214 215 try { 216 castPort._mirrorDisable = true; 217 castPort.moveToIndex(index); 218 } finally { 219 castPort._mirrorDisable = disableStatus; 220 } 221 } 222 } 223 } 224 225 return result; 226 } finally { 227 _workspace.doneWriting(); 228 } 229 } 230 231 /** Move this object to the last position in the list 232 * of attributes of the container. If this object is already last, 233 * do nothing. This method overrides the base class to mirror the change 234 * in any mirror ports. 235 * Increment the version of the workspace. 236 * @return The index of the specified object prior to moving it, 237 * or -1 if it is not moved. 238 * @exception IllegalActionException If this object has 239 * no container. 240 */ 241 @Override 242 public int moveToLast() throws IllegalActionException { 243 try { 244 _workspace.getWriteAccess(); 245 246 int result = super.moveToLast(); 247 248 if (result != -1) { 249 // Mirror the change in mirror ports. 250 MultiCompositeActor container = (MultiCompositeActor) getContainer(); 251 Iterator entities = container.entityList().iterator(); 252 253 while (entities.hasNext()) { 254 Entity entity = (Entity) entities.next(); 255 Port mirrorPort = entity.getPort(getName()); 256 257 if (mirrorPort instanceof RefinementPort) { 258 RefinementPort castPort = (RefinementPort) mirrorPort; 259 boolean disableStatus = castPort._mirrorDisable; 260 261 try { 262 castPort._mirrorDisable = true; 263 castPort.moveToLast(); 264 } finally { 265 castPort._mirrorDisable = disableStatus; 266 } 267 } 268 } 269 } 270 271 return result; 272 } finally { 273 _workspace.doneWriting(); 274 } 275 } 276 277 /** Move this object up by one in the list of 278 * attributes of the container. If this object is already first, do 279 * nothing. 280 * This method overrides the base class to mirror the change 281 * in any mirror ports. 282 * Increment the version of the workspace. 283 * @return The index of the specified object prior to moving it, 284 * or -1 if it is not moved. 285 * @exception IllegalActionException If this object has 286 * no container. 287 */ 288 @Override 289 public int moveUp() throws IllegalActionException { 290 try { 291 _workspace.getWriteAccess(); 292 293 int result = super.moveUp(); 294 295 if (result != -1) { 296 // Mirror the change in mirror ports. 297 MultiCompositeActor container = (MultiCompositeActor) getContainer(); 298 Iterator entities = container.entityList().iterator(); 299 300 while (entities.hasNext()) { 301 Entity entity = (Entity) entities.next(); 302 Port mirrorPort = entity.getPort(getName()); 303 304 if (mirrorPort instanceof RefinementPort) { 305 RefinementPort castPort = (RefinementPort) mirrorPort; 306 boolean disableStatus = castPort._mirrorDisable; 307 308 try { 309 castPort._mirrorDisable = true; 310 castPort.moveUp(); 311 } finally { 312 castPort._mirrorDisable = disableStatus; 313 } 314 } 315 } 316 } 317 318 return result; 319 } finally { 320 _workspace.doneWriting(); 321 } 322 } 323 324 /** Override the base class so that if the port is being removed 325 * from the current container, then it is also removed from the 326 * controller and from each of the refinements. This method is 327 * write-synchronized on the workspace. 328 * @param container The proposed container. 329 * @exception IllegalActionException If the proposed container is not a 330 * ComponentEntity, doesn't implement Actor, or has no name, 331 * or the port and container are not in the same workspace. Or 332 * it's not null 333 * @exception NameDuplicationException If the container already has 334 * a port with the name of this port. 335 */ 336 @Override 337 public void setContainer(Entity container) 338 throws IllegalActionException, NameDuplicationException { 339 try { 340 _workspace.getWriteAccess(); 341 342 MultiCompositeActor model = (MultiCompositeActor) getContainer(); 343 344 if (model != null && container != model) { 345 // The port is being removed from the current container. 346 // Remove it from the mirrored ports. 347 Iterator entities = model.entityList().iterator(); 348 349 while (entities.hasNext()) { 350 Entity entity = (Entity) entities.next(); 351 Port mirrorPort = entity.getPort(getName()); 352 353 if (mirrorPort instanceof RefinementPort) { 354 RefinementPort castPort = (RefinementPort) mirrorPort; 355 boolean disableStatus = castPort._mirrorDisable; 356 357 try { 358 castPort._mirrorDisable = true; 359 castPort.setContainer(null); 360 } finally { 361 castPort._mirrorDisable = disableStatus; 362 } 363 } 364 } 365 366 // Remove the relation as well. 367 ComponentRelation relation = model 368 .getRelation(getName() + "Relation"); 369 370 if (relation != null) { 371 relation.setContainer(null); 372 } 373 } 374 375 super.setContainer(container); 376 } finally { 377 _workspace.doneWriting(); 378 } 379 } 380 381 /** If the argument is true, make the port an input port. 382 * If the argument is false, make the port not an input port. 383 * This method overrides the base class to make the same 384 * change on the mirror ports in the controller and state refinments. 385 * This method invalidates the schedule and resolved types of the 386 * director of the container, if there is one. 387 * It is write-synchronized on the workspace, and increments 388 * the version of the workspace. 389 * @param isInput True to make the port an input. 390 * @exception IllegalActionException If changing the port status is 391 * not permitted. 392 */ 393 @Override 394 public void setInput(boolean isInput) throws IllegalActionException { 395 try { 396 _workspace.getWriteAccess(); 397 398 super.setInput(isInput); 399 400 // Mirror the change in mirror ports. 401 MultiCompositeActor container = (MultiCompositeActor) getContainer(); 402 Iterator entities = container.entityList().iterator(); 403 404 while (entities.hasNext()) { 405 Entity entity = (Entity) entities.next(); 406 Port mirrorPort = entity.getPort(getName()); 407 408 if (mirrorPort instanceof RefinementPort) { 409 RefinementPort castPort = (RefinementPort) mirrorPort; 410 boolean disableStatus = castPort._mirrorDisable; 411 412 try { 413 castPort._mirrorDisable = true; 414 castPort.setInput(isInput); 415 } finally { 416 castPort._mirrorDisable = disableStatus; 417 } 418 } 419 } 420 } finally { 421 _workspace.doneWriting(); 422 } 423 } 424 425 /** If the argument is true, make the port a multiport. 426 * If the argument is false, make the port not a multiport. 427 * This method overrides the base class to make the same 428 * change on the mirror ports in the controller and state refinments. 429 * This method invalidates the schedule and resolved types of the 430 * director of the container, if there is one. 431 * It is write-synchronized on the workspace, and increments 432 * the version of the workspace. 433 * @param isMultiport True to make the port a multiport. 434 * @exception IllegalActionException If changing the port status is 435 * not permitted. 436 */ 437 @Override 438 public void setMultiport(boolean isMultiport) 439 throws IllegalActionException { 440 try { 441 _workspace.getWriteAccess(); 442 443 super.setMultiport(isMultiport); 444 445 // Mirror the change in mirror ports. 446 MultiCompositeActor container = (MultiCompositeActor) getContainer(); 447 Iterator entities = container.entityList().iterator(); 448 449 while (entities.hasNext()) { 450 Entity entity = (Entity) entities.next(); 451 Port mirrorPort = entity.getPort(getName()); 452 453 if (mirrorPort instanceof RefinementPort) { 454 RefinementPort castPort = (RefinementPort) mirrorPort; 455 boolean disableStatus = castPort._mirrorDisable; 456 457 try { 458 castPort._mirrorDisable = true; 459 castPort.setMultiport(isMultiport); 460 } finally { 461 castPort._mirrorDisable = disableStatus; 462 } 463 } 464 } 465 } finally { 466 _workspace.doneWriting(); 467 } 468 } 469 470 /** Set the name of the port, and mirror the change in all the 471 * mirror ports. 472 * This method is write-synchronized on the workspace, and increments 473 * the version of the workspace. 474 * @exception IllegalActionException If the name has a period. 475 * @exception NameDuplicationException If there is already a port 476 * with the same name in the container. 477 */ 478 @Override 479 public void setName(String name) 480 throws IllegalActionException, NameDuplicationException { 481 try { 482 _workspace.getWriteAccess(); 483 484 String oldName = getName(); 485 super.setName(name); 486 487 // Mirror the change in mirror ports. 488 MultiCompositeActor container = (MultiCompositeActor) getContainer(); 489 490 // NOTE: This is called before there is even a container 491 // to originally set the name. 492 if (container != null) { 493 Iterator entities = container.entityList().iterator(); 494 495 while (entities.hasNext()) { 496 Entity entity = (Entity) entities.next(); 497 Port mirrorPort = entity.getPort(oldName); 498 499 if (mirrorPort instanceof RefinementPort) { 500 RefinementPort castPort = (RefinementPort) mirrorPort; 501 boolean disableStatus = castPort._mirrorDisable; 502 503 try { 504 castPort._mirrorDisable = true; 505 castPort.setName(name); 506 } finally { 507 castPort._mirrorDisable = disableStatus; 508 } 509 } 510 } 511 512 // Rename the corresponding relation. 513 Relation relation = container.getRelation(oldName + "Relation"); 514 515 if (relation != null) { 516 relation.setName(name + "Relation"); 517 } 518 } 519 } finally { 520 _workspace.doneWriting(); 521 } 522 } 523 524 /** If the argument is true, make the port an output port. 525 * If the argument is false, make the port not an output port. 526 * This method overrides the base class to make the same 527 * change on the mirror ports in the controller and state refinments. 528 * This method invalidates the schedule and resolved types of the 529 * director of the container, if there is one. 530 * It is write-synchronized on the workspace, and increments 531 * the version of the workspace. 532 * @param isOutput True to make the port an output. 533 * @exception IllegalActionException If changing the port status is 534 * not permitted. 535 */ 536 @Override 537 public void setOutput(boolean isOutput) throws IllegalActionException { 538 try { 539 _workspace.getWriteAccess(); 540 541 super.setOutput(isOutput); 542 543 // Mirror the change in mirror ports. 544 MultiCompositeActor container = (MultiCompositeActor) getContainer(); 545 Iterator entities = container.entityList().iterator(); 546 547 while (entities.hasNext()) { 548 Entity entity = (Entity) entities.next(); 549 Port mirrorPort = entity.getPort(getName()); 550 551 if (mirrorPort instanceof RefinementPort) { 552 RefinementPort castPort = (RefinementPort) mirrorPort; 553 boolean disableStatus = castPort._mirrorDisable; 554 555 try { 556 castPort._mirrorDisable = true; 557 castPort.setOutput(isOutput); 558 } finally { 559 castPort._mirrorDisable = disableStatus; 560 } 561 562 // If the entity is a controller, then set the 563 // port to also be an input. 564 if (entity.getName().equals("_Controller")) { 565 boolean controlPortStatus = castPort._mirrorDisable; 566 567 try { 568 castPort._mirrorDisable = true; 569 castPort.setInput(true); 570 571 // Mark that the input property is 572 // automatically set, so that if it 573 // is changed, that change is not 574 // mirrored. 575 if (!isInput()) { 576 castPort._automaticallyInput = true; 577 } 578 } finally { 579 castPort._mirrorDisable = controlPortStatus; 580 } 581 } 582 } 583 } 584 } finally { 585 _workspace.doneWriting(); 586 } 587 } 588 589 /////////////////////////////////////////////////////////////////// 590 //// protected methods //// 591 592 /** Override the base class to ensure that the proposed container 593 * is a MultiCompositeActor or null. 594 * @param container The proposed container. 595 * @exception IllegalActionException If the proposed container is not a 596 * TypedActor, or if the base class throws it. 597 */ 598 @Override 599 protected void _checkContainer(Entity container) 600 throws IllegalActionException { 601 if (!(container instanceof MultiCompositeActor) && container != null) { 602 throw new IllegalActionException(container, this, 603 "MultiCompositePort can only be contained by MultiCompositeActor objects. " 604 + "The container was: " + container); 605 } 606 } 607}