1 package com.github.mygreen.supercsv.expression;
2
3 import java.util.Arrays;
4 import java.util.Collections;
5 import java.util.HashMap;
6 import java.util.Map;
7 import java.util.Objects;
8 import java.util.stream.Collectors;
9
10 import org.apache.commons.jexl3.JexlBuilder;
11 import org.apache.commons.jexl3.JexlEngine;
12 import org.apache.commons.jexl3.JexlExpression;
13 import org.apache.commons.jexl3.MapContext;
14 import org.apache.commons.jexl3.introspection.JexlPermissions;
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17
18 import com.github.mygreen.supercsv.util.Utils;
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 public class ExpressionLanguageJEXLImpl implements ExpressionLanguage {
35
36 private static final Logger logger = LoggerFactory.getLogger(ExpressionLanguageJEXLImpl.class);
37
38
39
40
41 public static final String PROPERTY_JEXL_RESTRICTED = "supercsv.annotation.jexlRestricted";
42
43
44
45
46 protected static final String[] LIB_PERMISSIONS = {"com.github.mygreen.supercsv.*"};
47
48
49
50
51 protected static final String[] USER_PERMISSIONS;
52 static {
53 String value = System.getProperty("supercsv.annotation.jexlPermissions");
54 if(Utils.isNotEmpty(value)) {
55 USER_PERMISSIONS = Arrays.stream(value.split(","))
56 .map(String::trim)
57 .filter(Utils::isNotEmpty)
58 .collect(Collectors.toList())
59 .toArray(new String[0]);
60
61 } else {
62 USER_PERMISSIONS = new String[] {};
63 }
64 }
65
66
67
68
69
70 private static final int CACHE_SIZE = 256;
71
72 private final JexlEngine jexlEngine;
73
74
75
76
77
78
79
80
81 public ExpressionLanguageJEXLImpl(final String... userPermissions) {
82 this(Collections.emptyMap(), true, userPermissions);
83
84 }
85
86
87
88
89
90
91
92
93
94 public ExpressionLanguageJEXLImpl(final Map<String, Object> userFunctions, final boolean restricted, final String... userPermissions) {
95
96 this.jexlEngine = new JexlBuilder()
97 .namespaces(buildNamespace(userFunctions))
98 .permissions(buildPermissions(restricted, userPermissions))
99 .silent(true)
100 .cache(CACHE_SIZE)
101 .create();
102 }
103
104
105
106
107
108 public ExpressionLanguageJEXLImpl(final JexlEngine jexlEngine) {
109 this.jexlEngine = jexlEngine;
110 }
111
112
113
114
115
116
117
118 protected Map<String, Object> buildNamespace(final Map<String, Object> userFunctions) {
119
120
121 Map<String, Object> functions = new HashMap<>();
122 functions.put("f", CustomFunctions.class);
123
124 if (Utils.isNotEmpty(userFunctions)) {
125 functions.putAll(userFunctions);
126 }
127
128
129 return functions;
130 }
131
132
133
134
135
136
137
138
139 protected JexlPermissions buildPermissions(final boolean restricted, final String... userPermissions) {
140
141 final JexlPermissions permissions;
142 if(Utils.toBoolean(System.getProperty(PROPERTY_JEXL_RESTRICTED), restricted)) {
143
144
145
146
147
148
149 String[] concateedUserPermission = Utils.concat(USER_PERMISSIONS, userPermissions);
150 permissions = JexlPermissions.RESTRICTED
151 .compose(Utils.concat(LIB_PERMISSIONS, concateedUserPermission));
152
153 } else {
154
155 permissions = JexlPermissions.UNRESTRICTED;
156 }
157
158 return permissions;
159 }
160
161 @Override
162 public Object evaluate(final String expression, final Map<String, Object> values) {
163
164 Objects.requireNonNull(expression, "expression shoud not be null.");
165 Objects.requireNonNull(values, "values shoud not be null.");
166
167 if(logger.isDebugEnabled()) {
168 logger.debug("Evaluating JEXL expression: {}", expression);
169 }
170
171 try {
172 JexlExpression expr = jexlEngine.createExpression(expression);
173 return expr.evaluate(new MapContext((Map<String, Object>) values));
174
175 } catch(Exception ex) {
176 throw new ExpressionEvaluationException(String.format("Evaluating [%s] script with JEXL failed.", expression), ex,
177 expression, values);
178 }
179 }
180
181
182
183
184
185 public JexlEngine getJexlEngine() {
186 return jexlEngine;
187 }
188
189 }