package net.sf.springofeclipse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.InvalidRegistryObjectException;
import org.eclipse.core.runtime.Platform;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.BeanDefinitionStoreException;
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.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.core.io.Resource;
/**
* This class is an implementation of the interface {@link BeanDefinitionReader}
* and it loads the bean definitions via the extension-point
* <code>net.sf.springofeclipse.beans</code>.
*
* @see BeanDefinitionReader
* @see ApplicationContextFactory
*
* @author Zsolt Farkas
*
* @since 0.0.1
*/
public class BeansExtensionPointBeanDefinitionReader extends
AbstractBeanDefinitionReader {
/**
* The logger of the class.
*/
private static Log log = LogFactory
.getLog(BeansExtensionPointBeanDefinitionReader.class);
/**
* @param registry
*/
public BeansExtensionPointBeanDefinitionReader(
BeanDefinitionRegistry registry) {
super(registry);
}
/**
* @see org.springframework.beans.factory.support.BeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)
*/
@Override
public int loadBeanDefinitions(Resource resource)
throws BeanDefinitionStoreException {
throw new UnsupportedOperationException("operation is not supported");
}
/**
* @see org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String)
*/
public int loadBeanDefinitions(String contextId) {
if (log.isDebugEnabled()) {
log.debug("loading bean definitions for context: " + contextId);
}
int count = 0;
IExtensionPoint extensionPoint = Platform.getExtensionRegistry()
.getExtensionPoint("net.sf.springofeclipse.beans");
IExtension[] extensions = extensionPoint.getExtensions();
for (int i = 0; i < extensions.length; i++) {
IExtension extension = extensions[i];
IConfigurationElement[] beansElements = extension
.getConfigurationElements();
for (int j = 0; j < beansElements.length; j++) {
IConfigurationElement beansElement = beansElements[j];
String contextIdTemp = beansElement.getAttribute("contextId");
if (contextId.equals(contextIdTemp)) {
IConfigurationElement[] beanElements = beansElement
.getChildren();
for (int k = 0; k < beanElements.length; k++) {
IConfigurationElement beanElement = beanElements[k];
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
// bean id
String beanId = beanElement.getAttribute("id");
// bean class
String beanClassName = beanElement
.getAttribute("class");
beanDefinition.setBeanClass(resolveBeanClass(
beanElement, beanClassName));
if (log.isDebugEnabled()) {
log.debug("found bean for context [" + contextId
+ "]: [id=" + beanId + ";class="
+ beanClassName + "]");
}
// scope
String scope = beanElement.getAttribute("scope");
if (scope != null) {
beanDefinition.setScope(scope);
}
if (log.isDebugEnabled()) {
log.debug("scope: [" + scope + "]");
}
// abstract
String isAbstract = beanElement
.getAttribute("abstract");
if (isAbstract != null) {
beanDefinition.setAbstract(Boolean
.parseBoolean(isAbstract));
}
if (log.isDebugEnabled()) {
log.debug("abstract: [" + isAbstract + "]");
}
// parent
String parentName = beanElement.getAttribute("parent");
if (parentName != null) {
beanDefinition.setParentName(parentName);
}
if (log.isDebugEnabled()) {
log.debug("parent: [" + parentName + "]");
}
// lazy-init
String isLazyInit = beanElement
.getAttribute("lazy-init");
if (isLazyInit != null) {
beanDefinition.setLazyInit(Boolean
.parseBoolean(isLazyInit));
}
if (log.isDebugEnabled()) {
log.debug("lazy-init: [" + isLazyInit + "]");
}
// autowire
String autowireModeString = beanElement
.getAttribute("autowire");
if (autowireModeString != null) {
beanDefinition
.setAutowireMode(resolveAutowireMode(autowireModeString));
}
if (log.isDebugEnabled()) {
log.debug("autowire: [" + autowireModeString + "]");
}
// autowire candidate
String autowireCandidate = beanElement
.getAttribute("autowire-candidate");
if (autowireCandidate != null) {
beanDefinition.setAutowireCandidate(Boolean
.parseBoolean(autowireCandidate));
}
if (log.isDebugEnabled()) {
log.debug("autowire-candidate: ["
+ autowireCandidate + "]");
}
// primary
String isPrimary = beanElement.getAttribute("primary");
if (isPrimary != null) {
beanDefinition.setPrimary(Boolean
.parseBoolean(isPrimary));
}
if (log.isDebugEnabled()) {
log.debug("primary: [" + isPrimary + "]");
}
// init-method
String initMethod = beanElement
.getAttribute("init-method");
if (initMethod != null) {
beanDefinition.setInitMethodName(initMethod);
}
if (log.isDebugEnabled()) {
log.debug("init-method: [" + initMethod + "]");
}
// destroy-method
String destroyMethod = beanElement
.getAttribute("destroy-method");
if (destroyMethod != null) {
beanDefinition.setDestroyMethodName(destroyMethod);
}
if (log.isDebugEnabled()) {
log
.debug("destroy-method: [" + destroyMethod
+ "]");
}
// factory-method
String factoryMethod = beanElement
.getAttribute("factory-method");
if (factoryMethod != null) {
beanDefinition
.setFactoryMethodName("factory-method");
}
if (log.isDebugEnabled()) {
log
.debug("factory-method: [" + factoryMethod
+ "]");
}
// factory-bean
String factoryBean = beanElement
.getAttribute("factory-bean");
if (factoryBean != null) {
beanDefinition.setFactoryBeanName(factoryBean);
}
if (log.isDebugEnabled()) {
log.debug("factory-bean: [" + factoryBean + "]");
}
// constructor values
if (log.isDebugEnabled()) {
log.debug("resolving constructor values");
}
ConstructorArgumentValues constructorArgumentValues = resolveConstructorValues(beanElement);
if (!constructorArgumentValues.isEmpty()) {
beanDefinition
.setConstructorArgumentValues(constructorArgumentValues);
} else if (log.isDebugEnabled()) {
log.debug("no constructor values found");
}
// property values
if (log.isDebugEnabled()) {
log.debug("resolving property values");
}
MutablePropertyValues propertyValues = resolvePropertyValues(beanElement);
if (propertyValues.size() > 0) {
beanDefinition.setPropertyValues(propertyValues);
} else if (log.isDebugEnabled()) {
log.debug("no property values found");
}
if (beanDefinition.getBeanClass() == null) {
if (log.isWarnEnabled()) {
log
.warn("bean class of bean ["
+ beanId
+ "] could not be resolved; it will be ignored");
}
} else {
if (log.isDebugEnabled()) {
log.debug("registering bean definition: [id="
+ beanId + "; definition="
+ beanDefinition + "]");
}
getRegistry().registerBeanDefinition(beanId,
beanDefinition);
count++;
}
}
}
}
}
if (log.isDebugEnabled()) {
log.debug("count of registered beans: [" + count + "]");
}
return count;
}
private ConstructorArgumentValues resolveConstructorValues(
IConfigurationElement beanElement) {
ConstructorArgumentValues constructorValues = new ConstructorArgumentValues();
IConfigurationElement[] constructorElements = beanElement
.getChildren("constructor-arg");
for (int i = 0; i < constructorElements.length; i++) {
IConfigurationElement constructorElement = constructorElements[i];
String type = constructorElement.getAttribute("type");
String indexString = constructorElement.getAttribute("index");
if (log.isDebugEnabled()) {
log.debug("found a constructor-arg: [index=" + indexString
+ ";type=" + type + "]");
}
IConfigurationElement[] values = constructorElement.getChildren();
if (values.length > 0) {
IConfigurationElement value = values[0];
ValueHolder constructorValue = null;
if ("ref".equals(value.getName())) {
String ref = value.getAttribute("bean");
if (log.isDebugEnabled()) {
log.debug("constructor-arg references the bean: [name="
+ ref + "]");
}
constructorValue = new ValueHolder(
new RuntimeBeanReference(ref), type);
} else if ("value".equals(value.getName())) {
String valueString = value.getValue();
if (log.isDebugEnabled()) {
log.debug("constructor-arg has a value: ["
+ valueString + "]");
}
constructorValue = new ValueHolder(valueString, type);
} else if ("null".equals(value.getName())) {
if (log.isDebugEnabled()) {
log.debug("constructor-arg has a null value");
}
constructorValue = new ValueHolder(null, type);
}
if (constructorValue != null) {
int index = -1;
try {
index = Integer.parseInt(indexString);
} catch (NumberFormatException e) {
if (log.isWarnEnabled()) {
log.warn("constructor-arg index is invalid: " + e);
}
}
if (index >= 0) {
if (log.isDebugEnabled()) {
log.debug("constructor-arg added to the index: ["
+ index + "]");
}
constructorValues.addIndexedArgumentValue(index,
constructorValue);
} else {
if (log.isDebugEnabled()) {
log.debug("constructor-arg added without index");
}
constructorValues
.addGenericArgumentValue(constructorValue);
}
} else if (log.isWarnEnabled()) {
log
.warn("contructor-arg value is null; could not be added");
}
}
}
return constructorValues;
}
private MutablePropertyValues resolvePropertyValues(
IConfigurationElement beanElement) {
MutablePropertyValues propertyValues = new MutablePropertyValues();
IConfigurationElement[] properties = beanElement
.getChildren("property");
for (int i = 0; i < properties.length; i++) {
IConfigurationElement property = properties[i];
String name = property.getAttribute("name");
if (log.isDebugEnabled()) {
log.debug("property found [name=" + name + "]");
}
IConfigurationElement[] values = property.getChildren();
if (values.length > 0) {
IConfigurationElement value = values[0];
PropertyValue propertyValue = null;
if ("ref".equals(value.getName())) {
String ref = value.getAttribute("bean");
if (log.isDebugEnabled()) {
log.debug("property references a bean: [id=" + ref
+ "]");
}
propertyValue = new PropertyValue(name,
new RuntimeBeanReference(ref));
} else if ("value".equals(value.getName())) {
String valueString = value.getValue();
if (log.isDebugEnabled()) {
log.debug("property has the value: [" + valueString
+ "]");
}
propertyValue = new PropertyValue(name, valueString);
} else if ("null".equals(value.getName())) {
if (log.isDebugEnabled()) {
log.debug("property has a null value");
}
propertyValue = new PropertyValue(name, null);
}
if (propertyValue != null) {
if (log.isDebugEnabled()) {
log.debug("adding property with name: [" + name + "]");
}
propertyValues.addPropertyValue(propertyValue);
} else if (log.isWarnEnabled()) {
log
.warn("property value is null; could not be added: [name="
+ name + "]");
}
}
}
return propertyValues;
}
/**
* Loads the bean class.
*
* @param beanElement
* @param beanClassName
* @return the resolved bean class
*/
@SuppressWarnings("unchecked")
protected Class resolveBeanClass(IConfigurationElement beanElement,
String beanClassName) {
try {
return Platform.getBundle(beanElement.getNamespaceIdentifier())
.loadClass(beanClassName);
} catch (InvalidRegistryObjectException e) {
log.warn("bean class could not loaded: " + beanClassName, e);
} catch (ClassNotFoundException e) {
log.warn("bean class could not loaded: " + beanClassName, e);
}
return null;
}
private int resolveAutowireMode(String autowireModeString) {
if ("no".equals(autowireModeString)) {
return AbstractBeanDefinition.AUTOWIRE_NO;
} else if ("byName".equals(autowireModeString)) {
return AbstractBeanDefinition.AUTOWIRE_BY_NAME;
} else if ("byType".equals(autowireModeString)) {
return AbstractBeanDefinition.AUTOWIRE_BY_TYPE;
} else if ("constructor".equals(autowireModeString)) {
return AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR;
} else if ("autodetect".equals(autowireModeString)) {
return AbstractBeanDefinition.AUTOWIRE_AUTODETECT;
}
return -1;
}
}