001/* An attribute that is used for invoking Chic from inside a ptolemy model. 002 003 Copyright (c) 1998-2016 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.chic; 029 030import java.util.Iterator; 031import java.util.LinkedList; 032import java.util.List; 033 034import chic.ChicForPtolemy; 035import ptolemy.actor.Actor; 036import ptolemy.actor.CompositeActor; 037import ptolemy.actor.IOPort; 038import ptolemy.data.BooleanToken; 039import ptolemy.data.expr.SingletonParameter; 040import ptolemy.kernel.ComponentEntity; 041import ptolemy.kernel.util.Attribute; 042import ptolemy.kernel.util.IllegalActionException; 043import ptolemy.kernel.util.NameDuplicationException; 044import ptolemy.kernel.util.NamedObj; 045import ptolemy.kernel.util.Settable; 046import ptolemy.kernel.util.StringAttribute; 047 048/////////////////////////////////////////////////////////////////// 049//// ChicInvoker 050 051/** 052 This attribute is a visible attribute used for invoking Chic (Checker 053 for Interface Compatibility) on its container. Chic is invoked by 054 right clicking on the attribute and selecting one of the options: 055 "CHIC: Asynchronous I/O" and "CHIC: Synchronous A/G". 056 The expression of the InterfaceName attribute specifies the name of the 057 ChicAttribute that is going to be used upon invocation of Chic. 058 Note that every directly or indirectly contained port of the attribute's 059 container must have a name syntactically equivalent to a Java identifier. 060 061 @author Eleftherios Matsikoudis 062 @version $Id$ 063 @since Ptolemy II 3.0 064 @Pt.ProposedRating Red (cxh) 065 @Pt.AcceptedRating Red (cxh) 066 */ 067public class ChicInvoker extends Attribute { 068 /** Construct an attribute with the specified container and name. 069 * @param container The container. 070 * @param name The name of the attribute. 071 * @exception IllegalActionException If the factory is not of an 072 * acceptable attribute for the container. 073 * @exception NameDuplicationException If the name coincides with 074 * an attribute already in the container. 075 */ 076 public ChicInvoker(NamedObj container, String name) 077 throws IllegalActionException, NameDuplicationException { 078 super(container, name); 079 080 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-50\" y=\"-25\" " 081 + "width=\"100\" height=\"50\" " + "style=\"fill:white\"/>\n" 082 + "<image x=\"-50\" y=\"-25\" width=\"100\" height=\"50\" " 083 + "xlink:href=\"ptolemy/chic/chic.gif\"/>\n" + "</svg>\n"); 084 085 new ChicControllerFactory(this, "_controllerFactory"); 086 087 SingletonParameter hide = new SingletonParameter(this, "_hideName"); 088 hide.setToken(BooleanToken.TRUE); 089 hide.setVisibility(Settable.EXPERT); 090 091 chicAttributeName = new StringAttribute(this, "InterfaceName"); 092 } 093 094 /////////////////////////////////////////////////////////////////// 095 //// parameters //// 096 097 /** A StringAttribute representing the name of the ChicAttributes 098 * that are to be queried while collecting the interfaces upon which 099 * Chic is to be invoked. 100 */ 101 public StringAttribute chicAttributeName; 102 103 /////////////////////////////////////////////////////////////////// 104 //// public methods //// 105 106 /** Check the interface compatibility of all entities that are directly 107 * or indirectly contained by the container of this attribute. 108 * @param compiler The compiler of Chic to use. 109 * @see #ASYNCHRONOUS_IO 110 * @see #SYNCHRONOUS_AG 111 * @param silent True if the interface compatibility checking is to be 112 * carried out without invoking the user interface of Chic. 113 * @return True if the interfaces of the contained entities are 114 * compatible. 115 * @exception IllegalActionException If a port contained directly or 116 * indirectly by the <i>model</i> has width greater than one or is 117 * both an input and output port. 118 * @exception NameDuplicationException If the container of the attribute 119 * or one of the contained entities already contains an attribute of 120 * class other than ChicAttribute with the same name as the expression 121 * of the InterfaceName. 122 */ 123 public boolean checkInterfaceCompatibility(int compiler, boolean silent) 124 throws IllegalActionException, NameDuplicationException { 125 return _checkInterfaceCompatibility( 126 (CompositeActor) this.getContainer(), compiler, silent, 127 chicAttributeName.getExpression()); 128 } 129 130 /////////////////////////////////////////////////////////////////// 131 //// public variables //// 132 133 /** Indicate use of the Asynchronous I/O compiler. 134 */ 135 public static final int ASYNCHRONOUS_IO = ChicForPtolemy.ASYN; 136 137 // /** Indicate use of the Bidirectional Syn A/G compiler 138 // */ 139 // public static final int BIDIRECTIONAL_SYN_AG = ChicForPtolemy.BISYNAG; 140 // /** Indiate use of the Stateful Software compiler 141 // */ 142 // public static final int STATEFUL_SOFTWARE = ChicForPtolemy.SOFT_STATEFUL; 143 // /** Indicate use of the Stateless Software compiler 144 // */ 145 // public static final int STATELESS_SOFTWARE = ChicForPtolemy.SOFT_STATELESS; 146 147 /** Indicate use of the Synchronous A/G compiler. 148 */ 149 public static final int SYNCHRONOUS_AG = ChicForPtolemy.SYNAG; 150 151 /////////////////////////////////////////////////////////////////// 152 //// protected methods //// 153 154 /** Check the interface compatibility of all entities that are directly 155 * or indirectly contained by the <i>model</i>. 156 * @param model The model to check interface compatibility. 157 * @param compiler The compiler of Chic to use. 158 * @see #ASYNCHRONOUS_IO 159 * @see #SYNCHRONOUS_AG 160 * @param silent True if the interface compatibility checking is to be 161 * carried out without invoking the user interface of Chic. 162 * @param name The name of the ChicAttribute. 163 * @return True if the interfaces of the contained entities are 164 * compatible. 165 * @exception IllegalActionException If a port contained directly or 166 * indirectly by the <i>model</i> has width greater than one or is 167 * both an input and output port. 168 * @exception NameDuplicationException If the <i>model</i> or one of the 169 * contained entities already contains an attribute of class other than 170 * ChicAttribute with the same name as <i>name</i>. 171 */ 172 protected boolean _checkInterfaceCompatibility(CompositeActor model, 173 int compiler, boolean silent, String name) 174 throws IllegalActionException, NameDuplicationException { 175 ChicAttribute chicAttribute; 176 String chicInterface; 177 StringBuffer collectedInterfaces = new StringBuffer(""); 178 179 try { 180 _workspace.getReadAccess(); 181 182 Iterator entities = model.entityList().iterator(); 183 184 // Collect the interfaces from all directly contained entities. 185 while (entities.hasNext()) { 186 ComponentEntity entity = (ComponentEntity) entities.next(); 187 188 // Get the interface of the entity. 189 if (entity.isAtomic()) { 190 chicAttribute = (ChicAttribute) entity.getAttribute(name); 191 } else { 192 if (_checkInterfaceCompatibility((CompositeActor) entity, 193 compiler, true, name)) { 194 chicAttribute = (ChicAttribute) entity 195 .getAttribute(name); 196 } else { 197 return false; 198 } 199 } 200 201 // If the entity does not have a declared interface skip it. 202 if (chicAttribute == null) { 203 continue; 204 } 205 206 chicInterface = chicAttribute.getExpression(); 207 208 // Parse and refactor it. 209 // Construct an iterator for the list of opaque ports 210 // interfacing the entity. 211 Iterator ports; 212 213 if (entity.isOpaque()) { 214 ports = entity.portList().iterator(); 215 } else { 216 List insidePortList = new LinkedList(); 217 Iterator transparentPorts = entity.portList().iterator(); 218 219 while (transparentPorts.hasNext()) { 220 IOPort transparentPort = (IOPort) transparentPorts 221 .next(); 222 insidePortList 223 .addAll(transparentPort.deepInsidePortList()); 224 } 225 226 ports = insidePortList.iterator(); 227 } 228 229 // Refactor the interface according to its type. 230 switch (compiler) { 231 case ASYNCHRONOUS_IO: 232 233 while (ports.hasNext()) { 234 IOPort port = (IOPort) ports.next(); 235 236 // Currently ports with width greater than one are not supported. 237 if (port.getWidth() > 1) { 238 throw new IllegalActionException("Ports with " 239 + "width greater than one are not " 240 + "supported in the current " 241 + "implementation."); 242 } 243 244 // Replace port_name.remote.action with 245 // remote_port_ull_name.action 246 if (entity.deepContains(port)) { 247 Iterator connectedPorts = port 248 .deepConnectedPortList().iterator(); 249 250 while (connectedPorts.hasNext()) { 251 IOPort connectedPort = (IOPort) connectedPorts 252 .next(); 253 254 if (entity.isOpaque()) { 255 if (model.deepContains(connectedPort)) { 256 chicInterface = chicInterface 257 .replaceAll("(?<!(\\w|\\$|\\.))" 258 + port.getName() 259 + "\\.remote(?=\\.(\\w|\\$)+(\\s|$))", 260 (Actor) connectedPort 261 .getContainer() == model 262 ? _sanitizeName( 263 connectedPort 264 .getName() 265 + ".inside") 266 : _sanitizeName( 267 connectedPort 268 .getFullName())); 269 } else { 270 chicInterface = chicInterface 271 .replaceAll("(?<!(\\w|\\$|\\.))" 272 + port.getName() 273 + "\\.remote(?=\\.(\\w|\\$)+(\\s|$))", 274 _sanitizeName(port 275 .getFullName())); 276 } 277 } else { 278 if (model.deepContains(connectedPort)) { 279 chicInterface = chicInterface 280 .replaceAll("(?<!(\\w|\\$|\\.))" 281 + port.getFullName() 282 + "\\.remote(?=\\.(\\w|\\$)+(\\s|$))", 283 (Actor) connectedPort 284 .getContainer() == model 285 ? _sanitizeName( 286 connectedPort 287 .getName() 288 + ".inside") 289 : _sanitizeName( 290 connectedPort 291 .getFullName())); 292 } 293 } 294 } 295 296 // Replace port_name.action with port_full_name.action 297 chicInterface = chicInterface.replaceAll( 298 "(?<!(\\w|\\$|\\.))" + port.getName() 299 + "(?=\\.(\\w|\\$)+(\\s|$))", 300 _sanitizeName(port.getFullName())); 301 } 302 } 303 304 break; 305 306 case SYNCHRONOUS_AG: 307 308 while (ports.hasNext()) { 309 IOPort port = (IOPort) ports.next(); 310 311 // Currently ports with width greater than one and 312 // ports that are both input and output ports are 313 // not supported. 314 if (port.isInput() && port.isOutput() 315 || port.getWidth() > 1) { 316 throw new IllegalActionException( 317 "Ports with width greater than one or " 318 + "that are both input and output are not " 319 + "supported in the current " 320 + "implementation."); 321 } 322 323 if (entity.deepContains(port)) { 324 if (entity.isOpaque()) { 325 if (port.isInput()) { 326 Iterator sourcePorts = port.sourcePortList() 327 .iterator(); 328 329 if (sourcePorts.hasNext()) { 330 // Since its width is less than one 331 // there is only one port on the 332 // outside. 333 IOPort sourcePort = (IOPort) sourcePorts 334 .next(); 335 336 if (model.deepContains(sourcePort)) { 337 chicInterface = chicInterface 338 .replaceAll( 339 "(?<!(^|[\\n\\r]|\\w|\\$|\\.))" 340 + port.getName() 341 + "(?!(\\w|\\$|\\.))", 342 (Actor) sourcePort 343 .getContainer() == model 344 ? _sanitizeName( 345 sourcePort 346 .getName() 347 + ".inside") 348 : _sanitizeName( 349 sourcePort 350 .getFullName())); 351 } else { 352 chicInterface = chicInterface 353 .replaceAll( 354 "(?<!(^|[\\n\\r]|\\w|\\$|\\.))" 355 + port.getName() 356 + "(?!(\\w|\\$|\\.))", 357 _sanitizeName(port 358 .getFullName())); 359 } 360 } else { 361 chicInterface = chicInterface 362 .replaceAll( 363 "(?<!(^|[\\n\\r]|\\w|\\$|\\.))" 364 + port.getName() 365 + "(?!(\\w|\\$|\\.))", 366 _sanitizeName(port 367 .getFullName())); 368 } 369 } else { 370 chicInterface = chicInterface.replaceAll( 371 "(?<!(^|[\\n\\r]|\\w|\\$|\\.))" 372 + port.getName() 373 + "(?!(\\w|\\$|\\.))", 374 _sanitizeName(port.getFullName())); 375 } 376 } else { 377 if (port.isInput()) { 378 Iterator sourcePorts = port.sourcePortList() 379 .iterator(); 380 381 if (sourcePorts.hasNext()) { 382 // Since its width is less than one 383 // there is only one port on the 384 // outside. 385 IOPort sourcePort = (IOPort) sourcePorts 386 .next(); 387 388 if (model.deepContains(sourcePort)) { 389 chicInterface = chicInterface 390 .replaceAll( 391 "(?<!(^|[\\n\\r]|\\w|\\$|\\.))" 392 + port.getFullName() 393 + "(?!(\\w|\\$|\\.))", 394 (Actor) sourcePort 395 .getContainer() == model 396 ? _sanitizeName( 397 sourcePort 398 .getName() 399 + ".inside") 400 : _sanitizeName( 401 sourcePort 402 .getFullName())); 403 } 404 } 405 } 406 } 407 } 408 } 409 410 break; 411 412 default: 413 throw new IllegalActionException( 414 "Only \"Asynchronous I/O\" and \"Synchronous A/G\" " 415 + "are supported in current implementation."); 416 } 417 418 // Append the refactored interface to the collected interfaces. 419 collectedInterfaces.append(chicInterface + "\n"); 420 } 421 422 // Collect the interfaces from all directly contained opaque ports. 423 if (model.isOpaque()) { 424 Iterator ports = model.portList().iterator(); 425 426 while (ports.hasNext()) { 427 IOPort port = (IOPort) ports.next(); 428 429 // Get the interface of the port. 430 chicAttribute = (ChicAttribute) port.getAttribute(name); 431 432 // If the port does not have a declared interface skip it. 433 if (chicAttribute == null) { 434 continue; 435 } 436 437 chicInterface = chicAttribute.getExpression(); 438 439 // Parse and refactor it. 440 switch (compiler) { 441 case ASYNCHRONOUS_IO: 442 443 // Currently ports with width greater than one are not supported. 444 if (port.getWidth() > 1) { 445 throw new IllegalActionException("Ports with " 446 + "width greater than one are not " 447 + "supported in the current " 448 + "implementation."); 449 } { 450 Iterator insidePorts = port.deepInsidePortList() 451 .iterator(); 452 453 while (insidePorts.hasNext()) { 454 IOPort insidePort = (IOPort) insidePorts.next(); 455 chicInterface = chicInterface.replaceAll( 456 "(?<!(\\w|\\$|\\.))" + port.getName() 457 + "\\.inside\\.remote(?=\\.(\\w|\\$)+(\\s|$))", 458 (Actor) insidePort.getContainer() == model 459 ? _sanitizeName(insidePort.getName() 460 + ".inside") 461 : _sanitizeName( 462 insidePort.getFullName())); 463 } 464 } 465 466 break; 467 468 case SYNCHRONOUS_AG: 469 470 // Currently ports with width greater than one and 471 // ports that are both input and output ports are 472 // not supported. 473 if (port.isInput() && port.isOutput() 474 || port.getWidthInside() > 1) { 475 throw new IllegalActionException( 476 "Ports with width greater than one or " 477 + "that are both input and output are not " 478 + "supported in the current " 479 + "implementation."); 480 } 481 482 if (port.isOutput()) { 483 Iterator insidePorts = port.deepInsidePortList() 484 .iterator(); 485 486 if (insidePorts.hasNext()) { 487 // Since it is not a multiport or an input port, 488 // there is only one port on the inside. 489 IOPort sourcePort = (IOPort) insidePorts.next(); 490 chicInterface = chicInterface.replaceAll( 491 "(?<!(^|[\\n\\r]|\\w|\\$|\\.))" 492 + port.getName() + ".inside" 493 + "(?!(\\w|\\$|\\.))", 494 (Actor) sourcePort 495 .getContainer() == model 496 ? _sanitizeName( 497 sourcePort 498 .getName() 499 + ".inside") 500 : _sanitizeName( 501 sourcePort 502 .getFullName())); 503 } 504 } 505 506 break; 507 508 default: 509 throw new IllegalActionException( 510 "Only \"Asynchronous I/O\" and \"Synchronous A/G\" " 511 + "are supported in current implementation."); 512 } 513 514 // Append the refactored interface to the collected 515 // interfaces. 516 collectedInterfaces.append(chicInterface + "\n"); 517 } 518 } 519 } finally { 520 _workspace.doneReading(); 521 } 522 523 if (!(chicInterface = new String(collectedInterfaces)).equals("")) { 524 System.out.println(chicInterface + "\n"); 525 526 ChicForPtolemy chic = new ChicForPtolemy( 527 new String(collectedInterfaces), compiler, !silent); 528 529 if (chic.areCompatible()) { 530 chicAttribute = new ChicAttribute(model, name); 531 chicAttribute.setExpression(chic.getCompositeInterface()); 532 return true; 533 } else { 534 return false; 535 } 536 } 537 538 return true; 539 540 // if (!(chicInterface = new String(collectedInterfaces)).equals("")) { 541 // chicAttribute = new ChicAttribute(model, name); 542 // chicAttribute.setExpression(chicInterface); 543 // } 544 // if (!silent) System.out.println(chicInterface + "\n"); 545 // return true; 546 } 547 548 /////////////////////////////////////////////////////////////////// 549 //// private methods //// 550 // Sanitize a String so that it is syntactically equivallent to 551 // a (qualified) Java identifier. Characters that are not permitted 552 // in a (qualified) Java identifier are changed to underscores. 553 // This method does not check that the returned string is a 554 // keyword or literal. 555 // Note that two different strings can sanitize to the same 556 // string. 557 private String _sanitizeName(String name) { 558 name = name.replaceAll("[^(\\w|\\$|\\.)]", "_"); 559 560 // Substitute all $ with \\$ so that you don't get an exception 561 // from the matcher. 562 return name.replaceAll("\\$", "\\\\\\$"); 563 } 564 565 /////////////////////////////////////////////////////////////////// 566 //// private variables //// 567}