1classdef JobClass < NetworkElement
2 % An abstract
class for a collection of indistinguishable jobs
4 % Copyright (c) 2012-2026, Imperial College London
9 deadline; % relative deadline from arrival (Inf = no deadline)
10 refstat; % reference station
11 isrefclass; %
is this a reference
class within a chain?
14 completes; %
true if passage through reference station
is a completion
15 replySignalClass; % Signal
class that will unblock servers waiting for reply (for synchronous call semantics)
16 patience; % Global patience distribution
for this class (customers abandon queues after patience time)
17 impatienceType; % Global impatience type
for this class (ImpatienceType.RENEGING or ImpatienceType.BALKING)
18 immediateFeedback; % Boolean:
true if this class uses immediate feedback on self-loops globally
23 function self = JobClass(type, name)
24 % SELF = JOBCLASS(TYPE, NAME)
26 self@NetworkElement(name);
29 self.refstat = Node(
'Unallocated');
30 self.isrefclass =
false;
33 self.completes =
true;
34 self.replySignalClass = [];
36 self.impatienceType = [];
37 self.immediateFeedback =
false;
40 function self = setReferenceStation(self, source)
41 % SELF = SETREFERENCESTATION(SOURCE)
43 self.refstat = source;
46 function self = setReferenceClass(self,
bool)
47 % SELF = SETREFERENCECLASS(BOOL)
48 self.isrefclass = bool;
51 function boolIsa = isReferenceStation(self, node)
52 % BOOLISA = ISREFERENCESTATION(NODE)
54 boolIsa = strcmp(self.refstat.name,node.name);
57 function boolIsa = isReferenceClass(self)
58 % BOOLISA = ISREFERENCECLASS()
60 boolIsa = self.isrefclass;
63 % function self = set.priority(self, priority)
64 % SELF = SET.PRIORITY(PRIORITY)
66 % if ~(rem(priority,1) == 0 && priority >= 0)
67 % line_error(mfilename,'Priority must be an integer.\n');
69 % self.priority = priority;
73 methods (Access=public)
74 function ind = subsindex(self)
77 ind =
double(self.index)-1; % 0 based
80 function summary(self)
82 line_printf('Class (%s): <strong>%s</strong>',self.type,self.getName);
85 function self = setReplySignalClass(self, replyClass)
86 % SETREPLYSIGNALCLASS Set the Signal class for synchronous call reply
88 % self = SETREPLYSIGNALCLASS(self, replyClass) configures this job
89 % class to expect a reply signal from the specified Signal class.
90 % When a job of this class completes service, the server will block
91 % until receiving a REPLY signal from the specified class.
93 % This implements LQN-style synchronous call semantics where a
94 % client sends a request, blocks waiting for a reply, and then
95 % continues processing after the reply arrives.
97 % @param replyClass Signal
object with SignalType.REPLY that will unblock the server
98 % @return self The modified JobClass instance
100 if ~isa(replyClass, 'Signal')
101 line_error(mfilename, 'Reply class must be a Signal.');
103 if replyClass.signalType ~= SignalType.REPLY
104 line_error(mfilename, 'Reply class must have SignalType.REPLY.');
106 self.replySignalClass = replyClass;
109 function idx = getReplySignalClassIndex(self)
110 % GETREPLYSIGNALCLASSINDEX Get the index of the reply signal class
112 % idx = GETREPLYSIGNALCLASSINDEX(self) returns the index of the
113 % Signal class that will unblock servers waiting for this class,
114 % or -1 if no reply
is expected.
116 % @return idx Index of reply signal class, or -1 if none
118 if isempty(self.replySignalClass)
121 idx = self.replySignalClass.index;
125 function tf = expectsReply(self)
126 % EXPECTSREPLY Check if this class expects a reply signal
128 % tf = EXPECTSREPLY(self) returns true if this class has been
129 % configured to expect a reply signal (via setReplySignalClass).
131 % @return tf True if a reply signal
is expected
133 tf = ~isempty(self.replySignalClass);
136 function self = setPatience(self, varargin)
137 % SELF = SETPATIENCE(DISTRIBUTION) - Backwards compatible
138 % SELF = SETPATIENCE(IMPATIENCETYPE, DISTRIBUTION) - Explicit type
140 % Sets the global impatience type and distribution for this job class.
141 % This applies to all queues unless overridden by queue-specific settings.
144 % impatienceType - (Optional) ImpatienceType constant (RENEGING or BALKING)
145 % If omitted, defaults to ImpatienceType.RENEGING
146 % distribution - Any LINE distribution (Exp, Erlang, HyperExp, etc.)
147 % excluding modulated processes (BMAP, MAP, MMPP2)
150 %
jobclass.setPatience(Exp(0.1)) % Defaults to RENEGING
151 %
jobclass.setPatience(ImpatienceType.RENEGING, Exp(0.1))
152 %
jobclass.setPatience(ImpatienceType.BALKING, Det(5.0))
154 % Handle backwards compatibility: 1 or 2 arguments
155 if length(varargin) == 1
156 % Old signature: setPatience(distribution)
157 distribution = varargin{1};
158 impatienceType = ImpatienceType.RENEGING; % Default to RENEGING
159 elseif length(varargin) == 2
160 % New signature: setPatience(impatienceType, distribution)
161 impatienceType = varargin{1};
162 distribution = varargin{2};
164 line_error(mfilename,
'Invalid number of arguments. Use setPatience(distribution) or setPatience(impatienceType, distribution)');
167 if isa(distribution,
'BMAP') || isa(distribution,
'MAP') || isa(distribution,
'MMPP2')
168 line_error(mfilename, 'Modulated processes (BMAP, MAP, MMPP2) are not supported for patience distributions.');
171 % Validate impatience type
172 if impatienceType ~= ImpatienceType.RENEGING && impatienceType ~= ImpatienceType.BALKING
173 line_error(mfilename, 'Invalid impatience type. Use ImpatienceType.RENEGING or ImpatienceType.BALKING.');
176 % Only RENEGING
is currently supported
177 if impatienceType == ImpatienceType.BALKING
178 line_error(mfilename, 'BALKING impatience type
is not yet supported. Use ImpatienceType.RENEGING.');
182 self.patience = distribution;
183 self.impatienceType = impatienceType;
185 self.obj.setPatience(impatienceType, distribution.obj);
189 function distribution = getPatience(self)
190 % DISTRIBUTION = GETPATIENCE()
192 % Returns the global patience distribution for this job class.
195 % distribution - The patience distribution, or [] if not set
198 if ~isempty(self.patience)
199 distribution = self.patience;
204 distObj = self.obj.getPatience();
208 % Convert Java
object to MATLAB Distribution
209 distribution = Distribution.fromJavaObject(distObj);
214 function impatienceType = getImpatienceType(self)
215 % IMPATIENCETYPE = GETIMPATIENCETYPE()
217 % Returns the global impatience type for this job class.
220 % impatienceType - The impatience type (ImpatienceType constant), or [] if not set
223 if ~isempty(self.impatienceType)
224 impatienceType = self.impatienceType;
229 impatienceTypeObj = self.obj.getImpatienceType();
230 if isempty(impatienceTypeObj)
233 impatienceType = ImpatienceType.fromId(impatienceTypeObj.getID());
238 function tf = hasPatience(self)
241 % Returns true if this class has a patience distribution set.
243 dist = self.getPatience();
244 tf = ~isempty(dist) && ~isa(dist, 'Disabled');
247 function self = setImmediateFeedback(self, value)
248 % SETIMMEDIATEFEEDBACK Set immediate feedback for self-loops
250 % SETIMMEDIATEFEEDBACK(true) enables immediate feedback for this class globally
251 % SETIMMEDIATEFEEDBACK(false) disables immediate feedback for this class
253 % When enabled, a job of this class that self-loops at any station stays
254 % in service instead of going back to the queue.
257 self.immediateFeedback = logical(value);
259 self.obj.setImmediateFeedback(logical(value));
263 function tf = hasImmediateFeedback(self)
264 % HASIMMEDIATEFEEDBACK Check if immediate feedback
is enabled
266 % TF = HASIMMEDIATEFEEDBACK() returns true if immediate feedback
is enabled
269 tf = self.immediateFeedback;
271 tf = self.obj.hasImmediateFeedback();