blob: 92d36649c4e2b006a6d32b661fa10deb0654f8ca [file] [log] [blame]
m.rahil09251882019-04-15 22:58:33 +05301/*
2 * Copyright 2019-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.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import org.slf4j.Logger;
22import org.slf4j.LoggerFactory;
23import java.lang.annotation.Annotation;
24import java.lang.reflect.Field;
25import java.util.Map;
26import java.util.List;
27import java.util.Objects;
28import java.util.ArrayList;
29import java.util.HashMap;
30
31public class StaticDataModelInjector {
32
33 private static final Logger log = LoggerFactory.getLogger(StaticDataModelInjector.class);
34
35 /**
36 * Injects data model to work-let.
37 *
38 * @param worklet work-let to be injected
39 * @param workletDescription worklet description
40 * @throws WorkflowException workflow exception
41 */
42 public void inject(Worklet worklet, WorkletDescription workletDescription) throws WorkflowException {
43
44 handle(worklet, workletDescription, this::injectModel);
45 }
46
47 private void handle(Worklet worklet, WorkletDescription workletDescription, DataModelFieldBehavior func)
48 throws WorkflowException {
49 Class cl = worklet.getClass();
50 List<Field> fields = getInheritedFields(cl);
51 if (Objects.isNull(fields)) {
52 log.error("Invalid fields on {}", cl);
53 return;
54 }
55
56 for (Field field : fields) {
57 Annotation[] annotations = field.getAnnotations();
58 if (Objects.isNull(annotations)) {
59 continue;
60 }
61 for (Annotation annotation : annotations) {
62 if (!(annotation instanceof StaticDataModel)) {
63 continue;
64 }
65 StaticDataModel model = (StaticDataModel) annotation;
66 func.apply(worklet, workletDescription, field, model);
67 }
68 }
69 }
70
71 private static List<Field> getInheritedFields(Class<?> type) {
72 List<Field> fields = new ArrayList<Field>();
73
74 Class<?> cl = type;
75 while (cl != null && cl != Object.class) {
76 for (Field field : cl.getDeclaredFields()) {
77 if (!field.isSynthetic()) {
78 fields.add(field);
79 }
80 }
81 cl = cl.getSuperclass();
82 }
83 return fields;
84 }
85
86 /**
87 * Functional interface for json data model annotated field behavior.
88 */
89 @FunctionalInterface
90 public interface DataModelFieldBehavior {
91 void apply(Worklet worklet, WorkletDescription workletDescription, Field field, StaticDataModel model)
92 throws WorkflowException;
93 }
94
95 private static Map<Class, DataModelFieldBehavior> injectTypeMap = new HashMap<>();
96
97 static {
98 injectTypeMap.put(String.class, StaticDataModelInjector::injectText);
99 injectTypeMap.put(Integer.class, StaticDataModelInjector::injectInteger);
100 injectTypeMap.put(Boolean.class, StaticDataModelInjector::injectBoolean);
101 injectTypeMap.put(JsonNode.class, StaticDataModelInjector::injectJsonNode);
102 injectTypeMap.put(ArrayNode.class, StaticDataModelInjector::injectArrayNode);
103 injectTypeMap.put(ObjectNode.class, StaticDataModelInjector::injectObjectNode);
104 }
105
106 /**
107 * Injects data model on the filed of work-let.
108 *
109 * @param worklet work-let
110 * @param workletDescription worklet description
111 * @param field the field of work-let
112 * @param model data model for the field
113 * @throws WorkflowException workflow exception
114 */
115 private void injectModel(Worklet worklet, WorkletDescription workletDescription, Field field, StaticDataModel model)
116 throws WorkflowException {
117
118 DataModelFieldBehavior behavior = injectTypeMap.get(field.getType());
119 if (Objects.isNull(behavior)) {
120 throw new WorkflowException("Not supported type(" + field.getType() + ")");
121 }
122 behavior.apply(worklet, workletDescription, field, model);
123 }
124
125 /**
126 * Injects text data model on the filed of work-let.
127 *
128 * @param worklet work-let
129 * @param workletDescription worklet description
130 * @param field the field of work-let
131 * @param model text data model for the field
132 * @throws WorkflowException workflow exception
133 */
134 private static void injectText(Worklet worklet, WorkletDescription workletDescription, Field field,
135 StaticDataModel model) throws WorkflowException {
136
137 String text = ((JsonDataModelTree) workletDescription.data()).textAt(model.path());
138 if (Objects.isNull(text)) {
139 if (model.optional()) {
140 return;
141 }
142 throw new WorkflowException("Invalid array node data model on (" + model.path() + ")");
143 }
144
145
146 if (!(Objects.equals(field.getType(), String.class))) {
147 throw new WorkflowException("Target field (" + field + ") is not String");
148 }
149
150 try {
151 field.setAccessible(true);
152 field.set(worklet, text);
153 } catch (IllegalAccessException e) {
154 throw new WorkflowException(e);
155 }
156 }
157
158 /**
159 * Injects integer data model on the filed of work-let.
160 *
161 * @param worklet work-let
162 * @param workletDescription worklet description
163 * @param field the field of work-let
164 * @param model integer data model for the field
165 * @throws WorkflowException workflow exception
166 */
167 private static void injectInteger(Worklet worklet, WorkletDescription workletDescription, Field field,
168 StaticDataModel model) throws WorkflowException {
169
170 Integer number = ((JsonDataModelTree) workletDescription.data()).intAt(model.path());
171 if (Objects.isNull(number)) {
172 if (model.optional()) {
173 return;
174 }
175 throw new WorkflowException("Invalid array node data model on (" + model.path() + ")");
176 }
177 if (!(Objects.equals(field.getType(), Integer.class))) {
178 throw new WorkflowException("Target field (" + field + ") is not Integer");
179 }
180
181 try {
182 field.setAccessible(true);
183 field.set(worklet, number);
184 } catch (IllegalAccessException e) {
185 throw new WorkflowException(e);
186 }
187 }
188
189
190 /**
191 * Injects boolean data model on the filed of work-let.
192 *
193 * @param worklet work-let
194 * @param workletDescription worklet description
195 * @param field the field of work-let
196 * @param model boolean data model for the field
197 * @throws WorkflowException workflow exception
198 */
199 private static void injectBoolean(Worklet worklet, WorkletDescription workletDescription, Field field,
200 StaticDataModel model) throws WorkflowException {
201
202 Boolean bool = ((JsonDataModelTree) workletDescription.data()).booleanAt(model.path());
203 if (Objects.isNull(bool)) {
204 if (model.optional()) {
205 return;
206 }
207 throw new WorkflowException("Invalid boolean data model on (" + model.path() + ")");
208 }
209
210 if (!(Objects.equals(field.getType(), Boolean.class))) {
211 throw new WorkflowException("Target field (" + field + ") is not Boolean");
212 }
213
214 try {
215 field.setAccessible(true);
216 field.set(worklet, bool);
217 } catch (IllegalAccessException e) {
218 throw new WorkflowException(e);
219 }
220 }
221
222 /**
223 * Injects json node data model on the filed of work-let.
224 *
225 * @param worklet work-let
226 * @param workletDescription worklet description
227 * @param field the field of work-let
228 * @param model json node data model for the field
229 * @throws WorkflowException workflow exception
230 */
231 private static void injectJsonNode(Worklet worklet, WorkletDescription workletDescription, Field field,
232 StaticDataModel model) throws WorkflowException {
233
234 JsonNode jsonNode = ((JsonDataModelTree) workletDescription.data()).nodeAt(model.path());
235 if (Objects.isNull(jsonNode)) {
236 if (model.optional()) {
237 return;
238 }
239 throw new WorkflowException("Invalid json node data model on (" + model.path() + ")");
240 }
241
242 if (!(Objects.equals(field.getType(), JsonNode.class))) {
243 throw new WorkflowException("Target field (" + field + ") is not JsonNode");
244 }
245
246 try {
247 field.setAccessible(true);
248 field.set(worklet, jsonNode);
249 } catch (IllegalAccessException e) {
250 throw new WorkflowException(e);
251 }
252 }
253
254 /**
255 * Injects json array node data model on the filed of work-let.
256 *
257 * @param worklet work-let
258 * @param workletDescription worklet description
259 * @param field the field of work-let
260 * @param model json array node data model for the field
261 * @throws WorkflowException workflow exception
262 */
263 private static void injectArrayNode(Worklet worklet, WorkletDescription workletDescription, Field field,
264 StaticDataModel model) throws WorkflowException {
265
266 ArrayNode arrayNode = ((JsonDataModelTree) workletDescription.data()).arrayAt(model.path());
267 if (Objects.isNull(arrayNode)) {
268 if (model.optional()) {
269 return;
270 }
271 throw new WorkflowException("Invalid array node data model on (" + model.path() + ")");
272 }
273
274 if (!(Objects.equals(field.getType(), ArrayNode.class))) {
275 throw new WorkflowException("Target field (" + field + ") is not ArrayNode");
276 }
277
278 try {
279 field.setAccessible(true);
280 field.set(worklet, arrayNode);
281 } catch (IllegalAccessException e) {
282 throw new WorkflowException(e);
283 }
284 }
285
286 /**
287 * Injects json object node data model on the filed of work-let.
288 *
289 * @param worklet work-let
290 * @param workletDescription worklet description
291 * @param field the field of work-let
292 * @param model json object node data model for the field
293 * @throws WorkflowException workflow exception
294 */
295 private static void injectObjectNode(Worklet worklet, WorkletDescription workletDescription, Field field,
296 StaticDataModel model) throws WorkflowException {
297
298 ObjectNode objNode = ((JsonDataModelTree) workletDescription.data()).objectAt(model.path());
299 if (Objects.isNull(objNode)) {
300 if (model.optional()) {
301 return;
302 }
303 throw new WorkflowException("Invalid object node data model on (" + model.path() + ")");
304 }
305
306 if (!(Objects.equals(field.getType(), ObjectNode.class))) {
307 throw new WorkflowException("Target field (" + field + ") is not ObjectNode");
308 }
309
310 try {
311 field.setAccessible(true);
312 field.set(worklet, objNode);
313 } catch (IllegalAccessException e) {
314 throw new WorkflowException(e);
315 }
316 }
317}