From 2ad26cd7431d5d1d0b333ec18212eb5db29fd537 Mon Sep 17 00:00:00 2001 From: ramkumar Date: Fri, 31 Oct 2008 12:52:47 +0000 Subject: Checkin for TUSCANY-2654, TUSCANY-2655 and TUSCANY-2656 git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@709400 13f79535-47bb-0310-9956-ffa450edef68 --- .../spring/SpringImplementation.java | 37 +++- .../spring/SpringImplementationProvider.java | 25 ++- .../ComponentNameAnnotationProcessor.java | 151 ++++++++++++++ .../processor/ConstructorAnnotationProcessor.java | 119 +++++++++++ .../processor/InitDestroyAnnotationProcessor.java | 72 +++++++ .../processor/PropertyAnnotationProcessor.java | 220 +++++++++++++++++++++ .../processor/ReferenceAnnotationProcessor.java | 186 +++++++++++++++++ .../spring/xml/SpringBeanIntrospector.java | 12 +- .../spring/xml/SpringXMLComponentTypeLoader.java | 4 +- 9 files changed, 818 insertions(+), 8 deletions(-) create mode 100644 java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ComponentNameAnnotationProcessor.java create mode 100644 java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ConstructorAnnotationProcessor.java create mode 100644 java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/InitDestroyAnnotationProcessor.java create mode 100644 java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/PropertyAnnotationProcessor.java create mode 100644 java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ReferenceAnnotationProcessor.java (limited to 'java/sca/modules') diff --git a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java index ac3ab74f73..e4f62d3bb2 100644 --- a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java +++ b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java @@ -18,6 +18,7 @@ */ package org.apache.tuscany.sca.implementation.spring; +import java.lang.reflect.Method; import java.util.Hashtable; import java.util.List; @@ -28,6 +29,7 @@ import org.apache.tuscany.sca.assembly.Property; import org.apache.tuscany.sca.assembly.Reference; import org.apache.tuscany.sca.assembly.Service; import org.apache.tuscany.sca.assembly.impl.ImplementationImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaConstructorImpl; import org.apache.tuscany.sca.implementation.spring.xml.SpringBeanElement; import org.apache.tuscany.sca.policy.util.PolicyHandlerTuple; import org.springframework.core.io.Resource; @@ -47,8 +49,15 @@ public class SpringImplementation extends ImplementationImpl implements Implemen // Mapping of Services to Beans private Hashtable serviceMap; // Mapping of property names to Java class - private Hashtable propertyMap; + private Hashtable propertyMap; private List policyHandlerClassNames = null; + + // Method marked with @Init annotation + private Method initMethod = null; + // Method marked with @Destroy annotation + private Method destroyMethod = null; + // Method marked with @Constructor annotation + private JavaConstructorImpl constructorDefinition = null; protected SpringImplementation() { this.location = null; @@ -79,6 +88,30 @@ public class SpringImplementation extends ImplementationImpl implements Implemen public Resource getResource() { return resource; } + + public JavaConstructorImpl getConstructor() { + return constructorDefinition; + } + + public void setConstructor(JavaConstructorImpl definition) { + this.constructorDefinition = definition; + } + + public Method getInitMethod() { + return initMethod; + } + + public void setInitMethod(Method initMethod) { + this.initMethod = initMethod; + } + + public Method getDestroyMethod() { + return destroyMethod; + } + + public void setDestroyMethod(Method destroyMethod) { + this.destroyMethod = destroyMethod; + } /* * Returns the componentType for this Spring implementation @@ -155,5 +188,5 @@ public class SpringImplementation extends ImplementationImpl implements Implemen public void setPolicyHandlerClassNames(List policyHandlerClassNames) { this.policyHandlerClassNames = policyHandlerClassNames; - } + } // end method setPolicyHandlerClassNames } diff --git a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationProvider.java b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationProvider.java index 537a2c9a11..4717df2056 100644 --- a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationProvider.java +++ b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationProvider.java @@ -29,7 +29,15 @@ import org.apache.tuscany.sca.policy.util.PolicyHandlerTuple; import org.apache.tuscany.sca.provider.ImplementationProvider; import org.apache.tuscany.sca.runtime.RuntimeComponent; import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.GenericApplicationContext; +import org.apache.tuscany.sca.implementation.spring.processor.InitDestroyAnnotationProcessor; +import org.apache.tuscany.sca.implementation.spring.processor.ReferenceAnnotationProcessor; +import org.apache.tuscany.sca.implementation.spring.processor.PropertyAnnotationProcessor; +import org.apache.tuscany.sca.implementation.spring.processor.ConstructorAnnotationProcessor; +import org.apache.tuscany.sca.implementation.spring.processor.ComponentNameAnnotationProcessor; +import org.springframework.beans.factory.config.BeanPostProcessor; // TODO - create a working version of this class... /** @@ -62,7 +70,21 @@ public class SpringImplementationProvider implements ImplementationProvider { SCAParentApplicationContext scaParentContext = new SCAParentApplicationContext(component, implementation, proxyService, propertyValueObjectFactory); - springContext = new SCAApplicationContext(scaParentContext, implementation.getResource()); + //springContext = new SCAApplicationContext(scaParentContext, implementation.getResource()); + + XmlBeanFactory beanFactory = new XmlBeanFactory(implementation.getResource()); + BeanPostProcessor initDestroyProcessor = new InitDestroyAnnotationProcessor(); + beanFactory.addBeanPostProcessor(initDestroyProcessor); + BeanPostProcessor referenceProcessor = new ReferenceAnnotationProcessor(component); + beanFactory.addBeanPostProcessor(referenceProcessor); + BeanPostProcessor propertyProcessor = new PropertyAnnotationProcessor(propertyValueObjectFactory, component); + beanFactory.addBeanPostProcessor(propertyProcessor); + BeanPostProcessor componentNameProcessor = new ComponentNameAnnotationProcessor(component); + beanFactory.addBeanPostProcessor(componentNameProcessor); + BeanPostProcessor constructorProcessor = new ConstructorAnnotationProcessor(); + beanFactory.addBeanPostProcessor(constructorProcessor); + springContext = new GenericApplicationContext(beanFactory, scaParentContext); + } // end constructor public Invoker createInvoker(RuntimeComponentService service, Operation operation) { @@ -89,6 +111,7 @@ public class SpringImplementationProvider implements ImplementationProvider { */ public void stop() { // TODO - complete + springContext.close(); springContext.stop(); //System.out.println("SpringImplementationProvider: Spring context stopped"); } // end method stop diff --git a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ComponentNameAnnotationProcessor.java b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ComponentNameAnnotationProcessor.java new file mode 100644 index 0000000000..cd0567f461 --- /dev/null +++ b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ComponentNameAnnotationProcessor.java @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.spring.processor; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; + +import org.springframework.util.Assert; +import org.springframework.beans.BeanUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +import org.osoa.sca.annotations.ComponentName; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +public class ComponentNameAnnotationProcessor implements BeanPostProcessor { + + private Class componentNameAnnotationType = ComponentName.class; + + private RuntimeComponent component; + + public ComponentNameAnnotationProcessor (RuntimeComponent component) { + this.component = component; + } + + /** + * Gets componentName annotation type. + */ + protected Class getComponentNameAnnotationType() { + return this.componentNameAnnotationType; + } + + /** + * Sets componentName annotation type. + */ + public void setComponentNameAnnotationType(Class componentNameAnnotationType) { + Assert.notNull(componentNameAnnotationType, "'componentNameAnnotationType' type must not be null."); + this.componentNameAnnotationType = componentNameAnnotationType; + } + + /** + * This method is used to execute before a bean's initialization callback. + * + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String) + */ + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + processAnnotation(bean); + return bean; + } + + /** + * This method is used to execute after a bean's initialization callback. + * + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) + */ + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + /** + *

