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 }