001/* A schedule element that contains a reference to a firing element. 002 003 Copyright (c) 2003-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.graph.sched; 029 030import java.util.ConcurrentModificationException; 031import java.util.Iterator; 032import java.util.LinkedList; 033import java.util.List; 034import java.util.Map; 035import java.util.NoSuchElementException; 036 037import ptolemy.kernel.util.InvalidStateException; 038 039/////////////////////////////////////////////////////////////////// 040//// Firing 041 042/** 043 This class is a ScheduleElement that contains a reference to a 044 firing element. The firingElement could be any Object. 045 This class is used together with the Schedule class to 046 construct a Schedule. The setFiringElement() method is used to create the 047 reference to a firing element. The getFiringElement() method will return a 048 reference to this firing element. 049 <p> 050 051 It is more efficient to use this class than to simply maintain a list of 052 firing elements since firing elements will often firing multiple times 053 consecutively. Using 054 this class (and the Schedule data structure in general) greatly reduces the 055 memory requirements of most large schedules. 056 057 @author Shahrooz Shahparnia, Mingyung Ko, 058 University of Maryland at College Park based on a file by 059 Brian K. Vogel, Steve Neuendorffer 060 @version $Id$ 061 @since Ptolemy II 4.0 062 @Pt.ProposedRating red (shahrooz) 063 @Pt.AcceptedRating red (ssb) 064 @see ptolemy.graph.sched.Firing 065 @see ptolemy.graph.sched.Schedule 066 @see ptolemy.graph.sched.ScheduleElement 067 */ 068public class Firing extends ScheduleElement { 069 /** Construct a firing with a default iteration count equal to one 070 * and with no parent schedule. 071 */ 072 public Firing() { 073 super(); 074 } 075 076 /** Construct a firing with a firingElement, an iteration count equal to one 077 * and no parent schedule. A Firing constructed using this constructor, 078 * using the setFiringElement() method, will only accept firing elements 079 * with the same class type as the given firingElement, using the 080 * setFiringElement() method. 081 * @param firingElement The firing element in the firing. 082 */ 083 public Firing(Object firingElement) { 084 super(firingElement.getClass()); 085 _firingElement = firingElement; 086 } 087 088 /** Construct a firing with a given firing element type, an iteration 089 * count equal to one and no parent schedule. 090 * In a Firing constructed using this constructor, the 091 * setFiringElement() method, will only accept firing elements 092 * with the same given class type, using the setFiringElement() method. 093 * @param firingElementClass The class of the firing element in the firing. 094 */ 095 public Firing(Class firingElementClass) { 096 super(firingElementClass); 097 } 098 099 /////////////////////////////////////////////////////////////////// 100 //// public methods //// 101 102 /** Return the firing element invocation sequence of the schedule in the 103 * form of a sequence of firing elements. For a valid schedule, all of the 104 * lowest-level nodes should be an instance of Firing. If the 105 * schedule is not valid, then the returned iterator will contain 106 * null elements. 107 * <p> 108 * A runtime exception is thrown if the underlying schedule structure 109 * is modified while the iterator is active. 110 * 111 * @return An iterator over a sequence of firing elements. 112 * @exception ConcurrentModificationException If the 113 * underlying schedule structure is modified while the iterator 114 * is active. 115 */ 116 @Override 117 public Iterator firingElementIterator() { 118 return new FiringElementIterator(); 119 } 120 121 /** Return the firing element invocation sequence in the form 122 * of a sequence of firings. 123 * Since this ScheduleElement is a Firing, the 124 * iterator returned will contain exactly one Firing (this Firing). 125 * <p> 126 * A runtime exception is thrown if the 127 * underlying schedule structure is modified while the iterator 128 * is active. 129 * 130 * @return An iterator over a sequence of firings. 131 * @exception ConcurrentModificationException If the 132 * underlying schedule structure is modified while the iterator 133 * is active. 134 */ 135 @Override 136 public Iterator firingIterator() { 137 // FIXME: a ConcurrentModificationException will not necessarily 138 // be thrown, see the failing tests. 139 if (_firing == null) { 140 _firing = new LinkedList(); 141 _firing.add(this); 142 } 143 144 return _firing.iterator(); 145 } 146 147 /** Get the firing element associated with this Firing. The 148 * setFiringElement() method is used to set the firing element that this 149 * method returns. 150 * If setFiringElement() was never called, then throw an exception. 151 * 152 * @return The actor associated with this Firing. 153 * @see #setFiringElement(Object) 154 */ 155 public Object getFiringElement() { 156 // FIXME: the exception is never thrown in the original version 157 return _firingElement; 158 } 159 160 /** Set the firing element associated with this firing. This firing element 161 * will then be returned when the getFiringElement() method is invoked. 162 * If this firing already contains a reference to a firing element, 163 * then the reference will overwritten. 164 * 165 * @param firingElement The firing element to associate with this firing. 166 * @see #getFiringElement() 167 */ 168 public void setFiringElement(Object firingElement) { 169 if (this.firingElementClass() != null) { 170 if (this.firingElementClass() 171 .isAssignableFrom(firingElement.getClass())) { 172 _incrementVersion(); 173 _firingElement = firingElement; 174 175 if (_firing != null) { 176 _firing.clear(); 177 _firing.add(this); 178 } 179 } else { 180 throw new RuntimeException( 181 "Attempt to add a non " + "authorized firing element"); 182 } 183 } else { 184 _incrementVersion(); 185 _firingElement = firingElement; 186 187 if (_firing != null) { 188 _firing.clear(); 189 _firing.add(this); 190 } 191 } 192 } 193 194 /** Print the firing in a parenthesis style. 195 * 196 * @param nameMap A mapping from firing element to its short name. 197 * @param delimiter The delimiter between iteration count and iterand. 198 * @return The parenthesis expression for this firing. 199 */ 200 @Override 201 public String toParenthesisString(Map nameMap, String delimiter) { 202 String name = (String) nameMap.get(getFiringElement()); 203 int iterations = getIterationCount(); 204 205 if (iterations > 1) { 206 return "(" + iterations + delimiter + name + ")"; 207 } else { 208 return name; 209 } 210 } 211 212 /** Return a string representation of this Firing. 213 * 214 * @return Return a string representation of this Firing. 215 */ 216 @Override 217 public String toString() { 218 String result = "Fire firing element " + _firingElement; 219 220 if (getIterationCount() > 1) { 221 result += " " + getIterationCount() + " times"; 222 } 223 224 return result; 225 } 226 227 /////////////////////////////////////////////////////////////////// 228 //// inner classes //// 229 230 /** An adapter class for iterating over the elements of this 231 * schedule. An exception is thrown if the schedule structure 232 * changes while this iterator is active. 233 */ 234 private class FiringElementIterator implements Iterator { 235 // As of 8/02, it seems like this inner class is not really 236 // used except by the test suite. 237 238 /** Construct a ScheduleIterator. 239 */ 240 public FiringElementIterator() { 241 _startingVersion = _getVersion(); 242 _currentElement = 0; 243 } 244 245 /** Return true if the iteration has more elements. 246 * @exception ConcurrentModificationException If the schedule 247 * data structure has changed since this iterator 248 * was created. 249 * @return True if the iterator has more elements. 250 */ 251 @Override 252 public boolean hasNext() { 253 if (_startingVersion != _getVersion()) { 254 throw new ConcurrentModificationException( 255 "Schedule structure changed while iterator is active."); 256 } else { 257 return _currentElement <= getIterationCount(); 258 } 259 } 260 261 /** Return the next object in the iteration. 262 * 263 * @exception InvalidStateException If the schedule 264 * data structure has changed since this iterator 265 * was created. 266 * @return The next object in the iteration. 267 */ 268 @Override 269 public Object next() throws NoSuchElementException { 270 if (!hasNext()) { 271 throw new NoSuchElementException("No element to return."); 272 } else if (_startingVersion != _getVersion()) { 273 throw new ConcurrentModificationException( 274 "Schedule structure changed while iterator is active."); 275 } else { 276 _currentElement++; 277 return getFiringElement(); 278 } 279 } 280 281 /** Throw an exception, since removal is not allowed. It really 282 * doesn't make sense to remove an actor from an actor invocation 283 * sequence anyway. 284 */ 285 @Override 286 public void remove() { 287 throw new UnsupportedOperationException(); 288 } 289 290 private long _startingVersion; 291 292 private int _currentElement; 293 } 294 295 /////////////////////////////////////////////////////////////////// 296 //// private variables //// 297 // The firing element associated with this firing. 298 private Object _firingElement; 299 300 // The list containing this firing as the only element. 301 private List _firing = null; 302}