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