/****************************************************************************** * Copyright (c) 2006, 2010 VMware Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0 * is available at http://www.opensource.org/licenses/apache2.0.php. * You may elect to redistribute this code under either of these licenses. * * Contributors: * VMware Inc. *****************************************************************************/ package org.eclipse.gemini.blueprint.blueprint.container.support.internal.config; import java.util.ArrayList; import java.util.Collection; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.gemini.blueprint.blueprint.config.internal.ParsingUtils; import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder; import org.springframework.core.Ordered; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** * Simple processor for sorting out cycles between beans. Inspects the construction relationship between beans to * provide hints to the container. Specifically, it forces the creation of any beans referred inside the construction * through the 'depends-on' attribute on the inspected bean. * * @author Costin Leau */ public class CycleOrderingProcessor implements BeanFactoryPostProcessor, Ordered { public static final String SYNTHETIC_DEPENDS_ON = "org.eclipse.gemini.blueprint.blueprint.container.support.internal.config.dependson"; /** logger */ private static final Log log = LogFactory.getLog(CycleOrderingProcessor.class); public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { boolean trace = log.isTraceEnabled(); String[] names = beanFactory.getBeanDefinitionNames(); for (String name : names) { BeanDefinition definition = beanFactory.getBeanDefinition(name); if (definition.hasAttribute(ParsingUtils.BLUEPRINT_MARKER_NAME)) { ConstructorArgumentValues cArgs = definition.getConstructorArgumentValues(); if (trace) log.trace("Inspecting cycles for (blueprint) bean " + name); tag(cArgs.getGenericArgumentValues(), name, definition); tag(cArgs.getIndexedArgumentValues().values(), name, definition); } } } private void tag(Collection<ValueHolder> values, String name, BeanDefinition definition) { boolean trace = log.isTraceEnabled(); for (ValueHolder value : values) { Object val = value.getValue(); if (val instanceof BeanMetadataElement) { if (val instanceof RuntimeBeanReference) { String beanName = ((RuntimeBeanReference) val).getBeanName(); if (trace) { log.trace("Adding (cycle breaking) depends-on on " + name + " to " + beanName); } addSyntheticDependsOn(definition, beanName); } } } } private void addSyntheticDependsOn(BeanDefinition definition, String beanName) { if (StringUtils.hasText(beanName)) { String[] dependsOn = definition.getDependsOn(); if (dependsOn != null && dependsOn.length > 0) { for (String dependOn : dependsOn) { if (beanName.equals(dependOn)) { return; } } } // add depends on dependsOn = (String[]) ObjectUtils.addObjectToArray(dependsOn, beanName); definition.setDependsOn(dependsOn); Collection<String> markers = (Collection<String>) definition.getAttribute(SYNTHETIC_DEPENDS_ON); if (markers == null) { markers = new ArrayList<String>(2); definition.setAttribute(SYNTHETIC_DEPENDS_ON, markers); } markers.add(beanName); } } public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } }