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 }