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 }