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                            bindings.put(bindingName, binding.getObject());
119                        }
120                    }
121                } catch (NotContextException e) {
122                    //this context does not include the supplied name
123                }
124            }
125            return bindings;
126        }
127    
128        protected boolean addBinding(String name, Object value, boolean rebind) throws NamingException {
129            for (Context context : getFederatedContexts()) {
130    
131                try {
132                    if (rebind) {
133                        context.rebind(name, value);
134                    } else {
135                        context.bind(name, value);
136                    }
137                    return true;
138                } catch (OperationNotSupportedException ignored) {
139                }
140            }
141            return false;
142        }
143    
144        protected boolean removeBinding(String name) throws NamingException {
145            for (Context context : getFederatedContexts()) {
146    
147                try {
148                    context.unbind(name);
149                    return true;
150                } catch (OperationNotSupportedException ignored) {
151                }
152            }
153            return false;
154        }
155    
156        public Object lookup(Name name) {
157            for (Context federatedContext : getFederatedContexts()) {
158                try {
159                    Object value = federatedContext.lookup(name);
160                    if (value instanceof Context) {
161                        return new VirtualSubcontext(name, actualContext);
162                    } else {
163                        return value;
164                    }
165                } catch (NamingException ignored) {
166                }
167            }
168            return null;
169        }
170    
171        public ContextFederation createSubcontextFederation(String subcontextName, Context actualSubcontext) throws NamingException {
172            Name parsedSubcontextName = actualContext.getNameParser("").parse(subcontextName);
173    
174            ContextFederation subcontextFederation = new ContextFederation(actualSubcontext);
175            for (Context federatedContext : getFederatedContexts()) {
176                VirtualSubcontext virtualSubcontext = new VirtualSubcontext(parsedSubcontextName, federatedContext);
177                subcontextFederation.addContext(virtualSubcontext);
178            }
179            return subcontextFederation;
180        }
181    }