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