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 throw new PropsException("Props is empty: no properties declared!?");
103 }
104
105 Pattern pat = Pattern.compile("(?<=[^$]|^)(\\$\\{[^}]*\\})");
106 Matcher mat = pat.matcher(str);
107 StringBuilder expanded = new StringBuilder();
108 int offset = 0;
109 String property;
110 String value;
111
112 while (mat.find(offset))
113 {
114 property = cleanReference(mat.group(1));
115
116
117 if (seenStack.contains(property))
118 {
119 StringBuilder err = new StringBuilder();
120 err.append("Property expansion loop detected: ");
121 int idx = seenStack.lastIndexOf(property);
122 for (int i = idx; i < seenStack.size(); i++)
123 {
124 err.append(seenStack.get(i));
125 err.append(" -> ");
126 }
127 err.append(property);
128 throw new PropsException(err.toString());
129 }
130
131 seenStack.push(property);
132
133
134 expanded.append(str.subSequence(offset,mat.start(1)));
135
136 value = getString(property);
137 if (value == null)
138 {
139 StartLog.debug("Unable to expand: %s",property);
140 expanded.append(property);
141 }
142 else
143 {
144
145 value = expand(value,seenStack);
146 expanded.append(value);
147 }
148
149 offset = mat.end(1);
150 }
151
152
153 expanded.append(str.substring(offset));
154
155
156 if (expanded.indexOf("$$") >= 0)
157 {
158 return expanded.toString().replaceAll("\\$\\$","\\$");
159 }
160
161 return expanded.toString();
162 }
163
164 public Prop getProp(String key)
165 {
166 Prop prop = props.get(key);
167 if (prop == null)
168 {
169
170 prop = getSystemProperty(key);
171 }
172 return prop;
173 }
174
175 public String getString(String key)
176 {
177 if (key == null)
178 {
179 throw new PropsException("Cannot get value for null key");
180 }
181
182 String name = cleanReference(key);
183
184 if (name.length() == 0)
185 {
186 throw new PropsException("Cannot get value for empty key");
187 }
188
189 Prop prop = getProp(name);
190 if (prop == null)
191 {
192 return null;
193 }
194 return prop.value;
195 }
196
197 public String getString(String key, String defVal)
198 {
199 String val = getString(key);
200 if (val == null)
201 {
202 return defVal;
203 }
204 return val;
205 }
206
207 private Prop getSystemProperty(String key)
208 {
209 String value = System.getProperty(key);
210 if (value == null)
211 {
212 return null;
213 }
214 return new Prop(key,value,ORIGIN_SYSPROP);
215 }
216
217 @Override
218 public Iterator<Prop> iterator()
219 {
220 return props.values().iterator();
221 }
222
223 public void setProperty(Prop prop)
224 {
225 props.put(prop.key,prop);
226 }
227
228 public void setProperty(String key, String value, String origin)
229 {
230 Prop prop = props.get(key);
231 if (prop == null)
232 {
233 prop = new Prop(key,value,origin);
234 }
235 else
236 {
237 prop = new Prop(key,value,origin,prop);
238 }
239 props.put(key,prop);
240 }
241
242 public int size()
243 {
244 return props.size();
245 }
246
247 public void store(OutputStream stream, String comments) throws IOException
248 {
249 Properties props = new Properties();
250
251 for (Prop prop : this)
252 {
253 props.setProperty(prop.key,expand(prop.value));
254 }
255
256 props.store(stream,comments);
257 }
258 }