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.api.core.app; 17 18 import javax.naming.Context; 19 import javax.naming.NameAlreadyBoundException; 20 import javax.naming.NameClassPair; 21 import javax.naming.NameNotFoundException; 22 import javax.naming.NamingEnumeration; 23 import javax.naming.NamingException; 24 25 import org.apache.commons.lang.ObjectUtils; 26 import org.apache.commons.lang.StringUtils; 27 28 /** 29 * Defines constants for this library. 30 */ 31 public final class JndiContext 32 { 33 // ********************************* Fields ********************************* 34 35 // --- constants ------------------------------------------------------------ 36 37 /** 38 * The path within the JNDI context that provides information for 39 * smartics-properties. 40 */ 41 private static final String JNDI_CONTEXT_PATH = "/smartics-properties"; 42 43 /** 44 * The path within the JNDI context to access boot configuration properties. 45 */ 46 public static final String JNDI_CONTEXT_PATH_BOOT = JNDI_CONTEXT_PATH 47 + "/boot"; 48 49 /** 50 * The path within the JNDI context to access boot configuration properties. 51 */ 52 private static final String JNDI_CONTEXT_PATH_CONFIG = JNDI_CONTEXT_PATH 53 + "/config"; 54 55 // --- members -------------------------------------------------------------- 56 57 /** 58 * The context to lookup the values. 59 */ 60 private final Context context; 61 62 /** 63 * A path within the context to set the root of the configuration. May be 64 * <code>null</code> in which case the context is itself the root. The subpath 65 * is required to start with a slash ( <code>/</code>), but may be 66 * <code>null</code>. If it contains only whitespaces, the subpath is assumed 67 * to be <code>null</code>. 68 */ 69 private final String path; 70 71 // ****************************** Initializer ******************************* 72 73 // ****************************** Constructors ****************************** 74 75 /** 76 * Default constructor. 77 * 78 * @param context the context to lookup the values. 79 * @param subpath a path within the context to set the root of the 80 * configuration. The subpath is required to start with a slash ( 81 * <code>/</code>), but may be <code>null</code>. If it contains only 82 * whitespaces, the subpath is assumed to be <code>null</code>. 83 * @param configKey the configuration key which to be the last element of the 84 * subpath. The key is normalized so that all slashes are replaced by 85 * pipes. 86 * @throws IllegalArgumentException if the JNDI context cannot be initialized. 87 */ 88 private JndiContext(final Context context, final String subpath, 89 final String configKey) throws IllegalArgumentException 90 { 91 this.context = context; 92 this.path = calcPath(subpath, configKey); 93 94 initialize(); 95 } 96 97 // ****************************** Inner Classes ***************************** 98 99 // ********************************* Methods ******************************** 100 101 // --- init ----------------------------------------------------------------- 102 103 private static String calcPath(final String path, final String configKey) 104 { 105 return path + normalizeKey(configKey); 106 } 107 108 private static String normalizeKey(final String configKey) 109 { 110 if (StringUtils.isBlank(configKey)) 111 { 112 return ""; 113 } 114 115 return '/' + configKey.replace('/', '|'); 116 } 117 118 // --- factory -------------------------------------------------------------- 119 120 /** 121 * Provides access to the boot properties within a JNDI context. 122 * 123 * @param context the root context. 124 * @return the JNDI context for boot properties. 125 * @throws IllegalArgumentException if the JNDI context cannot be initialized. 126 */ 127 public static JndiContext boot(final Context context) 128 throws IllegalArgumentException 129 { 130 return new JndiContext(context, JNDI_CONTEXT_PATH_BOOT, null); 131 } 132 133 /** 134 * Provides access to the custom properties within a JNDI context. 135 * 136 * @param context the custom context. 137 * @param configKey the key to the configuration. Will be used as a path 138 * within the context to set the root of the configuration. 139 * @return the JNDI context for custom properties. 140 * @throws IllegalArgumentException if the JNDI context cannot be initialized. 141 */ 142 public static JndiContext config(final Context context, final String configKey) 143 throws IllegalArgumentException 144 { 145 return new JndiContext(context, JNDI_CONTEXT_PATH_CONFIG, configKey); 146 } 147 148 // --- get&set -------------------------------------------------------------- 149 150 // --- business ------------------------------------------------------------- 151 152 /** 153 * Initialized the context. 154 * 155 * @throws NamingException on any problem encountered. 156 */ 157 private void initialize() throws IllegalArgumentException 158 { 159 final String path = this.path.substring(1); 160 try 161 { 162 context.createSubcontext(path); 163 } 164 catch (final NameAlreadyBoundException e) 165 { 166 // OK, the context has already been established. 167 } 168 catch (final NamingException e) 169 { 170 throw new IllegalArgumentException("Cannot create subcontext for '" 171 + path + "'.", e); 172 } 173 } 174 175 /** 176 * Runs a lookup for the value with the given {@code key} in the JNDI context. 177 * 178 * @param key the key to the value. 179 * @return the value to the key in the context. 180 * @throws NamingException on any problem accessing the value. 181 */ 182 public Object lookupObject(final String key) throws NamingException 183 { 184 try 185 { 186 final String jndiKey = createJndiKey(key); 187 final Object value = context.lookup(jndiKey); 188 return value; 189 } 190 catch (final NameNotFoundException e) 191 { 192 return null; 193 } 194 195 } 196 197 private String createJndiKey(final String key) 198 { 199 final String normalized = key.replace('.', '/'); 200 return path + '/' + normalized; 201 } 202 203 /** 204 * Runs a lookup for the value with the given {@code key} in the JNDI context 205 * and returns the value as a {@link String}. 206 * 207 * @param key the key to the value. 208 * @return the value to the key in the context. 209 * @throws NamingException on any problem accessing the value. 210 */ 211 public String lookup(final String key) throws NamingException 212 { 213 try 214 { 215 final String value = ObjectUtils.toString(lookupObject(key), null); 216 return value; 217 } 218 catch (final NameNotFoundException e) 219 { 220 return null; 221 } 222 } 223 224 /** 225 * Runs a lookup for the value with the given {@code key} in the JNDI context. 226 * 227 * @param key the key to the value. 228 * @return the value to the key in the context. 229 * @throws NamingException on any problem accessing the value. 230 */ 231 public Boolean lookupBoolean(final String key) throws NamingException 232 { 233 final Object value = lookupObject(key); 234 235 if (value instanceof Boolean) 236 { 237 return (Boolean) value; 238 } 239 240 final Boolean booleanValue = 241 Boolean.valueOf(ObjectUtils.toString(value, null)); 242 return booleanValue; 243 } 244 245 /** 246 * Sets the value for the given {@code key}. 247 * 248 * @param key the key to the value. 249 * @param value the value to the key in the context. 250 * @throws NamingException on any problem accessing the value. 251 */ 252 public void set(final String key, final Object value) throws NamingException 253 { 254 final String jndiKey = createJndiKey(key); 255 if (value != null) 256 { 257 context.rebind(jndiKey, value); 258 } 259 else 260 { 261 try 262 { 263 if (context.lookup(jndiKey) != null) 264 { 265 context.unbind(jndiKey); 266 } 267 } 268 catch (final NameNotFoundException e) 269 { 270 // OK, not existing. 271 } 272 } 273 } 274 275 /** 276 * Returns the list of stored values in the context. 277 * 278 * @return the list of stored values in the context. 279 * @throws NamingException on any problem accessing the naming context. 280 */ 281 public NamingEnumeration<NameClassPair> list() throws NamingException 282 { 283 return context.list(path); 284 } 285 286 /** 287 * Returns the name of the JNDI namespace. 288 * 289 * @return the name of the JNDI namespace. 290 */ 291 public String getSourceId() 292 { 293 return "java:" + path; 294 } 295 296 // --- object basics -------------------------------------------------------- 297 298 }