001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.xbean.naming.context; 018 019 import org.apache.xbean.naming.reference.SimpleReference; 020 021 import javax.naming.Binding; 022 import javax.naming.CompoundName; 023 import javax.naming.Context; 024 import javax.naming.Name; 025 import javax.naming.NameClassPair; 026 import javax.naming.NameParser; 027 import javax.naming.NamingEnumeration; 028 import javax.naming.NamingException; 029 import javax.naming.Reference; 030 import javax.naming.spi.NamingManager; 031 import java.util.Enumeration; 032 import java.util.HashMap; 033 import java.util.Hashtable; 034 import java.util.Iterator; 035 import java.util.Map; 036 import java.util.Properties; 037 038 /** 039 * @version $Rev$ $Date$ 040 */ 041 public final class ContextUtil { 042 private ContextUtil() { 043 } 044 045 public final static NameParser NAME_PARSER = new SimpleNameParser(); 046 047 public static Name parseName(String name) throws NamingException { 048 return NAME_PARSER.parse(name); 049 } 050 051 public static Object resolve(Object value, String stringName, Name parsedName, Context nameCtx) throws NamingException { 052 if (!(value instanceof Reference)) { 053 return value; 054 } 055 056 Reference reference = (Reference) value; 057 058 // for SimpleReference we can just call the getContext method 059 if (reference instanceof SimpleReference) { 060 try { 061 return ((SimpleReference) reference).getContent(); 062 } catch (NamingException e) { 063 throw e; 064 } catch (Exception e) { 065 throw (NamingException) new NamingException("Could not look up : " + stringName == null? parsedName.toString(): stringName).initCause(e); 066 } 067 } 068 069 // for normal References we have to do it the slow way 070 try { 071 if (parsedName == null) { 072 parsedName = NAME_PARSER.parse(stringName); 073 } 074 return NamingManager.getObjectInstance(reference, parsedName, nameCtx, nameCtx.getEnvironment()); 075 } catch (NamingException e) { 076 throw e; 077 } catch (Exception e) { 078 throw (NamingException) new NamingException("Could not look up : " + stringName == null? parsedName.toString(): stringName).initCause(e); 079 } 080 } 081 082 public static Map<String, String> listToMap(NamingEnumeration enumeration) { 083 Map<String, String> result = new HashMap<String, String>(); 084 while (enumeration.hasMoreElements()) { 085 NameClassPair nameClassPair = (NameClassPair) enumeration.nextElement(); 086 String name = nameClassPair.getName(); 087 result.put(name, nameClassPair.getClassName()); 088 } 089 return result; 090 } 091 092 public static Map<String, Object> listBindingsToMap(NamingEnumeration enumeration) { 093 Map<String, Object> result = new HashMap<String, Object>(); 094 while (enumeration.hasMoreElements()) { 095 Binding binding = (Binding) enumeration.nextElement(); 096 String name = binding.getName(); 097 result.put(name, binding.getObject()); 098 } 099 return result; 100 } 101 102 public static final class ListEnumeration implements NamingEnumeration<NameClassPair> { 103 private final Iterator iterator; 104 105 public ListEnumeration(Map localBindings) { 106 this.iterator = localBindings.entrySet().iterator(); 107 } 108 109 public boolean hasMore() { 110 return iterator.hasNext(); 111 } 112 113 public boolean hasMoreElements() { 114 return iterator.hasNext(); 115 } 116 117 public NameClassPair next() { 118 return nextElement(); 119 } 120 121 public NameClassPair nextElement() { 122 Map.Entry entry = (Map.Entry) iterator.next(); 123 String name = (String) entry.getKey(); 124 Object value = entry.getValue(); 125 String className; 126 if (value instanceof Reference) { 127 Reference reference = (Reference) value; 128 className = reference.getClassName(); 129 } else { 130 className = value.getClass().getName(); 131 } 132 return new NameClassPair(name, className); 133 } 134 135 public void close() { 136 } 137 } 138 139 public static final class ListBindingEnumeration implements NamingEnumeration<Binding> { 140 private final Iterator iterator; 141 private final Context context; 142 143 public ListBindingEnumeration(Map localBindings, Context context) { 144 this.iterator = localBindings.entrySet().iterator(); 145 this.context = context; 146 } 147 148 public boolean hasMore() { 149 return iterator.hasNext(); 150 } 151 152 public boolean hasMoreElements() { 153 return iterator.hasNext(); 154 } 155 156 public Binding next() { 157 return nextElement(); 158 } 159 160 public Binding nextElement() { 161 Map.Entry entry = (Map.Entry) iterator.next(); 162 String name = (String) entry.getKey(); 163 Object value = entry.getValue(); 164 return new ReadOnlyBinding(name, value, context); 165 } 166 167 public void close() { 168 } 169 } 170 171 public static final class ReadOnlyBinding extends Binding { 172 private final Object value; 173 private final Context context; 174 175 public ReadOnlyBinding(String name, Object value, Context context) { 176 super(name, value); 177 this.value = value; 178 this.context = context; 179 } 180 181 public void setName(String name) { 182 throw new UnsupportedOperationException("Context is read only"); 183 } 184 185 public String getClassName() { 186 if (value instanceof Reference) { 187 Reference reference = (Reference) value; 188 return reference.getClassName(); 189 } 190 return value.getClass().getName(); 191 } 192 193 public void setClassName(String name) { 194 throw new UnsupportedOperationException("Context is read only"); 195 } 196 197 public Object getObject() { 198 try { 199 return resolve(value, getName(), null, context); 200 } catch (NamingException e) { 201 throw new RuntimeException(e); 202 } 203 } 204 205 public void setObject(Object obj) { 206 throw new UnsupportedOperationException("Context is read only"); 207 } 208 209 public boolean isRelative() { 210 return false; 211 } 212 213 public void setRelative(boolean r) { 214 throw new UnsupportedOperationException("Context is read only"); 215 } 216 } 217 218 219 private static final class SimpleNameParser implements NameParser { 220 private static final Properties PARSER_PROPERTIES = new Properties(); 221 222 static { 223 PARSER_PROPERTIES.put("jndi.syntax.direction", "left_to_right"); 224 PARSER_PROPERTIES.put("jndi.syntax.separator", "/"); 225 } 226 227 228 private SimpleNameParser() { 229 } 230 231 public Name parse(String name) throws NamingException { 232 return new CompoundName(name, PARSER_PROPERTIES); 233 } 234 } 235 236 public static Map<String, Object> createBindings(Map<String, Object> absoluteBindings, NestedContextFactory factory) throws NamingException { 237 // create a tree of Nodes using the absolute bindings 238 Node node = buildMapTree(absoluteBindings); 239 240 // convert the node tree into a tree of context objects 241 242 return ContextUtil.createBindings(null, node, factory); 243 } 244 245 private static Map<String, Object> createBindings(String nameInNameSpace, Node node, NestedContextFactory factory) throws NamingException { 246 Map<String, Object> bindings = new HashMap<String, Object>(node.size()); 247 for (Map.Entry<String, Object> entry : node.entrySet()) { 248 String name = entry.getKey(); 249 Object value = entry.getValue(); 250 251 // if this is a nested node we need to create a context for the node 252 if (value instanceof Node) { 253 Node nestedNode = (Node) value; 254 255 // recursive call create bindings to cause building the context depth first 256 String path = nameInNameSpace == null ? name : nameInNameSpace + "/" + name; 257 258 Map<String, Object> nestedBindings = createBindings(path, nestedNode, factory); 259 Context nestedContext = factory.createNestedSubcontext(path, nestedBindings); 260 bindings.put(name, nestedContext); 261 } else { 262 bindings.put(name, value); 263 } 264 } 265 return bindings; 266 } 267 268 269 /** 270 * Do nothing subclass of hashmap used to differentiate between a Map in the tree an a nested element during tree building 271 */ 272 public static final class Node extends HashMap<String, Object> { 273 } 274 275 public static Node buildMapTree(Map<String, Object> absoluteBindings) throws NamingException { 276 Node rootContext = new Node(); 277 278 for (Map.Entry<String, Object> entry : absoluteBindings.entrySet()) { 279 String name = entry.getKey(); 280 Object value = entry.getValue(); 281 282 Node parentContext = rootContext; 283 284 Name compoundName = ContextUtil.parseName(name); 285 for (Enumeration parts = compoundName.getAll(); parts.hasMoreElements();) { 286 String part = (String) parts.nextElement(); 287 // the last element in the path is the name of the value 288 if (parts.hasMoreElements()) { 289 // nest node into parent 290 Node bindings = (Node) parentContext.get(part); 291 if (bindings == null) { 292 bindings = new Node(); 293 parentContext.put(part, bindings); 294 } 295 296 parentContext = bindings; 297 } 298 } 299 300 parentContext.put(compoundName.get(compoundName.size() - 1), value); 301 } 302 return rootContext; 303 } 304 }