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 | } |