Skip to content

Commit c4e46e1

Browse files
authored
[Fix #786] Evaluate embedded properties (#787)
Signed-off-by: fjtirado <ftirados@redhat.com>
1 parent c868d49 commit c4e46e1

File tree

7 files changed

+322
-118
lines changed

7 files changed

+322
-118
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
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+
*/
16+
package io.serverlessworkflow.impl.expressions;
17+
18+
import java.util.Collection;
19+
20+
abstract class AbstractProxyCollection<T> {
21+
22+
protected Collection<T> values;
23+
24+
protected AbstractProxyCollection(Collection<T> values) {
25+
this.values = values;
26+
}
27+
28+
public int size() {
29+
return values.size();
30+
}
31+
32+
public boolean isEmpty() {
33+
return values.isEmpty();
34+
}
35+
36+
public boolean contains(Object o) {
37+
return values.contains(o);
38+
}
39+
40+
public boolean remove(Object o) {
41+
return values.remove(o);
42+
}
43+
44+
public boolean containsAll(Collection<?> c) {
45+
return values.containsAll(c);
46+
}
47+
48+
public boolean retainAll(Collection<?> c) {
49+
return values.retainAll(c);
50+
}
51+
52+
public boolean removeAll(Collection<?> c) {
53+
return values.removeAll(c);
54+
}
55+
56+
public void clear() {
57+
values.clear();
58+
}
59+
60+
public boolean addAll(Collection<? extends T> c) {
61+
return values.addAll(c);
62+
}
63+
64+
public boolean add(T e) {
65+
return values.add(e);
66+
}
67+
}

impl/core/src/main/java/io/serverlessworkflow/impl/expressions/ObjectExpressionFactory.java

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import io.serverlessworkflow.impl.WorkflowContext;
2020
import io.serverlessworkflow.impl.WorkflowModel;
2121
import io.serverlessworkflow.impl.WorkflowPredicate;
22+
import java.util.Collection;
2223
import java.util.Map;
2324

2425
public abstract class ObjectExpressionFactory extends AbstractExpressionFactory {
@@ -31,13 +32,36 @@ protected ObjectExpression buildExpression(ExpressionDescriptor desc) {
3132
return expression::eval;
3233
} else if (desc.asObject() != null) {
3334
Object exprObj = buildExpressionObject(desc.asObject(), this);
34-
return exprObj instanceof Map map
35-
? (w, t, n) -> evaluateExpressionMap(map, w, t, n)
36-
: (w, t, n) -> desc.asObject();
35+
return (w, t, n) -> evaluateExpressionObject(exprObj, w, t, n);
3736
}
3837
throw new IllegalArgumentException("Both object and str are null");
3938
}
4039

40+
private Object buildExpressionObject(Object obj, ExpressionFactory factory) {
41+
if (obj instanceof ObjectExpression expr) {
42+
return expr;
43+
} else if (obj instanceof Map map) {
44+
return buildExpressionMap(map, factory);
45+
} else if (obj instanceof Collection col) {
46+
return buildExpressionList(col, factory);
47+
} else {
48+
return obj;
49+
}
50+
}
51+
52+
private Object evaluateExpressionObject(
53+
Object obj, WorkflowContext workflow, TaskContext task, WorkflowModel model) {
54+
if (obj instanceof ObjectExpression expr) {
55+
return toJavaObject(expr.eval(workflow, task, model));
56+
} else if (obj instanceof Map map) {
57+
return evaluateExpressionMap(map, workflow, task, model);
58+
} else if (obj instanceof Collection col) {
59+
return evaluateExpressionCollection(col, workflow, task, model);
60+
} else {
61+
return obj;
62+
}
63+
}
64+
4165
@Override
4266
public WorkflowPredicate buildPredicate(ExpressionDescriptor desc) {
4367
ObjectExpression expr = buildExpression(desc);
@@ -51,22 +75,32 @@ protected Object toJavaObject(Object eval) {
5175
}
5276

5377
private Map<String, Object> buildExpressionMap(
54-
Map<String, Object> origMap, ExpressionFactory factory) {
78+
Map<String, Object> map, ExpressionFactory factory) {
5579
return new ProxyMap(
56-
origMap, o -> ExpressionUtils.isExpr(o) ? buildExpression(o.toString()) : o);
80+
map,
81+
o ->
82+
ExpressionUtils.isExpr(o)
83+
? buildExpression(o.toString())
84+
: buildExpressionObject(o, factory));
5785
}
5886

59-
private Object buildExpressionObject(Object obj, ExpressionFactory factory) {
60-
return obj instanceof Map map ? buildExpressionMap(map, factory) : obj;
87+
private Collection<Object> buildExpressionList(
88+
Collection<Object> col, ExpressionFactory factory) {
89+
return new ProxyCollection(
90+
col,
91+
o ->
92+
ExpressionUtils.isExpr(o)
93+
? buildExpression(o.toString())
94+
: buildExpressionObject(o, factory));
6195
}
6296

6397
private Map<String, Object> evaluateExpressionMap(
64-
Map<String, Object> origMap, WorkflowContext workflow, TaskContext task, WorkflowModel n) {
65-
return new ProxyMap(
66-
origMap,
67-
o ->
68-
o instanceof ObjectExpression
69-
? toJavaObject(((ObjectExpression) o).eval(workflow, task, n))
70-
: o);
98+
Map<String, Object> map, WorkflowContext workflow, TaskContext task, WorkflowModel n) {
99+
return new ProxyMap(map, o -> evaluateExpressionObject(o, workflow, task, n));
100+
}
101+
102+
private Collection<Object> evaluateExpressionCollection(
103+
Collection<Object> col, WorkflowContext workflow, TaskContext task, WorkflowModel n) {
104+
return new ProxyCollection(col, o -> evaluateExpressionObject(o, workflow, task, n));
71105
}
72106
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
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+
*/
16+
package io.serverlessworkflow.impl.expressions;
17+
18+
import java.util.Collection;
19+
import java.util.Iterator;
20+
import java.util.function.UnaryOperator;
21+
22+
class ProxyCollection extends AbstractProxyCollection<Object> implements Collection<Object> {
23+
24+
private final UnaryOperator<Object> function;
25+
26+
public ProxyCollection(Collection<Object> values, UnaryOperator<Object> function) {
27+
super(values);
28+
this.function = function;
29+
}
30+
31+
@Override
32+
public Iterator<Object> iterator() {
33+
return new ProxyIterator(values.iterator(), function);
34+
}
35+
36+
@Override
37+
public Object[] toArray() {
38+
return processArray(values.toArray());
39+
}
40+
41+
@Override
42+
public <T> T[] toArray(T[] a) {
43+
return processArray(values.toArray(a));
44+
}
45+
46+
private <S> S[] processArray(S[] array) {
47+
for (int i = 0; i < array.length; i++) {
48+
array[i] = (S) function.apply(array[i]);
49+
}
50+
return array;
51+
}
52+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
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+
*/
16+
package io.serverlessworkflow.impl.expressions;
17+
18+
import java.util.Iterator;
19+
import java.util.function.UnaryOperator;
20+
21+
class ProxyIterator implements Iterator<Object> {
22+
23+
private Iterator<Object> iter;
24+
private final UnaryOperator<Object> function;
25+
26+
public ProxyIterator(Iterator<Object> iter, UnaryOperator<Object> function) {
27+
this.iter = iter;
28+
this.function = function;
29+
}
30+
31+
@Override
32+
public boolean hasNext() {
33+
return iter.hasNext();
34+
}
35+
36+
@Override
37+
public Object next() {
38+
return function.apply(iter.next());
39+
}
40+
41+
@Override
42+
public void remove() {
43+
iter.remove();
44+
}
45+
}

impl/core/src/main/java/io/serverlessworkflow/impl/expressions/ProxyMap.java

Lines changed: 1 addition & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -83,63 +83,14 @@ public Set<String> keySet() {
8383

8484
@Override
8585
public Collection<Object> values() {
86-
return new ProxyCollection(map.values());
86+
return new ProxyCollection(map.values(), function);
8787
}
8888

8989
@Override
9090
public Set<Entry<String, Object>> entrySet() {
9191
return new ProxyEntrySet(map.entrySet());
9292
}
9393

94-
private abstract class AbstractProxyCollection<T> {
95-
96-
protected Collection<T> values;
97-
98-
protected AbstractProxyCollection(Collection<T> values) {
99-
this.values = values;
100-
}
101-
102-
public int size() {
103-
return values.size();
104-
}
105-
106-
public boolean isEmpty() {
107-
return values.isEmpty();
108-
}
109-
110-
public boolean contains(Object o) {
111-
return values.contains(o);
112-
}
113-
114-
public boolean remove(Object o) {
115-
return values.remove(o);
116-
}
117-
118-
public boolean containsAll(Collection<?> c) {
119-
return values.containsAll(c);
120-
}
121-
122-
public boolean retainAll(Collection<?> c) {
123-
return values.retainAll(c);
124-
}
125-
126-
public boolean removeAll(Collection<?> c) {
127-
return values.removeAll(c);
128-
}
129-
130-
public void clear() {
131-
values.clear();
132-
}
133-
134-
public boolean addAll(Collection<? extends T> c) {
135-
return values.addAll(c);
136-
}
137-
138-
public boolean add(T e) {
139-
return values.add(e);
140-
}
141-
}
142-
14394
private class ProxyEntrySet extends AbstractProxyCollection<Entry<String, Object>>
14495
implements Set<Entry<String, Object>> {
14596

@@ -170,36 +121,6 @@ private <T> T[] processEntries(T[] array) {
170121
}
171122
}
172123

173-
private class ProxyCollection extends AbstractProxyCollection<Object>
174-
implements Collection<Object> {
175-
176-
public ProxyCollection(Collection<Object> values) {
177-
super(values);
178-
}
179-
180-
@Override
181-
public Iterator<Object> iterator() {
182-
return new ProxyIterator(values.iterator());
183-
}
184-
185-
@Override
186-
public Object[] toArray() {
187-
return processArray(values.toArray());
188-
}
189-
190-
@Override
191-
public <T> T[] toArray(T[] a) {
192-
return processArray(values.toArray(a));
193-
}
194-
195-
private <S> S[] processArray(S[] array) {
196-
for (int i = 0; i < array.length; i++) {
197-
array[i] = (S) processValue(array[i]);
198-
}
199-
return array;
200-
}
201-
}
202-
203124
private class ProxyEntry implements Entry<String, Object> {
204125

205126
private Entry<String, Object> entry;
@@ -224,30 +145,6 @@ public Object setValue(Object value) {
224145
}
225146
}
226147

227-
private class ProxyIterator implements Iterator<Object> {
228-
229-
private Iterator<Object> iter;
230-
231-
public ProxyIterator(Iterator<Object> iter) {
232-
this.iter = iter;
233-
}
234-
235-
@Override
236-
public boolean hasNext() {
237-
return iter.hasNext();
238-
}
239-
240-
@Override
241-
public Object next() {
242-
return processValue(iter.next());
243-
}
244-
245-
@Override
246-
public void remove() {
247-
iter.remove();
248-
}
249-
}
250-
251148
private class ProxyEntryIterator implements Iterator<Entry<String, Object>> {
252149

253150
private Iterator<Entry<String, Object>> iter;

0 commit comments

Comments
 (0)