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 */ 017package org.apache.xbean.naming.context; 018 019import java.util.Collections; 020import java.util.HashMap; 021import java.util.LinkedHashSet; 022import java.util.Map; 023import java.util.Set; 024import java.util.concurrent.atomic.AtomicReference; 025 026import javax.naming.Binding; 027import javax.naming.Context; 028import javax.naming.Name; 029import javax.naming.NamingEnumeration; 030import javax.naming.NamingException; 031import javax.naming.NotContextException; 032import javax.naming.OperationNotSupportedException; 033 034/** 035 * @version $Rev$ $Date$ 036 */ 037public 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}