1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.start;
20
21 import java.io.IOException;
22 import java.io.OutputStream;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.Map;
26 import java.util.Properties;
27 import java.util.Stack;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30
31 import org.eclipse.jetty.start.Props.Prop;
32
33
34
35
36
37
38
39 public final class Props implements Iterable<Prop>
40 {
41 public static class Prop
42 {
43 public String key;
44 public String value;
45 public String origin;
46 public Prop overrides;
47
48 public Prop(String key, String value, String origin)
49 {
50 this.key = key;
51 this.value = value;
52 this.origin = origin;
53 }
54
55 public Prop(String key, String value, String origin, Prop overrides)
56 {
57 this(key,value,origin);
58 this.overrides = overrides;
59 }
60 }
61
62 public static final String ORIGIN_SYSPROP = "<system-property>";
63
64 private Map<String, Prop> props = new HashMap<>();
65
66 public String cleanReference(String property)
67 {
68 String name = property.trim();
69 if (name.startsWith("${") && name.endsWith("}"))
70 {
71 name = name.substring(2,name.length() - 1);
72 }
73 return name.trim();
74 }
75
76 public boolean containsKey(String key)
77 {
78 return props.containsKey(key);
79 }
80
81 public String expand(String str)
82 {
83 return expand(str,new Stack<String>());
84 }
85
86 public String expand(String str, Stack<String> seenStack)
87 {
88 if (str == null)
89 {
90 return str;
91 }
92
93 if (str.indexOf("${") < 0)
94 {
95
96 return str;
97 }
98
99 if (props.isEmpty())
100 {
101
102
103 return str;
104 }
105
106 Pattern pat = Pattern.compile("(?<=[^$]|^)(\\$\\{[^}]*\\})");
107 Matcher mat = pat.matcher(str);
108 StringBuilder expanded = new StringBuilder();
109 int offset = 0;
110 String property;
111 String value;
112
113 while (mat.find(offset))
114 {
115 property = cleanReference(mat.group(1));
116
117
118 if (seenStack.contains(property))
119 {
120 StringBuilder err = new StringBuilder();
121 err.append("Property expansion loop detected: ");
122 int idx = seenStack.lastIndexOf(property);
123 for (int i = idx; i < seenStack.size(); i++)
124 {
125 err.append(seenStack.get(i));
126 err.append(" -> ");
127 }
128 err.append(property);
129 throw new PropsException(err.toString());
130 }
131
132 seenStack.push(property);
133
134
135 expanded.append(str.subSequence(offset,mat.start(1)));
136
137 value = getString(property);
138 if (value == null)
139 {
140 StartLog.debug("Unable to expand: %s",property);
141 expanded.append(property);
142 }
143 else
144 {
145
146 value = expand(value,seenStack);
147 expanded.append(value);
148 }
149
150 offset = mat.end(1);
151 }
152
153
154 expanded.append(str.substring(offset));
155
156
157 if (expanded.indexOf("$$") >= 0)
158 {
159 return expanded.toString().replaceAll("\\$\\$","\\$");
160 }
161
162 return expanded.toString();
163 }
164
165 public Prop getProp(String key)
166 {
167 Prop prop = props.get(key);
168 if (prop == null)
169 {
170
171 prop = getSystemProperty(key);
172 }
173 return prop;
174 }
175
176 public String getString(String key)
177 {
178 if (key == null)
179 {
180 throw new PropsException("Cannot get value for null key");
181 }
182
183 String name = cleanReference(key);
184
185 if (name.length() == 0)
186 {
187 throw new PropsException("Cannot get value for empty key");
188 }
189
190 Prop prop = getProp(name);
191 if (prop == null)
192 {
193 return null;
194 }
195 return prop.value;
196 }
197
198 public String getString(String key, String defVal)
199 {
200 String val = getString(key);
201 if (val == null)
202 {
203 return defVal;
204 }
205 return val;
206 }
207
208 private Prop getSystemProperty(String key)
209 {
210 String value = System.getProperty(key);
211 if (value == null)
212 {
213 return null;
214 }
215 return new Prop(key,value,ORIGIN_SYSPROP);
216 }
217
218 @Override
219 public Iterator<Prop> iterator()
220 {
221 return props.values().iterator();
222 }
223
224 public void setProperty(Prop prop)
225 {
226 props.put(prop.key,prop);
227 }
228
229 public void setProperty(String key, String value, String origin)
230 {
231 Prop prop = props.get(key);
232 if (prop == null)
233 {
234 prop = new Prop(key,value,origin);
235 }
236 else
237 {
238 prop = new Prop(key,value,origin,prop);
239 }
240 props.put(key,prop);
241 }
242
243 public int size()
244 {
245 return props.size();
246 }
247
248 public void store(OutputStream stream, String comments) throws IOException
249 {
250 Properties props = new Properties();
251
252 for (Prop prop : this)
253 {
254 props.setProperty(prop.key,expand(prop.value));
255 }
256
257 props.store(stream,comments);
258 }
259 }