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.Map;
021    import java.util.Set;
022    
023    import javax.naming.Context;
024    import javax.naming.Name;
025    import javax.naming.NameAlreadyBoundException;
026    import javax.naming.NamingException;
027    
028    /**
029     * @version $Rev$ $Date$
030     */
031    public abstract class AbstractFederatedContext extends AbstractContext {
032        private final ContextFederation contextFederation;
033        private final AbstractFederatedContext masterContext;
034    
035        public AbstractFederatedContext() {
036            this("", ContextAccess.MODIFIABLE);
037        }
038    
039        public AbstractFederatedContext(String nameInNamespace) {
040            this(nameInNamespace, ContextAccess.MODIFIABLE);
041        }
042    
043        public AbstractFederatedContext(String nameInNamespace, ContextAccess contextAccess) {
044            super(nameInNamespace, contextAccess);
045            this.masterContext = this;
046            this.contextFederation = new ContextFederation(this);
047        }
048    
049        public AbstractFederatedContext(String nameInNamespace, ContextAccess contextAccess, Set<Context> federatedContexts) {
050            super(nameInNamespace, contextAccess);
051            this.masterContext = this;
052            this.contextFederation = new ContextFederation(this, federatedContexts);
053        }
054    
055        public AbstractFederatedContext(AbstractFederatedContext masterContext, String nameInNamespace) throws NamingException {
056            super(nameInNamespace, masterContext.getContextAccess());
057            this.masterContext = masterContext;
058            this.contextFederation = this.masterContext.contextFederation.createSubcontextFederation(nameInNamespace, this);
059        }
060    
061        protected Object faultLookup(String stringName, Name parsedName) {
062            Object value = contextFederation.lookup(parsedName);
063            if (value != null) {
064                return value;
065            }
066            return super.faultLookup(stringName, parsedName);
067        }
068    
069        @Override
070        protected Object getDeepBinding(String name) {
071            try {
072                Object value = contextFederation.getFederatedBinding(name);
073                if (value instanceof Context) {
074                    return null;
075                }
076                return value;
077            } catch (NamingException e) {
078                return null;
079            }
080        }
081    
082        @Override
083        protected Object getBinding(String name) throws NamingException {
084            Object value = contextFederation.getFederatedBinding(name);
085            if (value instanceof Context) {
086                return createNestedSubcontext(name, getBindings(name));
087            }
088            if (value == null) {
089                value = getWrapperBindings().get(name);
090            }
091            return value;
092        }
093    
094        protected final Map<String, Object> getBindings() throws NamingException {
095            return getBindings("");
096        }
097    
098        protected final Map<String, Object> getBindings(String name) throws NamingException {
099            Map<String, Object> bindings = contextFederation.getFederatedBindings(name);
100            bindings.putAll(getWrapperBindings());
101            return bindings;
102        }
103    
104        protected abstract Map<String, Object> getWrapperBindings() throws NamingException;
105    
106        protected boolean addBinding(String name, Object value, boolean rebind) throws NamingException {
107            if (!(value instanceof Context && !isNestedSubcontext(value))) {
108                return contextFederation.addBinding(name, value, rebind);
109            } else if (!isNestedSubcontext(value)) {
110                Context federatedContext = (Context) value;
111    
112                // if we already have a context bound at the specified value
113                Object existingValue = getBinding(name);
114                if (existingValue != null) {
115                    if (!(existingValue instanceof AbstractFederatedContext)) {
116                        throw new NameAlreadyBoundException(name);
117                    }
118    
119                    AbstractFederatedContext nestedContext = (AbstractFederatedContext) existingValue;
120                    addFederatedContext(nestedContext, federatedContext);
121                    return true;
122                } else {
123                    AbstractFederatedContext nestedContext = (AbstractFederatedContext) createNestedSubcontext(name, Collections.<String, Object>emptyMap());
124                    addFederatedContext(nestedContext, federatedContext);
125    
126                    // call back into this method using the new nested context
127                    // this gives subclasses a chance to handle the binding
128                    return addBinding(name, nestedContext, rebind);
129                }
130            }
131    
132            return false;
133        }
134    
135        protected boolean removeBinding(String name, boolean removeNotEmptyContext) throws NamingException {
136            return contextFederation.removeBinding(name);
137        }
138    
139        protected static void addFederatedContext(AbstractFederatedContext wrappingContext, Context innerContext) throws NamingException {
140            wrappingContext.contextFederation.addContext(innerContext);
141            for (Map.Entry<String, Object> entry : wrappingContext.getWrapperBindings().entrySet()) {
142                String name = entry.getKey();
143                Object value = entry.getValue();
144                if (value instanceof AbstractFederatedContext) {
145                    AbstractFederatedContext nestedContext = (AbstractFederatedContext) value;
146    
147                    Name parsedName = wrappingContext.getNameParser().parse(name);
148                    Name nameInNamespace = wrappingContext.getNameInNamespace(parsedName);
149    
150                    VirtualSubcontext virtualSubcontext = new VirtualSubcontext(nameInNamespace, innerContext);
151                    addFederatedContext(nestedContext, virtualSubcontext);
152                }
153            }
154        }
155        
156        protected static void removeFederatedContext(AbstractFederatedContext wrappingContext, Context innerContext) throws NamingException {
157            wrappingContext.contextFederation.removeContext(innerContext);
158            for (Map.Entry<String, Object> entry : wrappingContext.getWrapperBindings().entrySet()) {
159                String name = entry.getKey();
160                Object value = entry.getValue();
161                if (value instanceof AbstractFederatedContext) {
162                    AbstractFederatedContext nestedContext = (AbstractFederatedContext) value;
163    
164                    Name parsedName = wrappingContext.getNameParser().parse(name);
165                    Name nameInNamespace = wrappingContext.getNameInNamespace(parsedName);
166    
167                    VirtualSubcontext virtualSubcontext = new VirtualSubcontext(nameInNamespace, innerContext);
168                    removeFederatedContext(nestedContext, virtualSubcontext);
169                }
170            }
171        }
172    
173        public boolean isNestedSubcontext(Object value) {
174            if (value instanceof AbstractFederatedContext) {
175                AbstractFederatedContext context = (AbstractFederatedContext) value;
176                return getMasterContext() == context.getMasterContext();
177            }
178            return false;
179        }
180    
181        protected AbstractFederatedContext getMasterContext() {
182            return masterContext;
183        }
184    }