Java tutorial
/* * Copyright 2010-2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.data.gemfire; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.FatalBeanException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.access.BeanFactoryLocator; import org.springframework.beans.factory.access.BeanFactoryReference; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** * {@link BeanFactoryLocator} used for storing Spring application context/bean factory for Gemfire * user components (or {@link com.gemstone.gemfire.cache.Declarable}. As opposed to the "traditional" * {@link org.springframework.beans.factory.access.SingletonBeanFactoryLocator} this implementation does * not require any configuration file; it rather assume declaration inside an application context * (usually through {@link com.gemstone.gemfire.cache.CacheFactory} which it will store under the name * and aliases of the bean (so the same "registry" can be used for storing multiple BeanFactories). * If there is only one BeanFactory registered then a null value can be used with {@link #setBeanName(String)}. * * <p/> In most cases, one does not need to use this class directly as it is used internally * by {@link com.gemstone.gemfire.cache.CacheFactory}. * * @author Costin Leau */ public class GemfireBeanFactoryLocator implements BeanFactoryLocator, BeanFactoryAware, BeanNameAware, DisposableBean, InitializingBean { private static final Log log = LogFactory.getLog(GemfireBeanFactoryLocator.class); // alias/bean name <-> BeanFactory lookup private static final ConcurrentMap<String, BeanFactory> beanFactories = new ConcurrentHashMap<String, BeanFactory>(); // default factory to return private static volatile boolean canUseDefaultBeanFactory = true; private static volatile BeanFactory defaultFactory = null; private static class SimpleBeanFactoryReference implements BeanFactoryReference { private BeanFactory bf; SimpleBeanFactoryReference(BeanFactory bf) { this.bf = bf; } public BeanFactory getFactory() { Assert.notNull(bf, "beanFactory already released or closed"); return bf; } public void release() throws FatalBeanException { bf = null; } } private BeanFactory beanFactory; private String[] names; // default factory name private String factoryName = GemfireBeanFactoryLocator.class.getName(); public void afterPropertiesSet() { // add the factory as default if possible (if it's the only one) synchronized (GemfireBeanFactoryLocator.class) { canUseDefaultBeanFactory = beanFactories.isEmpty(); if (canUseDefaultBeanFactory) { if (defaultFactory == null) { defaultFactory = beanFactory; if (log.isDebugEnabled()) log.debug("default beanFactoryReference=" + defaultFactory); } else { if (log.isDebugEnabled()) log.debug("more then one beanFactory - default not possible to determine"); canUseDefaultBeanFactory = false; defaultFactory = null; } } } // add aliases if (StringUtils.hasText(factoryName)) { String[] aliases = beanFactory.getAliases(factoryName); names = (String[]) ObjectUtils.addObjectToArray(aliases, factoryName); for (String name : names) { if (log.isDebugEnabled()) log.debug("adding key=" + name + " w/ reference=" + beanFactory); if (beanFactories.containsKey(name) && !beanFactory.equals(beanFactories.get(name)) || beanFactories.putIfAbsent(name, beanFactory) != null) { throw new IllegalArgumentException( "a beanFactoryReference already exists for key " + factoryName); } } } } public void destroy() { if (names != null) { for (String name : names) { beanFactories.remove(name); } } if (beanFactory == defaultFactory) { synchronized (GemfireBeanFactoryLocator.class) { defaultFactory = null; canUseDefaultBeanFactory = beanFactories.isEmpty(); } } } public BeanFactoryReference useBeanFactory(final String factoryKey) throws BeansException { // see if there is a default FactoryBean BeanFactory factory; if (!StringUtils.hasText(factoryKey)) { if (!canUseDefaultBeanFactory) throw new IllegalArgumentException( "a non-null factoryKey needs to be specified as there are more then one factoryKeys available; " + beanFactories.keySet()); factory = defaultFactory; } else { factory = beanFactories.get(factoryKey); if (factory == null) throw new IllegalArgumentException("there is no beanFactory under key " + factoryKey); } return new SimpleBeanFactoryReference(factory); } public void setBeanName(String name) { factoryName = name; } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } }