001/* A parameter that is shared globally in a model. 002 003 Copyright (c) 2004-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 028 */ 029package ptolemy.actor.parameters; 030 031import java.io.Writer; 032import java.lang.ref.WeakReference; 033import java.util.Collection; 034import java.util.HashMap; 035import java.util.HashSet; 036import java.util.Iterator; 037import java.util.LinkedList; 038import java.util.List; 039 040import ptolemy.actor.ApplicationConfigurer; 041import ptolemy.actor.Executable; 042import ptolemy.actor.Initializable; 043import ptolemy.data.Token; 044import ptolemy.data.expr.Parameter; 045import ptolemy.kernel.util.IllegalActionException; 046import ptolemy.kernel.util.NameDuplicationException; 047import ptolemy.kernel.util.NamedObj; 048import ptolemy.kernel.util.Workspace; 049 050/////////////////////////////////////////////////////////////////// 051//// SharedParameter 052 053/** 054 This parameter is shared throughout a model. Changing the expression of 055 any one instance of the parameter will result in all instances that 056 are shared being changed to the same expression. An instance elsewhere 057 in the model (within the same top level) is shared if it has the 058 same name and its container is of the class specified in the 059 constructor (or of the container class, if no class is specified 060 in the constructor). Note that two parameters with the same 061 expression do not necessarily have the same value, since the 062 expression may reference other parameters that are in scope. 063 <p> 064 One exception is that if this parameter is (deeply) within an 065 instance of EntityLibrary, then the parameter is not shared. 066 Were this not the case, then opening a library containing this 067 parameter would force expansion of all the sublibraries of 068 EntityLibrary, which would defeat the lazy instantiation 069 of EntityLibrary. 070 <p> 071 When this parameter is constructed, the specified container 072 will be used to infer the parameter value from the container. 073 That is, if the container is within a model that has any 074 parameters shared with this one, then the value will be 075 set to the last of those encountered. 076 If the container is subsequently changed, it is up to the 077 code implementing the change to use the inferValueFromContext() 078 method to reset the value to match the new context. 079 Note that this really needs to be done if the container 080 of the container, or its container, or any container 081 above this parameter is changed. It is recommended to use 082 the four-argument constructor, so you can specify a default 083 value to use if there are no shared parameters. 084 <p> 085 Note that it might be tempting to use a static parameter field 086 to achieve this effect, but this would be problematic for two 087 reasons. First, the parameter would only be able to have one 088 container. Second, the parameter would be shared across all 089 models in the same Java virtual machine, not just within a 090 single model. 091 092 @author Edward A. Lee, contributor: Christopher Brooks, Bert Rodiers 093 @version $Id$ 094 @since Ptolemy II 8.0 095 @Pt.ProposedRating Green (eal) 096 @Pt.AcceptedRating Green (acataldo) 097 */ 098public class SharedParameter extends Parameter implements Initializable { 099 /** Construct a parameter with the given container and name. 100 * The container class will be used to determine which other 101 * instances of SharedParameter are shared with this one. 102 * @param container The container. 103 * @param name The name of the parameter. 104 * @exception IllegalActionException If the parameter is not of an 105 * acceptable class for the container. 106 * @exception NameDuplicationException If the name coincides with 107 * a parameter already in the container. 108 */ 109 public SharedParameter(NamedObj container, String name) 110 throws IllegalActionException, NameDuplicationException { 111 this(container, name, null, ""); 112 } 113 114 /** Construct a parameter with the given container, name, and 115 * container class. The specified class will be used to determine 116 * which other instances of SharedParameter are shared with this one. 117 * @param container The container. 118 * @param name The name of the parameter. 119 * @param containerClass The class used to determine shared instances. 120 * @exception IllegalActionException If the parameter is not of an 121 * acceptable class for the container. 122 * @exception NameDuplicationException If the name coincides with 123 * a parameter already in the container. 124 */ 125 public SharedParameter(NamedObj container, String name, 126 Class<?> containerClass) 127 throws IllegalActionException, NameDuplicationException { 128 this(container, name, containerClass, ""); 129 } 130 131 /** Construct a parameter with the given container, name, 132 * container class, and default value. This is the preferred 133 * constructor to use. 134 * The specified class will be used to determine 135 * which other instances of SharedParameter are shared with this one. 136 * @param container The container. 137 * @param name The name of the parameter. 138 * @param containerClass The class used to determine shared instances. 139 * An argument of null means simply to use the class of the container, 140 * whatever that happens to be. 141 * @param defaultValue The default value to use if the container's 142 * model has no shared parameters. 143 * @exception IllegalActionException If the parameter is not of an 144 * acceptable class for the container, or an empty string to specify no 145 * default value. 146 * @exception NameDuplicationException If the name coincides with 147 * a parameter already in the container. 148 */ 149 public SharedParameter(NamedObj container, String name, 150 Class<?> containerClass, String defaultValue) 151 throws IllegalActionException, NameDuplicationException { 152 super(container, name); 153 154 if (containerClass == null) { 155 containerClass = container.getClass(); 156 } 157 if (_delayValidation) { 158 _suppressingPropagation = true; 159 setLazy(true); 160 } 161 _containerClass = containerClass; 162 inferValueFromContext(defaultValue); 163 _constructionFinished = true; 164 } 165 166 /////////////////////////////////////////////////////////////////// 167 //// public methods //// 168 169 /** Add the specified object to the list of objects whose 170 * preinitialize(), initialize(), and wrapup() 171 * methods should be invoked upon invocation of the corresponding 172 * methods of this object. 173 * @param initializable The object whose methods should be invoked. 174 * @see #removeInitializable(Initializable) 175 * @see ptolemy.actor.CompositeActor#addPiggyback(Executable) 176 */ 177 @Override 178 public void addInitializable(Initializable initializable) { 179 if (_initializables == null) { 180 _initializables = new LinkedList<Initializable>(); 181 } 182 _initializables.add(initializable); 183 } 184 185 /** Override the base class to register the object, since setName() 186 * will not be called. 187 * @param workspace The workspace for the new object. 188 * @return A new NamedObj. 189 * @exception CloneNotSupportedException If any of the attributes 190 * cannot be cloned. 191 * @see #exportMoML(Writer, int, String) 192 * @see #setDeferringChangeRequests(boolean) 193 */ 194 @Override 195 public Object clone(Workspace workspace) throws CloneNotSupportedException { 196 SharedParameter newObject = (SharedParameter) super.clone(workspace); 197 SharedParameterRegistry registry = _getSharedParameterRegistry( 198 workspace); 199 registry.register(newObject); 200 newObject._sharedParameterSet = null; 201 return newObject; 202 } 203 204 /** Get the token contained by this variable. The type of the returned 205 * token is always that returned by getType(). Calling this method 206 * will trigger evaluation of the expression, if the value has been 207 * given by setExpression(). Notice the evaluation of the expression 208 * can trigger an exception if the expression is not valid, or if the 209 * result of the expression violates type constraints specified by 210 * setTypeEquals() or setTypeAtMost(), or if the result of the expression 211 * is null and there are other variables that depend on this one. 212 * The returned value will be null if neither an expression nor a 213 * token has been set, or either has been set to null. 214 * @return The token contained by this variable converted to the 215 * type of this variable, or null if there is none. 216 * @exception IllegalActionException If the expression cannot 217 * be parsed or cannot be evaluated, or if the result of evaluation 218 * violates type constraints, or if the result of evaluation is null 219 * and there are variables that depend on this one. 220 * @see #setToken(Token) 221 */ 222 @Override 223 public Token getToken() throws IllegalActionException { 224 if (_delayValidation) { 225 boolean previousSuppressing = _suppressingPropagation; 226 try { 227 _suppressingPropagation = false; 228 validate(); 229 return super.getToken(); 230 } finally { 231 _suppressingPropagation = previousSuppressing; 232 } 233 } else { 234 return super.getToken(); 235 } 236 } 237 238 /** Return the top level of the containment hierarchy, unless 239 * one of the containers is an instance of EntityLibrary, 240 * in which case, return null. 241 * @return The top level, or null if this is within a library. 242 */ 243 public NamedObj getRoot() { 244 NamedObj result = this; 245 246 while (result.getContainer() != null) { 247 result = result.getContainer(); 248 if (result instanceof ApplicationConfigurer) { 249 // If the results is a Configuration, then go no higher. 250 // If we do go higher, then we end up expanding the actor 251 // library tree which take a long time and fails if 252 // not all the actors are present. For example, not 253 // everyone will have Matlab or quicktime. 254 return null; 255 } 256 } 257 258 return result; 259 } 260 261 /** Infer the value of this parameter from the container 262 * context. That is, search for parameters that are 263 * shared with this one, and set the value of this parameter 264 * to match the first one encountered. 265 * If there are no shared parameters, then assign the 266 * default value given as an argument. 267 * @param defaultValue The default parameter value to use. 268 */ 269 public void inferValueFromContext(String defaultValue) { 270 SharedParameter candidate = null; 271 NamedObj toplevel = getRoot(); 272 273 if (toplevel != null && toplevel != this) { 274 candidate = _getOneSharedParameter(toplevel); 275 } 276 if (candidate != null) { 277 defaultValue = candidate.getExpression(); 278 } 279 boolean previousSuppressing = _suppressingPropagation; 280 try { 281 _suppressingPropagation = true; 282 283 setExpression(defaultValue); 284 285 // Try getting the evaluated token. 286 if (candidate != null && candidate.isKnown()) { 287 setToken(candidate.getToken()); 288 } 289 290 } catch (IllegalActionException e) { 291 // The token is not set when this happens. 292 293 } finally { 294 _suppressingPropagation = previousSuppressing; 295 } 296 } 297 298 /** Do nothing except invoke the initialize methods 299 * of objects that have been added using addInitializable(). 300 * @exception IllegalActionException If one of the added objects 301 * throws it. 302 */ 303 @Override 304 public void initialize() throws IllegalActionException { 305 // Invoke initializable methods. 306 if (_initializables != null) { 307 for (Initializable initializable : _initializables) { 308 initializable.initialize(); 309 } 310 } 311 } 312 313 /** Return true. 314 * @return True. 315 */ 316 public boolean isFireFunctional() { 317 return true; 318 } 319 320 /** Return false. 321 * @return False. 322 */ 323 public boolean isStrict() { 324 return false; 325 } 326 327 /** Return true if this instance is suppressing propagation. 328 * Unless setSuppressingPropagation() has been called, this 329 * returns false. 330 * @return Returns whether this instance is suppressing propagation. 331 * @see #setSuppressingPropagation(boolean) 332 */ 333 public boolean isSuppressingPropagation() { 334 return _suppressingPropagation; 335 } 336 337 /** Traverse the model and update values. 338 * @exception IllegalActionException Not thrown in this base class. 339 */ 340 @Override 341 public void preinitialize() throws IllegalActionException { 342 // Invoke initializable methods. 343 if (_initializables != null) { 344 for (Initializable initializable : _initializables) { 345 initializable.preinitialize(); 346 } 347 } 348 if (_delayValidation) { 349 _suppressingPropagation = false; 350 validate(); 351 } 352 } 353 354 /** Remove the specified object from the list of objects whose 355 * preinitialize(), initialize(), and wrapup() 356 * methods should be invoked upon invocation of the corresponding 357 * methods of this object. If the specified object is not 358 * on the list, do nothing. 359 * @param initializable The object whose methods should no longer be invoked. 360 * @see #addInitializable(Initializable) 361 * @see ptolemy.actor.CompositeActor#removePiggyback(Executable) 362 */ 363 @Override 364 public void removeInitializable(Initializable initializable) { 365 if (_initializables != null) { 366 _initializables.remove(initializable); 367 if (_initializables.size() == 0) { 368 _initializables = null; 369 } 370 } 371 } 372 373 /** Override the base class to register as an initializable slave with the 374 * new container. This results in the preinitialize(), initialize(), and 375 * wrapup() methods of this instance being invoked when the corresponding 376 * method of the container are invoked. 377 * @param container The proposed container. 378 * @exception IllegalActionException If the action would result in a 379 * recursive containment structure, or if 380 * this entity and container are not in the same workspace. 381 * @exception NameDuplicationException If the container already has 382 * an entity with the name of this entity. 383 */ 384 @Override 385 public void setContainer(NamedObj container) 386 throws IllegalActionException, NameDuplicationException { 387 NamedObj previousContainer = getContainer(); 388 if (previousContainer != container) { 389 if (previousContainer instanceof Initializable) { 390 ((Initializable) previousContainer).removeInitializable(this); 391 } 392 if (container instanceof Initializable) { 393 ((Initializable) container).addInitializable(this); 394 } 395 } 396 super.setContainer(container); 397 } 398 399 /** Override the base class to register as a shared parameter in the workspace. 400 * @param name The proposed name. 401 * @exception IllegalActionException If the name contains a period 402 * or if this variable is referenced in some other expression. 403 * @exception NameDuplicationException If there is already an 404 * attribute with the same name in the container. 405 */ 406 @Override 407 public void setName(String name) 408 throws IllegalActionException, NameDuplicationException { 409 if (name != null && !name.equals(getName())) { 410 SharedParameterRegistry registry = _getSharedParameterRegistry( 411 workspace()); 412 // Unregister under previous name. 413 if (getName() != null && !getName().equals("")) { 414 registry.unregister(this); 415 } 416 super.setName(name); 417 registry.register(this); 418 } 419 } 420 421 /** Override the base class to also set the expression of shared 422 * parameters. 423 * @param expression The expression. 424 */ 425 @Override 426 public void setExpression(String expression) { 427 // The expression may have already been inferred from context, 428 // in which case we don't want to set it again. This prevents 429 // spurious replication of the parameter in the MoML file. 430 if (expression != null && expression.equals(getExpression())) { 431 return; 432 } 433 super.setExpression(expression); 434 435 if (!_suppressingPropagation) { 436 Iterator<SharedParameter> sharedParameters = sharedParameterSet() 437 .iterator(); 438 439 while (sharedParameters.hasNext()) { 440 SharedParameter sharedParameter = sharedParameters.next(); 441 442 if (sharedParameter != this) { 443 try { 444 sharedParameter._suppressingPropagation = true; 445 446 if (!sharedParameter.getExpression() 447 .equals(expression)) { 448 sharedParameter.setExpression(expression); 449 } 450 } finally { 451 sharedParameter._suppressingPropagation = false; 452 } 453 } 454 } 455 } 456 } 457 458 /** Specify whether this instance should be suppressing 459 * propagation. If this is called with value true, then 460 * changes to this parameter will not propagate to other 461 * shared instances in the model. 462 * @param propagation True to suppress propagation. 463 * @see #isSuppressingPropagation() 464 */ 465 public void setSuppressingPropagation(boolean propagation) { 466 _suppressingPropagation = propagation; 467 } 468 469 /** Override the base class to also set the token of shared 470 * parameters. 471 * @param token The token. 472 * @exception IllegalActionException Thrown if super class throws it. 473 * @see #getToken() 474 */ 475 @Override 476 public void setToken(Token token) throws IllegalActionException { 477 478 super.setToken(token); 479 480 if (!_suppressingPropagation) { 481 Iterator<SharedParameter> sharedParameters = sharedParameterSet() 482 .iterator(); 483 484 while (sharedParameters.hasNext()) { 485 SharedParameter sharedParameter = sharedParameters.next(); 486 487 if (sharedParameter != this) { 488 try { 489 sharedParameter._suppressingPropagation = true; 490 sharedParameter.setToken(token); 491 } finally { 492 sharedParameter._suppressingPropagation = false; 493 } 494 } 495 } 496 } 497 } 498 499 /** Return a collection of all the shared parameters within the 500 * same model as this parameter. If there are no such parameters 501 * or if this parameter is deeply contained within an EntityLibrary, then 502 * return an empty collection. Otherwise, the list will include this 503 * instance if this instance has a container. If this instance has 504 * no container, then return an empty collection. 505 * A shared parameter is one that is an instance of SharedParameter, 506 * has the same name as this one, and is contained by the container 507 * class specified in the constructor. 508 * @return A collection of parameters. 509 */ 510 public synchronized Collection sharedParameterSet() { 511 // If we call clone(), then _sharedParameterSet could be null. 512 if (workspace().getVersion() != _sharedParameterSetVersion 513 || _sharedParameterSet == null) { 514 try { 515 workspace().getReadAccess(); 516 _sharedParameterSet = new HashSet<SharedParameter>(); 517 _sharedParameterSetVersion = workspace().getVersion(); 518 NamedObj root = getRoot(); 519 if (root != null) { 520 SharedParameterRegistry registry = _getSharedParameterRegistry( 521 workspace()); 522 for (WeakReference<SharedParameter> reference : registry 523 .getSharedParametersWithName(getName())) { 524 if (reference != null) { 525 SharedParameter parameter = reference.get(); 526 if (parameter != null) { 527 // Have a candidate. See if the roots match and if 528 // the container classes match. 529 if (parameter.getRoot() == root 530 && parameter._containerClass == _containerClass) { 531 _sharedParameterSet.add(parameter); 532 } 533 } 534 } 535 } 536 } 537 } finally { 538 workspace().doneReading(); 539 } 540 } 541 return _sharedParameterSet; 542 } 543 544 /** Supress propagation. 545 * @exception IllegalActionException Not thrown in this base class. 546 */ 547 @Override 548 public void wrapup() throws IllegalActionException { 549 // Invoke initializable methods. 550 if (_initializables != null) { 551 for (Initializable initializable : _initializables) { 552 initializable.wrapup(); 553 } 554 } 555 if (_delayValidation) { 556 _suppressingPropagation = true; 557 } 558 } 559 560 /** Override the base class to also validate the shared instances. 561 * @return A Collection of all the shared parameters within the same 562 * model as this parameter, see {@link #sharedParameterSet}. 563 * @exception IllegalActionException If this variable or a 564 * variable dependent on this variable cannot be evaluated (and is 565 * not lazy) and the model error handler throws an exception. 566 * Also thrown if the change is not acceptable to the container. 567 */ 568 @Override 569 public Collection validate() throws IllegalActionException { 570 Collection result = super.validate(); 571 if (result == null) { 572 result = new HashSet(); 573 } 574 575 // NOTE: This is called by setContainer(), which is called from 576 // within a base class constructor. That call occurs before this 577 // object has been fully constructed. It doesn't make sense at 578 // that time to propagate validation to shared instances, since 579 // in fact the value of this shared parameter will be inferred 580 // from those instances if there are any. So in that case, we 581 // just return. 582 if (!_constructionFinished) { 583 return result; 584 } 585 586 if (!_suppressingPropagation) { 587 Iterator<SharedParameter> sharedParameters = sharedParameterSet() 588 .iterator(); 589 while (sharedParameters.hasNext()) { 590 SharedParameter sharedParameter = sharedParameters.next(); 591 if (sharedParameter != this) { 592 try { 593 sharedParameter._suppressingPropagation = true; 594 result.addAll(sharedParameter.validate()); 595 result.add(sharedParameter); 596 } finally { 597 sharedParameter._suppressingPropagation = false; 598 } 599 } 600 } 601 } 602 return result; 603 } 604 605 /////////////////////////////////////////////////////////////////// 606 //// protected methods //// 607 608 /** Override the base class to do the propagation only if 609 * the specified destination is not shared, because if 610 * it is shared, then the value will be propagated 611 * in through the sharing mechanism. 612 * @param destination Object to which to propagate the 613 * value. 614 * @exception IllegalActionException If the value cannot 615 * be propagated. 616 */ 617 @Override 618 protected void _propagateValue(NamedObj destination) 619 throws IllegalActionException { 620 if (!sharedParameterSet().contains(destination)) { 621 super._propagateValue(destination); 622 } 623 } 624 625 /////////////////////////////////////////////////////////////////// 626 //// private methods //// 627 628 /** Find and return one shared parameter deeply contained by 629 * the specified container. If there is no such parameter, then 630 * return null. 631 * A shared parameter is one that is an instance of SharedParameter, 632 * has the same name as this one, and is contained by the container 633 * class specified in the constructor. 634 * @param container The container. 635 * @return A shared parameter different from this one, or null if 636 * there is none. 637 */ 638 private SharedParameter _getOneSharedParameter(NamedObj container) { 639 if (workspace().getVersion() != _sharedParameterVersion) { 640 try { 641 workspace().getReadAccess(); 642 _sharedParameter = null; 643 _sharedParameterVersion = workspace().getVersion(); 644 NamedObj root = getRoot(); 645 if (root != null) { 646 SharedParameterRegistry registry = _getSharedParameterRegistry( 647 workspace()); 648 for (WeakReference<SharedParameter> reference : registry 649 .getSharedParametersWithName(getName())) { 650 if (reference != null) { 651 SharedParameter parameter = reference.get(); 652 if (parameter != null) { 653 // Have a candidate. See if the roots match and if 654 // the container classes match. 655 if (parameter != this 656 && parameter.getRoot() == root 657 && parameter._containerClass == _containerClass) { 658 _sharedParameter = parameter; 659 // Successful match. No need to search further. 660 return _sharedParameter; 661 } 662 } 663 } 664 } 665 } 666 } finally { 667 workspace().doneReading(); 668 } 669 } 670 return _sharedParameter; 671 } 672 673 /** Return the shared parameter registry associated with this workspace. 674 */ 675 private static synchronized SharedParameterRegistry _getSharedParameterRegistry( 676 Workspace workspace) { 677 678 Iterator<SharedParameterRegistry> iterator = _REGISTRY.iterator(); 679 while (iterator.hasNext()) { 680 SharedParameterRegistry registry = iterator.next(); 681 Workspace registerWorkspace = registry.workspace(); 682 if (registerWorkspace == workspace) { 683 return registry; 684 } else if (registerWorkspace == null) { 685 // Clean up register. 686 // The workspace is a weak reference. If it is null, we know that the 687 // workspace is garbage collected and hence we can remove the entry in the 688 // list. 689 iterator.remove(); 690 } 691 } 692 SharedParameterRegistry result = new SharedParameterRegistry(workspace); 693 _REGISTRY.add(result); 694 return result; 695 } 696 697 /////////////////////////////////////////////////////////////////// 698 //// private variables //// 699 700 /** Indicator that the constructor has reached the end. */ 701 private boolean _constructionFinished = false; 702 703 /** The container class. */ 704 private Class<?> _containerClass; 705 706 /** True if we are delaying validation. 707 * FIXME: This variable is only present for testing and development. 708 * To try out the delay of validation, set it to true and recompile. 709 */ 710 private static final boolean _delayValidation = false; 711 712 /** Empty list. */ 713 private static Collection<WeakReference<SharedParameter>> _EMPTY_LIST = new LinkedList<WeakReference<SharedParameter>>(); 714 715 /** List of objects whose (pre)initialize() and wrapup() methods 716 * should be slaved to these. 717 */ 718 private transient List<Initializable> _initializables; 719 720 /** Cached version of a shared parameter. */ 721 private SharedParameter _sharedParameter; 722 723 /** Version for the cache. */ 724 private long _sharedParameterVersion = -1L; 725 726 /** Cached version of the shared parameter set. */ 727 private HashSet<SharedParameter> _sharedParameterSet; 728 729 /** Version for the cache. */ 730 private long _sharedParameterSetVersion = -1L; 731 732 /** Registry by workspace. */ 733 private static List<SharedParameterRegistry> _REGISTRY = new LinkedList<SharedParameterRegistry>(); 734 735 /** Indicator to suppress propagation. */ 736 private boolean _suppressingPropagation = false; 737 738 /////////////////////////////////////////////////////////////////// 739 //// inner classes //// 740 741 /** Registry of shared parameters. This is a data structure 742 * that registers all shared parameters in a workspace. This is 743 * more efficient than searching through a model to find all the 744 * shared parameters. It stores one collection of shared parameters 745 * for each name. 746 */ 747 private static class SharedParameterRegistry { 748 749 public SharedParameterRegistry(Workspace workspace) { 750 _workspace = new WeakReference<Workspace>(workspace); 751 } 752 753 /** Return all shared parameters with the specified name. 754 * This returns a collection of weak references. 755 */ 756 public synchronized Collection<WeakReference<SharedParameter>> getSharedParametersWithName( 757 String name) { 758 Collection<WeakReference<SharedParameter>> set = _sharedParametersByName 759 .get(name); 760 if (set == null) { 761 return _EMPTY_LIST; 762 } else { 763 return set; 764 } 765 } 766 767 /** Register the specified shared parameter. */ 768 public synchronized void register(SharedParameter parameter) { 769 Collection<WeakReference<SharedParameter>> set = _sharedParametersByName 770 .get(parameter.getName()); 771 if (set == null) { 772 set = new LinkedList<WeakReference<SharedParameter>>(); 773 _sharedParametersByName.put(parameter.getName(), set); 774 } 775 set.add(new WeakReference<SharedParameter>(parameter)); 776 } 777 778 public synchronized void unregister(SharedParameter parameter) { 779 Collection<WeakReference<SharedParameter>> set = _sharedParametersByName 780 .get(parameter.getName()); 781 if (set != null) { 782 set.remove(new WeakReference<SharedParameter>(parameter)); 783 } 784 } 785 786 /** Return the workspace. */ 787 public Workspace workspace() { 788 return _workspace.get(); 789 } 790 791 private HashMap<String, Collection<WeakReference<SharedParameter>>> _sharedParametersByName = new HashMap<String, Collection<WeakReference<SharedParameter>>>(); 792 793 private WeakReference<Workspace> _workspace; 794 } 795}