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.LinkedHashSet;
022 import java.util.Map;
023 import java.util.Set;
024 import java.util.concurrent.atomic.AtomicReference;
025
026 import javax.naming.Binding;
027 import javax.naming.Context;
028 import javax.naming.Name;
029 import javax.naming.NamingEnumeration;
030 import javax.naming.NamingException;
031 import javax.naming.NotContextException;
032 import javax.naming.OperationNotSupportedException;
033
034 /**
035 * @version $Rev$ $Date$
036 */
037 public class ContextFederation {
038 private final Context actualContext;
039 private final AtomicReference<Set<Context>> federatedContextRef = new AtomicReference<Set<Context>>(Collections.<Context>emptySet());
040 public static final int MAX_WRITE_ATTEMPTS = 10;
041
042 public ContextFederation(Context actualContext) {
043 this.actualContext = actualContext;
044 }
045
046 public ContextFederation(Context actualContext, Set<Context> federatedContexts) {
047 this.actualContext = actualContext;
048 Set<Context> copy = new LinkedHashSet<Context>(federatedContexts);
049 federatedContextRef.set(Collections.unmodifiableSet(copy));
050 }
051
052 public void addContext(Context context) {
053 Set<Context> federatedContext;
054 Set<Context> newFederatedContext;
055 for (int i = 0; i < MAX_WRITE_ATTEMPTS; i++) {
056 federatedContext = getFederatedContexts();
057
058 newFederatedContext = new LinkedHashSet<Context>(federatedContext);
059 newFederatedContext.add(context);
060 newFederatedContext = Collections.unmodifiableSet(newFederatedContext);
061 if (federatedContextRef.compareAndSet(federatedContext, newFederatedContext)) {
062 return;
063 }
064 }
065 throw new RuntimeException("Unable to update federatedContextRef within " + MAX_WRITE_ATTEMPTS + " attempts");
066 }
067
068 public void removeContext(Context context) {
069 Set<Context> federatedContext;
070 Set<Context> newFederatedContext;
071 for (int i = 0; i < MAX_WRITE_ATTEMPTS; i++) {
072 federatedContext = getFederatedContexts();
073
074 newFederatedContext = new LinkedHashSet<Context>(federatedContext);
075 newFederatedContext.remove(context);
076 newFederatedContext = Collections.unmodifiableSet(newFederatedContext);
077 if (federatedContextRef.compareAndSet(federatedContext, newFederatedContext)) {
078 return;
079 }
080 }
081 throw new RuntimeException("Unable to update federatedContextRef within " + MAX_WRITE_ATTEMPTS + " attempts");
082 }
083
084 public Set<Context> getFederatedContexts() {
085 return federatedContextRef.get();
086 }
087
088 public Object getFederatedBinding(String name) throws NamingException {
089 for (Context context : getFederatedContexts()) {
090
091 try {
092 Object value = context.lookup(name);
093 if (value != null) {
094 return value;
095 }
096 } catch (NamingException e) {
097 // ignore
098 }
099 }
100 return null;
101 }
102
103 public Map<String, Object> getFederatedBindings(String name) throws NamingException {
104 Map<String, Object> bindings = new HashMap<String, Object>();
105 for (Context context : getFederatedContexts()) {
106
107 // list federated context
108 try {
109 NamingEnumeration namingEnumeration = context.listBindings(name);
110
111 // add to bindings
112 while (namingEnumeration.hasMoreElements()) {
113 Binding binding = (Binding) namingEnumeration.nextElement();
114 String bindingName = binding.getName();
115
116 // don't overwrite existing bindings
117 if (!bindings.containsKey(bindingName)) {
118 try {
119 bindings.put(bindingName, binding.getObject());
120 } catch (RuntimeException e) {
121 // if this is a wrapped NamingException, unwrap and throw the original
122 Throwable cause = e.getCause();
123 if (cause != null && cause instanceof NamingException ) {
124 throw (NamingException)cause;
125 }
126 // Wrap this into a RuntimeException.
127 throw (NamingException)new NamingException("Could retrieve bound instance " + name).initCause(e);
128 }
129 }
130 }
131 } catch (NotContextException e) {
132 //this context does not include the supplied name
133 }
134 }
135 return bindings;
136 }
137
138 protected boolean addBinding(String name, Object value, boolean rebind) throws NamingException {
139 for (Context context : getFederatedContexts()) {
140
141 try {
142 if (rebind) {
143 context.rebind(name, value);
144 } else {
145 context.bind(name, value);
146 }
147 return true;
148 } catch (OperationNotSupportedException ignored) {
149 }
150 }
151 return false;
152 }
153
154 protected boolean removeBinding(String name) throws NamingException {
155 for (Context context : getFederatedContexts()) {
156
157 try {
158 context.unbind(name);
159 return true;
160 } catch (OperationNotSupportedException ignored) {
161 }
162 }
163 return false;
164 }
165
166 public Object lookup(Name name) {
167 for (Context federatedContext : getFederatedContexts()) {
168 try {
169 Object value = federatedContext.lookup(name);
170 if (value instanceof Context) {
171 return new VirtualSubcontext(name, actualContext);
172 } else {
173 return value;
174 }
175 } catch (NamingException ignored) {
176 }
177 }
178 return null;
179 }
180
181 public ContextFederation createSubcontextFederation(String subcontextName, Context actualSubcontext) throws NamingException {
182 Name parsedSubcontextName = actualContext.getNameParser("").parse(subcontextName);
183
184 ContextFederation subcontextFederation = new ContextFederation(actualSubcontext);
185 for (Context federatedContext : getFederatedContexts()) {
186 VirtualSubcontext virtualSubcontext = new VirtualSubcontext(parsedSubcontextName, federatedContext);
187 subcontextFederation.addContext(virtualSubcontext);
188 }
189 return subcontextFederation;
190 }
191 }