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.spring.jndi;
018    
019    import java.util.concurrent.ConcurrentHashMap;
020    
021    import org.apache.commons.logging.Log;
022    import org.apache.commons.logging.LogFactory;
023    import org.springframework.beans.factory.BeanFactory;
024    import org.springframework.core.io.ClassPathResource;
025    import org.springframework.core.io.Resource;
026    import org.springframework.core.io.ResourceEditor;
027    import org.apache.xbean.spring.context.impl.XBeanXmlBeanFactory;
028    
029    import javax.naming.Context;
030    import javax.naming.NamingException;
031    import javax.naming.spi.InitialContextFactory;
032    
033    import java.util.HashMap;
034    import java.util.Hashtable;
035    import java.util.Map;
036    
037    /**
038     * A simple JNDI initial context which loads the JNDI namespace from a spring.xml configuration file.
039     * The spring.xml configuration file can be specified by the {@link Context#PROVIDER_URL} property
040     * which can be any spring resource string (classpath://foo.xml, or file://foo/bar.xml or a URL)
041     * otherwise the jndi.xml file is found on the classpath.
042     *
043     * @version $Revision: 657 $
044     */
045    public class SpringInitialContextFactory implements InitialContextFactory {
046        private static final transient Log log = LogFactory.getLog(SpringInitialContextFactory.class);
047    
048        private static Map cache = new HashMap();
049    
050        private static Context singleton;
051    
052        /**
053         * A factory method which can be used to initialise a singleton JNDI context from inside a Spring.xml
054         * such that future calls to new InitialContext() will reuse it
055         */
056        public static Context makeInitialContext() {
057            singleton = new DefaultContext();
058            return singleton;
059        }
060    
061        public Context getInitialContext(Hashtable environment) throws NamingException {
062            if (singleton != null) {
063                return singleton;
064            }
065            Resource resource = null;
066            Object value = environment.get(Context.PROVIDER_URL);
067            String key = "jndi.xml";
068            if (value == null) {
069                resource = new ClassPathResource(key);
070            }
071            else {
072                if (value instanceof Resource) {
073                    resource = (Resource) value;
074                }
075                else {
076                    ResourceEditor editor = new ResourceEditor();
077                    key = value.toString();
078                    editor.setAsText(key);
079                    resource = (Resource) editor.getValue();
080                }
081            }
082            BeanFactory context = loadContext(resource, key);
083            Context answer = (Context) context.getBean("jndi");
084            if (answer == null) {
085                log.warn("No JNDI context available in JNDI resource: " + resource);
086                answer = new DefaultContext(environment, new ConcurrentHashMap());
087            }
088            return answer;
089        }
090    
091        protected BeanFactory loadContext(Resource resource, String key) {
092            synchronized (cache) {
093                BeanFactory answer = (BeanFactory) cache.get(key);
094                if (answer == null) {
095                    answer =  createContext(resource);
096                    cache.put(key, answer);
097                }
098                return answer;
099            }
100        }
101    
102        protected BeanFactory createContext(Resource resource) {
103            log.info("Loading JNDI context from: " + resource);
104            return new XBeanXmlBeanFactory(resource);
105        }
106    }