| 1 | package desmoj.core.simulator; |
| 2 | |
| 3 | import java.util.Enumeration; |
| 4 | import java.util.Vector; |
| 5 | |
| 6 | /** |
| 7 | * A <code>ComplexSimProcess</code> is a <code>SimProcess</code> which |
| 8 | * serves as a container for other <code>SimProcess</code> es. A |
| 9 | * <code>ComplexSimProcess</code> has its own lifecycle. As long as this |
| 10 | * <code>ComplexSimProcess</code> is active all its contained Simprocesses are |
| 11 | * passive. That means they are blocked and can not proceed in their lifeCycles. |
| 12 | * |
| 13 | * @version DESMO-J, Ver. 2.3.3 copyright (c) 2011 |
| 14 | * @author Soenke Claassen |
| 15 | * |
| 16 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 17 | * you may not use this file except in compliance with the License. You |
| 18 | * may obtain a copy of the License at |
| 19 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 20 | * |
| 21 | * Unless required by applicable law or agreed to in writing, software |
| 22 | * distributed under the License is distributed on an "AS IS" |
| 23 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| 24 | * or implied. See the License for the specific language governing |
| 25 | * permissions and limitations under the License. |
| 26 | * |
| 27 | */ |
| 28 | public abstract class ComplexSimProcess extends SimProcess { |
| 29 | |
| 30 | /** |
| 31 | * The <code>Vector</code> holding all the sim-processes which are |
| 32 | * contained in this ComplexSimProcess. |
| 33 | */ |
| 34 | private Vector<SimProcess> _components; |
| 35 | |
| 36 | /** |
| 37 | * Constructs a ComplexSimProcess. |
| 38 | * |
| 39 | * @param owner |
| 40 | * desmoj.Model : The model this ComplexSimProcess is associated |
| 41 | * to. |
| 42 | * @param name |
| 43 | * java.lang.String : The name of this ComplexSimProcess. |
| 44 | * @param showInTrace |
| 45 | * boolean : Flag for showing trace messages of this |
| 46 | * ComplexSimProcess in trace-files. Set it to <code>true</code> |
| 47 | * if ComplexSimProcess should show up in trace. Set it to |
| 48 | * <code>false</code> if ComplexSimProcess should not be shown |
| 49 | * in trace. |
| 50 | */ |
| 51 | public ComplexSimProcess(Model owner, String name, boolean showInTrace) { |
| 52 | |
| 53 | super(owner, name, showInTrace); // make a sim-process |
| 54 | |
| 55 | // make a new Vector to store all the components in |
| 56 | _components = new Vector<SimProcess>(); |
| 57 | |
| 58 | // this ComplexSimProcess is not contained in any other |
| 59 | // ComplexSimProcess yet |
| 60 | setSupervisor(null); |
| 61 | } |
| 62 | |
| 63 | /** |
| 64 | * Adds a sim-process as a component to this ComplexSimProcess. The |
| 65 | * Sim-process being added to the ComplexSimProcess will be passivated and |
| 66 | * blocked. Use method <code>removeComponent()</code> to remove the |
| 67 | * Sim-process from the ComplexSimProcess again. |
| 68 | * |
| 69 | * @param compnt |
| 70 | * desmoj.SimProcess : The sim-process to be added as a component |
| 71 | * to this ComplexSimProcess. |
| 72 | */ |
| 73 | public synchronized void addComponent(SimProcess compnt) { |
| 74 | |
| 75 | // check the given SimProcess |
| 76 | if (compnt == null) // if compnt is a null pointer instead of a process |
| 77 | { |
| 78 | sendWarning("Attempt to add a non existing process to a " |
| 79 | + "ComplexSimProcess. The attempted action is ignored!", |
| 80 | "ComplexSimProcess: " + getName() |
| 81 | + " Method: synchronized void" |
| 82 | + " addComponent(SimProcess compnt)", |
| 83 | "The given SimProcess is only a null pointer.", |
| 84 | "Make sure that only real SimProcesses are added to a " |
| 85 | + "ComplexSimProcess."); |
| 86 | |
| 87 | return; // ignore that rubbish |
| 88 | } |
| 89 | |
| 90 | if (!isModelCompatible(compnt)) // if compnt is not modelcompatible |
| 91 | { |
| 92 | sendWarning( |
| 93 | "The process trying to be added to a ComplexSimProcess does " |
| 94 | + "not belong to this model. The attempted action is ignored!", |
| 95 | "ComplexSimProcess: " + getName() |
| 96 | + " Method: synchronized void" |
| 97 | + " addComponent(SimProcess compnt)", |
| 98 | "The given process belongs to model " |
| 99 | + compnt.getModel().getQuotedName() |
| 100 | + " and therefore is not modelcompatible.", |
| 101 | "Make sure that the processes to be added to a ComplexSimProcess belong " |
| 102 | + "to the same model or overwrite the method " |
| 103 | + "<code>isModelCompatible()</code>"); |
| 104 | |
| 105 | return; // ignore that rubbish |
| 106 | } |
| 107 | |
| 108 | // the Simprocess component must not be contained twice in the container |
| 109 | if (_components.contains(compnt)) { |
| 110 | sendWarning( |
| 111 | "Attempt to add a process to a ComplexSimProcess twice. " |
| 112 | + "The attempted action is ignored!", |
| 113 | "ComplexSimProcess: " + getName() |
| 114 | + " Method: synchronized void" |
| 115 | + " addComponent(SimProcess compnt)", |
| 116 | "The given SimProcess is already a component of this " |
| 117 | + "ComplexSimProcess.", |
| 118 | "Make sure the sim-process is not contained in the " |
| 119 | + "ComplexSimProcess already."); |
| 120 | return; |
| 121 | } |
| 122 | |
| 123 | // the sim-process to be added to a ComplexSimProcess should be active or |
| 124 | // passivated but not scheduled. Just in case it is scheduled, cancel |
| 125 | // that |
| 126 | if (compnt.isScheduled()) { |
| 127 | sendWarning( |
| 128 | "The sim-process added to a ComplexSimProcess is scheduled! " |
| 129 | + "The scheduled activation of the sim-process will be " |
| 130 | + "cancelled.", |
| 131 | "ComplexSimProcess: " + getName() |
| 132 | + " Method: synchronized void" |
| 133 | + " addComponent(SimProcess compnt)", |
| 134 | "A sim-process added to a ComplexSimProcess is giving up its " |
| 135 | + "own lifeCycle and therefore should not be scheduled anymore." |
| 136 | + " It will be carried on by the lifeCycle of the " |
| 137 | + "ComplexSimProcess.", |
| 138 | "Make sure that the sim-process is either adding itself to a " |
| 139 | + "ComplexSimProcess or that the sim-process is passive."); |
| 140 | |
| 141 | compnt.skipTraceNote(); |
| 142 | compnt.cancel(); |
| 143 | } |
| 144 | |
| 145 | // set the supervisor of the sim-process added |
| 146 | compnt.setSupervisor(this); |
| 147 | |
| 148 | // the component SimProcess is blocked |
| 149 | compnt.setBlocked(true); |
| 150 | |
| 151 | // add the new SimProcess component to the components Vector |
| 152 | _components.addElement(compnt); |
| 153 | |
| 154 | // trace output |
| 155 | if (currentlySendTraceNotes()) { |
| 156 | sendTraceNote("adds " + compnt.getQuotedName() |
| 157 | + " as a component to " + this.getQuotedName()); |
| 158 | } |
| 159 | |
| 160 | // debug output |
| 161 | if (currentlySendDebugNotes()) { |
| 162 | sendDebugNote("adds " + compnt.getQuotedName() |
| 163 | + " to its components." + "it now looks like <br>" |
| 164 | + this.toString()); |
| 165 | } |
| 166 | |
| 167 | // either the component SimProcess is adding itself to the |
| 168 | // ComplexSimProcess |
| 169 | // or it is passive already |
| 170 | if (currentSimProcess() == compnt) // adds itself to the complex |
| 171 | { |
| 172 | compnt.skipTraceNote(); // don't tell the user, that we ... |
| 173 | compnt.passivate(); // passivate the component process |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | /** |
| 178 | * Checks if the given SimProcess is contained in this ComplexSimProcess |
| 179 | * already. |
| 180 | * |
| 181 | * @return boolean :<code>true</code> if and only if the specified |
| 182 | * SimProcess is the same as a component in this ComplexSimProcess, |
| 183 | * as determined by the <code>equals()</code> method; |
| 184 | * <code>false</code> otherwise. |
| 185 | * @param elem |
| 186 | * desmoj.SimProcess : The sim-process which might be an element |
| 187 | * of this ComplexSimPorcess already. |
| 188 | * @see java.util.Vector |
| 189 | */ |
| 190 | public synchronized boolean contains(SimProcess elem) { |
| 191 | |
| 192 | // forward to the internal Vector |
| 193 | return _components.contains(elem); |
| 194 | } |
| 195 | |
| 196 | /** |
| 197 | * Returns all the components of this ComplexSimProcess as an |
| 198 | * <code>java.util.Enumeration</code>. |
| 199 | * |
| 200 | * @return java.util.Enumeration : All the components of this |
| 201 | * ComplexSimProcess. |
| 202 | * @see java.util.Enumeration |
| 203 | */ |
| 204 | public synchronized Enumeration<SimProcess> getComponents() { |
| 205 | |
| 206 | return _components.elements(); |
| 207 | } |
| 208 | |
| 209 | /** |
| 210 | * Checks if this ComplexSimProcess has components or not. |
| 211 | * |
| 212 | * @return boolean :<code>true</code> if and only if this |
| 213 | * ComplexSimProcess has components; <code>false</code> otherwise. |
| 214 | */ |
| 215 | public boolean hasComponents() { |
| 216 | |
| 217 | // forward to the internal Vector |
| 218 | return (!_components.isEmpty()); |
| 219 | } |
| 220 | |
| 221 | /** |
| 222 | * Override this method in a subclass of <code>ComplexSimProcess</code> to |
| 223 | * implement the specific behaviour of this process. This method starts |
| 224 | * after a <code>ComplexSimProcess</code> has been created and activated |
| 225 | * by the scheduler. As long as this <code>ComplexSimProcess</code> is |
| 226 | * active all its contained Simprocesses are passive. That means they are |
| 227 | * blocked and can not proceed in their lifeCycles. |
| 228 | */ |
| 229 | public abstract void lifeCycle(); |
| 230 | |
| 231 | /** |
| 232 | * Removes all elements (SimProcesses and ComplexSimProcesses) from this |
| 233 | * ComplexSimProcess. This will be done for all ComplexSimPorcesses |
| 234 | * recursively, until all simple SimProcesses are removed. The sim-processes |
| 235 | * being removed from the ComplexSimProcess will be activated after the |
| 236 | * current SimProcess so they can follow their own lifeCycle again. Of |
| 237 | * course, this does only make sense for SimProcesses which are not |
| 238 | * terminated already. |
| 239 | */ |
| 240 | public synchronized void removeAllComponents() { |
| 241 | |
| 242 | // loop through all elements |
| 243 | for (Enumeration<?> e = getComponents(); e.hasMoreElements();) { |
| 244 | // buffer the current element |
| 245 | SimProcess elem = (SimProcess) e.nextElement(); |
| 246 | |
| 247 | // reset the supervisor of the sim-process element removed |
| 248 | elem.setSupervisor(null); |
| 249 | |
| 250 | // the sim-process element is not blocked anymore |
| 251 | elem.setBlocked(false); |
| 252 | |
| 253 | // activate the removed SimProcess (if it is not terminated yet) |
| 254 | if (!elem.isTerminated()) { |
| 255 | elem.skipTraceNote(); // don't tell the user, that we ... |
| 256 | elem.activateAfter(currentSimProcess()); // activate the |
| 257 | // process |
| 258 | // elem again |
| 259 | } |
| 260 | |
| 261 | // if this ComplexSimProcess contains other ComplexSimProcesses |
| 262 | // remove them also |
| 263 | if (elem instanceof ComplexSimProcess) { |
| 264 | ((ComplexSimProcess) elem).removeAllComponents(); |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | // remove the all the sim-process elements from the components Vector |
| 269 | _components.removeAllElements(); |
| 270 | |
| 271 | // trace output |
| 272 | if (currentlySendTraceNotes()) { |
| 273 | sendTraceNote("removes all elements from " + this.getQuotedName()); |
| 274 | } |
| 275 | |
| 276 | // debug output |
| 277 | if (currentlySendDebugNotes()) { |
| 278 | sendDebugNote("removes all its elements."); |
| 279 | } |
| 280 | |
| 281 | } |
| 282 | |
| 283 | /** |
| 284 | * Removes a sim-process from the elements of this ComplexSimProcess. The |
| 285 | * Sim-process being removed from the ComplexSimProcess will be activated |
| 286 | * after the current SimProcess so it can follow its own lifeCycle again. |
| 287 | * |
| 288 | * @param elem |
| 289 | * desmoj.SimProcess : The sim-process to be removed from the |
| 290 | * elements of this ComplexSimProcess. Be careful, it might also |
| 291 | * be a <code>ComplexSimProcess</code>. |
| 292 | */ |
| 293 | public synchronized void removeComponent(SimProcess elem) { |
| 294 | |
| 295 | // check the given SimProcess |
| 296 | if (elem == null) // if elem is a null pointer instead of a process |
| 297 | { |
| 298 | sendWarning("Attempt to remove a non existing process from a " |
| 299 | + "ComplexSimProcess. The attempted action is ignored!", |
| 300 | "ComplexSimProcess: " + getName() |
| 301 | + " Method: synchronized void" |
| 302 | + "removeComponent(SimProcess elem)", |
| 303 | "The given SimProcess is only a null pointer.", |
| 304 | "Make sure to remove only SimProcesses that are contained in this " |
| 305 | + "ComplexSimProcess."); |
| 306 | |
| 307 | return; // ignore that rubbish |
| 308 | } |
| 309 | |
| 310 | // the sim-process component must be contained in the container |
| 311 | if (!_components.contains(elem)) { |
| 312 | sendWarning( |
| 313 | "Attempt to remove a process which is not an element of this " |
| 314 | + "ComplexSimProcess. The attempted action is ignored!", |
| 315 | "ComplexSimProcess: " + getName() |
| 316 | + " Method: synchronized void" |
| 317 | + "removeComponent(SimProcess elem)", |
| 318 | "The given SimProcess is not a component of this " |
| 319 | + "ComplexSimProcess.", |
| 320 | "Make sure to remove only SimProcesses that are contained in " |
| 321 | + "this ComplexSimProcess."); |
| 322 | return; |
| 323 | } |
| 324 | |
| 325 | // reset the supervisor of the sim-process element removed |
| 326 | elem.setSupervisor(null); |
| 327 | |
| 328 | // remove the sim-process element from the components Vector |
| 329 | _components.remove(elem); |
| 330 | |
| 331 | // the sim-process element is not blocked anymore |
| 332 | elem.setBlocked(false); |
| 333 | |
| 334 | // activate the removed SimProcess (if it is not terminated yet) |
| 335 | if (!elem.isTerminated()) { |
| 336 | elem.skipTraceNote(); // don't tell the user, that we ... |
| 337 | elem.activateAfter(currentSimProcess()); // activate the process |
| 338 | // elem again |
| 339 | } |
| 340 | |
| 341 | // trace output |
| 342 | if (currentlySendTraceNotes()) { |
| 343 | sendTraceNote("removes " + elem.getQuotedName() + " from " |
| 344 | + this.getQuotedName()); |
| 345 | } |
| 346 | |
| 347 | // debug output |
| 348 | if (currentlySendDebugNotes()) { |
| 349 | sendDebugNote("removes " + elem.getQuotedName() |
| 350 | + " from its elements." + "it now looks like <br>" |
| 351 | + this.toString()); |
| 352 | } |
| 353 | |
| 354 | } |
| 355 | |
| 356 | /** |
| 357 | * Returns a <code>String</code> representation of this ComplexSimProcess, |
| 358 | * containing the <code>String</code> representation of each |
| 359 | * <code>SimProcess</code> component. |
| 360 | * |
| 361 | * @return java.lang.String : A <code>String</code> representation of this |
| 362 | * ComplexSimProcess. |
| 363 | */ |
| 364 | public String toString() { |
| 365 | |
| 366 | StringBuffer stringOfElems = new StringBuffer(); |
| 367 | |
| 368 | stringOfElems.append(this.getQuotedName() + " consists of : "); |
| 369 | |
| 370 | // make the String by collecting the Strings from all elements |
| 371 | if (!hasComponents()) { |
| 372 | stringOfElems.append("nothing else."); |
| 373 | } else { |
| 374 | // loop through all elements |
| 375 | for (Enumeration<?> e = getComponents(); e.hasMoreElements();) { |
| 376 | stringOfElems.append(((SimProcess) e.nextElement()) |
| 377 | .getQuotedName()); |
| 378 | |
| 379 | if (e.hasMoreElements()) { |
| 380 | stringOfElems.append(", "); |
| 381 | } else { |
| 382 | stringOfElems.append("."); |
| 383 | } |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | return stringOfElems.toString(); |
| 388 | } |
| 389 | } |