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(String name, Object value) 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 : " + name).initCause(e); 066 } 067 } 068 069 // for normal References we have to do it the slow way 070 try { 071 return NamingManager.getObjectInstance(reference, null, null, new Hashtable()); 072 } catch (NamingException e) { 073 throw e; 074 } catch (Exception e) { 075 throw (NamingException) new NamingException("Could not look up : " + name).initCause(e); 076 } 077 } 078 079 public static Map listToMap(NamingEnumeration enumeration) { 080 Map result = new HashMap(); 081 while (enumeration.hasMoreElements()) { 082 NameClassPair nameClassPair = (NameClassPair) enumeration.nextElement(); 083 String name = nameClassPair.getName(); 084 result.put(name, nameClassPair.getClassName()); 085 } 086 return result; 087 } 088 089 public static Map listBindingsToMap(NamingEnumeration enumeration) { 090 Map result = new HashMap(); 091 while (enumeration.hasMoreElements()) { 092 Binding binding = (Binding) enumeration.nextElement(); 093 String name = binding.getName(); 094 result.put(name, binding.getObject()); 095 } 096 return result; 097 } 098 099 public static final class ListEnumeration implements NamingEnumeration { 100 private final Iterator iterator; 101 102 public ListEnumeration(Map localBindings) { 103 this.iterator = localBindings.entrySet().iterator(); 104 } 105 106 public boolean hasMore() { 107 return iterator.hasNext(); 108 } 109 110 public boolean hasMoreElements() { 111 return iterator.hasNext(); 112 } 113 114 public Object next() { 115 return nextElement(); 116 } 117 118 public Object nextElement() { 119 Map.Entry entry = (Map.Entry) iterator.next(); 120 String name = (String) entry.getKey(); 121 Object value = entry.getValue(); 122 String className = null; 123 if (value instanceof Reference) { 124 Reference reference = (Reference) value; 125 className = reference.getClassName(); 126 } else { 127 className = value.getClass().getName(); 128 } 129 return new NameClassPair(name, className); 130 } 131 132 public void close() { 133 } 134 } 135 136 public static final class ListBindingEnumeration implements NamingEnumeration { 137 private final Iterator iterator; 138 139 public ListBindingEnumeration(Map localBindings) { 140 this.iterator = localBindings.entrySet().iterator(); 141 } 142 143 public boolean hasMore() { 144 return iterator.hasNext(); 145 } 146 147 public boolean hasMoreElements() { 148 return iterator.hasNext(); 149 } 150 151 public Object next() { 152 return nextElement(); 153 } 154 155 public Object nextElement() { 156 Map.Entry entry = (Map.Entry) iterator.next(); 157 String name = (String) entry.getKey(); 158 Object value = entry.getValue(); 159 return new ReadOnlyBinding(name, value); 160 } 161 162 public void close() { 163 } 164 } 165 166 public static final class ReadOnlyBinding extends Binding { 167 private final Object value; 168 169 public ReadOnlyBinding(String name, Object value) { 170 super(name, value); 171 this.value = value; 172 } 173 174 public void setName(String name) { 175 throw new UnsupportedOperationException("Context is read only"); 176 } 177 178 public String getClassName() { 179 if (value instanceof Reference) { 180 Reference reference = (Reference) value; 181 return reference.getClassName(); 182 } 183 return value.getClass().getName(); 184 } 185 186 public void setClassName(String name) { 187 throw new UnsupportedOperationException("Context is read only"); 188 } 189 190 public Object getObject() { 191 try { 192 return resolve(getName(), value); 193 } catch (NamingException e) { 194 throw new RuntimeException(e); 195 } 196 } 197 198 public void setObject(Object obj) { 199 throw new UnsupportedOperationException("Context is read only"); 200 } 201 202 public boolean isRelative() { 203 return false; 204 } 205 206 public void setRelative(boolean r) { 207 throw new UnsupportedOperationException("Context is read only"); 208 } 209 } 210 211 212 private static final class SimpleNameParser implements NameParser { 213 private static final Properties PARSER_PROPERTIES = new Properties(); 214 215 static { 216 PARSER_PROPERTIES.put("jndi.syntax.direction", "left_to_right"); 217 PARSER_PROPERTIES.put("jndi.syntax.separator", "/"); 218 } 219 220 221 private SimpleNameParser() { 222 } 223 224 public Name parse(String name) throws NamingException { 225 return new CompoundName(name, PARSER_PROPERTIES); 226 } 227 } 228 229 public static Map createBindings(Map absoluteBindings, NestedContextFactory factory) throws NamingException { 230 // create a tree of Nodes using the absolute bindings 231 Node node = buildMapTree(absoluteBindings); 232 233 // convert the node tree into a tree of context objects 234 Map localBindings = ContextUtil.createBindings(null, node, factory); 235 236 return localBindings; 237 } 238 239 private static Map createBindings(String nameInNameSpace, Node node, NestedContextFactory factory) throws NamingException { 240 Map bindings = new HashMap(node.size()); 241 for (Iterator iterator = node.entrySet().iterator(); iterator.hasNext();) { 242 Map.Entry entry = (Map.Entry) iterator.next(); 243 String name = (String) entry.getKey(); 244 Object value = entry.getValue(); 245 246 // if this is a nested node we need to create a context for the node 247 if (value instanceof Node) { 248 Node nestedNode = (Node) value; 249 250 // recursive call create bindings to cause building the context depth first 251 String path = nameInNameSpace == null ? name : nameInNameSpace + "/" + name; 252 253 Map nestedBindings = createBindings(path, nestedNode, factory); 254 Context nestedContext = factory.createNestedSubcontext(path, nestedBindings); 255 bindings.put(name, nestedContext); 256 } else { 257 bindings.put(name, value); 258 } 259 } 260 return bindings; 261 } 262 263 264 /** 265 * Do nothing subclass of hashmap used to differentiate between a Map in the tree an a nested element during tree building 266 */ 267 public static final class Node extends HashMap { 268 } 269 270 public static Node buildMapTree(Map absoluteBindings) throws NamingException { 271 Node rootContext = new Node(); 272 273 for (Iterator iterator = absoluteBindings.entrySet().iterator(); iterator.hasNext();) { 274 Map.Entry entry = (Map.Entry) iterator.next(); 275 String name = (String) entry.getKey(); 276 Object value = entry.getValue(); 277 278 Node parentContext = rootContext; 279 280 Name compoundName = ContextUtil.parseName(name); 281 for (Enumeration parts = compoundName.getAll(); parts.hasMoreElements(); ) { 282 String part = (String) parts.nextElement(); 283 // the last element in the path is the name of the value 284 if (parts.hasMoreElements()) { 285 // nest node into parent 286 Node bindings = (Node) parentContext.get(part); 287 if (bindings == null) { 288 bindings = new Node(); 289 parentContext.put(part, bindings); 290 } 291 292 parentContext = bindings; 293 } 294 } 295 296 parentContext.put(compoundName.get(compoundName.size() - 1), value); 297 } 298 return rootContext; 299 } 300 }