1 package io.guixer.tools;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4 import static com.google.common.collect.Maps.newHashMap;
5
6 import java.util.Map;
7
8 import javax.annotation.Nullable;
9
10 import com.google.common.collect.Iterables;
11
12 public abstract class AbstractExecutionContext implements ExecutionContext {
13
14 private final Map<String, Object> variables = newHashMap();
15 private final Map<String, Object> maskedVariables = newHashMap();
16 private final Functions functions;
17
18 public AbstractExecutionContext(
19 final Functions functions
20 ) {
21
22 this.functions = checkNotNull(functions, "functions");
23 }
24
25 @Override
26 public final String[] getVariableNames() {
27
28 return Iterables.toArray(variables.keySet(), String.class);
29 }
30
31 @Override
32 public final <T> T setVariable(
33 final String name,
34 final T value
35 ) {
36
37 checkNotNull(name, "name");
38 checkNotNull(value, "value");
39
40 maskedVariables.remove(name);
41
42 variables.put(name, value);
43
44 return value;
45 }
46
47 @Override
48 public final void setMaskedVariable(
49 final String name,
50 final Object value
51 ) {
52
53 checkNotNull(name, "name");
54 checkNotNull(value, "value");
55
56 variables.remove(name);
57
58 maskedVariables.put(name, value);
59 }
60
61 @Override
62 public boolean usesMaskedVariables(
63 final String value
64 ) {
65
66
67
68 for (int offset = 0;;) {
69 final int index = value.indexOf("${", offset);
70
71 if (index == -1) {
72 break;
73 }
74
75 final int end = value.indexOf("}", index);
76
77 offset = index + 1;
78
79 final String propertyName = value.substring(index + 2, end).trim();
80
81 if (maskedVariables.containsKey(propertyName)) {
82
83 return true;
84 }
85 }
86
87 return false;
88 }
89
90 @Override
91 @Nullable
92 public final Object getVariable(
93 final String name
94 ) {
95
96 checkNotNull(name, "name");
97
98 return variables.get(name);
99 }
100
101 @Override
102 public final void removeVariable(
103 final String name
104 ) {
105
106 checkNotNull(name, "name");
107
108 variables.remove(name);
109 }
110
111 @Override
112 public final String filterPlain(
113 final String value
114 ) {
115
116 return filter(value, false);
117 }
118
119 @Override
120 public final String filterMasked(
121 final String value
122 ) {
123
124 return filter(value, true);
125 }
126
127 private String filter(
128 final String value,
129 final boolean isMasked
130 ) {
131
132 checkNotNull(value, "value");
133
134 String filtered = value;
135
136
137
138 while (true) {
139
140 final int index = filtered.indexOf("$(");
141
142 if (index == -1) {
143 break;
144 }
145
146 final int end = filtered.indexOf(")", index);
147
148 final String functionName = filtered.substring(index + 2, end).trim();
149
150 final String result = functions.executeFunction(functionName);
151
152 filtered = filtered.substring(0, index)
153 + result
154 + filtered.substring(end + 1);
155 }
156
157
158
159 while (true) {
160
161 final int index = filtered.indexOf("${");
162
163 if (index == -1) {
164 break;
165 }
166
167 final int end = filtered.indexOf("}", index);
168
169 final String propertyName = filtered.substring(index + 2, end).trim();
170
171 @Nullable
172 final Object maskedPropertyValue = maskedVariables.get(propertyName);
173
174 if (maskedPropertyValue != null) {
175
176 if (isMasked) {
177
178 filtered = filtered.substring(0, index)
179 + maskedPropertyValue.toString()
180 + filtered.substring(end + 1);
181
182 continue;
183 }
184
185 throw new RuntimeException("Use of masked variable is forbidden: " + propertyName);
186 }
187
188 @Nullable
189 final Object propertyValue = variables.get(propertyName);
190
191 if (propertyValue == null) {
192 throw new IllegalStateException("Unknown context attribute: " + propertyName);
193 }
194
195 filtered = filtered.substring(0, index)
196 + propertyValue.toString()
197 + filtered.substring(end + 1);
198 }
199
200 return filtered;
201 }
202 }