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 java.util.Collections;
020 import java.util.HashMap;
021 import java.util.Map;
022
023 import javax.naming.Context;
024 import javax.naming.Name;
025 import javax.naming.NamingException;
026 import javax.naming.OperationNotSupportedException;
027
028 import org.apache.xbean.naming.reference.CachingReference;
029
030 /**
031 *
032 * @version $Rev: 417891 $ $Date: 2006-06-28 15:45:07 -0700 (Wed, 28 Jun 2006) $
033 */
034 public class ImmutableContext extends AbstractContext {
035 private final Map<String, Object> localBindings;
036 private final Map<String, Object> absoluteIndex;
037
038 public ImmutableContext(Map<String, Object> bindings) throws NamingException {
039 this("", bindings, true);
040 }
041
042 public ImmutableContext(Map<String, Object> bindings, boolean cacheReferences) throws NamingException {
043 this("", bindings, cacheReferences);
044 }
045
046 public ImmutableContext(String nameInNamespace, Map<String, Object> bindings, boolean cacheReferences) throws NamingException {
047 super(nameInNamespace, ContextAccess.UNMODIFIABLE);
048
049 if (cacheReferences) {
050 bindings = CachingReference.wrapReferences(bindings, this);
051 }
052
053 Map<String, Object> localBindings = ContextUtil.createBindings(bindings, this);
054 this.localBindings = Collections.unmodifiableMap(localBindings);
055
056 Map<String, Object> globalBindings = ImmutableContext.buildAbsoluteIndex("", localBindings);
057 this.absoluteIndex = Collections.unmodifiableMap(globalBindings);
058 }
059
060 private static Map<String, Object> buildAbsoluteIndex(String nameInNamespace, Map<String, Object> bindings) {
061 String path = nameInNamespace;
062 if (path.length() > 0) {
063 path += "/";
064 }
065
066 Map<String, Object> globalBindings = new HashMap<String, Object>();
067 for (Map.Entry<String, Object> entry : bindings.entrySet()) {
068 String name = entry.getKey();
069 Object value = entry.getValue();
070 if (value instanceof NestedImmutableContext) {
071 NestedImmutableContext nestedContext = (NestedImmutableContext) value;
072 globalBindings.putAll(ImmutableContext.buildAbsoluteIndex(nestedContext.getNameInNamespace(), nestedContext.localBindings));
073 }
074 globalBindings.put(path + name, value);
075 }
076 return globalBindings;
077 }
078
079 protected Object getDeepBinding(String name) {
080 return absoluteIndex.get(name);
081 }
082
083 protected Map<String, Object> getBindings() {
084 return localBindings;
085 }
086
087 protected final void addDeepBinding(String name, Object value, boolean createIntermediateContexts) throws NamingException {
088 throw new OperationNotSupportedException("Context is immutable");
089 }
090
091 protected final boolean addBinding(String name, Object value, boolean rebind) throws NamingException {
092 throw new OperationNotSupportedException("Context is immutable");
093 }
094
095 protected final void removeDeepBinding(Name name, boolean pruneEmptyContexts) throws NamingException {
096 throw new OperationNotSupportedException("Context is immutable");
097 }
098
099 protected final boolean removeBinding(String name, boolean removeNotEmptyContext) throws NamingException {
100 throw new OperationNotSupportedException("Context is immutable");
101 }
102
103 public boolean isNestedSubcontext(Object value) {
104 if (value instanceof NestedImmutableContext) {
105 NestedImmutableContext context = (NestedImmutableContext) value;
106 return this == context.getImmutableContext();
107 }
108 return false;
109 }
110
111 public Context createNestedSubcontext(String path, Map bindings) {
112 return new NestedImmutableContext(path, bindings);
113 }
114
115 /**
116 * Nested context which shares the absolute index map in MapContext.
117 */
118 public final class NestedImmutableContext extends AbstractContext {
119 private final Map<String, Object> localBindings;
120 private final String pathWithSlash;
121
122 public NestedImmutableContext(String path, Map<String, Object> bindings) {
123 super(ImmutableContext.this.getNameInNamespace(path), ContextAccess.UNMODIFIABLE);
124
125 path = getNameInNamespace();
126 if (!path.endsWith("/")) path += "/";
127 this.pathWithSlash = path;
128
129 this.localBindings = Collections.unmodifiableMap(bindings);
130 }
131
132 protected Object getDeepBinding(String name) {
133 String absoluteName = pathWithSlash + name;
134 return absoluteIndex.get(absoluteName);
135 }
136
137 protected Map<String, Object> getBindings() {
138 return localBindings;
139 }
140
141 protected final void addDeepBinding(String name, Object value, boolean createIntermediateContexts) throws NamingException {
142 throw new OperationNotSupportedException("Context is immutable");
143 }
144
145 protected final boolean addBinding(String name, Object value, boolean rebind) throws NamingException {
146 throw new OperationNotSupportedException("Context is immutable");
147 }
148
149 protected final void removeDeepBinding(Name name, boolean pruneEmptyContexts) throws NamingException {
150 throw new OperationNotSupportedException("Context is immutable");
151 }
152
153 protected final boolean removeBinding(String name, boolean removeNotEmptyContext) throws NamingException {
154 throw new OperationNotSupportedException("Context is immutable");
155 }
156
157 public boolean isNestedSubcontext(Object value) {
158 if (value instanceof NestedImmutableContext) {
159 NestedImmutableContext context = (NestedImmutableContext) value;
160 return getImmutableContext() == context.getImmutableContext();
161 }
162 return false;
163 }
164
165 public Context createNestedSubcontext(String path, Map<String, Object> bindings) {
166 return new NestedImmutableContext(path, bindings);
167 }
168
169 protected ImmutableContext getImmutableContext() {
170 return ImmutableContext.this;
171 }
172 }
173 }