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.Map;
021import java.util.Set;
022
023import javax.naming.Context;
024import javax.naming.Name;
025import javax.naming.NameAlreadyBoundException;
026import javax.naming.NamingException;
027
028/**
029 * @version $Rev$ $Date$
030 */
031public 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}