Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
EnvAppDefinitionKeyHelper |
|
|
3.0;3 |
1 | /* |
|
2 | * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH |
|
3 | * |
|
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 | * you may not use this file except in compliance with the License. |
|
6 | * You may obtain a copy of the License at |
|
7 | * |
|
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 | * |
|
10 | * Unless required by applicable law or agreed to in writing, software |
|
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 | * See the License for the specific language governing permissions and |
|
14 | * limitations under the License. |
|
15 | */ |
|
16 | package de.smartics.properties.impl.config.domain.key.envapp; |
|
17 | ||
18 | import static de.smartics.properties.api.config.domain.key.ApplicationId.ANY_APP; |
|
19 | import static de.smartics.properties.api.config.domain.key.EnvironmentId.ANY_ENV; |
|
20 | ||
21 | import java.io.Serializable; |
|
22 | import java.util.StringTokenizer; |
|
23 | ||
24 | import javax.annotation.concurrent.ThreadSafe; |
|
25 | ||
26 | import de.smartics.properties.api.config.domain.key.ApplicationId; |
|
27 | import de.smartics.properties.api.config.domain.key.ConfigurationKey; |
|
28 | import de.smartics.properties.api.config.domain.key.EnvironmentId; |
|
29 | import de.smartics.properties.spi.config.definition.DefinitionKeyHelper; |
|
30 | import de.smartics.properties.spi.config.domain.key.ConfigurationKeyContextManager; |
|
31 | import de.smartics.util.lang.Arg; |
|
32 | ||
33 | /** |
|
34 | * Derives a {@link ConfigurationKey} from a path found in a definition file. |
|
35 | */ |
|
36 | @ThreadSafe |
|
37 | public final class EnvAppDefinitionKeyHelper implements Serializable, |
|
38 | DefinitionKeyHelper |
|
39 | { |
|
40 | // ********************************* Fields ********************************* |
|
41 | ||
42 | // --- constants ------------------------------------------------------------ |
|
43 | ||
44 | /** |
|
45 | * The class version identifier. |
|
46 | */ |
|
47 | private static final long serialVersionUID = 1L; |
|
48 | ||
49 | // --- members -------------------------------------------------------------- |
|
50 | ||
51 | /** |
|
52 | * The context to evaluate the configuration keys from properties file paths. |
|
53 | * |
|
54 | * @serial |
|
55 | */ |
|
56 | private final EnvAppPropertiesDefinitionContext context; |
|
57 | ||
58 | // ****************************** Initializer ******************************* |
|
59 | ||
60 | // ****************************** Constructors ****************************** |
|
61 | ||
62 | /** |
|
63 | * Convenience constructor using the default TLDs and not registering any |
|
64 | * environments, nodes or groups. |
|
65 | */ |
|
66 | public EnvAppDefinitionKeyHelper() |
|
67 | { |
|
68 | 0 | this(new EnvAppPropertiesDefinitionContext()); |
69 | 0 | } |
70 | ||
71 | /** |
|
72 | * Default constructor. |
|
73 | * |
|
74 | * @param context the context to evaluate the configuration keys from |
|
75 | * properties file paths. |
|
76 | * @throws NullPointerException if {@code context} is <code>null</code>. |
|
77 | */ |
|
78 | public EnvAppDefinitionKeyHelper( |
|
79 | final EnvAppPropertiesDefinitionContext context) |
|
80 | throws NullPointerException |
|
81 | 0 | { |
82 | 0 | this.context = Arg.checkNotNull("context", context); |
83 | 0 | } |
84 | ||
85 | // ****************************** Inner Classes ***************************** |
|
86 | ||
87 | // ********************************* Methods ******************************** |
|
88 | ||
89 | // --- init ----------------------------------------------------------------- |
|
90 | ||
91 | // --- get&set -------------------------------------------------------------- |
|
92 | ||
93 | // --- business ------------------------------------------------------------- |
|
94 | ||
95 | /** |
|
96 | * Parses the given path to create a configuration key. |
|
97 | * <p> |
|
98 | * The expected syntax is as follows: |
|
99 | * </p> |
|
100 | * <ol> |
|
101 | * <li><code>/environment</code></li> |
|
102 | * <li><code>/environment/node</code></li> |
|
103 | * <li><code>/environment/node/group</code></li> |
|
104 | * <li><code>/environment/node/group/application</code></li> |
|
105 | * <li><code>/environment/node/group/application/version</code></li> |
|
106 | * <li><code>/environment/group</code></li> |
|
107 | * <li><code>/environment/group/application</code></li> |
|
108 | * <li><code>/environment/group/application/version</code></li> |
|
109 | * <li><code>/group</code></li> |
|
110 | * <li><code>/group/application</code></li> |
|
111 | * <li><code>/group/application/version</code></li> |
|
112 | * </ol> |
|
113 | * <p> |
|
114 | * A file ending with properties following the path will be chopped. |
|
115 | * </p> |
|
116 | * <p> |
|
117 | * The parser has to determine whether a part of the path is a |
|
118 | * <code>environment</code>, a <code>node</code> or a <code>group</code>. |
|
119 | * Since a <code>node</code> is always prefixed by an <code>environment</code> |
|
120 | * only the following two cases have to be dealt with: |
|
121 | * </p> |
|
122 | * <ol> |
|
123 | * <li><code>environment</code> vs. <code>group</code></li> |
|
124 | * <li><code>node</code> vs. <code>group</code></li> |
|
125 | * </ol> |
|
126 | * <p> |
|
127 | * <code>group</code>s start with |
|
128 | * </p> |
|
129 | * <ol> |
|
130 | * <li>A TLD as registered by default by |
|
131 | * {@link AbstractPropertiesDefinitionContext#DEFAULT_TLDS} or explicitly |
|
132 | * registered with {@link AbstractPropertiesDefinitionContext}</li> |
|
133 | * <li>Two letters followed by a dot (<code>.</code>)</li> |
|
134 | * <li>Any sequence of characters that is explicitly registered as a group in |
|
135 | * the <code>definition.xml</code> file</li> |
|
136 | * </ol> |
|
137 | * <p> |
|
138 | * <code>environment</code>s and <code>node</code>s do not start as |
|
139 | * <code>groups</code> except they are explicitly registered in the |
|
140 | * <code>definition.xml</code> file. |
|
141 | * </p> |
|
142 | * |
|
143 | * @param pathWithFile the path to parse. |
|
144 | * @return the configuration key. |
|
145 | * @throws IllegalArgumentException if the given {@code path} is not valid |
|
146 | * according to the rules given above. |
|
147 | */ |
|
148 | @Override |
|
149 | public ConfigurationKey<?> parse(final String pathWithFile) |
|
150 | throws IllegalArgumentException |
|
151 | { |
|
152 | 0 | final ConfigurationKey<?> explicitKey = fetchExplicitKey(pathWithFile); |
153 | 0 | if (explicitKey != null) |
154 | { |
|
155 | 0 | return explicitKey; |
156 | } |
|
157 | ||
158 | 0 | final String path = chopFile(pathWithFile); |
159 | ||
160 | 0 | final StringTokenizer tokenizer = new StringTokenizer(path, "/"); |
161 | 0 | if (tokenizer.hasMoreTokens()) |
162 | { |
|
163 | final ConfigurationKey<?> key; |
|
164 | ||
165 | 0 | final String token = tokenizer.nextToken(); |
166 | 0 | if (isGroup(token)) |
167 | { |
|
168 | 0 | key = parseApplicationKey(token, tokenizer); |
169 | } |
|
170 | else |
|
171 | { |
|
172 | 0 | key = parseEnvironmentKey(token, tokenizer); |
173 | } |
|
174 | ||
175 | 0 | return key; |
176 | } |
|
177 | ||
178 | 0 | return ConfigurationKeyContextManager.INSTANCE.context() |
179 | .configurationKeyFactory().createDefaultKey(); |
|
180 | // throw new IllegalArgumentException( |
|
181 | // "Path '" + path + "' does not contain an environment or group."); |
|
182 | } |
|
183 | ||
184 | private static String chopFile(final String pathWithFile) |
|
185 | { |
|
186 | 0 | if (pathWithFile.endsWith(".properties")) |
187 | { |
|
188 | 0 | final int lastSlash = pathWithFile.lastIndexOf('/'); |
189 | 0 | if (lastSlash != -1) |
190 | { |
|
191 | 0 | final String path = pathWithFile.substring(0, lastSlash); |
192 | 0 | return path; |
193 | } |
|
194 | ||
195 | 0 | return ""; |
196 | } |
|
197 | 0 | return pathWithFile; |
198 | } |
|
199 | ||
200 | private ConfigurationKey<?> fetchExplicitKey(final String path) |
|
201 | { |
|
202 | 0 | ConfigurationKey<?> key = context.getKey(path); |
203 | 0 | if (key == null) |
204 | { |
|
205 | 0 | key = context.getKey(null); |
206 | } |
|
207 | 0 | return key; |
208 | } |
|
209 | ||
210 | private boolean isGroup(final String token) |
|
211 | { |
|
212 | 0 | if (context.isRegisteredEnvironment(token) |
213 | || context.isRegisteredNode(token)) |
|
214 | { |
|
215 | 0 | return false; |
216 | } |
|
217 | ||
218 | 0 | return context.isGroup(token); |
219 | } |
|
220 | ||
221 | private ConfigurationKey<?> parseEnvironmentKey(final String environment, |
|
222 | final StringTokenizer tokenizer) |
|
223 | { |
|
224 | final EnvironmentId envId; |
|
225 | final ApplicationId appId; |
|
226 | 0 | if (tokenizer.hasMoreTokens()) |
227 | { |
|
228 | 0 | final String token = tokenizer.nextToken(); |
229 | 0 | if (isGroup(token)) |
230 | { |
|
231 | 0 | envId = new EnvironmentId(environment); |
232 | 0 | appId = parseAppId(token, tokenizer); |
233 | } |
|
234 | else |
|
235 | { |
|
236 | 0 | envId = new EnvironmentId(environment, token); |
237 | 0 | if (tokenizer.hasMoreTokens()) |
238 | { |
|
239 | 0 | appId = parseAppId(tokenizer.nextToken(), tokenizer); |
240 | } |
|
241 | else |
|
242 | { |
|
243 | 0 | appId = ANY_APP; |
244 | } |
|
245 | } |
|
246 | 0 | } |
247 | else |
|
248 | { |
|
249 | 0 | envId = new EnvironmentId(environment); |
250 | 0 | appId = ANY_APP; |
251 | } |
|
252 | ||
253 | 0 | final ConfigurationKey<?> key = new EnvAppConfigurationKey(envId, appId); |
254 | ||
255 | 0 | return key; |
256 | } |
|
257 | ||
258 | private ApplicationId parseAppId(final String group, |
|
259 | final StringTokenizer tokenizer) |
|
260 | { |
|
261 | 0 | String artifact = null; |
262 | 0 | String version = null; |
263 | 0 | if (tokenizer.hasMoreTokens()) |
264 | { |
|
265 | 0 | artifact = tokenizer.nextToken(); |
266 | 0 | if (tokenizer.hasMoreTokens()) |
267 | { |
|
268 | 0 | version = tokenizer.nextToken(); |
269 | } |
|
270 | } |
|
271 | ||
272 | 0 | return new ApplicationId(group, artifact, version); |
273 | } |
|
274 | ||
275 | private ConfigurationKey<?> parseApplicationKey(final String group, |
|
276 | final StringTokenizer tokenizer) |
|
277 | { |
|
278 | 0 | final EnvironmentId envId = ANY_ENV; |
279 | 0 | final ApplicationId appId = parseAppId(group, tokenizer); |
280 | ||
281 | 0 | return new EnvAppConfigurationKey(envId, appId); |
282 | } |
|
283 | ||
284 | // --- object basics -------------------------------------------------------- |
|
285 | ||
286 | } |