001/* A base class for schedulers. 002 003 Copyright (c) 1998-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 FIXME: Caching should move into StaticSchedulingDirector. 028 */ 029package ptolemy.actor.sched; 030 031import java.util.Iterator; 032import java.util.List; 033 034import ptolemy.actor.Actor; 035import ptolemy.actor.CompositeActor; 036import ptolemy.actor.Director; 037import ptolemy.kernel.util.Attribute; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.InternalErrorException; 040import ptolemy.kernel.util.KernelException; 041import ptolemy.kernel.util.NameDuplicationException; 042import ptolemy.kernel.util.Nameable; 043import ptolemy.kernel.util.NamedObj; 044import ptolemy.kernel.util.Workspace; 045 046/////////////////////////////////////////////////////////////////// 047//// Scheduler 048 049/** 050 The base class for schedulers. A scheduler schedules the execution 051 order of the containees of a CompositeActor. <p> 052 053 A scheduler is contained by a StaticSchedulingDirector, and provides 054 the schedule for it. The director will use this schedule to govern 055 the execution of a CompositeActor. <p> 056 057 A schedule is represented by the Schedule class, and determines the 058 order of the firing of the actors in a particular composite actor. In 059 this base class, the default schedule fires the deeply 060 contained actors in the order of their construction. A domain specific 061 scheduler will override this to provide a different order. <p> 062 063 The schedule, once constructed, is cached and reused as long as the 064 schedule is still valid. The validity of the schedule is set by the 065 setValid() method. If the current schedule is not valid, then the 066 schedule will be recomputed the next time the getSchedule() method is 067 called. However, derived classes will usually override only the 068 protected _getSchedule() method. <p> 069 070 The scheduler does not perform any mutations, and it does not listen 071 for changes in the model. Directors that use this scheduler should 072 normally invalidate the schedule when mutations occur. 073 074 @author Jie Liu, Steve Neuendorffer 075 @version $Id$ 076 @since Ptolemy II 0.2 077 @Pt.ProposedRating Green (neuendor) 078 @Pt.AcceptedRating Yellow (neuendor) 079 @see ptolemy.actor.sched.Schedule 080 */ 081public class Scheduler extends Attribute { 082 /** Construct a scheduler with no container(director) 083 * in the default workspace, the name of the scheduler is 084 * "Scheduler". 085 */ 086 public Scheduler() { 087 super(); 088 089 try { 090 setName(_DEFAULT_SCHEDULER_NAME); 091 } catch (KernelException ex) { 092 // Should not be thrown. 093 throw new InternalErrorException(this, ex, null); 094 } 095 } 096 097 /** Construct a scheduler in the given workspace with the name 098 * "Scheduler". 099 * If the workspace argument is null, use the default workspace. 100 * The scheduler is added to the list of objects in the workspace. 101 * Increment the version number of the workspace. 102 * @param workspace Object for synchronization and version tracking. 103 */ 104 public Scheduler(Workspace workspace) { 105 super(workspace); 106 107 try { 108 setName(_DEFAULT_SCHEDULER_NAME); 109 } catch (KernelException ex) { 110 // Should not be thrown. 111 throw new InternalErrorException(this, ex, null); 112 } 113 } 114 115 /** Construct a scheduler in the given container with the given name. 116 * The container argument must not be null, or a 117 * NullPointerException will be thrown. This attribute will use the 118 * workspace of the container for synchronization and version counts. 119 * If the name argument is null, then the name is set to the empty string. 120 * Increment the version of the workspace. 121 * @param container The container. 122 * @param name The name of this attribute. 123 * @exception IllegalActionException If the attribute is not of an 124 * acceptable class for the container, or if the name contains a period. 125 * @exception NameDuplicationException If the name coincides with 126 * an attribute already in the container. 127 */ 128 public Scheduler(Director container, String name) 129 throws IllegalActionException, NameDuplicationException { 130 super(container, name); 131 } 132 133 /////////////////////////////////////////////////////////////////// 134 //// public methods //// 135 136 /** Clone the scheduler into the specified workspace. The new object is 137 * <i>not</i> added to the directory of that workspace (you must do this 138 * yourself if you want it there). 139 * The result is a new scheduler with no container, and no valid schedule. 140 * @param workspace The workspace for the cloned object. 141 * @exception CloneNotSupportedException If one of the attributes 142 * cannot be cloned. 143 * @return The new Scheduler. 144 */ 145 @Override 146 public Object clone(Workspace workspace) throws CloneNotSupportedException { 147 Scheduler newObject = (Scheduler) super.clone(workspace); 148 newObject._valid = false; 149 newObject._cachedGetSchedule = null; 150 return newObject; 151 } 152 153 /** Return the scheduling sequence as an instance of the Schedule class. 154 * For efficiency, this method returns a cached version of the 155 * schedule, if it is valid. Otherwise, it calls the protected 156 * method _getSchedule() to update the schedule. Derived classes 157 * normally override the protected method, not this one. 158 * The validity of the current schedule is set by the setValid() 159 * method. This method is read-synchronized on the workspace. 160 * @return The Schedule returned by the _getSchedule() method. 161 * @exception IllegalActionException If the scheduler has no container 162 * (a director), or the director has no container (a CompositeActor), 163 * or the scheduling algorithm throws it. 164 * @exception NotSchedulableException If the _getSchedule() method 165 * throws it. Not thrown in this base class, but may be needed 166 * by the derived schedulers. 167 */ 168 public Schedule getSchedule() 169 throws IllegalActionException, NotSchedulableException { 170 try { 171 workspace().getReadAccess(); 172 173 StaticSchedulingDirector director = (StaticSchedulingDirector) getContainer(); 174 175 if (director == null) { 176 throw new IllegalActionException(this, 177 "Scheduler has no director."); 178 } 179 180 CompositeActor compositeActor = (CompositeActor) director 181 .getContainer(); 182 183 if (compositeActor == null) { 184 throw new IllegalActionException(this, 185 "Director has no container."); 186 } 187 188 if (!isValid() || _cachedGetSchedule == null) { 189 _cachedGetSchedule = _getSchedule(); 190 _workspaceVersion = workspace().getVersion(); 191 } 192 193 return _cachedGetSchedule; 194 } finally { 195 workspace().doneReading(); 196 } 197 } 198 199 /** Return true if the current schedule is valid. 200 * @return true if the current schedule is valid. 201 */ 202 public boolean isValid() { 203 if (_workspaceVersion != workspace().getVersion()) { 204 return false; 205 } 206 return _valid; 207 } 208 209 /** Specify the container. If the specified container is an instance 210 * of Director, then this becomes the active scheduler for 211 * that director. Otherwise, this is an attribute like any other within 212 * the container. If the container is not in the same 213 * workspace as this director, throw an exception. 214 * If this scheduler is already an attribute of the container, 215 * then this has the effect only of making it the active scheduler. 216 * If this scheduler already has a container, remove it 217 * from that container first. Otherwise, remove it from 218 * the directory of the workspace, if it is present. 219 * If the argument is null, then remove it from its container. 220 * This director is not added to the workspace directory, so calling 221 * this method with a null argument could result in 222 * this director being garbage collected. 223 * <p> 224 * If this method results in removing this director from a container 225 * that is a Director, then this scheduler ceases to be the active 226 * scheduler for that CompositeActor. Moreover, if the director 227 * contains any other schedulers, then the most recently added of those 228 * schedulers becomes the active scheduler. 229 * <p> 230 * This method is write-synchronized 231 * to the workspace and increments its version number. 232 * @param container The proposed container. 233 * @exception IllegalActionException If the action would result in a 234 * recursive containment structure, or if 235 * this scheduler and container are not in the same workspace, or 236 * if the protected method _checkContainer() throws it. 237 * @exception NameDuplicationException If the name of this scheduler 238 * collides with a name already in the container. This will not 239 * be thrown if the container argument is an instance of 240 * CompositeActor. 241 */ 242 @Override 243 public void setContainer(NamedObj container) 244 throws IllegalActionException, NameDuplicationException { 245 try { 246 _workspace.getWriteAccess(); 247 248 Nameable oldContainer = getContainer(); 249 250 if (oldContainer instanceof Director && oldContainer != container) { 251 // Need to remove this scheduler as the active one of the 252 // old container. Search for another scheduler contained 253 // by the composite. If it contains more than one, 254 // use the most recently added one. 255 Scheduler previous = null; 256 StaticSchedulingDirector castContainer = (StaticSchedulingDirector) oldContainer; 257 Iterator schedulers = castContainer 258 .attributeList(Scheduler.class).iterator(); 259 260 while (schedulers.hasNext()) { 261 Scheduler altScheduler = (Scheduler) schedulers.next(); 262 263 // Since we haven't yet removed this director, we have 264 // to be sure to not just set it to the active 265 // director again. 266 if (altScheduler != this) { 267 previous = altScheduler; 268 } 269 } 270 271 castContainer._setScheduler(previous); 272 } 273 274 super.setContainer(container); 275 276 if (container instanceof StaticSchedulingDirector) { 277 // Set cached value in director 278 ((StaticSchedulingDirector) container)._setScheduler(this); 279 } 280 } finally { 281 _workspace.doneWriting(); 282 } 283 } 284 285 /** Validate/invalidate the current schedule by giving a 286 * true/false argument. A true argument will indicate that the 287 * current schedule is valid and can be returned immediately when 288 * schedule() is called without running the scheduling 289 * algorithm. A false argument will invalidate it. 290 * @param valid True to set the current schedule to valid. 291 */ 292 public void setValid(boolean valid) { 293 _valid = valid; 294 if (valid == false) { 295 _cachedGetSchedule = null; 296 } else { 297 _workspaceVersion = workspace().getVersion(); 298 } 299 } 300 301 /////////////////////////////////////////////////////////////////// 302 //// protected variables //// 303 304 /** The default name. 305 */ 306 protected static final String _DEFAULT_SCHEDULER_NAME = "Scheduler"; 307 308 /////////////////////////////////////////////////////////////////// 309 //// protected methods //// 310 311 /** Reschedule the model. In this base class, this method returns 312 * the actors contained by the CompositeActor in the order of 313 * their construction, i.e. the same order as returned by the 314 * CompositeActor.deepGetEntities() method. Derived classes 315 * should override this method to provide a domain-specific 316 * scheduling algorithm. This method is not intended to be 317 * called directly, but is called in turn by the getSchedule() 318 * method. This method is not synchronized on the workspace, because 319 * the getSchedule() method is. 320 * 321 * @return A Schedule of the deeply contained opaque entities 322 * in the firing order. 323 * @exception IllegalActionException If the scheduling algorithm 324 * throws it. Not thrown in this base class, but may be thrown 325 * by derived classes. 326 * @exception NotSchedulableException If the CompositeActor is not 327 * schedulable. Not thrown in this base class, but may be thrown 328 * by derived classes. 329 * @see ptolemy.kernel.CompositeEntity#deepEntityList() 330 */ 331 protected Schedule _getSchedule() 332 throws IllegalActionException, NotSchedulableException { 333 StaticSchedulingDirector director = (StaticSchedulingDirector) getContainer(); 334 CompositeActor compositeActor = (CompositeActor) director 335 .getContainer(); 336 List actors = compositeActor.deepEntityList(); 337 Schedule schedule = new Schedule(); 338 Iterator actorIterator = actors.iterator(); 339 340 while (actorIterator.hasNext()) { 341 Actor actor = (Actor) actorIterator.next(); 342 Firing firing = new Firing(); 343 firing.setActor(actor); 344 schedule.add(firing); 345 } 346 347 return schedule; 348 } 349 350 /////////////////////////////////////////////////////////////////// 351 //// private variables //// 352 353 // The cached schedule for getSchedule(). 354 private Schedule _cachedGetSchedule = null; 355 356 // The flag that indicate whether the current schedule is valid. 357 private boolean _valid = false; 358 359 // Workspace version when the last schedule was constructed. 360 private long _workspaceVersion = -1L; 361}