Return-Path: Delivered-To: apmail-geronimo-scm-archive@www.apache.org Received: (qmail 88201 invoked from network); 3 Oct 2008 15:15:09 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 3 Oct 2008 15:15:09 -0000 Received: (qmail 31978 invoked by uid 500); 3 Oct 2008 15:15:08 -0000 Delivered-To: apmail-geronimo-scm-archive@geronimo.apache.org Received: (qmail 31846 invoked by uid 500); 3 Oct 2008 15:15:07 -0000 Mailing-List: contact scm-help@geronimo.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@geronimo.apache.org List-Id: Delivered-To: mailing list scm@geronimo.apache.org Received: (qmail 31837 invoked by uid 99); 3 Oct 2008 15:15:07 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 03 Oct 2008 08:15:07 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 03 Oct 2008 15:14:05 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id A1243238889E; Fri, 3 Oct 2008 08:14:40 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r701402 - /geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/ Date: Fri, 03 Oct 2008 15:14:40 -0000 To: scm@geronimo.apache.org From: jdillon@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20081003151440.A1243238889E@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: jdillon Date: Fri Oct 3 08:14:39 2008 New Revision: 701402 URL: http://svn.apache.org/viewvc?rev=701402&view=rev Log: Refactor the gshell-spring support to base its BeanContainerContext on the just from ApplicationContext, but ripped out all the excessive sub-class configuration crap and other junk we don't want/need/care about Added: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContext.java (with props) geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextException.java (with props) geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextImpl.java (contents, props changed) - copied, changed from r701228, geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContext.java geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextSupport.java (with props) geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerException.java (with props) Modified: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerAwareProcessor.java geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerImpl.java Modified: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerAwareProcessor.java URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerAwareProcessor.java?rev=701402&r1=701401&r2=701402&view=diff ============================================================================== --- geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerAwareProcessor.java (original) +++ geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerAwareProcessor.java Fri Oct 3 08:14:39 2008 @@ -41,10 +41,6 @@ public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException { assert bean != null; - // - // TODO: Support ResourceLoaderAware like ApplicationContextAwareProcessor does - // - if (bean instanceof BeanContainerAware) { ((BeanContainerAware)bean).setBeanContainer(container); } Added: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContext.java URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContext.java?rev=701402&view=auto ============================================================================== --- geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContext.java (added) +++ geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContext.java Fri Oct 3 08:14:39 2008 @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.geronimo.gshell.spring; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.HierarchicalBeanFactory; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.core.io.support.ResourcePatternResolver; + +import java.io.Closeable; + +/** + * Bean container context. + * + * This is basically a merged and trimmed down version of a Spring ConfigurableApplicationContext. + * + * @version $Rev$ $Date$ + */ +public interface BeanContainerContext + extends ListableBeanFactory, HierarchicalBeanFactory, ResourcePatternResolver, Closeable +{ + String getId(); + + BeanContainerContext getParent(); + + void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor); + + void refresh() throws BeansException, IllegalStateException; + + boolean isActive(); + + ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException; +} \ No newline at end of file Added: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextException.java URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextException.java?rev=701402&view=auto ============================================================================== --- geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextException.java (added) +++ geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextException.java Fri Oct 3 08:14:39 2008 @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.geronimo.gshell.spring; + +/** + * Thrown to indicate a {@link BeanContainerContext} related failure. + * + * @version $Rev$ $Date$ + */ +public class BeanContainerContextException + extends BeanContainerException +{ + public BeanContainerContextException(final String msg) { + super(msg); + } + + public BeanContainerContextException(final String msg, final Throwable cause) { + super(msg, cause); + } +} \ No newline at end of file Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextException.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextException.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextException.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Copied: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextImpl.java (from r701228, geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContext.java) URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextImpl.java?p2=geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextImpl.java&p1=geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContext.java&r1=701228&r2=701402&rev=701402&view=diff ============================================================================== --- geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContext.java (original) +++ geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextImpl.java Fri Oct 3 08:14:39 2008 @@ -19,37 +19,115 @@ package org.apache.geronimo.gshell.spring; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.Resource; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.Arrays; +import java.util.LinkedHashSet; /** - * ??? + * {@link BeanContainerContext} implementation used by {@link BeanContainerImpl} instances. * * @version $Rev$ $Date$ */ -public class BeanContainerContext - extends DefaultListableBeanFactory +public class BeanContainerContextImpl + extends BeanContainerContextSupport { - private final Logger log = LoggerFactory.getLogger(getClass()); + private final Set resources = new LinkedHashSet(); - // - // TODO: Add more muck to support stuff in AbstractApplicationContext here, move some of the container bits from BeanContainerImpl into here. - // - - public BeanContainerContext(final BeanContainerContext parent) { + public BeanContainerContextImpl(final ClassLoader classLoader) { + this(classLoader, null); + } + + public BeanContainerContextImpl(final ClassLoader classLoader, final BeanContainerContextImpl parent) { super(parent); + assert classLoader != null; + + setClassLoader(classLoader); } - public void addBeanPostProcessor(final BeanPostProcessor processor) { - assert processor != null; + public void configure(final String[] locations) { + assert locations != null; + + log.debug("Configuring with locations: {}", Arrays.asList(locations)); + + for (String location : locations) { + Resource[] resources; + try { + resources = getResources(location); + } + catch (IOException e) { + throw new BeanContainerContextException("Failed to load resources from location: " + location, e); + } + + BeanContainerContext parent = getParent(); + if (parent instanceof BeanContainerContextImpl) { + resources = ((BeanContainerContextImpl)parent).filterOwnedResources(resources); + } + + // Track which resources we own + this.resources.addAll(Arrays.asList(resources)); + } + } + + /** + * Filter owned resources from the given resources list. + */ + private Resource[] filterOwnedResources(final Resource[] resources) { + assert resources != null; + + List list = new ArrayList(); + + for (Resource resource : resources) { + if (this.resources.contains(resource)) { + log.trace("Filtered owned resource: {}", resource); + } + else { + list.add(resource); + } + } + + Resource[] filteredResources = list.toArray(new Resource[list.size()]); - if (processor instanceof BeanFactoryAware) { - ((BeanFactoryAware)processor).setBeanFactory(this); + // If we have a parent, then ask it to filter resources as well + BeanContainerContext parent = getParent(); + if (parent instanceof BeanContainerContextImpl) { + filteredResources = ((BeanContainerContextImpl)parent).filterOwnedResources(filteredResources); } - super.addBeanPostProcessor(processor); + return filteredResources; + } + + protected void loadBeanDefinitions(final XmlBeanDefinitionReader reader) throws BeansException, IOException { + assert reader != null; + + log.debug("Loading bean definitions from resources: {}", resources); + + reader.loadBeanDefinitions(resources.toArray(new Resource[resources.size()])); + } + + public void addBeanPostProcessor(final BeanPostProcessor processor) { + assert processor != null; + + addBeanFactoryPostProcessor(new BeanFactoryPostProcessor() { + public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException { + assert beanFactory != null; + + if (processor instanceof BeanFactoryAware) { + ((BeanFactoryAware)processor).setBeanFactory(beanFactory); + } + + beanFactory.addBeanPostProcessor(processor); + } + }); } -} \ No newline at end of file +} Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextImpl.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextImpl.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextImpl.java ------------------------------------------------------------------------------ svn:mergeinfo = Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextImpl.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextSupport.java URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextSupport.java?rev=701402&view=auto ============================================================================== --- geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextSupport.java (added) +++ geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextSupport.java Fri Oct 3 08:14:39 2008 @@ -0,0 +1,548 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.geronimo.gshell.spring; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.ResourceEntityResolver; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.beans.support.ResourceEditorRegistrar; +import org.springframework.core.OrderComparator; +import org.springframework.core.Ordered; +import org.springframework.core.PriorityOrdered; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.util.ObjectUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Support for {@link BeanContainerContext} implementations. + * + * This is basically a merged and trimmed down version of a Spring AbstractXmlApplicationContext. + * + * @version $Rev$ $Date$ + */ +public abstract class BeanContainerContextSupport + extends DefaultResourceLoader + implements BeanContainerContext, DisposableBean +{ + protected final Logger log = LoggerFactory.getLogger(getClass()); + + private String id = ObjectUtils.identityToString(this); + + private final BeanContainerContext parent; + + private final List beanFactoryPostProcessors = new ArrayList(); + + private boolean active = false; + + private final Object activeMonitor = new Object(); + + private final Object startupShutdownMonitor = new Object(); + + private final Thread shutdownHook; + + private final ResourcePatternResolver resourcePatternResolver; + + public BeanContainerContextSupport() { + this(null); + } + + public BeanContainerContextSupport(final BeanContainerContext parent) { + // parent could be null + + this.parent = parent; + this.resourcePatternResolver = new PathMatchingResourcePatternResolver(this); + this.shutdownHook = new Thread() { + public void run() { + doClose(); + } + }; + Runtime.getRuntime().addShutdownHook(shutdownHook); + } + + // + // BeanContainerContext + // + + public void setId(final String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public BeanContainerContext getParent() { + return parent; + } + + public void refresh() throws BeansException, IllegalStateException { + synchronized (startupShutdownMonitor) { + // Prepare this context for refreshing. + synchronized (activeMonitor) { + active = true; + } + + log.debug("Refreshing: {}", this); + + // Tell the subclass to refresh the internal bean factory. + ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); + + // Prepare the bean factory for use in this context. + prepareBeanFactory(beanFactory); + + try { + // Invoke factory processors registered as beans in the context. + invokeBeanFactoryPostProcessors(beanFactory); + + // Register bean processors that intercept bean creation. + registerBeanPostProcessors(beanFactory); + + // Instantiate all remaining (non-lazy-init) singletons. + finishBeanFactoryInitialization(beanFactory); + } + + catch (BeansException e) { + log.error("Refresh failed", e); + + // Destroy already created singletons to avoid dangling resources. + beanFactory.destroySingletons(); + + // Reset 'active' flag. + synchronized (this.activeMonitor) { + this.active = false; + } + + // Propagate exception to caller. + throw e; + } + } + } + + private ConfigurableListableBeanFactory obtainFreshBeanFactory() { + refreshBeanFactory(); + ConfigurableListableBeanFactory beanFactory = getBeanFactory(); + + log.info("Bean factory for application context [{}]: {}", getId(), ObjectUtils.identityToString(beanFactory)); + log.debug("{} beans defined in {}", beanFactory.getBeanDefinitionCount(), this); + + return beanFactory; + } + + private void prepareBeanFactory(final ConfigurableListableBeanFactory beanFactory) { + assert beanFactory != null; + + // Tell the internal bean factory to use the context's class loader. + beanFactory.setBeanClassLoader(getClassLoader()); + + // Populate the bean factory with context-specific resource editors. + beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this)); + + // BeanFactory interface not registered as resolvable type in a plain factory. + beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); + beanFactory.registerResolvableDependency(ResourceLoader.class, this); + beanFactory.registerResolvableDependency(BeanContainerContext.class, this); + } + + private void finishBeanFactoryInitialization(final ConfigurableListableBeanFactory beanFactory) { + assert beanFactory != null; + + // Stop using the temporary ClassLoader for type matching. + beanFactory.setTempClassLoader(null); + + // Allow for caching all bean definition metadata, not expecting further changes. + beanFactory.freezeConfiguration(); + + // Instantiate all remaining (non-lazy-init) singletons. + beanFactory.preInstantiateSingletons(); + } + + public void addBeanFactoryPostProcessor(final BeanFactoryPostProcessor beanFactoryPostProcessor) { + beanFactoryPostProcessors.add(beanFactoryPostProcessor); + } + + private void invokeBeanFactoryPostProcessors(final ConfigurableListableBeanFactory beanFactory) { + assert beanFactory != null; + + // Invoke factory processors registered with the context instance. + for (BeanFactoryPostProcessor factoryProcessor : beanFactoryPostProcessors) { + factoryProcessor.postProcessBeanFactory(beanFactory); + } + + // Do not initialize FactoryBeans here: We need to leave all regular beans + // uninitialized to let the bean factory post-processors apply to them! + String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); + + // Separate between BeanFactoryPostProcessors that implement PriorityOrdered, + // Ordered, and the rest. + List priorityOrderedPostProcessors = new ArrayList(); + List orderedPostProcessorNames = new ArrayList(); + List nonOrderedPostProcessorNames = new ArrayList(); + + for (String name : postProcessorNames) { + if (isTypeMatch(name, PriorityOrdered.class)) { + priorityOrderedPostProcessors.add((BeanFactoryPostProcessor) beanFactory.getBean(name)); + } + else if (isTypeMatch(name, Ordered.class)) { + orderedPostProcessorNames.add(name); + } + else { + nonOrderedPostProcessorNames.add(name); + } + } + + // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. + // noinspection unchecked + Collections.sort(priorityOrderedPostProcessors, new OrderComparator()); + invokeBeanFactoryPostProcessors(beanFactory, priorityOrderedPostProcessors); + + // Next, invoke the BeanFactoryPostProcessors that implement Ordered. + List orderedPostProcessors = new ArrayList(); + for (String name : orderedPostProcessorNames) { + orderedPostProcessors.add((BeanFactoryPostProcessor) getBean(name)); + } + // noinspection unchecked + Collections.sort(orderedPostProcessors, new OrderComparator()); + invokeBeanFactoryPostProcessors(beanFactory, orderedPostProcessors); + + // Finally, invoke all other BeanFactoryPostProcessors. + List nonOrderedPostProcessors = new ArrayList(); + for (String name : nonOrderedPostProcessorNames) { + nonOrderedPostProcessors.add((BeanFactoryPostProcessor) getBean(name)); + } + invokeBeanFactoryPostProcessors(beanFactory, nonOrderedPostProcessors); + } + + private void invokeBeanFactoryPostProcessors(final ConfigurableListableBeanFactory beanFactory, final List postProcessors) { + assert beanFactory != null; + assert postProcessors != null; + + for (BeanFactoryPostProcessor postProcessor : postProcessors) { + postProcessor.postProcessBeanFactory(beanFactory); + } + } + + private void registerBeanPostProcessors(final ConfigurableListableBeanFactory beanFactory) { + assert beanFactory != null; + + String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); + + // Register BeanPostProcessorChecker that logs an info message when + // a bean is created during BeanPostProcessor instantiation, i.e. when + // a bean is not eligible for getting processed by all BeanPostProcessors. + int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; + beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); + + // Separate between BeanPostProcessors that implement PriorityOrdered, Ordered, and the rest. + List priorityOrderedPostProcessors = new ArrayList(); + List orderedPostProcessorNames = new ArrayList(); + List nonOrderedPostProcessorNames = new ArrayList(); + + for (String name : postProcessorNames) { + if (isTypeMatch(name, PriorityOrdered.class)) { + priorityOrderedPostProcessors.add((BeanPostProcessor)beanFactory.getBean(name)); + } + else if (isTypeMatch(name, Ordered.class)) { + orderedPostProcessorNames.add(name); + } + else { + nonOrderedPostProcessorNames.add(name); + } + } + + // First, register the BeanPostProcessors that implement PriorityOrdered. + // noinspection unchecked + Collections.sort(priorityOrderedPostProcessors, new OrderComparator()); + registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); + + // Next, register the BeanPostProcessors that implement Ordered. + List orderedPostProcessors = new ArrayList(); + for (String name : orderedPostProcessorNames) { + orderedPostProcessors.add((BeanPostProcessor)getBean(name)); + } + + // noinspection unchecked + Collections.sort(orderedPostProcessors, new OrderComparator()); + registerBeanPostProcessors(beanFactory, orderedPostProcessors); + + // Finally, register all other BeanPostProcessors. + List nonOrderedPostProcessors = new ArrayList(); + for (String name : nonOrderedPostProcessorNames) { + nonOrderedPostProcessors.add((BeanPostProcessor)getBean(name)); + } + + registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); + } + + private void registerBeanPostProcessors(final ConfigurableListableBeanFactory beanFactory, final List postProcessors) { + assert beanFactory != null; + assert postProcessors != null; + + for (BeanPostProcessor postProcessor : postProcessors) { + beanFactory.addBeanPostProcessor(postProcessor); + } + } + + public void destroy() { + close(); + } + + public void close() { + synchronized (startupShutdownMonitor) { + doClose(); + + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } + } + + private void doClose() { + if (isActive()) { + log.info("Closing: {}", this); + + // Destroy all cached singletons in the context's BeanFactory. + destroyBeans(); + + // Close the state of this context itself. + closeBeanFactory(); + + synchronized (activeMonitor) { + active = false; + } + } + } + + private void destroyBeans() { + getBeanFactory().destroySingletons(); + } + + public boolean isActive() { + synchronized (activeMonitor) { + return active; + } + } + + // + // BeanFactory + // + + public Object getBean(final String name) throws BeansException { + return getBeanFactory().getBean(name); + } + + public Object getBean(final String name, final Class requiredType) throws BeansException { + return getBeanFactory().getBean(name, requiredType); + } + + public Object getBean(final String name, final Object[] args) throws BeansException { + return getBeanFactory().getBean(name, args); + } + + public boolean containsBean(final String name) { + return getBeanFactory().containsBean(name); + } + + public boolean isSingleton(final String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().isSingleton(name); + } + + public boolean isPrototype(final String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().isPrototype(name); + } + + public boolean isTypeMatch(final String name, final Class targetType) throws NoSuchBeanDefinitionException { + return getBeanFactory().isTypeMatch(name, targetType); + } + + public Class getType(final String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().getType(name); + } + + public String[] getAliases(final String name) { + return getBeanFactory().getAliases(name); + } + + // + // ListableBeanFactory + // + + public boolean containsBeanDefinition(final String name) { + return getBeanFactory().containsBeanDefinition(name); + } + + public int getBeanDefinitionCount() { + return getBeanFactory().getBeanDefinitionCount(); + } + + public String[] getBeanDefinitionNames() { + return getBeanFactory().getBeanDefinitionNames(); + } + + public String[] getBeanNamesForType(final Class type) { + return getBeanFactory().getBeanNamesForType(type); + } + + public String[] getBeanNamesForType(final Class type, final boolean includePrototypes, final boolean allowEagerInit) { + return getBeanFactory().getBeanNamesForType(type, includePrototypes, allowEagerInit); + } + + public Map getBeansOfType(final Class type) throws BeansException { + return getBeanFactory().getBeansOfType(type); + } + + public Map getBeansOfType(final Class type, final boolean includePrototypes, final boolean allowEagerInit) throws BeansException { + return getBeanFactory().getBeansOfType(type, includePrototypes, allowEagerInit); + } + + // + // HierarchicalBeanFactory + // + + public BeanFactory getParentBeanFactory() { + return getParent(); + } + + public boolean containsLocalBean(final String name) { + return getBeanFactory().containsLocalBean(name); + } + + // + // ResourcePatternResolver + // + + public Resource[] getResources(final String locationPattern) throws IOException { + return resourcePatternResolver.getResources(locationPattern); + } + + // + // BeanPostProcessorChecker + // + + /** + * Logs a message when a bean is created during BeanPostProcessor instantiation. + * i.e. when a bean is not eligible for getting processed by all BeanPostProcessors. + */ + private class BeanPostProcessorChecker + implements BeanPostProcessor + { + private final ConfigurableListableBeanFactory beanFactory; + + private final int beanPostProcessorTargetCount; + + public BeanPostProcessorChecker(final ConfigurableListableBeanFactory beanFactory, final int beanPostProcessorTargetCount) { + assert beanFactory != null; + + this.beanFactory = beanFactory; + this.beanPostProcessorTargetCount = beanPostProcessorTargetCount; + } + + public Object postProcessBeforeInitialization(final Object bean, final String beanName) { + return bean; + } + + public Object postProcessAfterInitialization(final Object bean, final String beanName) { + assert bean != null; + assert beanName != null; + + if (!(bean instanceof BeanPostProcessor) && beanFactory.getBeanPostProcessorCount() < beanPostProcessorTargetCount) { + log.info("Bean '{}' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)", beanName); + } + return bean; + } + } + + // + // AbstractRefreshableApplicationContext + // + + private DefaultListableBeanFactory beanFactory; + + private final Object beanFactoryMonitor = new Object(); + + private void refreshBeanFactory() throws BeansException { + if (hasBeanFactory()) { + destroyBeans(); + closeBeanFactory(); + } + + try { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(getParent() != null ? getParent().getBeanFactory() : null); + beanFactory.setAllowBeanDefinitionOverriding(true); + beanFactory.setAllowCircularReferences(true); + loadBeanDefinitions(beanFactory); + + synchronized (beanFactoryMonitor) { + this.beanFactory = beanFactory; + } + } + catch (IOException e) { + throw new BeanContainerContextException("I/O error parsing XML document for application context: " + this, e); + } + } + + private void loadBeanDefinitions(final DefaultListableBeanFactory beanFactory) throws IOException { + assert beanFactory != null; + + XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); + reader.setResourceLoader(this); + reader.setEntityResolver(new ResourceEntityResolver(this)); + loadBeanDefinitions(reader); + } + + protected abstract void loadBeanDefinitions(final XmlBeanDefinitionReader reader) throws BeansException, IOException; + + private void closeBeanFactory() { + synchronized (beanFactoryMonitor) { + beanFactory = null; + } + } + + private boolean hasBeanFactory() { + synchronized (beanFactoryMonitor) { + return beanFactory != null; + } + } + + public final ConfigurableListableBeanFactory getBeanFactory() { + synchronized (beanFactoryMonitor) { + if (beanFactory == null) { + throw new IllegalStateException("BeanFactory not initialized or already closed"); + } + + return beanFactory; + } + } +} \ No newline at end of file Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextSupport.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextSupport.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerContextSupport.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerException.java URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerException.java?rev=701402&view=auto ============================================================================== --- geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerException.java (added) +++ geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerException.java Fri Oct 3 08:14:39 2008 @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.geronimo.gshell.spring; + +import org.springframework.beans.FatalBeanException; + +/** + * Thrown to indicate a {@link BeanContainer} related failure. + * + * @version $Rev$ $Date$ + */ +public class BeanContainerException + extends FatalBeanException +{ + public BeanContainerException(final String msg) { + super(msg); + } + + public BeanContainerException(final String msg, final Throwable cause) { + super(msg, cause); + } +} \ No newline at end of file Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerException.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerException.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision HeadURL Propchange: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerException.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerImpl.java URL: http://svn.apache.org/viewvc/geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerImpl.java?rev=701402&r1=701401&r2=701402&view=diff ============================================================================== --- geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerImpl.java (original) +++ geronimo/gshell/trunk/gshell-support/gshell-spring/src/main/java/org/apache/geronimo/gshell/spring/BeanContainerImpl.java Fri Oct 3 08:14:39 2008 @@ -24,27 +24,14 @@ import org.codehaus.plexus.classworlds.realm.DuplicateRealmException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.FatalBeanException; -import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; -import org.springframework.beans.factory.xml.ResourceEntityResolver; -import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.beans.support.ResourceEditorRegistrar; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; import java.net.URL; -import java.util.ArrayList; import java.util.Arrays; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.UUID; /** * Default {@link BeanContainer} implementation. @@ -56,22 +43,14 @@ { private final Logger log = LoggerFactory.getLogger(getClass()); - private static final String REALM_ID = "gshell"; - private final ClassRealm classRealm; private final BeanContainerImpl parent; - private final ResourcePatternResolver resourceLoader; - - private final BeanContainerContext context; - - private final List beanFactoryPostProcessors = new ArrayList(); - - private final Set resources = new LinkedHashSet(); + private final BeanContainerContextImpl context; public BeanContainerImpl(final ClassLoader cl) { - this(createDefaultClassRealm(cl), null); + this(createClassRealm(cl), null); } private BeanContainerImpl(final ClassRealm classRealm, final BeanContainerImpl parent) { @@ -81,30 +60,19 @@ this.parent = parent; this.classRealm = classRealm; - // - // TODO: Move most of this to BeanContainerContext - // - - // Construct the bean factory - context = new BeanContainerContext(parent != null ? parent.getContext() : null); - context.setBeanClassLoader(classRealm); - context.registerResolvableDependency(BeanFactory.class, context); - - // Setup resource loading - resourceLoader = new PathMatchingResourcePatternResolver(new DefaultResourceLoader(classRealm)); - context.addPropertyEditorRegistrar(new ResourceEditorRegistrar(resourceLoader)); - context.registerResolvableDependency(ResourceLoader.class, resourceLoader); + // Construct the container and add customizations + context = new BeanContainerContextImpl(classRealm, parent != null ? parent.context : null); + context.setId(classRealm.getId()); // Add support for BeanContainerAware context.addBeanPostProcessor(new BeanContainerAwareProcessor(this)); - context.ignoreDependencyInterface(BeanContainerAware.class); // Hook up annotation processing context.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor()); context.addBeanPostProcessor(new LifecycleProcessor()); // Add automatic trace logging of loaded beans - beanFactoryPostProcessors.add(new LoggingProcessor()); + context.addBeanFactoryPostProcessor(new LoggingProcessor()); } public ClassRealm getClassRealm() { @@ -122,52 +90,10 @@ public void loadBeans(final String[] locations) throws Exception { assert locations != null; - log.debug("Loading beans"); - - for (String location : locations) { - Resource[] resources = resourceLoader.getResources(location); - - for (Resource resource : resources) { - if (parent != null && parent.isOwnedResource(resource)) { - log.trace("Omitting resource owned by parent: {}", resource); - } - else { - log.trace("Adding resource: {}", resource); - this.resources.add(resource); - } - } - } - - XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context); - reader.setResourceLoader(resourceLoader); - reader.setEntityResolver(new ResourceEntityResolver(resourceLoader)); - - log.debug("Loading bean definitions from {} resources", resources.size()); - - reader.loadBeanDefinitions(resources.toArray(new Resource[resources.size()])); - - for (BeanFactoryPostProcessor processor : beanFactoryPostProcessors) { - processor.postProcessBeanFactory(context); - } + context.configure(locations); + context.refresh(); } - private boolean isOwnedResource(final Resource resource) { - assert resource != null; - - if (resources.contains(resource)) { - return true; - } - else if (parent != null) { - return parent.isOwnedResource(resource); - } - - return false; - } - - // - // TODO: Bring back start/stop/destroy support - // - public BeanContainer createChild(final String id, final List classPath) { assert id != null; // classPath may be null @@ -189,7 +115,7 @@ childRealm = classRealm.createChildRealm(id); } catch (DuplicateRealmException e) { - throw new FatalBeanException("Failed to create child container realm: " + id, e); + throw new BeanContainerException("Failed to create child container realm: " + id, e); } if (classPath != null) { @@ -257,15 +183,11 @@ return createChild(id, null); } - // - // TODO: See if we can drop the need for this. - // - - private static ClassRealm createDefaultClassRealm(final ClassLoader cl) { + private static ClassRealm createClassRealm(final ClassLoader cl) { assert cl != null; try { - return new ClassWorld().newRealm(REALM_ID, cl); + return new ClassWorld().newRealm("gshell(" + UUID.randomUUID() + ")", cl); } catch (DuplicateRealmException e) { // Should never happen