1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package de.smartics.properties.spi.config.resolve;
17
18 import java.util.ArrayList;
19 import java.util.LinkedHashSet;
20 import java.util.Set;
21
22 import org.apache.commons.lang.StringUtils;
23
24 import de.smartics.properties.api.config.domain.UnknownPropertyException;
25 import de.smartics.properties.api.core.domain.PropertyValidationException;
26
27
28
29
30 class Resolver
31 {
32
33
34
35
36
37
38
39
40
41
42 private final ResolveContext context;
43
44
45
46
47
48 Resolver(final ResolveContext context)
49 {
50 this.context = context;
51 }
52
53
54
55
56
57
58 private static final class RecursionDetection
59 {
60
61
62
63
64
65
66
67
68
69 private final Set<String> path;
70
71
72
73
74
75 private RecursionDetection()
76 {
77 this.path = new LinkedHashSet<String>();
78 }
79
80 private RecursionDetection(final RecursionDetection parent)
81 {
82 this.path = new LinkedHashSet<String>(parent.path);
83 }
84
85
86
87
88
89
90
91
92
93
94
95 private void checkRecursion(final String key)
96 throws RecursivePropertyException
97 {
98 if (path.contains(key))
99 {
100 throw new RecursivePropertyException(key, new ArrayList<String>(path));
101 }
102 path.add(key);
103 }
104
105
106
107 @Override
108 public String toString()
109 {
110 return path.toString();
111 }
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 String resolve(final String expression) throws UnresolvablePropertyException,
135 UnknownPropertyException, PropertyValidationException
136 {
137 return resolve(new RecursionDetection(), expression);
138 }
139
140 private String resolve(final RecursionDetection recursionDetection,
141 final String expression) throws RecursivePropertyException
142 {
143 if (StringUtils.isBlank(expression))
144 {
145 return expression;
146 }
147
148 final int length = expression.length();
149 final StringBuilder buffer = new StringBuilder(length * 2);
150 int i = 0;
151 while (i < length)
152 {
153 final char c = expression.charAt(i++);
154 if (c == '$' && i < length - 1 && expression.charAt(i) == '{')
155 {
156 final RecursionDetection recursionDetection2 =
157 new RecursionDetection(recursionDetection);
158 i = parsePlaceHolder(recursionDetection2, expression, buffer, i);
159 }
160 else
161 {
162 buffer.append(c);
163 }
164 }
165
166 return buffer.toString();
167 }
168
169 private int parsePlaceHolder(final RecursionDetection recursionDetection,
170 final String expression, final StringBuilder buffer, final int index)
171 throws RecursivePropertyException
172 {
173 final int length = expression.length() - 1;
174 int i = index;
175
176 final StringBuilder keyBuffer = new StringBuilder(64);
177 i = readKey(expression, length, i, keyBuffer);
178 final String key = keyBuffer.toString();
179 recursionDetection.checkRecursion(key);
180 final String replacement = context.get(key);
181 if (replacement == null)
182 {
183 throw new NullValuePropertyException(key, new ArrayList<String>(
184 recursionDetection.path));
185 }
186 final String resolved = resolve(recursionDetection, replacement);
187 buffer.append(resolved);
188 return i + 1;
189 }
190
191 private int readKey(final String expression, final int length,
192 final int index, final StringBuilder keyBuffer)
193 {
194 int i = index;
195 char n = expression.charAt(++i);
196 while (n != '}' && i < length)
197 {
198 keyBuffer.append(n);
199 n = expression.charAt(++i);
200 }
201 return i;
202 }
203
204
205
206 }