/* * SpringAwareCacheFactory.java * * Copyright 2001-2007 by Oracle. All rights reserved. * * Oracle is a registered trademarks of Oracle Corporation and/or its affiliates. * * This software is the confidential and proprietary information of * Oracle Corporation. You shall not disclose such confidential and * proprietary information and shall use it only in accordance with the * terms of the license agreement you entered into with Oracle. * * This notice may not be removed or altered. */ package com.bagri.xdm.process.coherence.factory; import com.bagri.common.bean.SpringBeanProvider; import com.bagri.xdm.access.coherence.impl.CoherenceXDMFactory; import com.bagri.xdm.common.XDMHelper; import com.oracle.coherence.environment.extensible.ExtensibleEnvironment; import com.tangosol.net.BackingMapManagerContext; import com.tangosol.net.CacheFactory; import com.tangosol.net.ConfigurableCacheFactory; import com.tangosol.run.xml.SimpleElement; import com.tangosol.run.xml.XmlElement; import com.tangosol.run.xml.XmlHelper; import com.tangosol.util.ClassHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; //import javax.annotation.Nonnull; /** * SpringAwareCacheFactory provides a facility to access caches declared * in a "cache-config.dtd" compliant configuration file, similar to its super * class {@link DefaultConfigurableCacheFactory}. In addition, this factory * provides the ability to reference beans in a Spring application context * through the use of a class-scheme element. * <p/> * This factory can be configured to start its own Spring application context from which to retrieve these beans. This * can be useful for standalone JVMs such as cache servers. It can also be configured at run time with a pre-configured * Spring bean factory. This can be useful for Coherence applications running in an environment that is itself * responsible for starting the Spring bean factory, such as a web container. * * @see #instantiateAny(CacheInfo, XmlElement, BackingMapManagerContext, ClassLoader) */ public class SpringAwareCacheFactory extends ExtensibleEnvironment implements ApplicationContextAware, SpringBeanProvider { private static final Logger LOGGER = LoggerFactory.getLogger(SpringAwareCacheFactory.class); // ----- constructors ------------------------------------------------- /** * Construct a default DefaultConfigurableCacheFactory using the * default configuration file name. */ public SpringAwareCacheFactory() { super(); instance = this; //initXDMFactory(); LOG.info("<init 1>"); } /** * Construct a default DefaultConfigurableCacheFactory using the * default configuration file name. * * @param sCacheConfig location of a cache configuration */ public SpringAwareCacheFactory(String sCacheConfig) { super(sCacheConfig); instance = this; //initXDMFactory(); LOG.info("<init 2>. config: {}", sCacheConfig); } /** * Construct a SpringAwareCacheFactory using the specified path to * a "cache-config.dtd" compliant configuration file or resource. This * will also create a Spring ApplicationContext based on the supplied * path to a Spring compliant configuration file or resource. * * @param sCacheConfig location of a cache configuration * @param sAppContext location of a Spring application context */ public SpringAwareCacheFactory(String sCacheConfig, String sAppContext) { super(sCacheConfig); //initXDMFactory(); instance = this; LOG.info("<init 3>. config: {}; context: {}", sCacheConfig, sAppContext); initializeContext(sCacheConfig, sAppContext); } // ----- extended methods ----------------------------------------------- /** * Create an Object using the "class-scheme" element. * <p/> * In addition to the functionality provided by the super class, this will retrieve an object from the configured * Spring BeanFactory for class names that use the following format: * <p/> * <pre> * <class-name>spring-bean:sampleCacheStore</class-name> * </pre> * <p/> * Parameters may be passed to these beans through setter injection as well: * <p/> * <pre> * <init-params> * <init-param> * <param-name>setEntityName</param-name> * <param-value>{cache-name}</param-value> * </init-param> * </init-params> * </pre> * <p/> * Note that Coherence will manage the lifecycle of the instantiated Spring bean, therefore any beans that are * retrieved using this method should be scoped as a prototype in the Spring configuration file, for example: * <p/> * <pre> * <bean id="sampleCacheStore" * class="com.company.SampleCacheStore" * scope="prototype"/> * </pre> * * @param info the cache info * @param xmlClass "class-scheme" element. * @param context BackingMapManagerContext to be used * @param loader the ClassLoader to instantiate necessary classes * @return a newly instantiated Object */ public Object instantiateAny(CacheInfo info, XmlElement xmlClass, BackingMapManagerContext context, ClassLoader loader) { if (translateSchemeType(xmlClass.getName()) != SCHEME_CLASS) { throw new IllegalArgumentException("Invalid class definition: " + xmlClass); } String sClass = xmlClass.getSafeElement("class-name").getString(); if (sClass.startsWith(SPRING_BEAN_PREFIX)) { String sBeanName = sClass.substring(SPRING_BEAN_PREFIX.length()); LOG.trace("instantiateAny. going to instantiate: {}", sBeanName); azzert(sBeanName != null && sBeanName.length() > 0, "Bean name required"); XmlElement xmlParams = xmlClass.getElement("init-params"); XmlElement xmlConfig = null; if (xmlParams != null) { xmlConfig = new SimpleElement("config"); XmlHelper.transformInitParams(xmlConfig, xmlParams); } Object oBean = appContext.getBean(sBeanName); if (xmlConfig != null) { for (Object o : xmlConfig.getElementList()) { XmlElement xmlElement = (XmlElement) o; String sMethod = xmlElement.getName(); String sParam = xmlElement.getString(); try { LOG.trace("instantiateAny. about to invoke {}.{}()...", oBean, sMethod); ClassHelper.invoke(oBean, sMethod, new Object[]{sParam}); LOG.trace("instantiateAny. {}.{}() invoked successfully", oBean, sMethod); } catch (Exception e) { throw ensureRuntimeException(e, "Could not invoke " + sMethod + "(" + sParam + ") on bean " + oBean); } } } LOG.trace("instantiateAny. returning: {}", oBean); return oBean; } else { return super.instantiateAny(info, xmlClass, context, loader); } } /** * @param beanId Bean ID * @param cl Class * @param <T> Type class * @return SpringBean */ public <T> T getSpringBean(String beanId, Class<T> cls) { LOG.trace("getSpringBean. looking for: {}", beanId); return appContext.getBean(beanId, cls); } /** * Creates bean instance from static application context * * @param beanId id of bean * @return instance */ public static Object instantiateSpringBean(String beanId) { LOG.trace("instantiateSpringBean. instantiating: {}", beanId); return appContext.getBean(beanId); } /** * /** * Creates bean instance from static application context * * @param beanId id of bean * @param cl Class * @param <T> Type class * @return instance */ public static <T> T instantiateSpringBean(String beanId, Class<T> cl) { LOG.trace("instantiateSpringBean. instantiating: {}", beanId); return appContext.getBean(beanId, cl); } //public Service ensureService(String serviceName) { // LOG.trace("ensureService. serviceName: {}", serviceName); // Service result = super.ensureService(serviceName); // LOG.trace("ensureService. returning: {}", result); // return result; //} /** * Returns static application context * * @return static application context */ public static ApplicationContext getApplicationContext() { LOG.trace("getApplicationContext. returning: {}", appContext); return appContext; } /** * Setter for static application context * * @param applicationContext application context * @throws BeansException in case of error */ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // Assign the ApplicationContext into a static variable LOG.info("setApplicationContext. old: {} new: {}", appContext, applicationContext); appContext = applicationContext; } // ----- data fields ---------------------------------------------------- private static ConfigurableCacheFactory instance = null; public static ConfigurableCacheFactory getFactory() { return instance; } /** * Spring ApplicationContext used by this CacheFactory */ private static ApplicationContext appContext = null; private static synchronized void initializeContext(String sCacheConfig, String sAppContext) { if (appContext == null) { azzert(sAppContext != null && sAppContext.length() > 0, "Application context location required"); appContext = sCacheConfig.startsWith("file:") ? new FileSystemXmlApplicationContext(sAppContext) : new ClassPathXmlApplicationContext(sAppContext); // register a shutdown hook so the bean factory cleans up // upon JVM exit ((AbstractApplicationContext) appContext).registerShutdownHook(); } } /** * Prefix used in cache configuration "class-name" element to indicate * this bean is in Spring */ private static final String SPRING_BEAN_PREFIX = "spring-bean:"; private static final Logger LOG = LoggerFactory.getLogger(SpringAwareCacheFactory.class); /** * return non-null bean or throws IllegalStateException * * @param beanId bean's id * @param cl bean's class * @return IllegalStateException if fails to retrieve bean */ //@Nonnull public static <T> T getBeanOrThrowException(String beanId, Class<T> cl) { final ConfigurableCacheFactory factory = CacheFactory.getConfigurableCacheFactory(); if (factory instanceof SpringBeanProvider) { final T bean = ((SpringBeanProvider) factory).getSpringBean(beanId, cl); if (bean != null) { return bean; } } throw new IllegalStateException(); } //private void initXDMFactory() { //XDMHelper.registerXDMFactory(new CoherenceXDMFactory()); //LOG.debug("initXDMFactory. registered: {}", XDMHelper.getXDMFactory()); //} }