Processes a beans fields for injection if it has a {@link Reference} annotation.

+ */ + protected void processAnnotation(final Object bean) { + + final Class clazz = bean.getClass(); + + ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() { + public void doWith(Field field) { + Annotation annotation = field.getAnnotation(getComponentNameAnnotationType()); + + if (annotation != null) { + if (Modifier.isStatic(field.getModifiers())) { + throw new IllegalStateException("ComponentName annotation is not supported on static fields"); + } + + if (Modifier.isPrivate(field.getModifiers())) { + throw new IllegalStateException("ComponentName annotation is not supported on private fields"); + } + + ReflectionUtils.makeAccessible(field); + + if (field.getType().getName().equals("java.lang.String")) { + Object nameObj = component.getName(); + if (nameObj != null) + ReflectionUtils.setField(field, bean, nameObj); + } else { + throw new IllegalStateException("ComponentName annotation is supported only on java.lang.String field type."); + } + } + } + }); + + ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { + public void doWith(Method method) { + Annotation annotation = method.getAnnotation(getComponentNameAnnotationType()); + + if (annotation != null) { + if (Modifier.isStatic(method.getModifiers())) { + throw new IllegalStateException("ComponentName annotation is not supported on static methods"); + } + + if (Modifier.isPrivate(method.getModifiers())) { + throw new IllegalStateException("ComponentName annotation is not supported on private methods"); + } + + if (method.getParameterTypes().length == 0) { + throw new IllegalStateException("ComponentName annotation requires at least one argument: " + method); + } + + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); + + if (pd.getPropertyType().getName().equals("java.lang.String")) { + Object nameObj = component.getName(); + if (nameObj != null) { + try { + pd.getWriteMethod().invoke(bean, new Object[] { nameObj }); + } catch (Throwable e) { + throw new FatalBeanException("Problem injecting reference: " + e.getMessage(), e); + } + } + } else { + throw new IllegalStateException("ComponentName annotation is supported only on java.lang.String field type."); + } + } + } + }); + } +} diff --git a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ConstructorAnnotationProcessor.java b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ConstructorAnnotationProcessor.java new file mode 100644 index 0000000000..4dadf37189 --- /dev/null +++ b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ConstructorAnnotationProcessor.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.spring.processor; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Constructor; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.util.Assert; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; +import org.springframework.beans.factory.annotation.Autowired; + +public class ConstructorAnnotationProcessor extends InstantiationAwareBeanPostProcessorAdapter { + + private Class constructorAnnotationType + = org.osoa.sca.annotations.Constructor.class; + + private Class autowiredAnnotationType = Autowired.class; + + public ConstructorAnnotationProcessor () { + // Default constructor. + } + + /** + * Set the 'autowired' annotation type, to be used on constructors, fields, + * setter methods and arbitrary config methods. + */ + public void setAutowiredAnnotationType(Class autowiredAnnotationType) { + Assert.notNull(autowiredAnnotationType, "'autowiredAnnotationType' must not be null"); + this.autowiredAnnotationType = autowiredAnnotationType; + } + + /** + * Return the 'autowired' annotation type. + */ + protected Class getAutowiredAnnotationType() { + return this.autowiredAnnotationType; + } + + /** + * Return the 'constructor' annotation type. + */ + protected Class getConstructorAnnotationType() { + return this.constructorAnnotationType; + } + + /** + * Sets the 'constructor' annotation type. + */ + public void setConstructorAnnotationType(Class constructorAnnotationType) { + Assert.notNull(constructorAnnotationType, "'constructorAnnotationType' type must not be null."); + this.constructorAnnotationType = constructorAnnotationType; + } + + /** + * This method is used to execute before a bean's initialization callback. + * + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String) + */ + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + /** + * This method is used to execute after a bean's initialization callback. + * + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) + */ + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + public Constructor[] determineCandidateConstructors(Class beanClass, String beanName) throws BeansException { + /*Constructor[] declaredConstructors = beanClass.getDeclaredConstructors(); + Method[] declaredMethods = beanClass.getDeclaredMethods(); + List candidates = new ArrayList(declaredConstructors.length); + + for (int i = 0; i < declaredMethods.length; i++) { + Method method = declaredMethods[i]; + Annotation annotation = method.getAnnotation(getConstructorAnnotationType()); + if (annotation != null) { + if (Modifier.isStatic(method.getModifiers())) { + throw new IllegalStateException("Constructor annotation is not supported on static methods"); + } + + if (candidates.size() == 1) { + throw new IllegalStateException("Only one method is allowed to have constructor annotation in a bean: " + method); + } + + candidates.add(method); + } + } + + return (Constructor[]) candidates.toArray(new Constructor[candidates.size()]);*/ + return null; + } +} diff --git a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/InitDestroyAnnotationProcessor.java b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/InitDestroyAnnotationProcessor.java new file mode 100644 index 0000000000..44737bf9d1 --- /dev/null +++ b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/InitDestroyAnnotationProcessor.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.spring.processor; + +import java.lang.annotation.Annotation; +import org.osoa.sca.annotations.Init; +import org.osoa.sca.annotations.Destroy; +import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor; +import org.springframework.util.Assert; + +public class InitDestroyAnnotationProcessor extends InitDestroyAnnotationBeanPostProcessor { + + private static final long serialVersionUID = 0; + + private Class initAnnotationType = Init.class; + + private Class destroyAnnotationType = Destroy.class; + + /** + * Gets init annotation type. + */ + protected Class getInitAnnotationType() { + return this.initAnnotationType; + } + + /** + * Sets init annotation type. + */ + /*public void setInitAnnotationType(Class initAnnotationType) { + Assert.notNull(initAnnotationType, "Init annotation type must not be null."); + this.initAnnotationType = initAnnotationType; + }*/ + + /** + * Gets destroy annotation type. + */ + protected Class getDestroyAnnotationType() { + return this.destroyAnnotationType; + } + + /** + * Sets destroy annotation type. + */ + /*public void setDestroyAnnotationType(Class destroyAnnotationType) { + Assert.notNull(destroyAnnotationType, "Destroy annotation type must not be null."); + this.destroyAnnotationType = destroyAnnotationType; + }*/ + + public InitDestroyAnnotationProcessor () { + // Set the @Init annotation type + setInitAnnotationType(initAnnotationType); + + // Set the @Destroy annotation type + setDestroyAnnotationType(destroyAnnotationType); + } +} diff --git a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/PropertyAnnotationProcessor.java b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/PropertyAnnotationProcessor.java new file mode 100644 index 0000000000..d8755c58f4 --- /dev/null +++ b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/PropertyAnnotationProcessor.java @@ -0,0 +1,220 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.spring.processor; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.util.List; + +import org.springframework.util.Assert; +import org.springframework.beans.BeanUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +import org.osoa.sca.annotations.Property; +import org.apache.tuscany.sca.assembly.ComponentProperty; +import org.apache.tuscany.sca.core.factory.ObjectFactory; +import org.apache.tuscany.sca.implementation.java.injection.JavaPropertyValueObjectFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +public class PropertyAnnotationProcessor implements BeanPostProcessor { + + private Class propertyAnnotationType = Property.class; + + private RuntimeComponent component; + + private JavaPropertyValueObjectFactory propertyFactory; + + public PropertyAnnotationProcessor (JavaPropertyValueObjectFactory propertyFactory, + RuntimeComponent component) { + this.propertyFactory = propertyFactory; + this.component = component; + } + + /** + * Gets property annotation type. + */ + protected Class getPropertyAnnotationType() { + return this.propertyAnnotationType; + } + + /** + * Sets property annotation type. + */ + public void setPropertyAnnotationType(Class propertyAnnotationType) { + Assert.notNull(propertyAnnotationType, "'propertyAnnotationType' type must not be null."); + this.propertyAnnotationType = propertyAnnotationType; + } + + /** + * This method is used to execute before a bean's initialization callback. + * + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String) + */ + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + processAnnotation(bean); + return bean; + } + + /** + * This method is used to execute after a bean's initialization callback. + * + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) + */ + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + /** + *

Processes a beans fields for injection if it has a {@link Property} annotation.

+ */ + protected void processAnnotation(final Object bean) { + + final Class clazz = bean.getClass(); + + ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { + public void doWith(Method method) { + //Annotation annotation = method.getAnnotation(getPropertyAnnotationType()); + Property annotation = (Property) method.getAnnotation(getPropertyAnnotationType()); + + if (annotation != null) { + if (Modifier.isStatic(method.getModifiers())) { + throw new IllegalStateException("Property annotation is not supported on static methods"); + } + + if (Modifier.isPrivate(method.getModifiers())) { + throw new IllegalStateException("Property annotation is not supported on private methods"); + } + + if (method.getParameterTypes().length == 0) { + throw new IllegalStateException("Property annotation requires at least one argument: " + method); + } + + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); + if (pd != null) { + String propName = annotation.name(); + if ("".equals(propName)) { + injectProperty(bean, pd, getPropertyObj(pd.getPropertyType(), pd.getName())); + } else { + injectProperty(bean, pd, getPropertyObj(pd.getPropertyType(), propName)); + } + } + } + } + }); + + ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() { + public void doWith(Field field) { + //Annotation annotation = field.getAnnotation(getPropertyAnnotationType()); + Property annotation = (Property) field.getAnnotation(getPropertyAnnotationType()); + + if (annotation != null) { + if (Modifier.isStatic(field.getModifiers())) { + throw new IllegalStateException("Property annotation is not supported on static fields"); + } + + if (Modifier.isPrivate(field.getModifiers())) { + throw new IllegalStateException("Property annotation is not supported on private fields"); + } + + ReflectionUtils.makeAccessible(field); + + Object propertyObj = null; + String propName = annotation.name(); + if ("".equals(propName)) { + propertyObj = getPropertyObj(field.getType(), field.getName()); + } else { + propertyObj = getPropertyObj(field.getType(), propName); + } + + if (propertyObj != null) + ReflectionUtils.setField(field, bean, propertyObj); + } + } + }); + } + + /** + * Processes a property descriptor to inject a service. + */ + public Object getPropertyObj(Class requiredType, String name) { + + Object propertyObj = null; + + List props = component.getProperties(); + for (ComponentProperty prop : props) { + if (prop.getName().equals(name)) { + // On finding the property, create a factory for it and create a Bean using + // the factory + ObjectFactory factory = propertyFactory.createValueFactory(prop, prop.getValue(), requiredType); + propertyObj = factory.getInstance(); + } // end if + } // end for + + return propertyObj; + } + + + public void injectProperty(Object bean, PropertyDescriptor pd, Object propertyObj) { + + if (propertyObj != null) { + try { + pd.getWriteMethod().invoke(bean, new Object[] { propertyObj }); + } catch (Throwable e) { + throw new FatalBeanException("Problem injecting property: " + e.getMessage(), e); + } + } + } + + /** + * Processes a property descriptor to inject a service. + */ + /*public void injectMethod(Object bean, Method method) { + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); + + if (pd != null) { + Object propertyObj = null; + + List props = component.getProperties(); + for (ComponentProperty prop : props) { + if (prop.getName().equals(pd.getName())) { + // On finding the property, create a factory for it and create a Bean using + // the factory + ObjectFactory factory = propertyFactory.createValueFactory(prop, prop.getValue(), pd.getPropertyType()); + propertyObj = factory.getInstance(); + } // end if + } // end for + + if (propertyObj != null) { + try { + pd.getWriteMethod().invoke(bean, new Object[] { propertyObj }); + } catch (Throwable e) { + throw new FatalBeanException("Problem injecting property: " + e.getMessage(), e); + } + } + } + }*/ +} diff --git a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ReferenceAnnotationProcessor.java b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ReferenceAnnotationProcessor.java new file mode 100644 index 0000000000..52f8ac3684 --- /dev/null +++ b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ReferenceAnnotationProcessor.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.implementation.spring.processor; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; + +import org.springframework.util.Assert; +import org.springframework.beans.BeanUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +import org.osoa.sca.annotations.Reference; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +public class ReferenceAnnotationProcessor implements BeanPostProcessor { + + private Class referenceAnnotationType = Reference.class; + + private RuntimeComponent component; + + public ReferenceAnnotationProcessor (RuntimeComponent component) { + this.component = component; + } + + /** + * Gets referece annotation type. + */ + protected Class getReferenceAnnotationType() { + return this.referenceAnnotationType; + } + + /** + * Sets referece annotation type. + */ + public void setReferenceAnnotationType(Class referenceAnnotationType) { + Assert.notNull(referenceAnnotationType, "'referenceAnnotationType' type must not be null."); + this.referenceAnnotationType = referenceAnnotationType; + } + + /** + * This method is used to execute before a bean's initialization callback. + * + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String) + */ + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + processAnnotation(bean); + return bean; + } + + /** + * This method is used to execute after a bean's initialization callback. + * + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) + */ + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + /** + *

Processes a beans fields for injection if it has a {@link Reference} annotation.

+ */ + protected void processAnnotation(final Object bean) { + + final Class clazz = bean.getClass(); + + ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { + public void doWith(Method method) { + //Annotation annotation = method.getAnnotation(getReferenceAnnotationType()); + Reference annotation = (Reference) method.getAnnotation(getReferenceAnnotationType()); + + if (annotation != null) { + if (Modifier.isStatic(method.getModifiers())) { + throw new IllegalStateException("Reference annotation is not supported on static methods"); + } + + if (Modifier.isPrivate(method.getModifiers())) { + throw new IllegalStateException("Reference annotation is not supported on private methods"); + } + + if (method.getParameterTypes().length == 0) { + throw new IllegalStateException("Reference annotation requires at least one argument: " + method); + } + + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); + if (pd != null) { + String refName = annotation.name(); + if ("".equals(refName)) { + injectReference(bean, pd, pd.getName()); + } else { + injectReference(bean, pd, refName); + } + } + } + } + }); + + ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() { + public void doWith(Field field) { + //Annotation annotation = field.getAnnotation(getReferenceAnnotationType()); + Reference annotation = (Reference) field.getAnnotation(getReferenceAnnotationType()); + + if (annotation != null) { + if (Modifier.isStatic(field.getModifiers())) { + throw new IllegalStateException("Reference annotation is not supported on static fields"); + } + + if (Modifier.isPrivate(field.getModifiers())) { + throw new IllegalStateException("Reference annotation is not supported on private fields"); + } + + ReflectionUtils.makeAccessible(field); + + Object referenceObj = null; + String refName = annotation.name(); + if ("".equals(refName)) { + referenceObj = component.getComponentContext().getService(field.getType(), field.getName()); + } else { + referenceObj = component.getComponentContext().getService(field.getType(), refName); + } + + if (referenceObj != null) + ReflectionUtils.setField(field, bean, referenceObj); + } + } + }); + } + + /** + * Processes a property descriptor to inject a service. + */ + public void injectReference(Object bean, PropertyDescriptor pd, String name) { + + Object referenceObj = component.getComponentContext().getService(pd.getPropertyType(), name); + + if (referenceObj != null) { + try { + pd.getWriteMethod().invoke(bean, new Object[] { referenceObj }); + } catch (Throwable e) { + throw new FatalBeanException("Problem injecting reference: " + e.getMessage(), e); + } + } + } + + /** + * Processes a property descriptor to inject a service. + */ + /*public void injectMethod(Object bean, Method method) { + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); + + if (pd != null) { + Object referenceObj = component.getComponentContext().getService(pd.getPropertyType(), pd.getName()); + + if (referenceObj != null) { + try { + pd.getWriteMethod().invoke(bean, new Object[] { referenceObj }); + } catch (Throwable e) { + throw new FatalBeanException("Problem injecting reference: " + e.getMessage(), e); + } + } + } + }*/ +} diff --git a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanIntrospector.java b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanIntrospector.java index 625a46b12b..3e526cd20e 100644 --- a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanIntrospector.java +++ b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanIntrospector.java @@ -47,6 +47,7 @@ import org.apache.tuscany.sca.implementation.java.introspect.impl.ScopeProcessor import org.apache.tuscany.sca.implementation.java.introspect.impl.ServiceProcessor; import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; import org.apache.tuscany.sca.policy.PolicyFactory; +import org.apache.tuscany.sca.implementation.spring.SpringImplementation; /** * Provides introspection functions for Spring beans @@ -106,9 +107,9 @@ public class SpringBeanIntrospector { * Spring Bean or its componentType * */ - public Map introspectBean(Class beanClass, ComponentType componentType) - throws ContributionResolveException { - + public Map introspectBean(Class beanClass, ComponentType componentType, + SpringImplementation springImplementation) throws ContributionResolveException + { if (componentType == null) throw new ContributionResolveException("Introspect Spring bean: supplied componentType is null"); @@ -124,6 +125,11 @@ public class SpringBeanIntrospector { componentType.getServices().addAll(javaImplementation.getServices()); componentType.getReferences().addAll(javaImplementation.getReferences()); componentType.getProperties().addAll(javaImplementation.getProperties()); + + springImplementation.setInitMethod(javaImplementation.getInitMethod()); + springImplementation.setDestroyMethod(javaImplementation.getDestroyMethod()); + springImplementation.setConstructor(javaImplementation.getConstructor()); + } catch (IntrospectionException e) { throw new ContributionResolveException(e); } // end try diff --git a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLComponentTypeLoader.java b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLComponentTypeLoader.java index 9f41fd306f..34f46dacb9 100644 --- a/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLComponentTypeLoader.java +++ b/java/sca/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLComponentTypeLoader.java @@ -336,7 +336,7 @@ public class SpringXMLComponentTypeLoader { Class beanClass = cl.loadClass(beanElement.getClassName()); // Introspect the bean ComponentType beanComponentType = assemblyFactory.createComponentType(); - beanIntrospector.introspectBean(beanClass, beanComponentType); + beanIntrospector.introspectBean(beanClass, beanComponentType, implementation); // Get the service interface defined by this Spring Bean and add to // the component type of the Spring Assembly List beanServices = beanComponentType.getServices(); @@ -368,7 +368,7 @@ public class SpringXMLComponentTypeLoader { // Introspect the bean ComponentType beanComponentType = assemblyFactory.createComponentType(); Map propertyMap = - beanIntrospector.introspectBean(beanClass, beanComponentType); + beanIntrospector.introspectBean(beanClass, beanComponentType, implementation); // Get the references by this Spring Bean and add the unresolved ones to // the component type of the Spring Assembly List beanReferences = beanComponentType.getReferences(); -- cgit v1.2.3