blob: 1965c43f2512bdf9529540cad084c7a59512dadb [file] [log] [blame]
jaegonkim6a7b5242018-09-12 23:09:42 +09001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.workflow.api;
17
18import com.google.common.base.MoreObjects;
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.ImmutableSet;
21import com.google.common.collect.Lists;
22import com.google.common.collect.Sets;
23import org.onlab.osgi.DefaultServiceDirectory;
24import org.onlab.osgi.ServiceNotFoundException;
25
26import java.lang.reflect.Modifier;
27import java.net.URI;
jaegonkim4064ed12019-05-18 11:34:45 +090028import java.util.ArrayList;
jaegonkim6a7b5242018-09-12 23:09:42 +090029import java.util.List;
30import java.util.Objects;
31import java.util.Set;
32
jaegonkime0f45b52018-10-09 20:23:26 +090033import static org.onosproject.workflow.api.CheckCondition.check;
34
jaegonkim6a7b5242018-09-12 23:09:42 +090035/**
36 * Class for immutable list workflow.
37 */
38public final class ImmutableListWorkflow extends AbstractWorkflow {
39
40 /**
41 * Init worklet type(class name of init worklet type).
42 */
43 private String initWorkletType;
44
45 /**
jaegonkim4064ed12019-05-18 11:34:45 +090046 * Sequential program(List of worklet desc) to be executed.
jaegonkim6a7b5242018-09-12 23:09:42 +090047 */
jaegonkim4064ed12019-05-18 11:34:45 +090048 private List<WorkletDescription> program;
jaegonkim6a7b5242018-09-12 23:09:42 +090049
50 /**
51 * Set of workflow attributes.
52 */
53 private Set<WorkflowAttribute> attributes;
54
jaegonkime0f45b52018-10-09 20:23:26 +090055 private static JsonDataModelInjector dataModelInjector = new JsonDataModelInjector();
m.rahil09251882019-04-15 22:58:33 +053056 private static StaticDataModelInjector staticDataModelInjector = new StaticDataModelInjector();
jaegonkime0f45b52018-10-09 20:23:26 +090057
jaegonkim6a7b5242018-09-12 23:09:42 +090058 /**
Sanjana Venkatachalamfc25e872022-04-17 23:15:30 +053059 * Workflow Logger injector.
60 */
61 private WorkflowLoggerInjector workflowLoggerInjector = new WorkflowLoggerInjector();
62
63 /**
jaegonkim6a7b5242018-09-12 23:09:42 +090064 * Constructor of ImmutableListWorkflow.
mohamedrahilr63a921c2019-02-27 19:48:25 +053065 *
jaegonkim6a7b5242018-09-12 23:09:42 +090066 * @param builder builder of ImmutableListWorkflow
67 */
68 private ImmutableListWorkflow(Builder builder) {
69 super(builder.id);
70 this.initWorkletType = builder.initWorkletType;
jaegonkim4064ed12019-05-18 11:34:45 +090071 program = ImmutableList.copyOf(builder.workletDescList);
jaegonkim6a7b5242018-09-12 23:09:42 +090072 attributes = ImmutableSet.copyOf(builder.attributes);
73 }
74
75 @Override
76 public Worklet init(WorkflowContext context) throws WorkflowException {
77 if (Objects.isNull(initWorkletType)) {
78 return null;
79 }
80
81 return getWorkletInstance(initWorkletType);
82 }
83
jaegonkim6a7b5242018-09-12 23:09:42 +090084 @Override
jaegonkime0f45b52018-10-09 20:23:26 +090085 public ProgramCounter next(WorkflowContext context) throws WorkflowException {
jaegonkim6a7b5242018-09-12 23:09:42 +090086
87 int cnt = 0;
jaegonkime0f45b52018-10-09 20:23:26 +090088
jaegonkimf85ee3c2019-04-21 11:10:25 +090089 ProgramCounter current = context.current();
90 check(current != null, "Invalid program counter");
jaegonkime0f45b52018-10-09 20:23:26 +090091
jaegonkimf85ee3c2019-04-21 11:10:25 +090092 ProgramCounter pc = current.clone();
93
jaegonkim4064ed12019-05-18 11:34:45 +090094 for (int i = current.workletIndex(); i < program.size(); pc = increased(pc), i++) {
jaegonkim6a7b5242018-09-12 23:09:42 +090095
96 if (cnt++ > Worklet.MAX_WORKS) {
97 throw new WorkflowException("Maximum worklet execution exceeded");
98 }
jaegonkimf85ee3c2019-04-21 11:10:25 +090099 if (pc.isCompleted()) {
100 return pc;
jaegonkim6a7b5242018-09-12 23:09:42 +0900101 }
102
jaegonkimf85ee3c2019-04-21 11:10:25 +0900103 if (pc.isInit()) {
jaegonkim6a7b5242018-09-12 23:09:42 +0900104 continue;
105 }
106
jaegonkimf85ee3c2019-04-21 11:10:25 +0900107 Worklet worklet = getWorkletInstance(pc);
jaegonkim6a7b5242018-09-12 23:09:42 +0900108 Class workClass = worklet.getClass();
109
110 if (BranchWorklet.class.isAssignableFrom(workClass)) {
111 Class nextClass = ((BranchWorklet) worklet).next(context);
112 if (nextClass == null) {
113 throw new WorkflowException("Invalid next Worklet for " + workClass);
114 }
115
116 // TODO : it does not support duplicated use of WorkType. It needs to consider label concept
117 int nextIdx = getClassIndex(nextClass);
118 if (nextIdx == -1) {
119 throw new WorkflowException("Failed to find next " + nextClass + " for " + workClass);
120 }
121
122 i = nextIdx;
123 continue;
124
125 } else {
Sanjana Venkatachalamfc25e872022-04-17 23:15:30 +0530126 workflowLoggerInjector.inject(worklet, context);
jaegonkime0f45b52018-10-09 20:23:26 +0900127 // isNext is read only. It does not perform 'inhale'.
128 dataModelInjector.inject(worklet, context);
m.rahil09251882019-04-15 22:58:33 +0530129 WorkletDescription workletDesc = getWorkletDesc(pc);
130 if (Objects.nonNull(workletDesc)) {
131 if (!(workletDesc.tag().equals("INIT") || workletDesc.tag().equals("COMPLETED"))) {
132 staticDataModelInjector.inject(worklet, workletDesc);
133 }
134 }
senthilfdedda82024-02-17 21:22:27 +0900135 if (worklet.needsProcess(context)) {
jaegonkimf85ee3c2019-04-21 11:10:25 +0900136 return pc;
jaegonkim6a7b5242018-09-12 23:09:42 +0900137 }
138 }
139 }
jaegonkimf85ee3c2019-04-21 11:10:25 +0900140 throw new WorkflowException("workflow reached to end but not COMPLETED (pc:"
141 + current + ", workflow:" + this.toString());
jaegonkime0f45b52018-10-09 20:23:26 +0900142 }
143
144 @Override
145 public ProgramCounter increased(ProgramCounter pc) throws WorkflowException {
146
147 int increaedIndex = pc.workletIndex() + 1;
jaegonkim4064ed12019-05-18 11:34:45 +0900148 if (increaedIndex >= program.size()) {
jaegonkime0f45b52018-10-09 20:23:26 +0900149 throw new WorkflowException("Out of bound in program counter(" + pc + ")");
150 }
151
jaegonkim4064ed12019-05-18 11:34:45 +0900152 WorkletDescription workletDesc = program.get(increaedIndex);
m.rahil09251882019-04-15 22:58:33 +0530153 return ProgramCounter.valueOf(workletDesc.tag(), increaedIndex);
jaegonkim6a7b5242018-09-12 23:09:42 +0900154 }
155
156 @Override
jaegonkimf85ee3c2019-04-21 11:10:25 +0900157 public Worklet getWorkletInstance(ProgramCounter pc) throws WorkflowException {
158
jaegonkim4064ed12019-05-18 11:34:45 +0900159 return getWorkletInstance(program.get(pc.workletIndex()).tag());
jaegonkimf85ee3c2019-04-21 11:10:25 +0900160 }
161
jaegonkim4064ed12019-05-18 11:34:45 +0900162 private Worklet getWorkletInstance(String workletType) throws WorkflowException {
jaegonkim6a7b5242018-09-12 23:09:42 +0900163
jaegonkim13b25cb2019-03-22 06:23:23 +0900164 if (Worklet.Common.INIT.tag().equals(workletType)) {
165 return Worklet.Common.INIT;
166 }
167
jaegonkime0f45b52018-10-09 20:23:26 +0900168 if (Worklet.Common.COMPLETED.tag().equals(workletType)) {
169 return Worklet.Common.COMPLETED;
170 }
171
jaegonkim6a7b5242018-09-12 23:09:42 +0900172 WorkflowStore store;
173 try {
mohamedrahilr63a921c2019-02-27 19:48:25 +0530174 store = DefaultServiceDirectory.getService(WorkflowStore.class);
jaegonkim6a7b5242018-09-12 23:09:42 +0900175 } catch (ServiceNotFoundException e) {
176 throw new WorkflowException(e);
177 }
178
179 Class workClass;
180 try {
181 workClass = store.getClass(workletType);
182 } catch (ClassNotFoundException e) {
183 throw new WorkflowException(e);
184 }
185
186 if (!isAllowed(workClass)) {
187 throw new WorkflowException("Not allowed class(" + workClass.getSimpleName() + ")");
188 }
189
190 Worklet worklet;
191 try {
192 worklet = (Worklet) workClass.newInstance();
193 } catch (Exception e) {
194 throw new WorkflowException(e);
195 }
196
197 return worklet;
198 }
199
200 @Override
201 public Set<WorkflowAttribute> attributes() {
202 return ImmutableSet.copyOf(attributes);
203 }
204
mohamedrahilr63a921c2019-02-27 19:48:25 +0530205 @Override
jaegonkim4064ed12019-05-18 11:34:45 +0900206 public List<ProgramCounter> getProgram() {
207
208 int size = program.size();
209 List pcList = new ArrayList();
210 for (int i = 0; i < size; i++) {
211 pcList.add(ProgramCounter.valueOf(program.get(i).tag(), i));
212 }
213
214 return pcList;
mohamedrahilr63a921c2019-02-27 19:48:25 +0530215 }
216
m.rahil09251882019-04-15 22:58:33 +0530217 @Override
218 public WorkletDescription getWorkletDesc(ProgramCounter pc) {
m.rahilfaf04d72019-05-24 21:11:22 +0530219
220 WorkletDescription workletDescription = program.get(pc.workletIndex());
221 return workletDescription;
m.rahil09251882019-04-15 22:58:33 +0530222 }
223
224
jaegonkim6a7b5242018-09-12 23:09:42 +0900225 /**
226 * Gets index of class in worklet type list.
mohamedrahilr63a921c2019-02-27 19:48:25 +0530227 *
jaegonkim6a7b5242018-09-12 23:09:42 +0900228 * @param aClass class to get index
229 * @return index of class in worklet type list
230 */
231 private int getClassIndex(Class aClass) {
jaegonkim4064ed12019-05-18 11:34:45 +0900232 for (int i = 0; i < program.size(); i++) {
233 if (Objects.equals(aClass.getName(), program.get(i))) {
jaegonkim6a7b5242018-09-12 23:09:42 +0900234 return i;
235 }
236 }
237 return -1;
238 }
239
240 /**
241 * Checks whether class is allowed class or not.
mohamedrahilr63a921c2019-02-27 19:48:25 +0530242 *
jaegonkim6a7b5242018-09-12 23:09:42 +0900243 * @param clazz class to check
244 * @return Check result
245 */
246 private boolean isAllowed(Class clazz) {
247 // non static inner class is not allowed
248 if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) {
249 return false;
250 }
251 // enum is not allowed
252 if (clazz.isEnum()) {
253 return false;
254 }
255 // class should be subclass of Work
256 if (!Worklet.class.isAssignableFrom(clazz)) {
257 return false;
258 }
259 return true;
260 }
261
262 @Override
263 public int hashCode() {
264 return Objects.hash(this.toString());
265 }
266
267 @Override
268 public boolean equals(Object obj) {
269 if (obj == this) {
270 return true;
271 }
272 if (!(obj instanceof EventTask)) {
273 return false;
274 }
275 return Objects.equals(this.id(), ((ImmutableListWorkflow) obj).id())
276 && Objects.equals(this.initWorkletType, ((ImmutableListWorkflow) obj).initWorkletType)
jaegonkim4064ed12019-05-18 11:34:45 +0900277 && Objects.equals(this.program, ((ImmutableListWorkflow) obj).program)
jaegonkim6a7b5242018-09-12 23:09:42 +0900278 && Objects.equals(this.attributes, ((ImmutableListWorkflow) obj).attributes);
279 }
280
281 @Override
282 public String toString() {
283 return MoreObjects.toStringHelper(getClass())
284 .add("id", id())
285 .add("initWorklet", initWorkletType)
jaegonkim4064ed12019-05-18 11:34:45 +0900286 .add("workList", program)
jaegonkim6a7b5242018-09-12 23:09:42 +0900287 .add("attributes", attributes)
288 .toString();
289 }
290
291 /**
292 * Gets a instance of builder.
mohamedrahilr63a921c2019-02-27 19:48:25 +0530293 *
jaegonkim6a7b5242018-09-12 23:09:42 +0900294 * @return instance of builder
295 */
296 public static Builder builder() {
297 return new Builder();
298 }
299
300 /**
301 * Builder of ImmutableListWorkflow.
302 */
303 public static class Builder {
304
305 private URI id;
306 private String initWorkletType;
m.rahil09251882019-04-15 22:58:33 +0530307 private final List<WorkletDescription> workletDescList = Lists.newArrayList();
jaegonkim6a7b5242018-09-12 23:09:42 +0900308 private final Set<WorkflowAttribute> attributes = Sets.newHashSet();
309
310 /**
311 * Sets id of immutable list workflow.
mohamedrahilr63a921c2019-02-27 19:48:25 +0530312 *
jaegonkim6a7b5242018-09-12 23:09:42 +0900313 * @param uri id of immutable list workflow
314 * @return builder
315 */
316 public Builder id(URI uri) {
317 this.id = uri;
m.rahil09251882019-04-15 22:58:33 +0530318 workletDescList.add(new DefaultWorkletDescription(Worklet.Common.INIT.tag()));
jaegonkim6a7b5242018-09-12 23:09:42 +0900319 return this;
320 }
321
322 /**
323 * Sets init worklet class name of immutable list workflow.
mohamedrahilr63a921c2019-02-27 19:48:25 +0530324 *
jaegonkim6a7b5242018-09-12 23:09:42 +0900325 * @param workletClassName class name of worklet
326 * @return builder
327 */
328 public Builder init(String workletClassName) {
329 this.initWorkletType = workletClassName;
330 return this;
331 }
332
333 /**
334 * Chains worklet class name of immutable list workflow.
mohamedrahilr63a921c2019-02-27 19:48:25 +0530335 *
jaegonkim6a7b5242018-09-12 23:09:42 +0900336 * @param workletClassName class name of worklet
337 * @return builder
338 */
339 public Builder chain(String workletClassName) {
m.rahil09251882019-04-15 22:58:33 +0530340 workletDescList.add(new DefaultWorkletDescription(workletClassName));
jaegonkim6a7b5242018-09-12 23:09:42 +0900341 return this;
342 }
343
344 /**
345 * Adds workflow attribute.
mohamedrahilr63a921c2019-02-27 19:48:25 +0530346 *
jaegonkim6a7b5242018-09-12 23:09:42 +0900347 * @param attribute workflow attribute to be added
348 * @return builder
349 */
350 public Builder attribute(WorkflowAttribute attribute) {
351 attributes.add(attribute);
352 return this;
353 }
354
355 /**
356 * Builds ImmutableListWorkflow.
mohamedrahilr63a921c2019-02-27 19:48:25 +0530357 *
jaegonkim6a7b5242018-09-12 23:09:42 +0900358 * @return instance of ImmutableListWorkflow
359 */
360 public ImmutableListWorkflow build() {
m.rahil09251882019-04-15 22:58:33 +0530361 workletDescList.add(new DefaultWorkletDescription(Worklet.Common.COMPLETED.tag()));
jaegonkim6a7b5242018-09-12 23:09:42 +0900362 return new ImmutableListWorkflow(this);
363 }
m.rahil09251882019-04-15 22:58:33 +0530364
365 public Builder chain(DefaultWorkletDescription workletDesc) {
366 workletDescList.add(workletDesc);
367 return this;
368 }
jaegonkim6a7b5242018-09-12 23:09:42 +0900369 }
370}