Jeff Brown
12 years ago
17 changed files with 3573 additions and 1 deletions
@ -0,0 +1,148 @@
@@ -0,0 +1,148 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy |
||||
|
||||
import groovy.xml.StreamingMarkupBuilder |
||||
import org.apache.commons.logging.LogFactory |
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder |
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException |
||||
import org.springframework.beans.factory.parsing.Location |
||||
import org.springframework.beans.factory.parsing.Problem |
||||
import org.springframework.beans.factory.xml.DefaultDocumentLoader |
||||
import org.springframework.beans.factory.xml.DelegatingEntityResolver |
||||
import org.springframework.beans.factory.xml.NamespaceHandler |
||||
import org.springframework.beans.factory.xml.ParserContext |
||||
import org.springframework.core.io.ByteArrayResource |
||||
import org.springframework.util.xml.SimpleSaxErrorHandler |
||||
import org.springframework.util.xml.XmlValidationModeDetector |
||||
import org.w3c.dom.Element |
||||
import org.xml.sax.EntityResolver |
||||
import org.xml.sax.ErrorHandler |
||||
import org.xml.sax.InputSource |
||||
|
||||
/** |
||||
* Used by GroovyBeanDefinitionReader to read a Spring namespace expression in the Groovy DSL |
||||
* |
||||
* @see GroovyBeanDefinitionReader |
||||
* |
||||
*/ |
||||
|
||||
class DynamicElementReader extends GroovyObjectSupport{ |
||||
|
||||
|
||||
private static final LOG = LogFactory.getLog(GroovyBeanDefinitionReader) |
||||
|
||||
private Map xmlNamespaces |
||||
private String rootNamespace |
||||
ErrorHandler errorHandler = new SimpleSaxErrorHandler(LOG); |
||||
int validationMode = XmlValidationModeDetector.VALIDATION_NONE |
||||
EntityResolver entityResolver = new DelegatingEntityResolver(DynamicElementReader.class.getClassLoader()) |
||||
ParserContext parserContext |
||||
NamespaceHandler namespaceHandler |
||||
BeanConfiguration beanConfiguration |
||||
boolean beanDecorator = false |
||||
boolean firstCall = true |
||||
|
||||
public DynamicElementReader(String namespace, Map namespaceMap=Collections.EMPTY_MAP, NamespaceHandler namespaceHandler = null, ParserContext parserContext = null) { |
||||
super(); |
||||
this.xmlNamespaces = namespaceMap; |
||||
this.rootNamespace = namespace |
||||
this.namespaceHandler = namespaceHandler |
||||
this.parserContext = parserContext |
||||
} |
||||
|
||||
void setClassLoader(ClassLoader classLoader) { |
||||
entityResolver = new DelegatingEntityResolver(classLoader) |
||||
} |
||||
|
||||
/** |
||||
* Hook that subclass or anonymous classes can overwrite to implement custom behavior after invocation |
||||
* completes |
||||
*/ |
||||
protected void afterInvocation() { |
||||
// NOOP |
||||
} |
||||
|
||||
@Override |
||||
public Object invokeMethod(String name, Object args) { |
||||
boolean invokeAfterInterceptor = false |
||||
if(firstCall) { |
||||
invokeAfterInterceptor = true |
||||
firstCall=false |
||||
} |
||||
if(name.equals("doCall")) { |
||||
def callable = args[0] |
||||
callable.resolveStrategy = Closure.DELEGATE_FIRST |
||||
callable.delegate = this |
||||
def result = callable.call() |
||||
if(invokeAfterInterceptor) { |
||||
afterInvocation() |
||||
} |
||||
return result |
||||
} |
||||
else { |
||||
StreamingMarkupBuilder builder = new StreamingMarkupBuilder(); |
||||
def myNamespaces = xmlNamespaces |
||||
def myNamespace = rootNamespace |
||||
|
||||
def callable = { |
||||
for(namespace in myNamespaces) { |
||||
mkp.declareNamespace( [(namespace.key):namespace.value] ) |
||||
} |
||||
if(args && (args[-1] instanceof Closure)) { |
||||
args[-1].resolveStrategy = Closure.DELEGATE_FIRST |
||||
args[-1].delegate = builder |
||||
} |
||||
delegate."$myNamespace"."$name"(*args) |
||||
} |
||||
|
||||
callable.resolveStrategy=Closure.DELEGATE_FIRST |
||||
callable.delegate = builder |
||||
def writable = builder.bind( callable ) |
||||
|
||||
def sw = new StringWriter() |
||||
writable.writeTo(sw) |
||||
|
||||
def documentLoader = new DefaultDocumentLoader() |
||||
InputSource is = new InputSource(new StringReader(sw.toString())) |
||||
Element element = documentLoader.loadDocument(is, entityResolver, errorHandler, validationMode, true).getDocumentElement() |
||||
|
||||
parserContext?.delegate?.initDefaults element |
||||
if(namespaceHandler && parserContext) { |
||||
if(beanDecorator && beanConfiguration) { |
||||
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanConfiguration.getBeanDefinition(), beanConfiguration.getName()); |
||||
holder = namespaceHandler.decorate(element,holder, parserContext) |
||||
beanConfiguration.setBeanDefinition(holder.getBeanDefinition()) |
||||
} |
||||
else { |
||||
|
||||
def beanDefinition = namespaceHandler.parse(element, parserContext) |
||||
if(beanDefinition) { |
||||
beanConfiguration?.setBeanDefinition(beanDefinition) |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
throw new BeanDefinitionParsingException(new Problem("No namespace handler found for element ${sw}", new Location(parserContext?.readerContext?.resource ?: new ByteArrayResource(new byte[0])))) |
||||
} |
||||
if(invokeAfterInterceptor) { |
||||
afterInvocation() |
||||
} |
||||
return element |
||||
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy; |
||||
|
||||
|
||||
import org.springframework.context.ApplicationContext |
||||
import org.springframework.core.io.ClassPathResource |
||||
|
||||
class GroovyBeanDefinitionApplicationContext { |
||||
|
||||
@Delegate |
||||
private ApplicationContext applicationContext |
||||
|
||||
GroovyBeanDefinitionApplicationContext(String resource) { |
||||
this([resource] as String[]) |
||||
} |
||||
|
||||
GroovyBeanDefinitionApplicationContext(String[] resources) { |
||||
initializeApplicationContext resources |
||||
} |
||||
|
||||
GroovyBeanDefinitionApplicationContext(String resource, Class clazz) { |
||||
this([resource] as String[], clazz) |
||||
} |
||||
|
||||
GroovyBeanDefinitionApplicationContext(String[] resources, Class clazz) { |
||||
def classPathResources = resources.collect { new ClassPathResource(it, clazz) } |
||||
initializeApplicationContext classPathResources |
||||
} |
||||
|
||||
private initializeApplicationContext(resources) { |
||||
def bb = new GroovyBeanDefinitionReader() |
||||
resources.each { bb.loadBeans it } |
||||
applicationContext = bb.createApplicationContext() |
||||
} |
||||
|
||||
def propertyMissing(String propertyName) { |
||||
applicationContext.getBean(propertyName) |
||||
} |
||||
} |
@ -0,0 +1,143 @@
@@ -0,0 +1,143 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy; |
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition; |
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
|
||||
/** |
||||
* An interface that represent a runtime bean configuration |
||||
* |
||||
* Credit must go to Solomon Duskis and the |
||||
* article: http://jroller.com/page/Solomon?entry=programmatic_configuration_in_spring
|
||||
* |
||||
*/ |
||||
|
||||
public interface BeanConfiguration { |
||||
String AUTOWIRE_BY_TYPE = "byType"; |
||||
String AUTOWIRE_BY_NAME = "byName"; |
||||
|
||||
/** |
||||
* |
||||
* @return The name of the bean |
||||
*/ |
||||
String getName(); |
||||
|
||||
/** |
||||
* |
||||
* @return True if the bean is singleton |
||||
*/ |
||||
boolean isSingleton(); |
||||
|
||||
/** |
||||
* |
||||
* @return The Spring bean definition instance |
||||
*/ |
||||
AbstractBeanDefinition getBeanDefinition(); |
||||
|
||||
/** |
||||
* Adds a property value to this bean |
||||
* @param propertyName The name of the property |
||||
* @param propertyValue The value of the property |
||||
* |
||||
* @return Returns this bean configuration |
||||
*/ |
||||
BeanConfiguration addProperty(String propertyName, Object propertyValue); |
||||
|
||||
/** |
||||
* Sets the name of the method to call when destroying the bean |
||||
* |
||||
* @param methodName The method name |
||||
* @return This bean configuration |
||||
*/ |
||||
BeanConfiguration setDestroyMethod(String methodName); |
||||
|
||||
/** |
||||
* Sets the names of the beans this bean configuration depends on |
||||
* |
||||
* @param dependsOn Bean names it depends on |
||||
* @return This bean configuration |
||||
*/ |
||||
BeanConfiguration setDependsOn(String[] dependsOn); |
||||
|
||||
/** |
||||
* |
||||
* @param beanName |
||||
* @return This BeanConfiguration |
||||
*/ |
||||
BeanConfiguration setFactoryBean(String beanName); |
||||
|
||||
/** |
||||
* |
||||
* @param methodName |
||||
* @return This BeanConfiguration |
||||
*/ |
||||
BeanConfiguration setFactoryMethod(String methodName); |
||||
|
||||
/** |
||||
* Sets the autowire type, either "byType" or "byName" |
||||
* |
||||
* @param type The type |
||||
* @return This BeanConfiguration |
||||
*/ |
||||
BeanConfiguration setAutowire(String type); |
||||
|
||||
|
||||
/** |
||||
* Sets the name of the bean in the app ctx |
||||
* @param beanName The bean name |
||||
*/ |
||||
void setName(String beanName); |
||||
|
||||
/** |
||||
* Returns true if the bean config has the name property set |
||||
* @param name The name of the property |
||||
* @return True if it does have a property with the given name |
||||
*/ |
||||
boolean hasProperty(String name); |
||||
|
||||
/** |
||||
* Returns the value of the given property or throws a MissingPropertyException |
||||
* |
||||
* @param name The name of the property |
||||
* @return The value of the property |
||||
*/ |
||||
Object getPropertyValue(String name); |
||||
|
||||
/** |
||||
* Sets a property value on the bean configuration |
||||
* |
||||
* @param property The name of the property |
||||
* @param newValue The value |
||||
*/ |
||||
void setPropertyValue(String property, Object newValue); |
||||
|
||||
/** |
||||
* Sets the BeanConfiguration as an Abstract bean definition |
||||
* @param isAbstract Whether its abstract or not |
||||
* @return This BeanConfiguration object |
||||
*/ |
||||
BeanConfiguration setAbstract(boolean isAbstract); |
||||
|
||||
/** |
||||
* Sets the name of the parent bean |
||||
* |
||||
* @param name Either a string which is the name of the bean, a RuntimeBeanReference or a BeanConfiguration |
||||
*/ |
||||
void setParent(Object name); |
||||
|
||||
void setBeanDefinition(BeanDefinition definition); |
||||
} |
@ -0,0 +1,299 @@
@@ -0,0 +1,299 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy; |
||||
|
||||
import groovy.lang.GroovyObjectSupport; |
||||
import org.springframework.beans.BeanWrapper; |
||||
import org.springframework.beans.BeanWrapperImpl; |
||||
import org.springframework.beans.PropertyValue; |
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory; |
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues; |
||||
import org.springframework.beans.factory.config.RuntimeBeanReference; |
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition; |
||||
import org.springframework.beans.factory.support.GenericBeanDefinition; |
||||
|
||||
import java.util.*; |
||||
|
||||
/** |
||||
* Default implementation of the BeanConfiguration interface |
||||
* |
||||
* Credit must go to Solomon Duskis and the |
||||
* article: http://jroller.com/page/Solomon?entry=programmatic_configuration_in_spring
|
||||
* |
||||
*/ |
||||
public class DefaultBeanConfiguration extends GroovyObjectSupport implements BeanConfiguration { |
||||
|
||||
private static final String AUTOWIRE = "autowire"; |
||||
private static final String CONSTRUCTOR_ARGS = "constructorArgs"; |
||||
private static final String DESTROY_METHOD = "destroyMethod"; |
||||
private static final String FACTORY_BEAN = "factoryBean"; |
||||
private static final String FACTORY_METHOD = "factoryMethod"; |
||||
private static final String INIT_METHOD = "initMethod"; |
||||
private static final String BY_NAME = "byName"; |
||||
private static final String PARENT = "parent"; |
||||
private static final String BY_TYPE = "byType"; |
||||
private static final String BY_CONSTRUCTOR = "constructor"; |
||||
private static final List DYNAMIC_PROPS = new ArrayList(){ { |
||||
add(AUTOWIRE); |
||||
add(CONSTRUCTOR_ARGS); |
||||
add(DESTROY_METHOD); |
||||
add(FACTORY_BEAN); |
||||
add(FACTORY_METHOD); |
||||
add(INIT_METHOD); |
||||
add(BY_NAME); |
||||
add(BY_TYPE); |
||||
add(BY_CONSTRUCTOR); |
||||
} }; |
||||
private String parentName; |
||||
|
||||
public Object getProperty(String property) { |
||||
AbstractBeanDefinition bd = getBeanDefinition(); |
||||
if(wrapper.isReadableProperty(property)) { |
||||
return wrapper.getPropertyValue(property); |
||||
} |
||||
else if(DYNAMIC_PROPS.contains(property)) { |
||||
return null; |
||||
} |
||||
return super.getProperty(property); |
||||
} |
||||
|
||||
public void setProperty(String property, Object newValue) { |
||||
if(PARENT.equals(property)) { |
||||
setParent(newValue); |
||||
} |
||||
else { |
||||
AbstractBeanDefinition bd = getBeanDefinition(); |
||||
if(AUTOWIRE.equals(property)) { |
||||
if(BY_NAME.equals(newValue)) { |
||||
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME); |
||||
} |
||||
else if(BY_TYPE.equals(newValue)) { |
||||
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE); |
||||
} |
||||
else if(Boolean.TRUE.equals(newValue)) { |
||||
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME); |
||||
} |
||||
else if(BY_CONSTRUCTOR.equals(newValue)) { |
||||
bd.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); |
||||
} |
||||
} |
||||
// constructorArgs
|
||||
else if(CONSTRUCTOR_ARGS.equals(property) && newValue instanceof List) { |
||||
ConstructorArgumentValues cav = new ConstructorArgumentValues(); |
||||
List args = (List)newValue; |
||||
for (Iterator i = args.iterator(); i.hasNext();) { |
||||
Object e = i.next(); |
||||
cav.addGenericArgumentValue(e); |
||||
} |
||||
bd.setConstructorArgumentValues(cav); |
||||
} |
||||
// destroyMethod
|
||||
else if(DESTROY_METHOD.equals(property)) { |
||||
if(newValue != null) |
||||
bd.setDestroyMethodName(newValue.toString()); |
||||
} |
||||
// factoryBean
|
||||
else if(FACTORY_BEAN.equals(property)) { |
||||
if(newValue != null) |
||||
bd.setFactoryBeanName(newValue.toString()); |
||||
} |
||||
// factoryMethod
|
||||
else if(FACTORY_METHOD.equals(property)) { |
||||
if(newValue != null) |
||||
bd.setFactoryMethodName(newValue.toString()); |
||||
} |
||||
// initMethod
|
||||
else if(INIT_METHOD.equals(property)) { |
||||
if(newValue != null) |
||||
bd.setInitMethodName(newValue.toString()); |
||||
} |
||||
else if(wrapper.isWritableProperty(property)) { |
||||
|
||||
wrapper.setPropertyValue(property, newValue); |
||||
} |
||||
// autowire
|
||||
else { |
||||
super.setProperty(property, newValue); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private Class clazz; |
||||
private String name; |
||||
private boolean singleton = true; |
||||
private AbstractBeanDefinition definition; |
||||
private Collection constructorArgs = Collections.EMPTY_LIST; |
||||
private BeanWrapper wrapper; |
||||
|
||||
public DefaultBeanConfiguration(String name, Class clazz) { |
||||
this.name = name; |
||||
this.clazz = clazz; |
||||
} |
||||
|
||||
public DefaultBeanConfiguration(String name, Class clazz, boolean prototype) { |
||||
this(name,clazz,Collections.EMPTY_LIST); |
||||
this.singleton = !prototype; |
||||
} |
||||
|
||||
public DefaultBeanConfiguration(String name) { |
||||
this(name,null,Collections.EMPTY_LIST); |
||||
} |
||||
|
||||
public DefaultBeanConfiguration(Class clazz2) { |
||||
this.clazz = clazz2; |
||||
} |
||||
|
||||
public DefaultBeanConfiguration(String name2, Class clazz2, Collection args) { |
||||
this.name = name2; |
||||
this.clazz = clazz2; |
||||
this.constructorArgs = args; |
||||
} |
||||
|
||||
public DefaultBeanConfiguration(String name2, boolean prototype) { |
||||
this(name2,null,Collections.EMPTY_LIST); |
||||
this.singleton = !prototype; |
||||
} |
||||
|
||||
public DefaultBeanConfiguration(Class clazz2, Collection constructorArguments) { |
||||
this.clazz = clazz2; |
||||
this.constructorArgs = constructorArguments; |
||||
} |
||||
|
||||
public String getName() { |
||||
return this.name; |
||||
} |
||||
|
||||
public boolean isSingleton() { |
||||
return this.singleton ; |
||||
} |
||||
|
||||
public AbstractBeanDefinition getBeanDefinition() { |
||||
if (definition == null) |
||||
definition = createBeanDefinition(); |
||||
return definition; |
||||
} |
||||
|
||||
public void setBeanDefinition(BeanDefinition definition) { |
||||
this.definition = (AbstractBeanDefinition)definition; |
||||
} |
||||
|
||||
protected AbstractBeanDefinition createBeanDefinition() { |
||||
AbstractBeanDefinition bd = new GenericBeanDefinition(); |
||||
if(constructorArgs.size() > 0) { |
||||
ConstructorArgumentValues cav = new ConstructorArgumentValues(); |
||||
for (Object constructorArg : constructorArgs) { |
||||
cav.addGenericArgumentValue(constructorArg); |
||||
} |
||||
bd.setConstructorArgumentValues(cav); |
||||
} |
||||
bd.setBeanClass(clazz); |
||||
bd.setScope(singleton ? AbstractBeanDefinition.SCOPE_SINGLETON : AbstractBeanDefinition.SCOPE_PROTOTYPE); |
||||
if(parentName != null) { |
||||
bd.setParentName(parentName); |
||||
} |
||||
wrapper = new BeanWrapperImpl(bd); |
||||
return bd; |
||||
} |
||||
|
||||
public BeanConfiguration addProperty(String propertyName, Object propertyValue) { |
||||
if(propertyValue instanceof BeanConfiguration) { |
||||
propertyValue = ((BeanConfiguration)propertyValue).getBeanDefinition(); |
||||
} |
||||
getBeanDefinition() |
||||
.getPropertyValues() |
||||
.addPropertyValue(propertyName,propertyValue); |
||||
|
||||
return this; |
||||
} |
||||
|
||||
public BeanConfiguration setDestroyMethod(String methodName) { |
||||
getBeanDefinition().setDestroyMethodName(methodName); |
||||
return this; |
||||
} |
||||
|
||||
public BeanConfiguration setDependsOn(String[] dependsOn) { |
||||
getBeanDefinition().setDependsOn(dependsOn); |
||||
return this; |
||||
} |
||||
|
||||
public BeanConfiguration setFactoryBean(String beanName) { |
||||
getBeanDefinition().setFactoryBeanName(beanName); |
||||
|
||||
return this; |
||||
} |
||||
|
||||
public BeanConfiguration setFactoryMethod(String methodName) { |
||||
getBeanDefinition().setFactoryMethodName(methodName); |
||||
return this; |
||||
} |
||||
|
||||
public BeanConfiguration setAutowire(String type) { |
||||
if("byName".equals(type)) { |
||||
getBeanDefinition().setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME); |
||||
} |
||||
else if("byType".equals(type)){ |
||||
getBeanDefinition().setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
public void setName(String beanName) { |
||||
this.name = beanName; |
||||
} |
||||
|
||||
public Object getPropertyValue(String name) { |
||||
PropertyValue propertyValue = getBeanDefinition() |
||||
.getPropertyValues() |
||||
.getPropertyValue(name); |
||||
if(propertyValue== null) { |
||||
return null; |
||||
} |
||||
else { |
||||
return propertyValue |
||||
.getValue(); |
||||
} |
||||
} |
||||
|
||||
public boolean hasProperty(String name) { |
||||
return getBeanDefinition().getPropertyValues().contains(name); |
||||
} |
||||
|
||||
public void setPropertyValue(String property, Object newValue) { |
||||
getBeanDefinition().getPropertyValues().addPropertyValue(property, newValue); |
||||
} |
||||
|
||||
public BeanConfiguration setAbstract(boolean isAbstract) { |
||||
getBeanDefinition().setAbstract(isAbstract); |
||||
return this; |
||||
} |
||||
|
||||
public void setParent(Object obj) { |
||||
if(obj == null) throw new IllegalArgumentException("Parent bean cannot be set to a null runtime bean reference!"); |
||||
if(obj instanceof String) |
||||
this.parentName = (String)obj; |
||||
else if(obj instanceof RuntimeBeanReference) { |
||||
this.parentName = ((RuntimeBeanReference)obj).getBeanName(); |
||||
} |
||||
else if(obj instanceof BeanConfiguration) { |
||||
this.parentName = ((BeanConfiguration)obj).getName(); |
||||
} |
||||
getBeanDefinition().setParentName(parentName); |
||||
setAbstract(false); |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,357 @@
@@ -0,0 +1,357 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy; |
||||
|
||||
import groovy.lang.GroovySystem; |
||||
import groovy.lang.MetaClass; |
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.springframework.beans.PropertyValue; |
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; |
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition; |
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry; |
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
||||
import org.springframework.beans.factory.ListableBeanFactory; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.support.GenericApplicationContext; |
||||
import org.springframework.util.Assert; |
||||
|
||||
import java.util.*; |
||||
|
||||
/** |
||||
* A programmable runtime Spring configuration that allows a spring ApplicationContext |
||||
* to be constructed at runtime |
||||
* |
||||
* Credit must go to Solomon Duskis and the |
||||
* article: http://jroller.com/page/Solomon?entry=programmatic_configuration_in_spring
|
||||
* |
||||
*/ |
||||
public class DefaultRuntimeSpringConfiguration implements |
||||
RuntimeSpringConfiguration { |
||||
|
||||
private static final Log LOG = LogFactory.getLog(DefaultRuntimeSpringConfiguration.class); |
||||
protected GenericApplicationContext context; |
||||
private Map<String, BeanConfiguration> beanConfigs = new HashMap<String, BeanConfiguration>(); |
||||
private Map<String, BeanDefinition> beanDefinitions = new HashMap<String, BeanDefinition>(); |
||||
private List<String> beanNames = new ArrayList<String>(); |
||||
protected ApplicationContext parent; |
||||
protected ClassLoader classLoader; |
||||
protected Map<String, List> aliases = new HashMap<String, List>(); |
||||
protected ListableBeanFactory beanFactory; |
||||
|
||||
public DefaultRuntimeSpringConfiguration() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Creates the ApplicationContext instance. Subclasses can override to customise the used ApplicationContext |
||||
* |
||||
* @param parent The parent ApplicationContext instance. Can be null. |
||||
* |
||||
* @return An instance of GenericApplicationContext |
||||
*/ |
||||
protected GenericApplicationContext createApplicationContext(ApplicationContext parent) { |
||||
if(parent != null && beanFactory!=null) { |
||||
if(beanFactory instanceof DefaultListableBeanFactory) { |
||||
return new GroovyPropertyApplicationContext((DefaultListableBeanFactory) beanFactory,parent); |
||||
} |
||||
else { |
||||
throw new IllegalArgumentException("ListableBeanFactory set must be a subclass of DefaultListableBeanFactory"); |
||||
} |
||||
} |
||||
else if(beanFactory!=null) { |
||||
if(beanFactory instanceof DefaultListableBeanFactory) { |
||||
return new GroovyPropertyApplicationContext((DefaultListableBeanFactory) beanFactory); |
||||
} |
||||
else { |
||||
throw new IllegalArgumentException("ListableBeanFactory set must be a subclass of DefaultListableBeanFactory"); |
||||
} |
||||
} |
||||
else if(parent !=null) { |
||||
return new GroovyPropertyApplicationContext(parent); |
||||
} |
||||
else { |
||||
return new GroovyPropertyApplicationContext(); |
||||
} |
||||
} |
||||
|
||||
public DefaultRuntimeSpringConfiguration(ApplicationContext parent) { |
||||
this(parent, null); |
||||
} |
||||
|
||||
public DefaultRuntimeSpringConfiguration(ApplicationContext parent, ClassLoader cl) { |
||||
super(); |
||||
this.parent = parent; |
||||
this.classLoader = cl; |
||||
} |
||||
|
||||
private void setClassLoaderOnContext(ClassLoader cl) { |
||||
this.context.setClassLoader(cl); |
||||
this.context.getBeanFactory().setBeanClassLoader(cl); |
||||
} |
||||
|
||||
/** |
||||
* Initialises the ApplicationContext instance |
||||
*/ |
||||
protected void initialiseApplicationContext() { |
||||
if(this.context == null) { |
||||
this.context = createApplicationContext(this.parent); |
||||
if(classLoader != null) { |
||||
setClassLoaderOnContext(classLoader); |
||||
} |
||||
|
||||
Assert.notNull(context); |
||||
} |
||||
} |
||||
|
||||
|
||||
public BeanConfiguration addSingletonBean(String name, Class clazz) { |
||||
BeanConfiguration bc = new DefaultBeanConfiguration(name,clazz); |
||||
registerBeanConfiguration(name, bc); |
||||
return bc; |
||||
} |
||||
|
||||
public BeanConfiguration addPrototypeBean(String name, Class clazz) { |
||||
BeanConfiguration bc = new DefaultBeanConfiguration(name,clazz,true); |
||||
registerBeanConfiguration(name, bc); |
||||
return bc; |
||||
} |
||||
|
||||
public ApplicationContext getApplicationContext() { |
||||
initialiseApplicationContext(); |
||||
registerBeansWithContext(context); |
||||
context.refresh(); |
||||
return context; |
||||
} |
||||
|
||||
public ApplicationContext getUnrefreshedApplicationContext() { |
||||
initialiseApplicationContext(); |
||||
return context; |
||||
} |
||||
|
||||
public BeanConfiguration addSingletonBean(String name) { |
||||
BeanConfiguration bc = new DefaultBeanConfiguration(name); |
||||
registerBeanConfiguration(name, bc); |
||||
return bc; |
||||
} |
||||
|
||||
public BeanConfiguration createSingletonBean(Class clazz) { |
||||
return new DefaultBeanConfiguration(clazz); |
||||
} |
||||
|
||||
public BeanConfiguration addSingletonBean(String name, Class clazz, Collection args) { |
||||
BeanConfiguration bc = new DefaultBeanConfiguration(name,clazz,args); |
||||
registerBeanConfiguration(name, bc); |
||||
return bc; |
||||
} |
||||
|
||||
public BeanConfiguration addPrototypeBean(String name) { |
||||
BeanConfiguration bc = new DefaultBeanConfiguration(name,true); |
||||
registerBeanConfiguration(name, bc); |
||||
return bc; |
||||
} |
||||
|
||||
private void registerBeanConfiguration(String name, BeanConfiguration bc) { |
||||
beanConfigs.put(name,bc); |
||||
beanNames.add(name); |
||||
} |
||||
|
||||
public BeanConfiguration createSingletonBean(Class clazz, Collection constructorArguments) { |
||||
return new DefaultBeanConfiguration(clazz, constructorArguments); |
||||
} |
||||
|
||||
|
||||
public BeanConfiguration createPrototypeBean(String name) { |
||||
return new DefaultBeanConfiguration(name,true); |
||||
} |
||||
|
||||
public BeanConfiguration createSingletonBean(String name) { |
||||
return new DefaultBeanConfiguration(name); |
||||
} |
||||
|
||||
public void addBeanConfiguration(String beanName, BeanConfiguration beanConfiguration) { |
||||
beanConfiguration.setName(beanName); |
||||
registerBeanConfiguration(beanName, beanConfiguration); |
||||
} |
||||
|
||||
public void addBeanDefinition(String name, BeanDefinition bd) { |
||||
beanDefinitions.put(name,bd); |
||||
beanNames.add(name); |
||||
} |
||||
|
||||
public boolean containsBean(String name) { |
||||
return beanNames .contains(name); |
||||
} |
||||
|
||||
public BeanConfiguration getBeanConfig(String name) { |
||||
return beanConfigs.get(name); |
||||
} |
||||
|
||||
public AbstractBeanDefinition createBeanDefinition(String name) { |
||||
if(containsBean(name)) { |
||||
if(beanDefinitions.containsKey(name)) |
||||
return (AbstractBeanDefinition)beanDefinitions.get(name); |
||||
else if(beanConfigs.containsKey(name)) |
||||
return beanConfigs.get(name).getBeanDefinition(); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public void registerPostProcessor(BeanFactoryPostProcessor processor) { |
||||
initialiseApplicationContext(); |
||||
this.context.addBeanFactoryPostProcessor(processor); |
||||
} |
||||
|
||||
|
||||
|
||||
public List getBeanNames() { |
||||
return beanNames; |
||||
} |
||||
|
||||
public void registerBeansWithContext(GenericApplicationContext applicationContext) { |
||||
registerBeansWithRegistry(applicationContext); |
||||
} |
||||
|
||||
public void registerBeansWithRegistry(BeanDefinitionRegistry registry) { |
||||
|
||||
registerUnrefreshedBeansWithRegistry(registry); |
||||
registerBeanConfigsWithRegistry(registry); |
||||
registerBeanDefinitionsWithRegistry(registry); |
||||
|
||||
} |
||||
|
||||
private void registerUnrefreshedBeansWithRegistry(BeanDefinitionRegistry registry) { |
||||
if(context != null) { |
||||
for(String beanName : context.getBeanDefinitionNames()) { |
||||
registry.registerBeanDefinition(beanName, context.getBeanDefinition(beanName)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void registerBeanConfigsWithRegistry(BeanDefinitionRegistry registry) { |
||||
for (Object o : beanConfigs.values()) { |
||||
BeanConfiguration bc = (BeanConfiguration) o; |
||||
String beanName = bc.getName(); |
||||
if (LOG.isDebugEnabled()) { |
||||
LOG.debug("[RuntimeConfiguration] Registering bean [" + beanName + "]"); |
||||
if (LOG.isTraceEnabled()) { |
||||
PropertyValue[] pvs = bc.getBeanDefinition() |
||||
.getPropertyValues() |
||||
.getPropertyValues(); |
||||
for (PropertyValue pv : pvs) { |
||||
LOG.trace("[RuntimeConfiguration] With property [" + pv.getName() + "] set to [" + pv.getValue() + "]"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
if (registry.containsBeanDefinition(beanName)) { |
||||
removeBeanDefinition(registry, beanName); |
||||
} |
||||
|
||||
registry.registerBeanDefinition(beanName, |
||||
bc.getBeanDefinition()); |
||||
|
||||
registerBeanAliases(registry, beanName); |
||||
} |
||||
} |
||||
|
||||
private void registerBeanDefinitionsWithRegistry(BeanDefinitionRegistry registry) { |
||||
for (Object key : beanDefinitions.keySet()) { |
||||
BeanDefinition bd = beanDefinitions.get(key); |
||||
if (LOG.isDebugEnabled()) { |
||||
LOG.debug("[RuntimeConfiguration] Registering bean [" + key + "]"); |
||||
if (LOG.isTraceEnabled()) { |
||||
PropertyValue[] pvs = bd.getPropertyValues().getPropertyValues(); |
||||
for (PropertyValue pv : pvs) { |
||||
LOG.trace("[RuntimeConfiguration] With property [" + pv.getName() + "] set to [" + pv.getValue() + "]"); |
||||
} |
||||
} |
||||
} |
||||
final String beanName = key.toString(); |
||||
if (registry.containsBeanDefinition(beanName)) { |
||||
removeBeanDefinition(registry, beanName); |
||||
} |
||||
|
||||
registry.registerBeanDefinition(beanName, bd); |
||||
|
||||
registerBeanAliases(registry, beanName); |
||||
} |
||||
} |
||||
|
||||
public void registerBeansWithConfig(RuntimeSpringConfiguration targetSpringConfig) { |
||||
if(targetSpringConfig!=null) { |
||||
ApplicationContext ctx = targetSpringConfig.getUnrefreshedApplicationContext(); |
||||
if(ctx instanceof BeanDefinitionRegistry) { |
||||
final BeanDefinitionRegistry registry = (BeanDefinitionRegistry) ctx; |
||||
registerUnrefreshedBeansWithRegistry(registry); |
||||
registerBeansWithRegistry(registry); |
||||
} |
||||
for (Map.Entry<String, BeanConfiguration> beanEntry : beanConfigs.entrySet()) { |
||||
targetSpringConfig.addBeanConfiguration(beanEntry.getKey(), beanEntry.getValue()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void registerBeanAliases(BeanDefinitionRegistry beanDefinitionRegistry, String beanName) { |
||||
List beanAliases = (List)aliases.get(beanName); |
||||
if(beanAliases != null && !beanAliases.isEmpty()) { |
||||
for (Object beanAliase : beanAliases) { |
||||
String alias = (String) beanAliase; |
||||
beanDefinitionRegistry.registerAlias(beanName, alias); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void removeBeanDefinition(BeanDefinitionRegistry registry, String beanName) { |
||||
MetaClass mc = GroovySystem.getMetaClassRegistry().getMetaClass(registry.getClass()); |
||||
if(mc.respondsTo(registry, "removeBeanDefinition").size()>0) { |
||||
mc.invokeMethod(registry,"removeBeanDefinition",new Object[]{beanName}); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Adds an abstract bean and returns the BeanConfiguration instance |
||||
* |
||||
* @param name The name of the bean |
||||
* @return The BeanConfiguration object |
||||
*/ |
||||
public BeanConfiguration addAbstractBean(String name) { |
||||
BeanConfiguration bc = new DefaultBeanConfiguration(name); |
||||
bc.setAbstract(true); |
||||
registerBeanConfiguration(name, bc); |
||||
|
||||
return bc; |
||||
} |
||||
|
||||
public void addAlias(String alias, String beanName) { |
||||
List beanAliases = this.aliases.get(beanName); |
||||
if(beanAliases == null) { |
||||
beanAliases = new ArrayList(); |
||||
this.aliases.put(beanName, beanAliases); |
||||
} |
||||
beanAliases.add(alias); |
||||
} |
||||
|
||||
public BeanDefinition getBeanDefinition(String beanName) { |
||||
return this.beanDefinitions.get(beanName); |
||||
} |
||||
|
||||
public void setBeanFactory(ListableBeanFactory beanFactory) { |
||||
this.beanFactory = beanFactory; |
||||
} |
||||
} |
@ -0,0 +1,968 @@
@@ -0,0 +1,968 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy; |
||||
|
||||
import groovy.lang.Binding; |
||||
import groovy.lang.Closure; |
||||
import groovy.lang.GString; |
||||
import groovy.lang.GroovyObject; |
||||
import groovy.lang.GroovyObjectSupport; |
||||
import groovy.lang.GroovyShell; |
||||
import groovy.lang.MetaClass; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Arrays; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.codehaus.groovy.runtime.DefaultGroovyMethods; |
||||
import org.codehaus.groovy.runtime.InvokerHelper; |
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.config.RuntimeBeanReference; |
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; |
||||
import org.springframework.beans.factory.parsing.EmptyReaderEventListener; |
||||
import org.springframework.beans.factory.parsing.FailFastProblemReporter; |
||||
import org.springframework.beans.factory.parsing.Location; |
||||
import org.springframework.beans.factory.parsing.NullSourceExtractor; |
||||
import org.springframework.beans.factory.parsing.Problem; |
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition; |
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry; |
||||
import org.springframework.beans.factory.support.ManagedList; |
||||
import org.springframework.beans.factory.support.ManagedMap; |
||||
import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry; |
||||
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate; |
||||
import org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver; |
||||
import org.springframework.beans.factory.xml.NamespaceHandler; |
||||
import org.springframework.beans.factory.xml.NamespaceHandlerResolver; |
||||
import org.springframework.beans.factory.xml.ParserContext; |
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; |
||||
import org.springframework.beans.factory.xml.XmlReaderContext; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.support.GenericApplicationContext; |
||||
import org.springframework.core.io.ByteArrayResource; |
||||
import org.springframework.core.io.Resource; |
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; |
||||
import org.springframework.core.io.support.ResourcePatternResolver; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* <p>Runtime bean configuration wrapper. Like a Groovy builder, but more of a DSL for |
||||
* Spring configuration. Allows syntax like:</p> |
||||
* |
||||
* <pre> |
||||
* import org.hibernate.SessionFactory |
||||
* import org.apache.commons.dbcp.BasicDataSource |
||||
* |
||||
* GroovyBeanDefinitionReader builder = new GroovyBeanDefinitionReader() |
||||
* builder.beans { |
||||
* dataSource(BasicDataSource) { // <--- invokeMethod
|
||||
* driverClassName = "org.hsqldb.jdbcDriver" |
||||
* url = "jdbc:hsqldb:mem:grailsDB" |
||||
* username = "sa" // <-- setProperty
|
||||
* password = "" |
||||
* settings = [mynew:"setting"] |
||||
* } |
||||
* sessionFactory(SessionFactory) { |
||||
* dataSource = dataSource // <-- getProperty for retrieving refs
|
||||
* } |
||||
* myService(MyService) { |
||||
* nestedBean = { AnotherBean bean-> // <-- setProperty with closure for nested bean
|
||||
* dataSource = dataSource |
||||
* } |
||||
* } |
||||
* } |
||||
* </pre> |
||||
* <p> |
||||
* You can also use the Spring IO API to load resources containing beans defined as a Groovy |
||||
* script using either the constructors or the loadBeans(Resource[] resources) method |
||||
* </p> |
||||
* |
||||
*/ |
||||
public class GroovyBeanDefinitionReader extends GroovyObjectSupport { |
||||
private static final Log LOG = LogFactory.getLog(GroovyBeanDefinitionReader.class); |
||||
private static final String CREATE_APPCTX = "createApplicationContext"; |
||||
private static final String REGISTER_BEANS = "registerBeans"; |
||||
private static final String BEANS = "beans"; |
||||
private static final String REF = "ref"; |
||||
private RuntimeSpringConfiguration springConfig; |
||||
private BeanConfiguration currentBeanConfig; |
||||
private Map<String, DeferredProperty> deferredProperties = new HashMap<String, DeferredProperty>(); |
||||
private ApplicationContext parentCtx; |
||||
private Map binding = Collections.EMPTY_MAP; |
||||
private ClassLoader classLoader = null; |
||||
private NamespaceHandlerResolver namespaceHandlerResolver; |
||||
private Map<String, NamespaceHandler> namespaceHandlers = new HashMap<String, NamespaceHandler>(); |
||||
private XmlBeanDefinitionReader xmlBeanDefinitionReader; |
||||
private Map<String, String> namespaces = new HashMap<String, String>(); |
||||
private Resource beanBuildResource = new ByteArrayResource(new byte[0]); |
||||
private XmlReaderContext readerContext; |
||||
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); |
||||
|
||||
public GroovyBeanDefinitionReader() { |
||||
this(null,null); |
||||
} |
||||
|
||||
public GroovyBeanDefinitionReader(ClassLoader classLoader) { |
||||
this(null, classLoader); |
||||
} |
||||
|
||||
public GroovyBeanDefinitionReader(ApplicationContext parent) { |
||||
this(parent, null); |
||||
} |
||||
|
||||
public GroovyBeanDefinitionReader(ApplicationContext parent,ClassLoader classLoader) { |
||||
this(parent,null, classLoader); |
||||
|
||||
} |
||||
|
||||
public GroovyBeanDefinitionReader(ApplicationContext parentCtx, RuntimeSpringConfiguration springConfig, ClassLoader classLoader) { |
||||
this.springConfig = springConfig == null ? createRuntimeSpringConfiguration(parentCtx, classLoader) : springConfig; |
||||
this.parentCtx = parentCtx; |
||||
this.classLoader = classLoader; |
||||
initializeSpringConfig(); |
||||
} |
||||
|
||||
public void setResourcePatternResolver(ResourcePatternResolver resourcePatternResolver) { |
||||
Assert.notNull(resourcePatternResolver, "The argument [resourcePatternResolver] cannot be null"); |
||||
this.resourcePatternResolver = resourcePatternResolver; |
||||
} |
||||
|
||||
|
||||
protected void initializeSpringConfig() { |
||||
this.xmlBeanDefinitionReader = new XmlBeanDefinitionReader((GenericApplicationContext)springConfig.getUnrefreshedApplicationContext()); |
||||
initializeGroovyBeanDefinitionReaderForClassLoader(this.classLoader); |
||||
} |
||||
|
||||
public void setClassLoader(ClassLoader classLoader) { |
||||
this.classLoader = classLoader == null ? getClass().getClassLoader() : classLoader; |
||||
initializeGroovyBeanDefinitionReaderForClassLoader(classLoader); |
||||
|
||||
} |
||||
|
||||
protected void initializeGroovyBeanDefinitionReaderForClassLoader(ClassLoader classLoader) { |
||||
xmlBeanDefinitionReader.setBeanClassLoader(classLoader); |
||||
this.namespaceHandlerResolver = new DefaultNamespaceHandlerResolver(this.classLoader); |
||||
this.readerContext = new XmlReaderContext(beanBuildResource,new FailFastProblemReporter(),new EmptyReaderEventListener(),new NullSourceExtractor(),xmlBeanDefinitionReader,namespaceHandlerResolver); |
||||
} |
||||
|
||||
public void setNamespaceHandlerResolver(NamespaceHandlerResolver namespaceHandlerResolver) { |
||||
this.namespaceHandlerResolver = namespaceHandlerResolver; |
||||
} |
||||
|
||||
protected RuntimeSpringConfiguration createRuntimeSpringConfiguration(ApplicationContext parent, ClassLoader classLoader) { |
||||
return new DefaultRuntimeSpringConfiguration(parent, classLoader); |
||||
} |
||||
|
||||
public Log getLog() { |
||||
return LOG; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Imports Spring bean definitions from either XML or Groovy sources into the current bean builder instance |
||||
* |
||||
* @param resourcePattern The resource pattern |
||||
*/ |
||||
public void importBeans(String resourcePattern) { |
||||
try { |
||||
Resource[] resources =resourcePatternResolver.getResources(resourcePattern); |
||||
for (int i = 0; i < resources.length; i++) { |
||||
Resource resource = resources[i]; |
||||
if(resource.getFilename().endsWith(".groovy")) { |
||||
loadBeans(resource); |
||||
} |
||||
else if(resource.getFilename().endsWith(".xml")) { |
||||
SimpleBeanDefinitionRegistry beanRegistry = new SimpleBeanDefinitionRegistry(); |
||||
XmlBeanDefinitionReader beanReader = new XmlBeanDefinitionReader(beanRegistry); |
||||
beanReader.loadBeanDefinitions(resource); |
||||
String[] beanNames = beanRegistry.getBeanDefinitionNames(); |
||||
for (int j = 0; j < beanNames.length; j++) { |
||||
String beanName = beanNames[j]; |
||||
springConfig.addBeanDefinition(beanName, beanRegistry.getBeanDefinition(beanName)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} catch (IOException e) { |
||||
LOG.error("Error loading beans for resource pattern: " + resourcePattern, e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Defines an Spring namespace definition to use |
||||
* |
||||
* @param definition The definition |
||||
*/ |
||||
public void xmlns(Map<String, String> definition) { |
||||
Assert.notNull(namespaceHandlerResolver, "You cannot define a Spring namespace without a [namespaceHandlerResolver] set"); |
||||
if(!definition.isEmpty()) { |
||||
|
||||
|
||||
for(Map.Entry<String,String> entry : definition.entrySet()) { |
||||
String namespace = entry.getKey(); |
||||
String uri = null; |
||||
if(entry.getValue() != null) { |
||||
uri = entry.getValue(); |
||||
} |
||||
|
||||
if(uri==null) { |
||||
throw new IllegalArgumentException("Namespace definition cannot supply a null URI"); |
||||
} |
||||
final NamespaceHandler namespaceHandler = namespaceHandlerResolver.resolve(uri); |
||||
if(namespaceHandler == null) { |
||||
throw new BeanDefinitionParsingException(new Problem("No namespace handler found for URI: " + uri, new Location(this.readerContext.getResource()))); |
||||
} |
||||
namespaceHandlers.put(namespace, namespaceHandler); |
||||
namespaces.put(namespace, uri); |
||||
|
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Retrieves the parent ApplicationContext |
||||
* @return The parent ApplicationContext |
||||
*/ |
||||
public ApplicationContext getParentCtx() { |
||||
return parentCtx; |
||||
} |
||||
|
||||
/** |
||||
* Retrieves the RuntimeSpringConfiguration instance used the the GroovyBeanDefinitionReader |
||||
* @return The RuntimeSpringConfiguration instance |
||||
*/ |
||||
public RuntimeSpringConfiguration getSpringConfig() { |
||||
return springConfig; |
||||
} |
||||
|
||||
/** |
||||
* Retrieves a BeanDefinition for the given name |
||||
* @param name The bean definition |
||||
* @return The BeanDefinition instance |
||||
*/ |
||||
public BeanDefinition getBeanDefinition(String name) { |
||||
if(!getSpringConfig().containsBean(name)) |
||||
return null; |
||||
return getSpringConfig().getBeanConfig(name).getBeanDefinition(); |
||||
} |
||||
|
||||
/** |
||||
* Retrieves all BeanDefinitions for this GroovyBeanDefinitionReader |
||||
* |
||||
* @return A map of BeanDefinition instances with the bean id as the key |
||||
*/ |
||||
public Map<String, BeanDefinition> getBeanDefinitions() { |
||||
|
||||
Map<String, BeanDefinition> beanDefinitions = new HashMap<String, BeanDefinition>(); |
||||
final List beanNames = getSpringConfig().getBeanNames(); |
||||
for (Object beanName1 : beanNames) { |
||||
String beanName = (String) beanName1; |
||||
BeanDefinition bd = getSpringConfig() |
||||
.getBeanConfig(beanName) |
||||
.getBeanDefinition(); |
||||
beanDefinitions.put(beanName, bd); |
||||
} |
||||
return beanDefinitions; |
||||
} |
||||
|
||||
/** |
||||
* Sets the runtime Spring configuration instance to use. This is not necessary to set |
||||
* and is configured to default value if not, but is useful for integrating with other |
||||
* spring configuration mechanisms @see org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator |
||||
* |
||||
* @param springConfig The spring config |
||||
*/ |
||||
public void setSpringConfig(RuntimeSpringConfiguration springConfig) { |
||||
this.springConfig = springConfig; |
||||
initializeSpringConfig(); |
||||
} |
||||
|
||||
/** |
||||
* This class is used to defer the adding of a property to a bean definition until later |
||||
* This is for a case where you assign a property to a list that may not contain bean references at |
||||
* that point of asignment, but may later hence it would need to be managed |
||||
* |
||||
* @author Graeme Rocher |
||||
*/ |
||||
private class DeferredProperty { |
||||
private BeanConfiguration config; |
||||
private String name; |
||||
private Object value; |
||||
|
||||
DeferredProperty(BeanConfiguration config, String name, Object value) { |
||||
this.config = config; |
||||
this.name = name; |
||||
this.value = value; |
||||
} |
||||
|
||||
public void setInBeanConfig() { |
||||
this.config.addProperty(name, value); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* A RuntimeBeanReference that takes care of adding new properties to runtime references |
||||
* |
||||
* @author Graeme Rocher |
||||
* @since 0.4 |
||||
* |
||||
*/ |
||||
private class ConfigurableRuntimeBeanReference extends RuntimeBeanReference implements GroovyObject { |
||||
|
||||
private MetaClass metaClass; |
||||
private BeanConfiguration beanConfig; |
||||
|
||||
public ConfigurableRuntimeBeanReference(String beanName, BeanConfiguration beanConfig) { |
||||
this(beanName, beanConfig, false); |
||||
} |
||||
|
||||
public ConfigurableRuntimeBeanReference(String beanName, BeanConfiguration beanConfig, boolean toParent) { |
||||
super(beanName, toParent); |
||||
this.beanConfig = beanConfig; |
||||
if(beanConfig == null) |
||||
throw new IllegalArgumentException("Argument [beanConfig] cannot be null"); |
||||
this.metaClass = InvokerHelper.getMetaClass(this); |
||||
} |
||||
|
||||
public MetaClass getMetaClass() { |
||||
return this.metaClass; |
||||
} |
||||
|
||||
public Object getProperty(String property) { |
||||
if(property.equals("beanName")) |
||||
return getBeanName(); |
||||
else if(property.equals("source")) |
||||
return getSource(); |
||||
else if(this.beanConfig != null) { |
||||
return new WrappedPropertyValue(property,beanConfig.getPropertyValue(property)); |
||||
} |
||||
else |
||||
return this.metaClass.getProperty(this, property); |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* Wraps a BeanConfiguration property an ensures that any RuntimeReference additions to it are |
||||
* deferred for resolution later |
||||
* |
||||
* @author Graeme Rocher |
||||
* @since 0.4 |
||||
* |
||||
*/ |
||||
private class WrappedPropertyValue extends GroovyObjectSupport { |
||||
private Object propertyValue; |
||||
private String propertyName; |
||||
public WrappedPropertyValue(String propertyName, Object propertyValue) { |
||||
this.propertyValue = propertyValue; |
||||
this.propertyName = propertyName; |
||||
} |
||||
|
||||
public void leftShift(Object value) { |
||||
InvokerHelper.invokeMethod(propertyValue, "leftShift", value); |
||||
updateDeferredProperties(value); |
||||
} |
||||
|
||||
public boolean add(Object value) { |
||||
boolean retval = (Boolean) InvokerHelper.invokeMethod(propertyValue, "add", value); |
||||
updateDeferredProperties(value); |
||||
return retval; |
||||
} |
||||
|
||||
public boolean addAll(Collection values) { |
||||
boolean retval = (Boolean) InvokerHelper.invokeMethod(propertyValue, "addAll", values); |
||||
for (Object value : values) { |
||||
updateDeferredProperties(value); |
||||
} |
||||
return retval; |
||||
} |
||||
|
||||
public Object invokeMethod(String name, Object args) { |
||||
return InvokerHelper.invokeMethod(propertyValue, name, args); |
||||
} |
||||
|
||||
public Object getProperty(String name) { |
||||
return InvokerHelper.getProperty(propertyValue, name); |
||||
} |
||||
|
||||
public void setProperty(String name, Object value) { |
||||
InvokerHelper.setProperty(propertyValue, name, value); |
||||
} |
||||
|
||||
private void updateDeferredProperties(Object value) { |
||||
if (value instanceof RuntimeBeanReference) { |
||||
deferredProperties.put(beanConfig.getName(), new DeferredProperty(beanConfig, propertyName, propertyValue)); |
||||
} |
||||
} |
||||
} |
||||
public Object invokeMethod(String name, Object args) { |
||||
return this.metaClass.invokeMethod(this, name, args); |
||||
} |
||||
|
||||
public void setMetaClass(MetaClass metaClass) { |
||||
this.metaClass = metaClass; |
||||
} |
||||
|
||||
public void setProperty(String property, Object newValue) { |
||||
if(!addToDeferred(beanConfig,property, newValue)) { |
||||
beanConfig.setPropertyValue(property, newValue); |
||||
} |
||||
} |
||||
} |
||||
/** |
||||
* Takes a resource pattern as (@see org.springframework.core.io.support.PathMatchingResourcePatternResolver) |
||||
* This allows you load multiple bean resources in this single builder |
||||
* |
||||
* eg loadBeans("classpath:*Beans.groovy") |
||||
* |
||||
* @param resourcePattern The resource pattern |
||||
* @throws IOException When the path cannot be matched |
||||
*/ |
||||
public void loadBeans(String resourcePattern) throws IOException { |
||||
loadBeans(new PathMatchingResourcePatternResolver().getResources(resourcePattern)); |
||||
} |
||||
|
||||
/** |
||||
* Loads a single Resource into the bean builder |
||||
* |
||||
* @param resource The resource to load |
||||
* @throws IOException When an error occurs |
||||
*/ |
||||
public void loadBeans(Resource resource) throws IOException { |
||||
this.beanBuildResource = resource; |
||||
loadBeans(new Resource[]{resource}); |
||||
} |
||||
|
||||
/** |
||||
* Loads a set of given beans |
||||
* @param resources The resources to load |
||||
* @throws IOException Thrown if there is an error reading one of the passes resources |
||||
*/ |
||||
public void loadBeans(Resource[] resources) throws IOException { |
||||
Closure beans = new Closure(this){ |
||||
public Object call(Object[] args) { |
||||
invokeBeanDefiningClosure((Closure)args[0]); |
||||
return null; |
||||
} |
||||
}; |
||||
Binding b = new Binding() { |
||||
@Override |
||||
public void setVariable(String name, Object value) { |
||||
if(currentBeanConfig!=null) { |
||||
setPropertyOnBeanConfig(name, value); |
||||
} |
||||
else { |
||||
super.setVariable(name, value); |
||||
} |
||||
} |
||||
}; |
||||
b.setVariable("beans", beans); |
||||
|
||||
|
||||
for (Resource resource : resources) { |
||||
try { |
||||
GroovyShell shell = classLoader != null ? new GroovyShell(classLoader, b) : new GroovyShell(b); |
||||
shell.evaluate(resource.getInputStream()); |
||||
} |
||||
catch (Throwable e) { |
||||
throw new BeanDefinitionParsingException(new Problem("Error evaluating bean definition script: " + e.getMessage(), new Location(resource), null, e)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Register a set of beans with the given bean registry. Most |
||||
* application contexts are bean registries. |
||||
*/ |
||||
public void registerBeans(BeanDefinitionRegistry registry) { |
||||
finalizeDeferredProperties(); |
||||
|
||||
if (registry instanceof GenericApplicationContext) { |
||||
GenericApplicationContext ctx = (GenericApplicationContext) registry; |
||||
ctx.setClassLoader(this.classLoader); |
||||
ctx.getBeanFactory().setBeanClassLoader(this.classLoader); |
||||
} |
||||
|
||||
springConfig.registerBeansWithRegistry(registry); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Registers bean definitions with another instance of RuntimeSpringConfiguration, overriding any beans in the target. |
||||
* |
||||
* @param targetSpringConfig The RuntimeSpringConfiguration object |
||||
*/ |
||||
public void registerBeans(RuntimeSpringConfiguration targetSpringConfig) { |
||||
this.springConfig.registerBeansWithConfig(targetSpringConfig); |
||||
} |
||||
|
||||
/** |
||||
* This method overrides method invocation to create beans for each method name that |
||||
* takes a class argument |
||||
*/ |
||||
public Object invokeMethod(String name, Object arg) { |
||||
Object[] args = (Object[])arg; |
||||
|
||||
if(CREATE_APPCTX.equals(name)) { |
||||
return createApplicationContext(); |
||||
} |
||||
else if(REGISTER_BEANS.equals(name) && args.length == 1 && args[0] instanceof GenericApplicationContext) { |
||||
registerBeans((GenericApplicationContext)args[0]); |
||||
return null; |
||||
} |
||||
else if(BEANS.equals(name) && args.length == 1 && args[0] instanceof Closure) { |
||||
return beans((Closure)args[0]); |
||||
} |
||||
else if(REF.equals(name)) { |
||||
String refName; |
||||
if(args[0] == null) |
||||
throw new IllegalArgumentException("Argument to ref() is not a valid bean or was not found"); |
||||
|
||||
if(args[0] instanceof RuntimeBeanReference) { |
||||
refName = ((RuntimeBeanReference)args[0]).getBeanName(); |
||||
} |
||||
else { |
||||
refName = args[0].toString(); |
||||
} |
||||
|
||||
boolean parentRef = false; |
||||
if(args.length > 1) { |
||||
if(args[1] instanceof Boolean) { |
||||
parentRef = (Boolean) args[1]; |
||||
} |
||||
} |
||||
return new RuntimeBeanReference(refName, parentRef); |
||||
} |
||||
else if(namespaceHandlers.containsKey(name) && args.length > 0 && (args[0] instanceof Closure)) { |
||||
DynamicElementReader reader = createDynamicElementReader(name, true); |
||||
reader.invokeMethod("doCall",args); |
||||
} |
||||
else if(args.length > 0 && args[0] instanceof Closure) { |
||||
// abstract bean definition
|
||||
return invokeBeanDefiningMethod(name, args); |
||||
} |
||||
else if(args.length > 0 && args[0] instanceof Class || args.length > 0 && args[0] instanceof RuntimeBeanReference || args.length > 0 &&args[0] instanceof Map) { |
||||
return invokeBeanDefiningMethod(name, args); |
||||
} |
||||
else if (args.length > 1 && args[args.length -1] instanceof Closure) { |
||||
return invokeBeanDefiningMethod(name, args); |
||||
} |
||||
ApplicationContext ctx = springConfig.getUnrefreshedApplicationContext(); |
||||
MetaClass mc = DefaultGroovyMethods.getMetaClass(ctx); |
||||
if(!mc.respondsTo(ctx, name, args).isEmpty()){ |
||||
return mc.invokeMethod(ctx,name, args); |
||||
} |
||||
|
||||
return this; |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* Defines a set of beans for the given block or closure. |
||||
* |
||||
* @param c The block or closure |
||||
* @return This GroovyBeanDefinitionReader instance |
||||
*/ |
||||
public GroovyBeanDefinitionReader beans(Closure c) { |
||||
return invokeBeanDefiningClosure(c); |
||||
} |
||||
|
||||
/** |
||||
* Creates an ApplicationContext from the current state of the GroovyBeanDefinitionReader |
||||
* @return The ApplicationContext instance |
||||
*/ |
||||
public ApplicationContext createApplicationContext() { |
||||
finalizeDeferredProperties(); |
||||
return springConfig.getApplicationContext(); |
||||
} |
||||
|
||||
protected void finalizeDeferredProperties() { |
||||
for (Object o : deferredProperties.values()) { |
||||
DeferredProperty dp = (DeferredProperty) o; |
||||
|
||||
if (dp.value instanceof List) { |
||||
dp.value = manageListIfNecessary(dp.value); |
||||
} |
||||
else if (dp.value instanceof Map) { |
||||
dp.value = manageMapIfNecessary(dp.value); |
||||
} |
||||
dp.setInBeanConfig(); |
||||
} |
||||
deferredProperties.clear(); |
||||
} |
||||
|
||||
protected boolean addToDeferred(BeanConfiguration beanConfig,String property, Object newValue) { |
||||
if(newValue instanceof List) { |
||||
deferredProperties.put(currentBeanConfig.getName()+property,new DeferredProperty(currentBeanConfig, property, newValue)); |
||||
return true; |
||||
} |
||||
else if(newValue instanceof Map) { |
||||
deferredProperties.put(currentBeanConfig.getName()+property,new DeferredProperty(currentBeanConfig, property, newValue)); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
/** |
||||
* This method is called when a bean definition node is called |
||||
* |
||||
* @param name The name of the bean to define |
||||
* @param args The arguments to the bean. The first argument is the class name, the last argument is sometimes a closure. All |
||||
* the arguments in between are constructor arguments |
||||
* @return The bean configuration instance |
||||
*/ |
||||
protected BeanConfiguration invokeBeanDefiningMethod(String name, Object[] args) { |
||||
|
||||
boolean hasClosureArgument = args[args.length - 1] instanceof Closure; |
||||
if(args[0] instanceof Class) { |
||||
Class beanClass = args[0] instanceof Class ? (Class)args[0] : args[0].getClass(); |
||||
|
||||
if(args.length >= 1) { |
||||
if(hasClosureArgument) { |
||||
if(args.length-1 != 1) { |
||||
currentBeanConfig = springConfig.addSingletonBean(name, beanClass, resolveConstructorArguments(args,1,args.length-1)); |
||||
} |
||||
else { |
||||
currentBeanConfig = springConfig.addSingletonBean(name, beanClass); |
||||
} |
||||
} |
||||
else { |
||||
currentBeanConfig = springConfig.addSingletonBean(name, beanClass, resolveConstructorArguments(args,1,args.length)); |
||||
} |
||||
|
||||
} |
||||
} |
||||
else if(args[0] instanceof RuntimeBeanReference) { |
||||
currentBeanConfig = springConfig.addSingletonBean(name); |
||||
currentBeanConfig.setFactoryBean(((RuntimeBeanReference)args[0]).getBeanName()); |
||||
} |
||||
else if(args[0] instanceof Map) { |
||||
// named constructor arguments
|
||||
if(args.length > 1 && args[1] instanceof Class) { |
||||
List constructorArgs = resolveConstructorArguments(args, 2, hasClosureArgument ? args.length-1 : args.length); |
||||
currentBeanConfig = springConfig.addSingletonBean(name, (Class)args[1], constructorArgs); |
||||
|
||||
Map namedArgs = (Map)args[0]; |
||||
for (Object o : namedArgs.keySet()) { |
||||
String propName = (String) o; |
||||
setProperty(propName, namedArgs.get(propName)); |
||||
} |
||||
} |
||||
// factory method syntax
|
||||
else { |
||||
currentBeanConfig = springConfig.addSingletonBean(name); |
||||
//First arg is the map containing factoryBean : factoryMethod
|
||||
Map.Entry factoryBeanEntry = (Map.Entry)((Map)args[0]).entrySet().iterator().next(); |
||||
// If we have a closure body, that will be the last argument.
|
||||
// In between are the constructor args
|
||||
int constructorArgsTest = hasClosureArgument?2:1; |
||||
// If we have more than this number of args, we have constructor args
|
||||
if(args.length > constructorArgsTest){ |
||||
//factory-method requires args
|
||||
int endOfConstructArgs = hasClosureArgument? args.length-1 : args.length; |
||||
currentBeanConfig = springConfig.addSingletonBean(name, null, resolveConstructorArguments(args, 1, endOfConstructArgs)); |
||||
} else { |
||||
currentBeanConfig = springConfig.addSingletonBean(name); |
||||
} |
||||
currentBeanConfig.setFactoryBean(factoryBeanEntry.getKey().toString()); |
||||
currentBeanConfig.setFactoryMethod(factoryBeanEntry.getValue().toString()); |
||||
} |
||||
|
||||
} |
||||
else if(args[0] instanceof Closure) { |
||||
currentBeanConfig = springConfig.addAbstractBean(name); |
||||
} |
||||
else { |
||||
List constructorArgs = resolveConstructorArguments(args, 0, hasClosureArgument ? args.length-1 : args.length); |
||||
currentBeanConfig = new DefaultBeanConfiguration(name, null, constructorArgs); |
||||
springConfig.addBeanConfiguration(name,currentBeanConfig); |
||||
} |
||||
|
||||
|
||||
if(hasClosureArgument) { |
||||
Closure callable = (Closure)args[args.length-1]; |
||||
callable.setDelegate(this); |
||||
callable.setResolveStrategy(Closure.DELEGATE_FIRST); |
||||
callable.call(new Object[]{currentBeanConfig}); |
||||
|
||||
} |
||||
|
||||
BeanConfiguration beanConfig = currentBeanConfig; |
||||
currentBeanConfig = null; |
||||
return beanConfig; |
||||
} |
||||
|
||||
protected List resolveConstructorArguments(Object[] args, int start, int end) { |
||||
Object[] constructorArgs = subarray(args, start, end); |
||||
filterGStringReferences(constructorArgs); |
||||
List constructorArgsList = Arrays.asList(constructorArgs); |
||||
return constructorArgsList; |
||||
} |
||||
|
||||
protected Object[] subarray(Object[] args, int i, int j) { |
||||
if(j > args.length) throw new IllegalArgumentException("Upper bound can't be greater than array length"); |
||||
Object[] b = new Object[j-i]; |
||||
int n = 0; |
||||
for (int k = i; k < j; k++,n++) { |
||||
b[n] = args[k]; |
||||
|
||||
} |
||||
return b; |
||||
} |
||||
|
||||
protected void filterGStringReferences(Object[] constructorArgs) { |
||||
for (int i = 0; i < constructorArgs.length; i++) { |
||||
Object constructorArg = constructorArgs[i]; |
||||
if(constructorArg instanceof GString) constructorArgs[i] = constructorArg.toString(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* When an methods argument is only a closure it is a set of bean definitions |
||||
* |
||||
* @param callable The closure argument |
||||
* @return This GroovyBeanDefinitionReader instance |
||||
*/ |
||||
protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure callable) { |
||||
|
||||
callable.setDelegate(this); |
||||
// callable.setResolveStrategy(Closure.DELEGATE_FIRST);
|
||||
callable.call(); |
||||
finalizeDeferredProperties(); |
||||
|
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* This method overrides property setting in the scope of the GroovyBeanDefinitionReader to set |
||||
* properties on the current BeanConfiguration |
||||
*/ |
||||
public void setProperty(String name, Object value) { |
||||
if(currentBeanConfig != null) { |
||||
setPropertyOnBeanConfig(name, value); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Defines an inner bean definition |
||||
* |
||||
* @param type The bean type |
||||
* @return The bean definition |
||||
*/ |
||||
public AbstractBeanDefinition bean(Class type) { |
||||
return springConfig.createSingletonBean(type).getBeanDefinition(); |
||||
} |
||||
|
||||
/** |
||||
* Defines an inner bean definition |
||||
* |
||||
* @param type The bean type |
||||
* @param args The constructors arguments and closure configurer |
||||
* @return The bean definition |
||||
*/ |
||||
public AbstractBeanDefinition bean(Class type, Object...args) { |
||||
BeanConfiguration current = currentBeanConfig; |
||||
try { |
||||
|
||||
Closure callable = null; |
||||
Collection constructorArgs = null; |
||||
if(args != null && args.length > 0) { |
||||
int index = args.length; |
||||
Object lastArg = args[index-1]; |
||||
|
||||
if(lastArg instanceof Closure) { |
||||
callable = (Closure) lastArg; |
||||
index--; |
||||
} |
||||
if(index > -1) { |
||||
constructorArgs = resolveConstructorArguments(args, 0, index); |
||||
} |
||||
} |
||||
currentBeanConfig = constructorArgs != null ? springConfig.createSingletonBean(type,constructorArgs) : springConfig.createSingletonBean(type); |
||||
if(callable != null) { |
||||
callable.call(new Object[]{currentBeanConfig}); |
||||
} |
||||
return currentBeanConfig.getBeanDefinition(); |
||||
|
||||
} |
||||
finally { |
||||
currentBeanConfig = current; |
||||
} |
||||
} |
||||
|
||||
protected void setPropertyOnBeanConfig(String name, Object value) { |
||||
if(value instanceof GString)value = value.toString(); |
||||
if(addToDeferred(currentBeanConfig, name, value)) { |
||||
return; |
||||
} |
||||
else if(value instanceof Closure) { |
||||
BeanConfiguration current = currentBeanConfig; |
||||
try { |
||||
Closure callable = (Closure)value; |
||||
|
||||
Class parameterType = callable.getParameterTypes()[0]; |
||||
if(parameterType.equals(Object.class)) { |
||||
currentBeanConfig = springConfig.createSingletonBean(""); |
||||
callable.call(new Object[]{currentBeanConfig}); |
||||
} |
||||
else { |
||||
currentBeanConfig = springConfig.createSingletonBean(parameterType); |
||||
callable.call(null); |
||||
} |
||||
|
||||
value = currentBeanConfig.getBeanDefinition(); |
||||
} |
||||
finally { |
||||
currentBeanConfig = current; |
||||
} |
||||
} |
||||
currentBeanConfig.addProperty(name, value); |
||||
} |
||||
|
||||
/** |
||||
* Checks whether there are any runtime refs inside a Map and converts |
||||
* it to a ManagedMap if necessary |
||||
* |
||||
* @param value The current map |
||||
* @return A ManagedMap or a normal map |
||||
*/ |
||||
protected Object manageMapIfNecessary(Object value) { |
||||
Map map = (Map)value; |
||||
boolean containsRuntimeRefs = false; |
||||
for (Object e : map.values()) { |
||||
if (e instanceof RuntimeBeanReference) { |
||||
containsRuntimeRefs = true; |
||||
break; |
||||
} |
||||
} |
||||
if(containsRuntimeRefs) { |
||||
Map managedMap = new ManagedMap(); |
||||
managedMap.putAll(map); |
||||
return managedMap; |
||||
} |
||||
return value; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether there are any runtime refs inside the list and |
||||
* converts it to a ManagedList if necessary |
||||
* |
||||
* @param value The object that represents the list |
||||
* @return Either a new list or a managed one |
||||
*/ |
||||
protected Object manageListIfNecessary(Object value) { |
||||
List list = (List)value; |
||||
boolean containsRuntimeRefs = false; |
||||
for (Object e : list) { |
||||
if (e instanceof RuntimeBeanReference) { |
||||
containsRuntimeRefs = true; |
||||
break; |
||||
} |
||||
} |
||||
if(containsRuntimeRefs) { |
||||
List tmp = new ManagedList(); |
||||
tmp.addAll((List)value); |
||||
value = tmp; |
||||
} |
||||
return value; |
||||
} |
||||
|
||||
/** |
||||
* This method overrides property retrieval in the scope of the GroovyBeanDefinitionReader to either: |
||||
* |
||||
* a) Retrieve a variable from the bean builder's binding if it exists |
||||
* b) Retrieve a RuntimeBeanReference for a specific bean if it exists |
||||
* c) Otherwise just delegate to super.getProperty which will resolve properties from the GroovyBeanDefinitionReader itself |
||||
*/ |
||||
public Object getProperty(String name) { |
||||
|
||||
if(binding.containsKey(name)) { |
||||
return binding.get(name); |
||||
} |
||||
else { |
||||
if(namespaceHandlers.containsKey(name)) { |
||||
return createDynamicElementReader(name, currentBeanConfig!=null); |
||||
|
||||
} |
||||
if(springConfig.containsBean(name)) { |
||||
BeanConfiguration beanConfig = springConfig.getBeanConfig(name); |
||||
if(beanConfig != null) { |
||||
return new ConfigurableRuntimeBeanReference(name, springConfig.getBeanConfig(name) ,false); |
||||
} |
||||
else |
||||
return new RuntimeBeanReference(name,false); |
||||
} |
||||
// this is to deal with the case where the property setter is the last
|
||||
// statement in a closure (hence the return value)
|
||||
else if(currentBeanConfig != null) { |
||||
if(currentBeanConfig.hasProperty(name)) |
||||
return currentBeanConfig.getPropertyValue(name); |
||||
else { |
||||
DeferredProperty dp = deferredProperties.get(currentBeanConfig.getName()+name); |
||||
if(dp!=null) { |
||||
return dp.value; |
||||
} |
||||
else { |
||||
return super.getProperty(name); |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
return super.getProperty(name); |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected DynamicElementReader createDynamicElementReader(String namespace, final boolean decorator) { |
||||
NamespaceHandler handler = namespaceHandlers.get(namespace); |
||||
ParserContext parserContext = new ParserContext(readerContext, new BeanDefinitionParserDelegate(readerContext)); |
||||
final DynamicElementReader dynamicElementReader = new DynamicElementReader(namespace, this.namespaces, handler, parserContext) { |
||||
@Override |
||||
protected void afterInvocation() { |
||||
if(!decorator) { |
||||
currentBeanConfig = null; |
||||
} |
||||
} |
||||
}; |
||||
dynamicElementReader.setClassLoader(classLoader); |
||||
if(currentBeanConfig!=null) { |
||||
dynamicElementReader.setBeanConfiguration(currentBeanConfig); |
||||
} |
||||
else if(!decorator) { |
||||
currentBeanConfig = new DefaultBeanConfiguration(namespace); |
||||
dynamicElementReader.setBeanConfiguration(currentBeanConfig); |
||||
} |
||||
dynamicElementReader.setBeanDecorator(decorator); |
||||
return dynamicElementReader; |
||||
} |
||||
|
||||
/** |
||||
* Sets the binding (the variables available in the scope of the GroovyBeanDefinitionReader) |
||||
* @param b The Binding instance |
||||
*/ |
||||
public void setBinding(Binding b) { |
||||
this.binding = b.getVariables(); |
||||
} |
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,160 @@
@@ -0,0 +1,160 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy; |
||||
|
||||
import groovy.lang.GroovyObject; |
||||
import groovy.lang.GroovySystem; |
||||
import groovy.lang.MetaClass; |
||||
import org.springframework.beans.BeanWrapper; |
||||
import org.springframework.beans.BeanWrapperImpl; |
||||
import org.springframework.beans.BeansException; |
||||
import org.springframework.beans.MutablePropertyValues; |
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.support.GenericBeanDefinition; |
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
||||
import org.springframework.context.support.GenericApplicationContext; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.ui.context.Theme; |
||||
import org.springframework.ui.context.ThemeSource; |
||||
import org.springframework.ui.context.support.UiApplicationContextUtils; |
||||
|
||||
/** |
||||
* An ApplicationContext that extends StaticApplicationContext and implements GroovyObject such that beans can be retrieved with the dot |
||||
* de-reference syntax instead of using getBean('name') |
||||
* |
||||
*/ |
||||
public class GroovyPropertyApplicationContext extends GenericApplicationContext implements GroovyObject { |
||||
protected MetaClass metaClass; |
||||
private BeanWrapper ctxBean = new BeanWrapperImpl(this); |
||||
private ThemeSource themeSource; |
||||
|
||||
public GroovyPropertyApplicationContext(DefaultListableBeanFactory defaultListableBeanFactory) { |
||||
super(defaultListableBeanFactory); |
||||
this.metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass()); |
||||
} |
||||
|
||||
public GroovyPropertyApplicationContext(DefaultListableBeanFactory defaultListableBeanFactory, ApplicationContext applicationContext) { |
||||
super(defaultListableBeanFactory, applicationContext); |
||||
this.metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass()); |
||||
} |
||||
|
||||
public GroovyPropertyApplicationContext(org.springframework.context.ApplicationContext parent) throws org.springframework.beans.BeansException { |
||||
super(parent); |
||||
this.metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass()); |
||||
} |
||||
|
||||
public GroovyPropertyApplicationContext() throws org.springframework.beans.BeansException { |
||||
this.metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass()); |
||||
} |
||||
|
||||
public MetaClass getMetaClass() { |
||||
return this.metaClass; |
||||
} |
||||
|
||||
public Object getProperty(String property) { |
||||
if(containsBean(property)) { |
||||
return getBean(property); |
||||
} |
||||
else if(ctxBean.isReadableProperty(property)) { |
||||
return ctxBean.getPropertyValue(property); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public Object invokeMethod(String name, Object args) { |
||||
return metaClass.invokeMethod(this, name, args); |
||||
} |
||||
|
||||
public void setMetaClass(MetaClass metaClass) { |
||||
this.metaClass = metaClass; |
||||
} |
||||
|
||||
/** |
||||
* Initialize the theme capability. |
||||
*/ |
||||
protected void onRefresh() { |
||||
this.themeSource = UiApplicationContextUtils.initThemeSource(this); |
||||
} |
||||
|
||||
public Theme getTheme(String themeName) { |
||||
return this.themeSource.getTheme(themeName); |
||||
} |
||||
|
||||
public void setProperty(String property, Object newValue) { |
||||
if(newValue instanceof BeanDefinition) { |
||||
if(containsBean(property)) { |
||||
removeBeanDefinition(property); |
||||
} |
||||
|
||||
registerBeanDefinition(property, (BeanDefinition)newValue); |
||||
} |
||||
else { |
||||
metaClass.setProperty(this, property, newValue); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Register a singleton bean with the underlying bean factory. |
||||
* <p>For more advanced needs, register with the underlying BeanFactory directly. |
||||
* @see #getDefaultListableBeanFactory |
||||
*/ |
||||
public void registerSingleton(String name, Class clazz) throws BeansException { |
||||
GenericBeanDefinition bd = new GenericBeanDefinition(); |
||||
bd.setBeanClass(clazz); |
||||
getDefaultListableBeanFactory().registerBeanDefinition(name, bd); |
||||
} |
||||
|
||||
/** |
||||
* Register a singleton bean with the underlying bean factory. |
||||
* <p>For more advanced needs, register with the underlying BeanFactory directly. |
||||
* @see #getDefaultListableBeanFactory |
||||
*/ |
||||
public void registerSingleton(String name, Class clazz, MutablePropertyValues pvs) throws BeansException { |
||||
GenericBeanDefinition bd = new GenericBeanDefinition(); |
||||
bd.setBeanClass(clazz); |
||||
bd.setPropertyValues(pvs); |
||||
getDefaultListableBeanFactory().registerBeanDefinition(name, bd); |
||||
} |
||||
|
||||
/** |
||||
* Register a prototype bean with the underlying bean factory. |
||||
* <p>For more advanced needs, register with the underlying BeanFactory directly. |
||||
* @see #getDefaultListableBeanFactory |
||||
*/ |
||||
public void registerPrototype(String name, Class clazz) throws BeansException { |
||||
GenericBeanDefinition bd = new GenericBeanDefinition(); |
||||
bd.setScope(GenericBeanDefinition.SCOPE_PROTOTYPE); |
||||
bd.setBeanClass(clazz); |
||||
getDefaultListableBeanFactory().registerBeanDefinition(name, bd); |
||||
} |
||||
|
||||
/** |
||||
* Register a prototype bean with the underlying bean factory. |
||||
* <p>For more advanced needs, register with the underlying BeanFactory directly. |
||||
* @see #getDefaultListableBeanFactory |
||||
*/ |
||||
public void registerPrototype(String name, Class clazz, MutablePropertyValues pvs) throws BeansException { |
||||
GenericBeanDefinition bd = new GenericBeanDefinition(); |
||||
bd.setScope(GenericBeanDefinition.SCOPE_PROTOTYPE); |
||||
bd.setBeanClass(clazz); |
||||
bd.setPropertyValues(pvs); |
||||
getDefaultListableBeanFactory().registerBeanDefinition(name, bd); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
@ -0,0 +1,232 @@
@@ -0,0 +1,232 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy; |
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; |
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition; |
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry; |
||||
import org.springframework.beans.factory.ListableBeanFactory; |
||||
import org.springframework.context.ApplicationContext; |
||||
import org.springframework.context.support.GenericApplicationContext; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* A programmable runtime Spring configuration that allows a spring ApplicationContext |
||||
* to be constructed at runtime |
||||
* |
||||
* Credit must go to Solomon Duskis and the |
||||
* article: http://jroller.com/page/Solomon?entry=programmatic_configuration_in_spring
|
||||
* |
||||
*/ |
||||
public interface RuntimeSpringConfiguration { |
||||
|
||||
/** |
||||
* Adds a singleton bean definition |
||||
* |
||||
* @param name The name of the bean |
||||
* @param clazz The class of the bean |
||||
* @return A BeanConfiguration instance |
||||
*/ |
||||
public BeanConfiguration addSingletonBean(String name, Class clazz); |
||||
|
||||
public ApplicationContext getUnrefreshedApplicationContext(); |
||||
/** |
||||
* Adds a prototype bean definition |
||||
* |
||||
* @param name The name of the bean |
||||
* @param clazz The class of the bean |
||||
* @return A BeanConfiguration instance |
||||
*/ |
||||
public BeanConfiguration addPrototypeBean(String name, Class clazz); |
||||
|
||||
/** |
||||
* Retrieves the application context from the current state |
||||
* |
||||
* @return The ApplicationContext instance |
||||
*/ |
||||
ApplicationContext getApplicationContext(); |
||||
|
||||
/** |
||||
* Adds an empty singleton bean configuration |
||||
* @param name The name of the singleton bean |
||||
* |
||||
* @return A BeanConfiguration instance |
||||
*/ |
||||
public BeanConfiguration addSingletonBean(String name); |
||||
|
||||
/** |
||||
* Adds an empty prototype bean configuration |
||||
* |
||||
* @param name The name of the prototype bean |
||||
* @return A BeanConfiguration instance |
||||
*/ |
||||
public BeanConfiguration addPrototypeBean(String name); |
||||
|
||||
/** |
||||
* Creates a singleton bean configuration. Differs from addSingletonBean in that |
||||
* it doesn't add the bean to the list of bean references. Hence should be used for |
||||
* creating nested beans |
||||
* |
||||
* @param clazz |
||||
* @return A BeanConfiguration instance |
||||
*/ |
||||
public BeanConfiguration createSingletonBean(Class clazz); |
||||
|
||||
/** |
||||
* Creates a new singleton bean and adds it to the list of bean references |
||||
* |
||||
* @param name The name of the bean |
||||
* @param clazz The class of the bean |
||||
* @param args The constructor arguments of the bean |
||||
* @return A BeanConfiguration instance |
||||
*/ |
||||
public BeanConfiguration addSingletonBean(String name, Class clazz, Collection args); |
||||
|
||||
/** |
||||
* Creates a singleton bean configuration. Differs from addSingletonBean in that |
||||
* it doesn't add the bean to the list of bean references. Hence should be used for |
||||
* creating nested beans |
||||
* |
||||
* @param clazz The bean class |
||||
* @param constructorArguments The constructor arguments |
||||
* @return A BeanConfiguration instance |
||||
*/ |
||||
public BeanConfiguration createSingletonBean(Class clazz, Collection constructorArguments); |
||||
|
||||
|
||||
/** |
||||
* Creates a new prototype bean configuration. Differs from addPrototypeBean in that |
||||
* it doesn't add the bean to the list of bean references to be created via the getApplicationContext() |
||||
* method, hence can be used for creating nested beans |
||||
* |
||||
* @param name The bean name |
||||
* @return A BeanConfiguration instance |
||||
* |
||||
*/ |
||||
public BeanConfiguration createPrototypeBean(String name); |
||||
|
||||
/** |
||||
* Creates a new singleton bean configuration. Differs from addSingletonBean in that |
||||
* it doesn't add the bean to the list of bean references to be created via the getApplicationContext() |
||||
* method, hence can be used for creating nested beans |
||||
* |
||||
* @param name The bean name |
||||
* @return A BeanConfiguration instance |
||||
* |
||||
*/ |
||||
public BeanConfiguration createSingletonBean(String name); |
||||
|
||||
/** |
||||
* Adds a bean configuration to the list of beans to be created |
||||
* |
||||
* @param beanName The name of the bean in the context |
||||
* @param beanConfiguration The BeanConfiguration instance |
||||
*/ |
||||
void addBeanConfiguration(String beanName, BeanConfiguration beanConfiguration); |
||||
/** |
||||
* Adds a Spring BeanDefinition. Differs from BeanConfiguration which is a factory class |
||||
* for creating BeanDefinition instances |
||||
* @param name The name of the bean |
||||
* @param bd The BeanDefinition instance |
||||
*/ |
||||
public void addBeanDefinition(String name, BeanDefinition bd); |
||||
|
||||
/** |
||||
* Returns whether the runtime spring config contains the specified bean |
||||
* |
||||
* @param name The bean name |
||||
* @return True if it does |
||||
*/ |
||||
public boolean containsBean(String name); |
||||
/** |
||||
* Returns the BeanConfiguration for the specified name |
||||
* @param name The name of the bean configuration |
||||
* @return The BeanConfiguration |
||||
*/ |
||||
public BeanConfiguration getBeanConfig(String name); |
||||
|
||||
/** |
||||
* Creates and returns the BeanDefinition that is regsitered within the given name or returns null |
||||
* |
||||
* @param name The name of the bean definition |
||||
* @return A BeanDefinition |
||||
*/ |
||||
public AbstractBeanDefinition createBeanDefinition(String name); |
||||
|
||||
/** |
||||
* Registers a bean factory post processor with the context |
||||
* |
||||
* @param processor The BeanFactoryPostProcessor instance |
||||
*/ |
||||
public void registerPostProcessor(BeanFactoryPostProcessor processor); |
||||
|
||||
List getBeanNames(); |
||||
|
||||
/** |
||||
* Registers the beans held within this RuntimeSpringConfiguration instance with the given ApplicationContext |
||||
* |
||||
* @param applicationContext The ApplicationContext instance |
||||
*/ |
||||
void registerBeansWithContext(GenericApplicationContext applicationContext); |
||||
|
||||
|
||||
/** |
||||
* Registers the beans held within this RuntimeSpringConfiguration instance with the given BeanDefinitionRegistry |
||||
* |
||||
* @param registry The BeanDefinitionRegistry instance |
||||
*/ |
||||
void registerBeansWithRegistry(BeanDefinitionRegistry registry); |
||||
|
||||
/** |
||||
* Registers the beans held within this RuntimeSpringConfiguration instance with the given RuntimeSpringConfiguration |
||||
* |
||||
* @param targetSpringConfig The RuntimeSpringConfiguration instance |
||||
*/ |
||||
void registerBeansWithConfig(RuntimeSpringConfiguration targetSpringConfig); |
||||
|
||||
/** |
||||
* Adds an abstract bean definition to the bean factory and returns the BeanConfiguration object |
||||
* |
||||
* @param name The name of the bean |
||||
* @return The BeanConfiguration object |
||||
*/ |
||||
BeanConfiguration addAbstractBean(String name); |
||||
|
||||
/** |
||||
* Adds an alias to a given bean name |
||||
* |
||||
* @param alias The alias |
||||
* @param beanName The bean |
||||
*/ |
||||
void addAlias(String alias, String beanName); |
||||
|
||||
/** |
||||
* Obtains a BeanDefinition instance for the given beanName |
||||
* |
||||
* @param beanName The beanName |
||||
* @return The BeanDefinition or null if it doesn't exit |
||||
*/ |
||||
BeanDefinition getBeanDefinition(String beanName); |
||||
|
||||
/** |
||||
* Sets the BeanFactory implementation to use |
||||
* @param beanFactory The BeanFactory implementation |
||||
*/ |
||||
void setBeanFactory(ListableBeanFactory beanFactory); |
||||
} |
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy |
||||
|
||||
import org.springframework.context.groovy.DynamicElementReader; |
||||
import org.w3c.dom.Element |
||||
|
||||
public class DynamicElementReaderTests extends GroovyTestCase{ |
||||
|
||||
void testReadMethodToElement() { |
||||
|
||||
def elementReader = new DynamicElementReader("jee", [jee:"http://www.springframework.org/schema/jee"]) |
||||
|
||||
try { |
||||
elementReader.'jndi-lookup'(id:"dataSource", 'jndi-name':"jdbc/petstore") |
||||
} |
||||
catch (e) { |
||||
assertEquals """Configuration problem: No namespace handler found for element <jee:jndi-lookup id='dataSource' jndi-name='jdbc/petstore' xmlns:jee='http://www.springframework.org/schema/jee'/> |
||||
Offending resource: resource loaded from byte array""", e.message |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy |
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException |
||||
|
||||
public class GroovyBeanDefinitionApplicationContextDynamicBeanPropertyTests extends GroovyTestCase { |
||||
|
||||
void testAccessDynamicBeanProperties() { |
||||
def ctx = new GroovyBeanDefinitionApplicationContext( |
||||
"org/springframework/context/groovy/applicationContext.groovy"); |
||||
|
||||
def framework = ctx.framework |
||||
assertNotNull 'could not find framework bean', framework |
||||
assertEquals 'Grails', framework |
||||
} |
||||
|
||||
void testAccessingNonExistentBeanViaDynamicProperty() { |
||||
def ctx = new GroovyBeanDefinitionApplicationContext( |
||||
"org/springframework/context/groovy/applicationContext.groovy"); |
||||
|
||||
def err = shouldFail(NoSuchBeanDefinitionException) { |
||||
ctx.someNonExistentBean |
||||
} |
||||
|
||||
assertEquals "No bean named 'someNonExistentBean' is defined", err |
||||
} |
||||
} |
@ -0,0 +1,968 @@
@@ -0,0 +1,968 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy |
||||
|
||||
import org.springframework.aop.SpringProxy |
||||
import org.springframework.beans.factory.ObjectFactory |
||||
import org.springframework.beans.factory.config.Scope |
||||
import org.springframework.context.ApplicationContext |
||||
import org.springframework.context.support.GenericApplicationContext |
||||
import org.springframework.mock.jndi.SimpleNamingContextBuilder |
||||
import org.springframework.stereotype.Component |
||||
|
||||
class GroovyBeanDefinitionReaderTests extends GroovyTestCase { |
||||
|
||||
void testImportSpringXml() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
beanReader.beans { |
||||
importBeans "classpath:org/springframework/context/groovy/test.xml" |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def foo = ctx.getBean("foo") |
||||
assertEquals "hello", foo |
||||
} |
||||
|
||||
void testImportBeansFromGroovy() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
beanReader.beans { |
||||
importBeans "file:src/test/resources/org/springframework/context/groovy/applicationContext.groovy" |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def foo = ctx.getBean("foo") |
||||
assertEquals "hello", foo |
||||
} |
||||
|
||||
void testInheritPropertiesFromAbstractBean() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
beanReader.beans { |
||||
myB(Bean1){ |
||||
person = "wombat" |
||||
} |
||||
|
||||
myAbstractA(Bean2){ bean -> |
||||
bean.'abstract' = true |
||||
age = 10 |
||||
bean1 = myB |
||||
} |
||||
myConcreteB { |
||||
it.parent = myAbstractA |
||||
} |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
def bean = ctx.getBean("myConcreteB") |
||||
|
||||
assertEquals 10, bean.age |
||||
assertNotNull bean.bean1 |
||||
} |
||||
|
||||
void testContextComponentScanSpringTag() { |
||||
if(notYetImplemented()) return |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
beanReader.beans { |
||||
xmlns grailsContext:"http://grails.org/schema/context" |
||||
|
||||
grailsContext.'component-scan'( 'base-package' :"**" ) |
||||
} |
||||
|
||||
def appCtx = beanReader.createApplicationContext() |
||||
|
||||
def p = appCtx.getBean("person") |
||||
|
||||
assertTrue( p instanceof AdvisedPerson ) |
||||
assertNotNull p |
||||
} |
||||
|
||||
void testUseSpringNamespaceAsMethod() { |
||||
if(notYetImplemented()) return |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
beanReader.beans { |
||||
xmlns aop:"http://www.springframework.org/schema/aop" |
||||
|
||||
fred(AdvisedPerson) { |
||||
name = "Fred" |
||||
age = 45 |
||||
} |
||||
birthdayCardSenderAspect(BirthdayCardSender) |
||||
|
||||
aop { |
||||
config("proxy-target-class":true) { |
||||
aspect( id:"sendBirthdayCard",ref:"birthdayCardSenderAspect" ) { |
||||
after method:"onBirthday", pointcut: "execution(void grails.spring.AdvisedPerson.birthday()) and this(person)" |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
def appCtx = beanReader.createApplicationContext() |
||||
def fred = appCtx.getBean("fred") |
||||
assertTrue (fred instanceof SpringProxy ) |
||||
|
||||
|
||||
fred.birthday() |
||||
|
||||
BirthdayCardSender birthDaySender = appCtx.getBean("birthdayCardSenderAspect") |
||||
|
||||
assertEquals 1, birthDaySender.peopleSentCards.size() |
||||
assertEquals "Fred", birthDaySender.peopleSentCards[0].name |
||||
} |
||||
|
||||
void testUseTwoSpringNamespaces() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder() |
||||
try { |
||||
|
||||
builder.bind("bar", "success") |
||||
builder.activate() |
||||
TestScope scope = new TestScope() |
||||
|
||||
GenericApplicationContext appCtx = beanReader.getSpringConfig().getUnrefreshedApplicationContext() |
||||
appCtx.getBeanFactory().registerScope("test", scope) |
||||
beanReader.beans { |
||||
xmlns aop:"http://www.springframework.org/schema/aop" |
||||
xmlns jee:"http://www.springframework.org/schema/jee" |
||||
scopedList(ArrayList) { bean -> |
||||
bean.scope = "test" |
||||
aop.'scoped-proxy'() |
||||
} |
||||
|
||||
jee.'jndi-lookup'(id:"foo", 'jndi-name':"bar") |
||||
|
||||
} |
||||
|
||||
appCtx = beanReader.createApplicationContext() |
||||
|
||||
assertEquals "success", appCtx.getBean("foo") |
||||
|
||||
assertNotNull appCtx.getBean("scopedList") |
||||
assertNotNull appCtx.getBean("scopedList").size() |
||||
assertNotNull appCtx.getBean("scopedList").size() |
||||
|
||||
// should only be true because bean not initialized until proxy called |
||||
assertEquals 2, scope.instanceCount |
||||
|
||||
beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
appCtx = beanReader.getSpringConfig().getUnrefreshedApplicationContext() |
||||
appCtx.getBeanFactory().registerScope("test", scope) |
||||
beanReader.beans { |
||||
xmlns aop:"http://www.springframework.org/schema/aop", |
||||
jee:"http://www.springframework.org/schema/jee" |
||||
scopedList(ArrayList) { bean -> |
||||
bean.scope = "test" |
||||
aop.'scoped-proxy'() |
||||
} |
||||
|
||||
jee.'jndi-lookup'(id:"foo", 'jndi-name':"bar") |
||||
|
||||
} |
||||
appCtx = beanReader.createApplicationContext() |
||||
|
||||
assertEquals "success", appCtx.getBean("foo") |
||||
|
||||
assertNotNull appCtx.getBean("scopedList") |
||||
assertNotNull appCtx.getBean("scopedList").size() |
||||
assertNotNull appCtx.getBean("scopedList").size() |
||||
|
||||
// should only be true because bean not initialized until proxy called |
||||
assertEquals 4, scope.instanceCount |
||||
|
||||
|
||||
} |
||||
finally { |
||||
builder.deactivate() |
||||
} |
||||
} |
||||
|
||||
void testSpringAOPSupport() { |
||||
if(notYetImplemented()) return |
||||
|
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
beanReader.beans { |
||||
xmlns aop:"http://www.springframework.org/schema/aop" |
||||
|
||||
fred(AdvisedPerson) { |
||||
name = "Fred" |
||||
age = 45 |
||||
} |
||||
birthdayCardSenderAspect(BirthdayCardSender) |
||||
|
||||
aop.config("proxy-target-class":true) { |
||||
aspect( id:"sendBirthdayCard",ref:"birthdayCardSenderAspect" ) { |
||||
after method:"onBirthday", pointcut: "execution(void grails.spring.AdvisedPerson.birthday()) and this(person)" |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
def appCtx = beanReader.createApplicationContext() |
||||
def fred = appCtx.getBean("fred") |
||||
assertTrue (fred instanceof SpringProxy ) |
||||
|
||||
|
||||
fred.birthday() |
||||
|
||||
BirthdayCardSender birthDaySender = appCtx.getBean("birthdayCardSenderAspect") |
||||
|
||||
assertEquals 1, birthDaySender.peopleSentCards.size() |
||||
assertEquals "Fred", birthDaySender.peopleSentCards[0].name |
||||
|
||||
} |
||||
|
||||
void testSpringScopedProxyBean() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
GenericApplicationContext appCtx = beanReader.getSpringConfig().getUnrefreshedApplicationContext() |
||||
TestScope scope = new TestScope() |
||||
appCtx.getBeanFactory().registerScope("test", scope) |
||||
beanReader.beans { |
||||
xmlns aop:"http://www.springframework.org/schema/aop" |
||||
scopedList(ArrayList) { bean -> |
||||
bean.scope = "test" |
||||
aop.'scoped-proxy'() |
||||
} |
||||
} |
||||
|
||||
appCtx = beanReader.createApplicationContext() |
||||
|
||||
|
||||
assertNotNull appCtx.getBean("scopedList") |
||||
assertNotNull appCtx.getBean("scopedList").size() |
||||
assertNotNull appCtx.getBean("scopedList").size() |
||||
|
||||
// should only be true because bean not initialized until proxy called |
||||
assertEquals 2, scope.instanceCount |
||||
} |
||||
|
||||
void testSpringNamespaceBean() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder() |
||||
try { |
||||
|
||||
builder.bind("bar", "success") |
||||
builder.activate() |
||||
|
||||
beanReader.beans { |
||||
xmlns jee:"http://www.springframework.org/schema/jee" |
||||
jee.'jndi-lookup'(id:"foo", 'jndi-name':"bar") |
||||
} |
||||
|
||||
ApplicationContext appCtx = beanReader.createApplicationContext() |
||||
|
||||
assertEquals "success", appCtx.getBean("foo") |
||||
} |
||||
finally { |
||||
builder.deactivate() |
||||
} |
||||
} |
||||
|
||||
void testNamedArgumentConstructor() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
holyGrail(HolyGrailQuest) |
||||
knights(KnightOfTheRoundTable, "Camelot", leader:"lancelot", quest: holyGrail) |
||||
} |
||||
|
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
KnightOfTheRoundTable knights = ctx.getBean("knights") |
||||
HolyGrailQuest quest = ctx.getBean("holyGrail") |
||||
|
||||
assertEquals "Camelot", knights.name |
||||
assertEquals "lancelot", knights.leader |
||||
assertEquals quest, knights.quest |
||||
} |
||||
|
||||
void testAbstractBeanDefinition() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
abstractBean { |
||||
leader = "Lancelot" |
||||
} |
||||
quest(HolyGrailQuest) |
||||
knights(KnightOfTheRoundTable, "Camelot") { bean -> |
||||
bean.parent = abstractBean |
||||
quest = quest |
||||
} |
||||
} |
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def knights = ctx.knights |
||||
assert knights |
||||
shouldFail(org.springframework.beans.factory.BeanIsAbstractException) { |
||||
ctx.abstractBean |
||||
} |
||||
assertEquals "Lancelot", knights.leader |
||||
} |
||||
|
||||
void testAbstractBeanDefinitionWithClass() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
abstractBean(KnightOfTheRoundTable) { bean -> |
||||
bean.'abstract' = true |
||||
leader = "Lancelot" |
||||
} |
||||
quest(HolyGrailQuest) |
||||
knights("Camelot") { bean -> |
||||
bean.parent = abstractBean |
||||
quest = quest |
||||
} |
||||
} |
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
shouldFail(org.springframework.beans.factory.BeanIsAbstractException) { |
||||
ctx.abstractBean |
||||
} |
||||
def knights = ctx.knights |
||||
assert knights |
||||
assertEquals "Lancelot", knights.leader |
||||
} |
||||
|
||||
|
||||
void testScopes() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
myBean(ScopeTest) { bean -> |
||||
bean.scope = "prototype" |
||||
} |
||||
myBean2(ScopeTest) |
||||
} |
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def b1 = ctx.myBean |
||||
def b2 = ctx.myBean |
||||
|
||||
assert b1 != b2 |
||||
|
||||
b1 = ctx.myBean2 |
||||
b2 = ctx.myBean2 |
||||
|
||||
assertEquals b1, b2 |
||||
} |
||||
|
||||
void testSimpleBean() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
bean1(Bean1) { |
||||
person = "homer" |
||||
age = 45 |
||||
props = [overweight:true, height:"1.8m"] |
||||
children = ["bart", "lisa"] |
||||
} |
||||
} |
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
assert ctx.containsBean("bean1") |
||||
def bean1 = ctx.getBean("bean1") |
||||
|
||||
assertEquals "homer", bean1.person |
||||
assertEquals 45, bean1.age |
||||
assertEquals true, bean1.props?.overweight |
||||
assertEquals "1.8m", bean1.props?.height |
||||
assertEquals(["bart", "lisa"], bean1.children) |
||||
|
||||
} |
||||
|
||||
void testBeanWithParentRef() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
homer(Bean1) { |
||||
person = "homer" |
||||
age = 45 |
||||
props = [overweight:true, height:"1.8m"] |
||||
children = ["bart", "lisa"] |
||||
} |
||||
} |
||||
beanReader = new GroovyBeanDefinitionReader(beanReader.createApplicationContext()) |
||||
beanReader.beans { |
||||
bart(Bean2) { |
||||
person = "bart" |
||||
parent = ref("homer", true) |
||||
} |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
assert ctx != null |
||||
assert ctx.containsBean("bart") |
||||
def bart = ctx.getBean("bart") |
||||
assertEquals "homer",bart.parent?.person |
||||
} |
||||
|
||||
void testWithAnonymousInnerBean() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
bart(Bean1) { |
||||
person = "bart" |
||||
age = 11 |
||||
} |
||||
lisa(Bean1) { |
||||
person = "lisa" |
||||
age = 9 |
||||
} |
||||
marge(Bean2) { |
||||
person = "marge" |
||||
bean1 = { Bean1 b -> |
||||
person = "homer" |
||||
age = 45 |
||||
props = [overweight:true, height:"1.8m"] |
||||
children = ["bart", "lisa"] } |
||||
children = [bart, lisa] |
||||
} |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def marge = ctx.getBean("marge") |
||||
|
||||
assertEquals "homer", marge.bean1.person |
||||
} |
||||
|
||||
void testWithUntypedAnonymousInnerBean() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
homer(Bean1Factory) |
||||
bart(Bean1) { |
||||
person = "bart" |
||||
age = 11 |
||||
} |
||||
lisa(Bean1) { |
||||
person = "lisa" |
||||
age = 9 |
||||
} |
||||
marge(Bean2) { |
||||
person = "marge" |
||||
bean1 = { bean -> |
||||
bean.factoryBean = "homer" |
||||
bean.factoryMethod = "newInstance" |
||||
person = "homer" } |
||||
children = [bart, lisa] |
||||
} |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def marge = ctx.getBean("marge") |
||||
|
||||
assertEquals "homer", marge.bean1.person |
||||
} |
||||
|
||||
void testBeanReferences() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
homer(Bean1) { |
||||
person = "homer" |
||||
age = 45 |
||||
props = [overweight:true, height:"1.8m"] |
||||
children = ["bart", "lisa"] |
||||
} |
||||
bart(Bean1) { |
||||
person = "bart" |
||||
age = 11 |
||||
} |
||||
lisa(Bean1) { |
||||
person = "lisa" |
||||
age = 9 |
||||
} |
||||
marge(Bean2) { |
||||
person = "marge" |
||||
bean1 = homer |
||||
children = [bart, lisa] |
||||
} |
||||
} |
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def homer = ctx.getBean("homer") |
||||
def marge = ctx.getBean("marge") |
||||
def bart = ctx.getBean("bart") |
||||
def lisa = ctx.getBean("lisa") |
||||
|
||||
assertEquals homer, marge.bean1 |
||||
assertEquals 2, marge.children.size() |
||||
|
||||
assertTrue marge.children.contains(bart) |
||||
assertTrue marge.children.contains(lisa) |
||||
} |
||||
|
||||
void testBeanWithConstructor() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
homer(Bean1) { |
||||
person = "homer" |
||||
age = 45 |
||||
} |
||||
marge(Bean3, "marge", homer) { |
||||
age = 40 |
||||
} |
||||
} |
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def marge = ctx.getBean("marge") |
||||
|
||||
assertEquals "marge", marge.person |
||||
assertEquals "homer", marge.bean1.person |
||||
assertEquals 40, marge.age |
||||
} |
||||
|
||||
void testBeanWithFactoryMethod() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
homer(Bean1) { |
||||
person = "homer" |
||||
age = 45 |
||||
} |
||||
def marge = marge(Bean4) { |
||||
person = "marge" |
||||
} |
||||
marge.factoryMethod = "getInstance" |
||||
} |
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def marge = ctx.getBean("marge") |
||||
|
||||
assert "marge", marge.person |
||||
|
||||
} |
||||
|
||||
void testBeanWithFactoryMethodUsingClosureArgs() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
homer(Bean1) { |
||||
person = "homer" |
||||
age = 45 |
||||
} |
||||
marge(Bean4) { bean -> |
||||
bean.factoryMethod = "getInstance" |
||||
person = "marge" |
||||
} |
||||
} |
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def marge = ctx.getBean("marge") |
||||
|
||||
assert "marge", marge.person |
||||
} |
||||
|
||||
void testBeanWithFactoryMethodWithConstructorArgs() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
beanFactory(Bean1FactoryWithArgs){} |
||||
|
||||
homer(beanFactory:"newInstance", "homer") { |
||||
age = 45 |
||||
} |
||||
//Test with no closure body |
||||
marge(beanFactory:"newInstance", "marge") |
||||
|
||||
//Test more verbose method |
||||
mcBain("mcBain"){ |
||||
bean -> |
||||
bean.factoryBean="beanFactory" |
||||
bean.factoryMethod="newInstance" |
||||
|
||||
} |
||||
} |
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def homer = ctx.getBean("homer") |
||||
|
||||
assert "homer", homer.person |
||||
assert 45, homer.age |
||||
|
||||
assert "marge", ctx.getBean("marge").person |
||||
|
||||
assert "mcBain", ctx.getBean("mcBain").person |
||||
} |
||||
|
||||
void testGetBeanDefinitions() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
jeff(Bean1) { |
||||
person = 'jeff' |
||||
} |
||||
graeme(Bean1) { |
||||
person = 'graeme' |
||||
} |
||||
guillaume(Bean1) { |
||||
person = 'guillaume' |
||||
} |
||||
} |
||||
|
||||
def beanDefinitions = beanReader.beanDefinitions |
||||
assertNotNull 'beanDefinitions was null', beanDefinitions |
||||
assertEquals 'beanDefinitions was the wrong size', 3, beanDefinitions.size() |
||||
assertNotNull 'beanDefinitions did not contain jeff', beanDefinitions['jeff'] |
||||
assertNotNull 'beanDefinitions did not contain guillaume', beanDefinitions['guillaume'] |
||||
assertNotNull 'beanDefinitions did not contain graeme', beanDefinitions['graeme'] |
||||
} |
||||
|
||||
void testBeanWithFactoryBean() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
myFactory(Bean1Factory) |
||||
|
||||
homer(myFactory) { bean -> |
||||
bean.factoryMethod = "newInstance" |
||||
person = "homer" |
||||
age = 45 |
||||
} |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def homer = ctx.getBean("homer") |
||||
|
||||
assertEquals "homer", homer.person |
||||
} |
||||
|
||||
void testBeanWithFactoryBeanAndMethod() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
myFactory(Bean1Factory) |
||||
|
||||
homer(myFactory:"newInstance") { bean -> |
||||
person = "homer" |
||||
age = 45 |
||||
} |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def homer = ctx.getBean("homer") |
||||
|
||||
assertEquals "homer", homer.person |
||||
} |
||||
|
||||
void testLoadExternalBeans() { |
||||
def pr = new org.springframework.core.io.support.PathMatchingResourcePatternResolver() |
||||
def r = pr.getResource("file:src/test/resources/org/springframework/context/groovy/applicationContext.groovy") |
||||
|
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.loadBeans(r) |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
assert ctx.containsBean("foo") |
||||
|
||||
def foo = ctx.getBean("foo") |
||||
|
||||
} |
||||
|
||||
void testHolyGrailWiring() { |
||||
|
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
beanReader.beans { |
||||
quest(HolyGrailQuest) |
||||
|
||||
knight(KnightOfTheRoundTable, "Bedivere") { |
||||
quest = ref("quest") |
||||
} |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def knight = ctx.getBean("knight") |
||||
|
||||
knight.embarkOnQuest() |
||||
|
||||
} |
||||
|
||||
void testAbstractBeanSpecifyingClass() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
beanReader.beans { |
||||
abstractKnight(KnightOfTheRoundTable) { bean -> |
||||
bean.'abstract' = true |
||||
leader = "King Arthur" |
||||
} |
||||
|
||||
lancelot("lancelot") { bean -> |
||||
bean.parent = ref("abstractKnight") |
||||
} |
||||
|
||||
abstractPerson(Bean1) { bean -> |
||||
bean.'abstract'=true |
||||
age = 45 |
||||
} |
||||
homerBean { bean -> |
||||
bean.parent = ref("abstractPerson") |
||||
person = "homer" |
||||
} |
||||
} |
||||
|
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def lancelot = ctx.getBean("lancelot") |
||||
assertEquals "King Arthur", lancelot.leader |
||||
assertEquals "lancelot", lancelot.name |
||||
|
||||
def homerBean = ctx.getBean("homerBean") |
||||
|
||||
assertEquals 45, homerBean.age |
||||
assertEquals "homer", homerBean.person |
||||
} |
||||
|
||||
void testGroovyBeanDefinitionReaderWithScript() { |
||||
def script = ''' |
||||
def beanReader = new org.springframework.context.groovy.GroovyBeanDefinitionReader() |
||||
|
||||
beanReader.beans { |
||||
quest(org.springframework.context.groovy.HolyGrailQuest) {} |
||||
|
||||
knight(org.springframework.context.groovy.KnightOfTheRoundTable, "Bedivere") { quest = quest } |
||||
} |
||||
beanReader.createApplicationContext() |
||||
''' |
||||
def ctx = new GroovyShell().evaluate(script) |
||||
|
||||
def knight = ctx.getBean('knight') |
||||
knight.embarkOnQuest() |
||||
} |
||||
|
||||
// test for GRAILS-5057 |
||||
void testRegisterBeans() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
beanReader.beans { |
||||
personA(AdvisedPerson) { |
||||
name = "Bob" |
||||
} |
||||
} |
||||
|
||||
def appCtx = beanReader.createApplicationContext() |
||||
|
||||
assertEquals "Bob", appCtx.getBean("personA").name |
||||
|
||||
beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
personA(AdvisedPerson) { |
||||
name = "Fred" |
||||
} |
||||
} |
||||
beanReader.registerBeans(appCtx) |
||||
|
||||
assertEquals "Fred", appCtx.getBean("personA").name |
||||
} |
||||
|
||||
// test for GRAILS-4995 |
||||
void testListOfBeansAsConstructorArg() { |
||||
if(notYetImplemented()) return |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
|
||||
beanReader.beans { |
||||
someotherbean(SomeOtherClass, new File('somefile.txt')) |
||||
someotherbean2(SomeOtherClass, new File('somefile.txt')) |
||||
|
||||
somebean(SomeClass, [someotherbean, someotherbean2]) |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
assert ctx.containsBean('someotherbean') |
||||
assert ctx.containsBean('someotherbean2') |
||||
assert ctx.containsBean('somebean') |
||||
} |
||||
|
||||
void testAnonymousInnerBeanViaBeanMethod() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
bart(Bean1) { |
||||
person = "bart" |
||||
age = 11 |
||||
} |
||||
lisa(Bean1) { |
||||
person = "lisa" |
||||
age = 9 |
||||
} |
||||
marge(Bean2) { |
||||
person = "marge" |
||||
bean1 = bean(Bean1) { |
||||
person = "homer" |
||||
age = 45 |
||||
props = [overweight:true, height:"1.8m"] |
||||
children = ["bart", "lisa"] |
||||
} |
||||
children = [bart, lisa] |
||||
} |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def marge = ctx.getBean("marge") |
||||
|
||||
assertEquals "homer", marge.bean1.person |
||||
} |
||||
|
||||
void testAnonymousInnerBeanViaBeanMethodWithConstructorArgs() { |
||||
def beanReader = new GroovyBeanDefinitionReader() |
||||
beanReader.beans { |
||||
bart(Bean1) { |
||||
person = "bart" |
||||
age = 11 |
||||
} |
||||
lisa(Bean1) { |
||||
person = "lisa" |
||||
age = 9 |
||||
} |
||||
marge(Bean2) { |
||||
person = "marge" |
||||
bean3 = bean(Bean3, "homer", lisa) { |
||||
person = "homer" |
||||
age = 45 |
||||
} |
||||
children = [bart, lisa] |
||||
} |
||||
} |
||||
|
||||
def ctx = beanReader.createApplicationContext() |
||||
|
||||
def marge = ctx.getBean("marge") |
||||
|
||||
assertEquals "homer", marge.bean3.person |
||||
assertEquals "lisa", marge.bean3.bean1.person |
||||
} |
||||
|
||||
} |
||||
|
||||
class HolyGrailQuest { |
||||
void start() { println "lets begin" } |
||||
} |
||||
class KnightOfTheRoundTable { |
||||
String name |
||||
String leader |
||||
KnightOfTheRoundTable(String n) { |
||||
this.name = n |
||||
} |
||||
HolyGrailQuest quest |
||||
|
||||
void embarkOnQuest() { |
||||
quest.start() |
||||
} |
||||
} |
||||
|
||||
// simple bean |
||||
class Bean1 { |
||||
String person |
||||
int age |
||||
Properties props |
||||
List children |
||||
} |
||||
// bean referencing other bean |
||||
class Bean2 { |
||||
int age |
||||
String person |
||||
Bean1 bean1 |
||||
Bean3 bean3 |
||||
Properties props |
||||
List children |
||||
Bean1 parent |
||||
} |
||||
// bean with constructor args |
||||
class Bean3 { |
||||
Bean3(String person, Bean1 bean1) { |
||||
this.person = person |
||||
this.bean1 = bean1 |
||||
} |
||||
String person |
||||
Bean1 bean1 |
||||
int age |
||||
} |
||||
// bean with factory method |
||||
class Bean4 { |
||||
private Bean4() {} |
||||
static Bean4 getInstance() { |
||||
return new Bean4() |
||||
} |
||||
String person |
||||
} |
||||
// a factory bean |
||||
class Bean1Factory { |
||||
Bean1 newInstance() { |
||||
return new Bean1() |
||||
} |
||||
} |
||||
class ScopeTest {} |
||||
class TestScope implements Scope { |
||||
|
||||
int instanceCount |
||||
|
||||
|
||||
public Object remove(String name) { |
||||
// do nothing |
||||
} |
||||
|
||||
public void registerDestructionCallback(String name, Runnable callback) { |
||||
} |
||||
|
||||
public String getConversationId() { |
||||
return "mock" |
||||
} |
||||
|
||||
public Object get(String name, ObjectFactory<?> objectFactory) { |
||||
instanceCount++ |
||||
objectFactory.getObject() |
||||
|
||||
} |
||||
|
||||
public Object resolveContextualObject(String s) { |
||||
return null; // noop |
||||
} |
||||
} |
||||
class BirthdayCardSender { |
||||
List peopleSentCards = [] |
||||
public void onBirthday(AdvisedPerson person) { |
||||
peopleSentCards << person |
||||
} |
||||
} |
||||
@Component(value = "person") |
||||
public class AdvisedPerson { |
||||
int age; |
||||
String name; |
||||
|
||||
public void birthday() { |
||||
++age; |
||||
} |
||||
} |
||||
|
||||
class SomeClass { |
||||
public SomeClass(List<SomeOtherClass> soc) {} |
||||
} |
||||
|
||||
class SomeOtherClass { |
||||
public SomeOtherClass(File f) {} |
||||
} |
||||
|
||||
// a factory bean that takes arguments |
||||
class Bean1FactoryWithArgs { |
||||
Bean1 newInstance(String name) { |
||||
new Bean1(person:name) |
||||
} |
||||
} |
@ -0,0 +1,125 @@
@@ -0,0 +1,125 @@
|
||||
/* |
||||
* Copyright 2010 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.context.groovy; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
import org.springframework.context.ApplicationContext; |
||||
|
||||
public class GroovyBeanDefinitionApplicationContextTests extends TestCase { |
||||
|
||||
/* |
||||
NOTE: The code in this test case includes casts that look a bit funky... |
||||
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(resources); |
||||
|
||||
Important to note is that the cast is only necessary because this test is being compiled along |
||||
with GroovyBeanDefinitionApplicationContext. This is related to a limitation in the compiler with respect |
||||
to AST transformations, in this case @Delegate. The problem will not show up when building via |
||||
gradle or other build tools. The problem may show up in an IDE where the IDE doesn't "think" |
||||
that GroovyBeanDefinitionApplicationContext is a ApplicationContext. |
||||
|
||||
Normal users of GroovyBeanDefinitionApplicationContext will not need to impose this cast |
||||
because the compiled GroovyBeanDefinitionApplicationContext class will in fact implement ApplicationContext. |
||||
*/ |
||||
|
||||
|
||||
public void testLoadingMultipleConfigFiles() { |
||||
String[] resources = new String[] { |
||||
"org/springframework/context/groovy/applicationContext2.groovy", |
||||
"org/springframework/context/groovy/applicationContext.groovy" }; |
||||
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(resources); |
||||
|
||||
Object framework = ctx.getBean("framework"); |
||||
assertNotNull("could not find framework bean", framework); |
||||
assertEquals("Grails", framework); |
||||
|
||||
Object company = ctx.getBean("company"); |
||||
assertNotNull("could not find company bean", company); |
||||
assertEquals("SpringSource", company); |
||||
} |
||||
|
||||
public void testLoadingConfigFile() { |
||||
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext( |
||||
"org/springframework/context/groovy/applicationContext.groovy"); |
||||
|
||||
Object framework = ctx.getBean("framework"); |
||||
assertNotNull("could not find framework bean", framework); |
||||
assertEquals("Grails", framework); |
||||
} |
||||
|
||||
public void testLoadingConfigFileRelativeToClass() { |
||||
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext( |
||||
"applicationContext.groovy", GroovyBeanDefinitionApplicationContextTests.class); |
||||
|
||||
Object framework = ctx.getBean("framework"); |
||||
assertNotNull("could not find framework bean", framework); |
||||
assertEquals("Grails", framework); |
||||
} |
||||
|
||||
public void testLoadingMultipleConfigFilesRelativeToClass() { |
||||
String[] resources = new String[] { |
||||
"applicationContext2.groovy", |
||||
"applicationContext.groovy" }; |
||||
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(resources, GroovyBeanDefinitionApplicationContextTests.class); |
||||
|
||||
Object framework = ctx.getBean("framework"); |
||||
assertNotNull("could not find framework bean", framework); |
||||
assertEquals("Grails", framework); |
||||
|
||||
Object company = ctx.getBean("company"); |
||||
assertNotNull("could not find company bean", company); |
||||
assertEquals("SpringSource", company); |
||||
} |
||||
|
||||
public void testLoadingConfigFileWithFileReference() { |
||||
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext( |
||||
"file:src/test/resources/org/springframework/context/groovy/applicationContext.groovy"); |
||||
|
||||
Object framework = ctx.getBean("framework"); |
||||
assertNotNull("could not find framework bean", framework); |
||||
assertEquals("Grails", framework); |
||||
} |
||||
|
||||
public void testLoadingMultipleConfigFilesWithFileReferences() { |
||||
String[] resources = new String[] { |
||||
"file:src/test/resources/org/springframework/context/groovy/applicationContext2.groovy", |
||||
"file:src/test/resources/org/springframework/context/groovy/applicationContext.groovy" }; |
||||
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(resources); |
||||
|
||||
Object framework = ctx.getBean("framework"); |
||||
assertNotNull("could not find framework bean", framework); |
||||
assertEquals("Grails", framework); |
||||
|
||||
Object company = ctx.getBean("company"); |
||||
assertNotNull("could not find company bean", company); |
||||
assertEquals("SpringSource", company); |
||||
} |
||||
|
||||
public void testLoadingMultipleConfigFilesWithFileAndClasspathReferences() { |
||||
String[] resources = new String[] { |
||||
"file:src/test/resources/org/springframework/context/groovy/applicationContext2.groovy", |
||||
"classpath:org/springframework/context/groovy/applicationContext.groovy" }; |
||||
ApplicationContext ctx = (ApplicationContext) new GroovyBeanDefinitionApplicationContext(resources); |
||||
|
||||
Object framework = ctx.getBean("framework"); |
||||
assertNotNull("could not find framework bean", framework); |
||||
assertEquals("Grails", framework); |
||||
|
||||
Object company = ctx.getBean("company"); |
||||
assertNotNull("could not find company bean", company); |
||||
assertEquals("SpringSource", company); |
||||
} |
||||
} |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
beans { |
||||
framework String, 'Grails' |
||||
foo String, 'hello' |
||||
} |
@ -0,0 +1,3 @@
@@ -0,0 +1,3 @@
|
||||
beans { |
||||
company String, 'SpringSource' |
||||
} |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<beans xmlns="http://www.springframework.org/schema/beans" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> |
||||
|
||||
<bean id="foo" class="java.lang.String"> |
||||
<constructor-arg value="hello" /> |
||||
</bean> |
||||
</beans> |
Loading…
Reference in new issue