1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.settings4j.connector;
21
22 import java.util.Properties;
23
24 import javax.naming.Context;
25 import javax.naming.InitialContext;
26 import javax.naming.NameNotFoundException;
27 import javax.naming.NamingException;
28 import javax.naming.NoInitialContextException;
29
30 import org.apache.commons.lang3.BooleanUtils;
31 import org.apache.commons.lang3.StringUtils;
32 import org.apache.commons.lang3.Validate;
33 import org.settings4j.Constants;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 public class JNDIConnector extends AbstractConnector {
93
94
95 private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(JNDIConnector.class);
96
97 private String providerUrl;
98
99 private String initialContextFactory;
100
101 private String urlPkgPrefixes;
102
103 private String contextPathPrefix = "java:comp/env/";
104
105 private Boolean isJNDIAvailable;
106
107 @Override
108
109 @SuppressWarnings("PMD.ReturnEmptyArrayRatherThanNull")
110 public byte[] getContent(final String key) {
111 Validate.notNull(key);
112 final Object obj = lookupInContext(key);
113 if (obj == null) {
114 return null;
115 }
116
117
118
119 if (obj instanceof String && getContentResolver() != null) {
120 final byte[] content = getContentResolver().getContent((String) obj);
121 if (content != null) {
122 return content;
123 }
124 }
125
126 if (obj instanceof byte[]) {
127 return (byte[]) obj;
128 }
129
130 LOG.warn("Wrong Type: {} for Key: {}", obj.getClass().getName(), key);
131 return null;
132 }
133
134 @Override
135 public Object getObject(final String key) {
136 Validate.notNull(key);
137 final Object obj = lookupInContext(key);
138
139
140
141 if (obj instanceof String && getObjectResolver() != null) {
142 final Object convertedObject = getObjectResolver().getObject((String) obj, getContentResolver());
143 if (convertedObject != null) {
144 return convertedObject;
145 }
146 }
147
148 return obj;
149 }
150
151 @Override
152 public String getString(final String key) {
153 Validate.notNull(key);
154 final Object obj = lookupInContext(key);
155 try {
156 return (String) obj;
157 } catch (final ClassCastException e) {
158 logInfoButExceptionDebug(String.format("Wrong Type: %s for Key: %s", obj.getClass().getName(), key), e);
159 return null;
160 }
161 }
162
163
164
165
166
167
168
169
170
171
172
173
174
175 public int setObject(final String key, final Object value) {
176 return rebindToContext(normalizeKey(key), value);
177 }
178
179 private InitialContext getJNDIContext() throws NamingException {
180 InitialContext initialContext;
181
182 if (StringUtils.isEmpty(this.providerUrl) && StringUtils.isEmpty(this.initialContextFactory)
183 && StringUtils.isEmpty(this.urlPkgPrefixes)) {
184
185 initialContext = new InitialContext();
186 } else {
187 final Properties prop = new Properties();
188 prop.put(Context.PROVIDER_URL, this.providerUrl);
189 prop.put(Context.INITIAL_CONTEXT_FACTORY, this.initialContextFactory);
190 prop.put(Context.URL_PKG_PREFIXES, this.urlPkgPrefixes);
191 initialContext = new InitialContext(prop);
192 }
193
194 return initialContext;
195 }
196
197
198
199
200
201
202
203
204
205 public boolean isJNDIAvailable() {
206 if (this.isJNDIAvailable == null) {
207 try {
208 getJNDIContext().lookup(getContextPathPrefix());
209 LOG.debug("JNDI Context is available.");
210 this.isJNDIAvailable = Boolean.TRUE;
211 } catch (final NoInitialContextException e) {
212 LOG.info("No JNDI Context available! JNDIConnector will be disabled: {}", e.getMessage());
213 this.isJNDIAvailable = Boolean.FALSE;
214 } catch (final NamingException e) {
215 logInfoButExceptionDebug(String.format("JNDI Context is available but %s", e.getMessage()), e);
216 this.isJNDIAvailable = Boolean.TRUE;
217 }
218 }
219
220 return this.isJNDIAvailable.booleanValue();
221 }
222
223 public void setProviderUrl(final String providerUrl) {
224 this.providerUrl = providerUrl;
225 }
226
227 public void setInitialContextFactory(final String initialContextFactory) {
228 this.initialContextFactory = initialContextFactory;
229 }
230
231 public void setUrlPkgPrefixes(final String urlPkgPrefixes) {
232 this.urlPkgPrefixes = urlPkgPrefixes;
233 }
234
235 private Object lookupInContext(final String key) {
236 return lookupInContext(key, true);
237 }
238
239 private Object lookupInContext(final String key, final boolean withPrefix) {
240 if (!isJNDIAvailable()) {
241 return null;
242 }
243 final String normalizedKey = normalizeKey(key, withPrefix);
244 InitialContext ctx = null;
245 Object result = null;
246 try {
247 ctx = getJNDIContext();
248 result = ctx.lookup(normalizedKey);
249 } catch (final NoInitialContextException e) {
250 logInfoButExceptionDebug(String.format("Maybe no JNDI-Context available. %s", e.getMessage()), e);
251 } catch (final NamingException e) {
252 LOG.debug("cannot lookup key: {} ({})", key, normalizedKey, e);
253 if (withPrefix) {
254 result = lookupInContext(key, false);
255 }
256 } finally {
257 closeQuietly(ctx);
258 }
259 return result;
260 }
261
262
263
264
265
266
267
268 protected void closeQuietly(final InitialContext ctx) {
269 if (ctx != null) {
270 try {
271 ctx.close();
272 } catch (final NamingException e) {
273 LOG.info("cannot close context: {}", ctx, e);
274 }
275 }
276 }
277
278
279
280
281
282
283 public int rebindToContext(final String key, final Object value) {
284
285 if (BooleanUtils.isFalse(this.isJNDIAvailable)) {
286
287 return Constants.SETTING_NOT_POSSIBLE;
288 }
289
290 LOG.debug("Try to rebind Key '{}' with value: {}", key, value);
291
292 InitialContext ctx = null;
293 int result = Constants.SETTING_NOT_POSSIBLE;
294 try {
295 ctx = getJNDIContext();
296 createParentContext(ctx, key);
297 ctx.rebind(key, value);
298 result = Constants.SETTING_SUCCESS;
299 } catch (final NoInitialContextException e) {
300 logInfoButExceptionDebug(String.format("Maybe no JNDI-Context available. %s", e.getMessage()), e);
301 } catch (final NamingException e) {
302
303
304
305 logInfoButExceptionDebug(String.format("cannot bind key: '%s'. %s", key, e.getMessage()), e);
306 } finally {
307 closeQuietly(ctx);
308 }
309 return result;
310 }
311
312 private static void createParentContext(final Context ctx, final String key) throws NamingException {
313
314
315 LOG.debug("createParentContext: {}", key);
316
317 final String[] path = key.split("/");
318
319 final int lastIndex = path.length - 1;
320
321 Context tmpCtx = ctx;
322
323 for (int i = 0; i < lastIndex; i++) {
324 Object obj = null;
325 try {
326 obj = tmpCtx.lookup(path[i]);
327 } catch (@SuppressWarnings("unused") final NameNotFoundException e) {
328 LOG.debug("obj is null and subcontext will be generated: {}", path[i]);
329 }
330
331 if (obj == null) {
332 tmpCtx = tmpCtx.createSubcontext(path[i]);
333 LOG.debug("createSubcontext: {}", path[i]);
334 } else if (obj instanceof Context) {
335 tmpCtx = (Context) obj;
336 } else {
337 throw new RuntimeException("Illegal node/branch clash. At branch value '" + path[i]
338 + "' an Object was found: " + obj);
339 }
340 }
341 }
342
343 private String normalizeKey(final String key) {
344 return normalizeKey(key, true);
345 }
346
347 private String normalizeKey(final String key, final boolean withPrefix) {
348 Validate.notNull(key);
349 String normalizeKey = key;
350 if (normalizeKey.startsWith(this.contextPathPrefix)) {
351 return normalizeKey;
352 }
353
354 normalizeKey = normalizeKey.replace('\\', '/');
355
356 if (startsWithSlash(normalizeKey)) {
357 normalizeKey = normalizeKey.substring(1);
358 }
359 if (withPrefix) {
360 return this.contextPathPrefix + normalizeKey;
361 }
362 return normalizeKey;
363 }
364
365 private boolean startsWithSlash(final String normalizeKey) {
366 return normalizeKey.charAt(0) == '/';
367 }
368
369 public String getContextPathPrefix() {
370 return this.contextPathPrefix;
371 }
372
373 public void setContextPathPrefix(final String contextPathPrefix) {
374 this.contextPathPrefix = contextPathPrefix;
375 }
376
377 protected Boolean getIsJNDIAvailable() {
378 return this.isJNDIAvailable;
379 }
380
381 protected void setIsJNDIAvailable(final Boolean isJNDIAvailable) {
382 this.isJNDIAvailable = isJNDIAvailable;
383 }
384
385
386
387
388
389
390
391 protected void logInfoButExceptionDebug(final String message, final Exception exc) {
392 LOG.info(message);
393 LOG.debug(message, exc);
394 }
395 }