From ff6d646fcbd9f06f013cf934fcdde66c213c7db2 Mon Sep 17 00:00:00 2001 From: ramkumar Date: Mon, 9 Mar 2009 10:00:30 +0000 Subject: Fixes for TUSCANY-2642, 2909, 2910 git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@751642 13f79535-47bb-0310-9956-ffa450edef68 --- .../spring/SpringImplementation.java | 62 +- .../spring/SpringImplementationProvider.java | 118 +++- .../spring/xml/SpringBeanElement.java | 9 + .../spring/xml/SpringBeanIntrospector.java | 27 +- .../spring/xml/SpringBeanPojoProcessor.java | 648 +++++++++++++++++++++ .../spring/xml/SpringConstructorArgElement.java | 9 + .../spring/xml/SpringXMLComponentTypeLoader.java | 205 +++++-- 7 files changed, 924 insertions(+), 154 deletions(-) create mode 100644 branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanPojoProcessor.java (limited to 'branches/sca-java-1.x/modules/implementation-spring/src/main/java') diff --git a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java index 165dfae8be..6f22567070 100644 --- a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java +++ b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementation.java @@ -18,9 +18,7 @@ */ package org.apache.tuscany.sca.implementation.spring; -import java.lang.reflect.Method; import java.util.Hashtable; -import java.util.Enumeration; import java.util.List; import org.apache.tuscany.sca.assembly.Component; @@ -33,7 +31,6 @@ import org.apache.tuscany.sca.assembly.Service; import org.apache.tuscany.sca.assembly.impl.ImplementationImpl; import org.apache.tuscany.sca.interfacedef.InterfaceContract; import org.apache.tuscany.sca.assembly.builder.ComponentPreProcessor; -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.apache.tuscany.sca.runtime.RuntimeComponent; @@ -58,13 +55,6 @@ public class SpringImplementation extends ImplementationImpl implements Implemen private List policyHandlerClassNames = null; // List of unresolved bean property references private Hashtable unresolvedBeanRef; - - // 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; @@ -96,30 +86,6 @@ 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 @@ -219,16 +185,6 @@ public class SpringImplementation extends ImplementationImpl implements Implemen RuntimeComponent rtc = (RuntimeComponent) component; - // Check if the SCDL is properly configured for all the services - // exposed by Spring application context, otherwise report a error - /*Enumeration itr = serviceMap.elements(); - while (itr.hasMoreElements()) { - SpringBeanElement beanElement = itr.nextElement(); - if (!rtc.getServices().contains(beanElement.getId())) { - throw new AssertionError("Configuration Error:"); - } - }*/ - for (Reference reference : rtc.getReferences()) { if (unresolvedBeanRef.containsKey(reference.getName())) { Reference ref = unresolvedBeanRef.get(reference.getName()); @@ -244,23 +200,7 @@ public class SpringImplementation extends ImplementationImpl implements Implemen this.setPropertyClass(property.getName(), property.getClass()); unresolvedBeanRef.remove(property.getName()); } - } - - // Check if the SCDL is properly configured for all the SCA references - // used in the Spring application context, otherwise report a error - /*for (Reference reference: componentType.getReferences()) { - if (!rtc.getReferences().contains(reference.getName())) { - throw new AssertionError("Configuration Error:"); - } - }*/ - - // Check if the SCDL is properly configured for all the SCA property - // used in the Spring application context, otherwise report a error - /*for (Property property: componentType.getProperties()) { - if (!rtc.getProperties().contains(property.getName())) { - throw new AssertionError("Configuration Error:"); - } - }*/ + } } protected Reference createReference(Reference reference, InterfaceContract interfaze) { diff --git a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationProvider.java b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationProvider.java index 4717df2056..88358732ed 100644 --- a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationProvider.java +++ b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/SpringImplementationProvider.java @@ -16,10 +16,10 @@ * specific language governing permissions and limitations * under the License. */ - package org.apache.tuscany.sca.implementation.spring; import java.util.List; +import java.util.Iterator; import org.apache.tuscany.sca.core.invocation.ProxyFactory; import org.apache.tuscany.sca.implementation.java.injection.JavaPropertyValueObjectFactory; @@ -30,16 +30,22 @@ 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.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.GenericApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; 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; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.config.TypedStringValue; +import org.springframework.beans.factory.support.ManagedList; -// TODO - create a working version of this class... /** * A provider class for runtime Spring implementation instances * @version $Rev: 511195 $ $Date: 2007-02-24 02:29:46 +0000 (Sat, 24 Feb 2007) $ @@ -51,6 +57,8 @@ public class SpringImplementationProvider implements ImplementationProvider { private AbstractApplicationContext springContext; private SpringImplementation implementation; + + private JavaPropertyValueObjectFactory propertyValueObjectFactory; /** * Constructor for the provider - takes a component definition and a Spring implementation @@ -66,24 +74,15 @@ public class SpringImplementationProvider implements ImplementationProvider { super(); this.implementation = implementation; this.component = component; + this.propertyValueObjectFactory = propertyValueObjectFactory; this.implementation.setPolicyHandlerClassNames(policyHandlerClassNames); 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); + springContext = createApplicationContext(beanFactory, scaParentContext); } // end constructor @@ -110,10 +109,93 @@ public class SpringImplementationProvider implements ImplementationProvider { * Stop this implementation instance */ public void stop() { - // TODO - complete - springContext.close(); - springContext.stop(); + // TODO - complete + springContext.close(); + if (springContext instanceof GenericApplicationContext) + springContext.stop(); //System.out.println("SpringImplementationProvider: Spring context stopped"); } // end method stop - + + + /** + * Include BeanPostProcessor to deal with SCA Annotations in Spring Bean + */ + private void includeAnnotationProcessors(ConfigurableListableBeanFactory beanFactory) { + + // Processor to deal with @Init and @Destroy SCA Annotations + BeanPostProcessor initDestroyProcessor = new InitDestroyAnnotationProcessor(); + beanFactory.addBeanPostProcessor(initDestroyProcessor); + + // Processor to deal with @Reference SCA Annotations + BeanPostProcessor referenceProcessor = new ReferenceAnnotationProcessor(component); + beanFactory.addBeanPostProcessor(referenceProcessor); + + // Processor to deal with @Property SCA Annotations + BeanPostProcessor propertyProcessor = new PropertyAnnotationProcessor(propertyValueObjectFactory, component); + beanFactory.addBeanPostProcessor(propertyProcessor); + + // Processor to deal with @ComponentName SCA Annotations + BeanPostProcessor componentNameProcessor = new ComponentNameAnnotationProcessor(component); + beanFactory.addBeanPostProcessor(componentNameProcessor); + + // Processor to deal with @Constructor SCA Annotations + BeanPostProcessor constructorProcessor = new ConstructorAnnotationProcessor(); + beanFactory.addBeanPostProcessor(constructorProcessor); + } + + + /** + * Include BeanPostProcessor to deal with SCA Annotations in Spring Bean + */ + private AbstractApplicationContext createApplicationContext(XmlBeanFactory beanFactory, + SCAParentApplicationContext scaParentContext) { + AbstractApplicationContext appContext = null; + + for (String bean : beanFactory.getBeanDefinitionNames()) { + String beanClassName = (beanFactory.getType(bean)).getName(); + if (beanClassName.indexOf(".ClassPathXmlApplicationContext") != -1 || + beanClassName.indexOf(".FileSystemXmlApplicationContext") != -1) + { + BeanDefinition beanDef = beanFactory.getBeanDefinition(bean); + String[] listValues = null; + List conArgs = + beanDef.getConstructorArgumentValues().getGenericArgumentValues(); + for (ConstructorArgumentValues.ValueHolder conArg : conArgs) { + if (conArg.getValue() instanceof TypedStringValue) { + TypedStringValue value = (TypedStringValue) conArg.getValue(); + if (value.getValue().indexOf(".xml") != -1) + listValues = new String[]{value.getValue()}; + } + if (conArg.getValue() instanceof ManagedList) { + Iterator itml = ((ManagedList)conArg.getValue()).iterator(); + StringBuffer values = new StringBuffer(); + while (itml.hasNext()) { + TypedStringValue next = (TypedStringValue)itml.next(); + if (next.getValue().indexOf(".xml") != -1) { + values.append(next.getValue()); + values.append("~"); + } + } + listValues = (values.toString()).split("~"); + } + } + + if (beanClassName.indexOf(".ClassPathXmlApplicationContext") != -1) { + appContext = new ClassPathXmlApplicationContext(listValues, false, scaParentContext); + //includeAnnotationProcessors(appContext.getBeanFactory()); + return appContext; + } else { + appContext = new FileSystemXmlApplicationContext(listValues, false, scaParentContext); + //includeAnnotationProcessors(appContext.getBeanFactory()); + return appContext; + } + } + } + + // use the generic application context as default + includeAnnotationProcessors(beanFactory); + appContext = new GenericApplicationContext(beanFactory, scaParentContext); + return appContext; + } + } // end class SpringImplementationProvider diff --git a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanElement.java b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanElement.java index f9a9fee58f..629a72e22d 100644 --- a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanElement.java +++ b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanElement.java @@ -32,6 +32,7 @@ public class SpringBeanElement { private String id; private String className; + private boolean innerBean = false; private List properties = new ArrayList(); private List constructorargs = new ArrayList(); @@ -63,5 +64,13 @@ public class SpringBeanElement { public void addCustructorArgs(SpringConstructorArgElement args) { constructorargs.add(args); } + + public boolean isInnerBean() { + return innerBean; + } + + public void setInnerBean(boolean innerBean) { + this.innerBean = innerBean; + } } // end class SpringBeanElement diff --git a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanIntrospector.java b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanIntrospector.java index 3e526cd20e..df85e4f302 100644 --- a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanIntrospector.java +++ b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanIntrospector.java @@ -18,8 +18,6 @@ */ package org.apache.tuscany.sca.implementation.spring.xml; -import java.util.Map; - import org.apache.tuscany.sca.assembly.AssemblyFactory; import org.apache.tuscany.sca.assembly.ComponentType; import org.apache.tuscany.sca.contribution.service.ContributionResolveException; @@ -27,7 +25,6 @@ import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFacto import org.apache.tuscany.sca.implementation.java.IntrospectionException; import org.apache.tuscany.sca.implementation.java.JavaImplementation; import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; -import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor; import org.apache.tuscany.sca.implementation.java.introspect.impl.AllowsPassByReferenceProcessor; import org.apache.tuscany.sca.implementation.java.introspect.impl.BaseJavaClassVisitor; @@ -47,7 +44,6 @@ 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 @@ -89,7 +85,7 @@ public class SpringBeanIntrospector { new ResourceProcessor(assemblyFactory), new ScopeProcessor(assemblyFactory), new ServiceProcessor(assemblyFactory, javaFactory), - new HeuristicPojoProcessor(assemblyFactory, javaFactory), + new SpringBeanPojoProcessor(assemblyFactory, javaFactory), new PolicyProcessor(assemblyFactory, policyFactory)}; for (JavaClassVisitor extension : extensions) { javaImplementationFactory.addClassVisitor(extension); @@ -107,8 +103,7 @@ public class SpringBeanIntrospector { * Spring Bean or its componentType * */ - public Map introspectBean(Class beanClass, ComponentType componentType, - SpringImplementation springImplementation) throws ContributionResolveException + public JavaImplementation introspectBean(Class beanClass, ComponentType componentType) throws ContributionResolveException { if (componentType == null) throw new ContributionResolveException("Introspect Spring bean: supplied componentType is null"); @@ -126,21 +121,17 @@ public class SpringBeanIntrospector { 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 - //List services = javaImplementation.getServices(); - //for (Service service : services) { - //String name = service.getName(); - //System.out.println("Spring Bean: found service with name: " + name); - //} // end for - - return javaImplementation.getPropertyMembers(); + /* List services = javaImplementation.getServices(); + for (Service service : services) { + String name = service.getName(); + System.out.println("Spring Bean: found service with name: " + name); + } // end for */ + + return javaImplementation; } // end method introspectBean diff --git a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanPojoProcessor.java b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanPojoProcessor.java new file mode 100644 index 0000000000..0510a6d338 --- /dev/null +++ b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringBeanPojoProcessor.java @@ -0,0 +1,648 @@ +/* + * 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.xml; + +import static org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper.getAllInterfaces; +import static org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper.getPrivateFields; +import static org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper.getAllPublicAndProtectedFields; +import static org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper.getAllUniquePublicProtectedMethods; +import static org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper.toPropertyName; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.jws.WebService; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.impl.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.util.JavaXMLMapper; +import org.osoa.sca.annotations.Callback; +import org.osoa.sca.annotations.Context; +import org.osoa.sca.annotations.Property; +import org.osoa.sca.annotations.Reference; +import org.osoa.sca.annotations.Remotable; + +import org.apache.tuscany.sca.implementation.java.introspect.impl.BaseJavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.impl.NoConstructorException; +import org.apache.tuscany.sca.implementation.java.introspect.impl.AmbiguousConstructorException; +import org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper; +import org.apache.tuscany.sca.implementation.java.introspect.impl.InvalidServiceType; +import org.apache.tuscany.sca.implementation.java.introspect.impl.Resource; + +/** + * Heuristically evaluates an un-annotated Java implementation type to determine + * services, references, and properties according to the algorithm described in + * the SCA Java Client and Implementation Model Specification

TODO + * Implement:

When no service interface is annotated, need to calculate a + * single service comprising all public methods that are not reference or + * property injection sites. If that service can be exactly mapped to an + * interface implemented by the class then the service interface will be defined + * in terms of that interface. + * + * @version $Rev: 689426 $ $Date: 2008-08-27 14:56:06 +0530 (Wed, 27 Aug 2008) $ + */ +public class SpringBeanPojoProcessor extends BaseJavaClassVisitor { + private JavaInterfaceFactory javaFactory; + + public SpringBeanPojoProcessor(AssemblyFactory assemblyFactory, JavaInterfaceFactory javaFactory) { + super(assemblyFactory); + this.javaFactory = javaFactory; + } + + @Override + public void visitEnd(Class clazz, JavaImplementation type) throws IntrospectionException { + List services = type.getServices(); + if (services.isEmpty()) { + // heuristically determine the service + /** + * The following is quoted from Java Specification 1.2.1.3. Introspecting services offered by a Java implementation + * In the cases described below, the services offered by a Java implementation class may be determined + * through introspection, eliding the need to specify them using @Service. The following algorithm is used + * to determine how services are introspected from an implementation class: + * + * If the interfaces of the SCA services are not specified with the @Service annotation on the + * implementation class, it is assumed that all implemented interfaces that have been annotated + * as @Remotable are the service interfaces provided by the component. If none of the implemented + * interfaces is remotable, then by default the implementation offers a single service whose type + * is the implementation class. + */ + Set interfaces = getAllInterfaces(clazz); + for (Class i : interfaces) { + if (i.isAnnotationPresent(Remotable.class) || i.isAnnotationPresent(WebService.class)) { + addService(type, i); + } + } + if (services.isEmpty()) { + // class is the interface + addService(type, clazz); + } + } + Set methods = getAllUniquePublicProtectedMethods(clazz, false); + if (!type.getReferenceMembers().isEmpty() || !type.getPropertyMembers().isEmpty()) { + // references and properties have been explicitly defined + // if (type.getServices().isEmpty()) { + // calculateServiceInterface(clazz, type, methods); + // if (type.getServices().isEmpty()) { + // throw new ServiceTypeNotFoundException(clazz.getName()); + // } + // } + evaluateConstructor(type, clazz); + return; + } + calcPropRefs(methods, services, type, clazz); + evaluateConstructor(type, clazz); + } + + private void addService(JavaImplementation type, Class clazz) throws IntrospectionException { + try { + org.apache.tuscany.sca.assembly.Service service = createService(clazz); + type.getServices().add(service); + } catch (InvalidInterfaceException e) { + throw new IntrospectionException(e); + } + } + + private boolean isPublicSetter(Method method) { + return method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers()) + && method.getName().startsWith("set") + && method.getReturnType() == void.class; + } + + private boolean isProtectedSetter(Method method) { + return method.getParameterTypes().length == 1 && Modifier.isProtected(method.getModifiers()) + && method.getName().startsWith("set") + && method.getReturnType() == void.class; + } + + private void calcPropRefs(Set methods, + List services, + JavaImplementation type, + Class clazz) throws IntrospectionException { + // heuristically determine the properties references + // make a first pass through all public methods with one param + Set setters = new HashSet(); + Set others = new HashSet(); + for (Method method : methods) { + if (!isPublicSetter(method)) { + continue; + } + if (method.isAnnotationPresent(Callback.class) || method.isAnnotationPresent(Context.class)) { + // Add the property name as others + others.add(toPropertyName(method.getName())); + continue; + } + if (!isInServiceInterface(method, services)) { + // Not part of the service interface + String name = toPropertyName(method.getName()); + setters.add(name); + // avoid duplicate property or ref names + if (!type.getPropertyMembers().containsKey(name) && !type.getReferenceMembers().containsKey(name)) { + Class param = method.getParameterTypes()[0]; + Type genericType = method.getGenericParameterTypes()[0]; + if (isReferenceType(param, genericType)) { + type.getReferences().add(createReference(name, param)); + type.getReferenceMembers().put(name, new JavaElementImpl(method, 0)); + } else { + type.getProperties().add(createProperty(name, param)); + type.getPropertyMembers().put(name, new JavaElementImpl(method, 0)); + } + } + } + } + // second pass for protected methods with one param + for (Method method : methods) { + if (!isProtectedSetter(method)) { + continue; + } + if (method.isAnnotationPresent(Callback.class) || method.isAnnotationPresent(Context.class)) { + // Add the property name as others + others.add(toPropertyName(method.getName())); + continue; + } + Class param = method.getParameterTypes()[0]; + String name = toPropertyName(method.getName()); + setters.add(name); + // avoid duplicate property or ref names + if (isReferenceType(param, method.getGenericParameterTypes()[0])) { + if (!type.getReferenceMembers().containsKey(name)) { + type.getReferences().add(createReference(name, param)); + type.getReferenceMembers().put(name, new JavaElementImpl(method, 0)); + } + } else { + if (!type.getPropertyMembers().containsKey(name)) { + type.getProperties().add(createProperty(name, param)); + type.getPropertyMembers().put(name, new JavaElementImpl(method, 0)); + } + } + } + + // Public or protected fields unless there is a public or protected + // setter method + // for the same name + Set fields = getAllPublicAndProtectedFields(clazz, false); + for (Field field : fields) { + if (field.isAnnotationPresent(Callback.class) || field.isAnnotationPresent(Context.class)) { + continue; + } + if (setters.contains(field.getName()) || others.contains(field.getName())) { + continue; + } + String name = field.getName(); + Class paramType = field.getType(); + if (isReferenceType(paramType, field.getGenericType())) { + if (!type.getReferenceMembers().containsKey(name)) { + type.getReferences().add(createReference(name, paramType)); + type.getReferenceMembers().put(name, new JavaElementImpl(field)); + } + } else { + if (!type.getPropertyMembers().containsKey(name)) { + type.getProperties().add(createProperty(name, paramType)); + type.getPropertyMembers().put(name, new JavaElementImpl(field)); + } + } + } + + // Private fields unless there is a public or protected + // setter method for the same name + Set privateFields = getPrivateFields(clazz); + for (Field field : privateFields) { + if (field.isAnnotationPresent(Callback.class) || field.isAnnotationPresent(Context.class)) { + continue; + } + if (setters.contains(field.getName()) || others.contains(field.getName())) { + continue; + } + String name = field.getName(); + Class paramType = field.getType(); + if (isReferenceType(paramType, field.getGenericType())) { + if (!type.getReferenceMembers().containsKey(name)) { + type.getReferences().add(createReference(name, paramType)); + type.getReferenceMembers().put(name, new JavaElementImpl(field)); + } + } else { + if (!type.getPropertyMembers().containsKey(name)) { + type.getProperties().add(createProperty(name, paramType)); + type.getPropertyMembers().put(name, new JavaElementImpl(field)); + } + } + } + } + + /** + * Determines the constructor to use based on the component type's + * references and properties + * + * @param type the component type + * @param clazz the implementation class corresponding to the component type + * @throws NoConstructorException if no suitable constructor is found + * @throws AmbiguousConstructorException if the parameters of a constructor + * cannot be unambiguously mapped to references and properties + */ + @SuppressWarnings("unchecked") + private void evaluateConstructor(JavaImplementation type, Class clazz) throws IntrospectionException { + // determine constructor if one is not annotated + JavaConstructorImpl definition = type.getConstructor(); + Constructor constructor; + boolean explict = false; + if (definition != null && definition.getConstructor() + .isAnnotationPresent(org.osoa.sca.annotations.Constructor.class)) { + // the constructor was already defined explicitly + return; + } else if (definition != null) { + explict = true; + constructor = definition.getConstructor(); + } else { + // no definition, heuristically determine constructor + Constructor[] constructors = clazz.getConstructors(); + if (constructors.length == 0) { + throw new NoConstructorException("No public constructor for class"); + } else if (constructors.length == 1) { + // Only one constructor, take it + constructor = constructors[0]; + } else { + // FIXME multiple constructors, none yet done + Constructor selected = null; + int sites = type.getPropertyMembers().size() + type.getReferenceMembers().size(); + for (Constructor ctor : constructors) { + if (ctor.getParameterTypes().length == 0) { + selected = ctor; + } + if (ctor.getParameterTypes().length == sites) { + // TODO finish + // selected = constructor; + // select constructor + // break; + } + } + if (selected == null) { + throw new NoConstructorException(); + } + constructor = selected; + definition = type.getConstructors().get(selected); + type.setConstructor(definition); + // return; + } + definition = type.getConstructors().get(constructor); + type.setConstructor(definition); + } + JavaParameterImpl[] parameters = definition.getParameters(); + if (parameters.length == 0) { + return; + } + Map props = type.getPropertyMembers(); + Map refs = type.getReferenceMembers(); + Annotation[][] annotations = constructor.getParameterAnnotations(); + if (!explict) { + // the constructor wasn't defined by an annotation, so check to see + // if any of the params have an annotation + // which we can impute as explicitly defining the constructor, e.g. + // @Property, @Reference, or @Autowire + explict = injectionAnnotationsPresent(annotations); + } + if (explict) { + for (int i = 0; i < parameters.length; i++) { + if (isAnnotated(parameters[i])) { + continue; + } else if (!findReferenceOrProperty(parameters[i], props, refs)) { + throw new AmbiguousConstructorException(parameters[i].toString()); + } + } + } else { + if (!areUnique(parameters)) { + throw new AmbiguousConstructorException("Cannot resolve non-unique parameter types, use @Constructor"); + } + if (!calcPropRefUniqueness(props.values(), refs.values())) { + throw new AmbiguousConstructorException("Cannot resolve non-unique parameter types, use @Constructor"); + } + if (!(props.isEmpty() && refs.isEmpty())) { + calcParamNames(parameters, props, refs); + } else { + heuristicParamNames(type, parameters); + + } + } + } + + private void calcParamNames(JavaParameterImpl[] parameters, + Map props, + Map refs) throws AmbiguousConstructorException { + // the constructor param types must unambiguously match defined + // reference or property types + for (JavaParameterImpl param : parameters) { + if (!findReferenceOrProperty(param, props, refs)) { + throw new AmbiguousConstructorException(param.getName()); + } + } + } + + private void heuristicParamNames(JavaImplementation type, JavaParameterImpl[] parameters) + throws IntrospectionException { + // heuristically determine refs and props from the parameter types + for (JavaParameterImpl p : parameters) { + String name = p.getType().getSimpleName().toLowerCase(); + if (isReferenceType(p.getType(), p.getGenericType())) { + type.getReferences().add(createReference(name, p.getType())); + p.setClassifer(Reference.class); + type.getReferenceMembers().put(name, p); + } else { + type.getProperties().add(createProperty(name, p.getType())); + p.setClassifer(Property.class); + type.getPropertyMembers().put(name, p); + } + p.setName(name); + } + } + + private static boolean areUnique(Class[] collection) { + Set set = new HashSet(Arrays.asList(collection)); + return set.size() == collection.length; + } + + /** + * Returns true if the union of the given collections of properties and + * references have unique Java types + */ + private boolean calcPropRefUniqueness(Collection props, Collection refs) { + + Class[] classes = new Class[props.size() + refs.size()]; + int i = 0; + for (JavaElementImpl property : props) { + classes[i] = property.getType(); + i++; + } + for (JavaElementImpl reference : refs) { + classes[i] = reference.getType(); + i++; + } + return areUnique(classes); + } + + /** + * Unambiguously finds the reference or property associated with the given + * type + * + * @return the name of the reference or property if found, null if not + * @throws AmbiguousConstructorException if the constructor parameter cannot + * be resolved to a property or reference + */ + private boolean findReferenceOrProperty(JavaParameterImpl parameter, + Map props, + Map refs) throws AmbiguousConstructorException { + + boolean found = false; + if (!"".equals(parameter.getName())) { + // Match by name + JavaElementImpl prop = props.get(parameter.getName()); + if (prop != null && prop.getType() == parameter.getType()) { + parameter.setClassifer(Property.class); + return true; + } + JavaElementImpl ref = refs.get(parameter.getName()); + if (ref != null && ref.getType() == parameter.getType()) { + parameter.setClassifer(Reference.class); + return true; + } + } + for (JavaElementImpl property : props.values()) { + if (property.getType() == parameter.getType()) { + if (found) { + throw new AmbiguousConstructorException("Ambiguous property or reference for constructor type", + (Member)parameter.getAnchor()); + } + parameter.setClassifer(Property.class); + parameter.setName(property.getName()); + found = true; + // do not break since ambiguities must be checked, i.e. more + // than one prop or ref of the same type + } + } + for (JavaElementImpl reference : refs.values()) { + if (reference.getType() == parameter.getType()) { + if (found) { + throw new AmbiguousConstructorException("Ambiguous property or reference for constructor type", + (Member)parameter.getAnchor()); + } + parameter.setClassifer(Reference.class); + parameter.setName(reference.getName()); + found = true; + // do not break since ambiguities must be checked, i.e. more + // than one prop or ref of the same type + } + } + return found; + } + + /** + * Returns true if a given type is reference according to the SCA + * specification rules for determining reference types The following rules + * are used to determine whether an unannotated field or setter method is a + * property or reference: + *

    + *
  1. If its type is simple, then it is a property. + *
  2. If its type is complex, then if the type is an interface marked by + * + * @Remotable, then it is a reference; otherwise, it is a property. + *
  3. Otherwise, if the type associated with the member is an + * array or a java.util.Collection, the basetype is the element + * type of the array or the parameterized type of the + * Collection; otherwise the basetype is the member type. If the + * basetype is an interface with an + * @Remotable or + * @Service annotation then the member is defined as a reference. Otherwise, + * it is defined as a property. + *
+ *

+ * The name of the reference or of the property is derived from the + * name found on the setter method or on the field. + */ + private boolean isReferenceType(Class cls, Type genericType) { + Class baseType = JavaIntrospectionHelper.getBaseType(cls, genericType); + return baseType.isInterface() && baseType.isAnnotationPresent(Remotable.class); + } + + /** + * Returns true if the given operation is defined in the collection of + * service interfaces + */ + private boolean isInServiceInterface(Method operation, List services) { + for (org.apache.tuscany.sca.assembly.Service service : services) { + Interface interface1 = service.getInterfaceContract().getInterface(); + if (interface1 instanceof JavaInterface) { + Class clazz = ((JavaInterface)interface1).getJavaClass(); + if (isMethodMatched(clazz, operation)) { + return true; + } + } + } + return false; + } + + /** + * Test if the class declares a method which matches the signature of the + * given method + * + * @param clazz + * @param method + * @return + */ + private boolean isMethodMatched(Class clazz, Method method) { + if (method.getDeclaringClass() == clazz) { + return true; + } + Method[] methods = clazz.getMethods(); + for (Method m : methods) { + if (JavaIntrospectionHelper.exactMethodMatch(method, m)) { + return true; + } + } + return false; + } + + /** + * Creates a mapped property. + * + * @param name the property name + * @param paramType the property type + */ + private org.apache.tuscany.sca.assembly.Property createProperty(String name, Class paramType) { + org.apache.tuscany.sca.assembly.Property property = assemblyFactory.createProperty(); + property.setName(name); + property.setXSDType(JavaXMLMapper.getXMLType(paramType)); + return property; + } + + private boolean isAnnotated(JavaParameterImpl parameter) { + for (Annotation annotation : parameter.getAnnotations()) { + Class annotType = annotation.annotationType(); + if (annotType.equals(Property.class) || annotType.equals(Reference.class) + || annotType.equals(Resource.class)) { + return true; + } + } + return false; + } + + public boolean areUnique(JavaParameterImpl[] parameters) { + Set set = new HashSet(parameters.length); + for (JavaParameterImpl p : parameters) { + if (!set.add(p.getType())) { + return false; + } + } + return true; + } + + public org.apache.tuscany.sca.assembly.Reference createReference(String name, Class paramType) + throws IntrospectionException { + org.apache.tuscany.sca.assembly.Reference reference = assemblyFactory.createReference(); + reference.setName(name); + JavaInterfaceContract interfaceContract = javaFactory.createJavaInterfaceContract(); + reference.setInterfaceContract(interfaceContract); + try { + JavaInterface callInterface = javaFactory.createJavaInterface(paramType); + reference.getInterfaceContract().setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + JavaInterface callbackInterface = javaFactory.createJavaInterface(callInterface.getCallbackClass()); + reference.getInterfaceContract().setCallbackInterface(callbackInterface); + } + reference.setMultiplicity(Multiplicity.ZERO_ONE); + } catch (InvalidInterfaceException e1) { + throw new IntrospectionException(e1); + } + + // FIXME: This part seems to have already been taken care above!! + try { + processCallback(paramType, reference); + } catch (InvalidServiceType e) { + throw new IntrospectionException(e); + } + return reference; + } + + public org.apache.tuscany.sca.assembly.Service createService(Class interfaze) throws InvalidInterfaceException { + org.apache.tuscany.sca.assembly.Service service = assemblyFactory.createService(); + service.setName(interfaze.getSimpleName()); + + JavaInterfaceContract interfaceContract = javaFactory.createJavaInterfaceContract(); + service.setInterfaceContract(interfaceContract); + + JavaInterface callInterface = javaFactory.createJavaInterface(interfaze); + service.getInterfaceContract().setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + JavaInterface callbackInterface = javaFactory.createJavaInterface(callInterface.getCallbackClass()); + service.getInterfaceContract().setCallbackInterface(callbackInterface); + } + + Interface javaInterface = service.getInterfaceContract().getInterface(); + javaInterface.setRemotable(interfaze.getAnnotation(Remotable.class) != null); + service.getInterfaceContract().setInterface(javaInterface); + return service; + } + + public void processCallback(Class interfaze, Contract contract) throws InvalidServiceType { + Callback callback = interfaze.getAnnotation(Callback.class); + if (callback != null && !Void.class.equals(callback.value())) { + Class callbackClass = callback.value(); + JavaInterface javaInterface; + try { + javaInterface = javaFactory.createJavaInterface(callbackClass); + contract.getInterfaceContract().setCallbackInterface(javaInterface); + } catch (InvalidInterfaceException e) { + throw new InvalidServiceType("Invalid callback interface "+callbackClass, interfaze); + } + } else if (callback != null && Void.class.equals(callback.value())) { + throw new InvalidServiceType("No callback interface specified on annotation", interfaze); + } + } + + public boolean injectionAnnotationsPresent(Annotation[][] annots) { + for (Annotation[] annotations : annots) { + for (Annotation annotation : annotations) { + Class annotType = annotation.annotationType(); + if (annotType.equals(Property.class) || annotType.equals(Reference.class) + || annotType.equals(Resource.class)) { + return true; + } + } + } + return false; + } +} diff --git a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringConstructorArgElement.java b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringConstructorArgElement.java index 57f4a26ba3..ce83baee05 100644 --- a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringConstructorArgElement.java +++ b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringConstructorArgElement.java @@ -31,6 +31,7 @@ public class SpringConstructorArgElement { private String ref; private String type; + private int index; private List values = new ArrayList(); public SpringConstructorArgElement(String ref, String type) { @@ -50,6 +51,14 @@ public class SpringConstructorArgElement { this.ref = ref; } + public int getIndex() { + return this.index; + } + + public void setIndex(int index) { + this.index = index; + } + public List getValues() { return this.values; } diff --git a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLComponentTypeLoader.java b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLComponentTypeLoader.java index d584329e88..0100bb8fc5 100644 --- a/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLComponentTypeLoader.java +++ b/branches/sca-java-1.x/modules/implementation-spring/src/main/java/org/apache/tuscany/sca/implementation/spring/xml/SpringXMLComponentTypeLoader.java @@ -47,7 +47,10 @@ import org.apache.tuscany.sca.assembly.Reference; import org.apache.tuscany.sca.assembly.Service; import org.apache.tuscany.sca.contribution.service.ContributionReadException; import org.apache.tuscany.sca.contribution.service.ContributionResolveException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.impl.JavaParameterImpl; import org.apache.tuscany.sca.implementation.spring.SpringImplementation; import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; import org.apache.tuscany.sca.interfacedef.java.JavaInterface; @@ -72,6 +75,7 @@ public class SpringXMLComponentTypeLoader { private ClassLoader cl; private SpringBeanIntrospector beanIntrospector; + private String contextPath; public SpringXMLComponentTypeLoader(AssemblyFactory assemblyFactory, JavaInterfaceFactory javaFactory, @@ -94,7 +98,7 @@ public class SpringXMLComponentTypeLoader { */ public void load(SpringImplementation implementation) throws ContributionReadException { //System.out.println("Spring TypeLoader - load method start"); - ComponentType componentType = implementation.getComponentType(); + ComponentType componentType = implementation.getComponentType(); /* Check that there is a component type object already set */ if (componentType == null) { throw new ContributionReadException("SpringXMLLoader load: implementation has no ComponentType object"); @@ -124,22 +128,22 @@ public class SpringXMLComponentTypeLoader { Resource resource; - String location = implementation.getLocation(); + contextPath = implementation.getLocation(); try { // FIXME - is the ContextClassLoader the right place to start the search? cl = Thread.currentThread().getContextClassLoader(); - resource = getApplicationContextResource(location, cl); + resource = getApplicationContextResource(contextPath, cl); implementation.setResource(resource); // The URI is used to uniquely identify the Implementation - implementation.setURI(resource.getURL().toString()); + implementation.setURI(resource.getURL().toString()); // FIXME - need a better way to handle the XMLInputFactory than allocating a new one every time XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); reader = xmlFactory.createXMLStreamReader(resource.getInputStream()); // System.out.println("Spring TypeLoader - starting to read context file"); - readContextDefinition(reader, beans, services, references, scaproperties); + readContextDefinition(reader, beans, services, references, scaproperties); } catch (IOException e) { throw new ContributionReadException(e); @@ -153,18 +157,18 @@ public class SpringXMLComponentTypeLoader { generateComponentType(implementation, beans, services, references, scaproperties); return; - } // end method loadFromXML + } // end method loadFromXML /** * Method which returns the XMLStreamReader for the Spring application-context.xml file * specified in the location attribute */ - private XMLStreamReader getApplicationContextReader (String location) throws ContributionReadException { + private XMLStreamReader getApplicationContextReader(String location) throws ContributionReadException { try { // FIXME - is the ContextClassLoader the right place to start the search? - cl = Thread.currentThread().getContextClassLoader(); - Resource resource = getApplicationContextResource(location, cl); + cl = Thread.currentThread().getContextClassLoader(); + Resource resource = getApplicationContextResource(location, cl); // FIXME - need a better way to handle the XMLInputFactory than allocating a new one every time XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); XMLStreamReader reader = xmlFactory.createXMLStreamReader(resource.getInputStream()); @@ -199,7 +203,9 @@ public class SpringXMLComponentTypeLoader { //FIXME - put the sequence of code below which gets the ireader into a subsidiary method String location = reader.getAttributeValue(null, "resource"); if (location != null) { - XMLStreamReader ireader = getApplicationContextReader(location); + // FIXME - need to find a right way of generating this path + String resourcePath = contextPath.substring(0, contextPath.lastIndexOf("/")+1) + location; + XMLStreamReader ireader = getApplicationContextReader(resourcePath); // Read the context definition for the identified imported resource readContextDefinition(ireader, beans, services, references, scaproperties); } @@ -264,6 +270,7 @@ public class SpringXMLComponentTypeLoader { if (Constants.BEAN_ELEMENT.equals(qname)) { innerbean = new SpringBeanElement(reader.getAttributeValue(null, "id"), reader .getAttributeValue(null, "class")); + innerbean.setInnerBean(true); beans.add(innerbean); readBeanDefinition(reader, innerbean, beans, services, references, scaproperties); } else if (Constants.PROPERTY_ELEMENT.equals(qname)) { @@ -273,6 +280,20 @@ public class SpringXMLComponentTypeLoader { } else if (Constants.CONSTRUCTORARG_ELEMENT.equals(qname)) { constructorArg = new SpringConstructorArgElement(reader.getAttributeValue(null, "ref"), reader.getAttributeValue(null, "type")); + if (reader.getAttributeValue(null, "index") != null) + constructorArg.setIndex((new Integer(reader.getAttributeValue(null, "index"))).intValue()); + if (reader.getAttributeValue(null, "value") != null) { + String value = reader.getAttributeValue(null, "value"); + constructorArg.addValue(value); + if ((value.indexOf(".xml") != -1)) { + if ((bean.getClassName().indexOf(".ClassPathXmlApplicationContext") != -1) || + (bean.getClassName().indexOf(".FileSystemXmlApplicationContext") != -1)) { + XMLStreamReader creader = getApplicationContextReader(value); + // Read the context definition for the constructor-arg resources + readContextDefinition(creader, beans, services, references, scaproperties); + } + } + } bean.addCustructorArgs(constructorArg); } else if (Constants.REF_ELEMENT.equals(qname)) { String ref = reader.getAttributeValue(null, "bean"); @@ -282,11 +303,9 @@ public class SpringXMLComponentTypeLoader { if (constructorArg != null) constructorArg.setRef(ref); } else if (Constants.VALUE_ELEMENT.equals(qname)) { String value = reader.getElementText(); - // Check if the parent element is a property - if (property != null) property.addValue(value); // Check if the parent element is a constructor-arg if (constructorArg != null) { - constructorArg.addValue(value); + constructorArg.addValue(value); // Identify the XML resource specified for the constructor-arg element if ((value.indexOf(".xml") != -1)) { if ((bean.getClassName().indexOf(".ClassPathXmlApplicationContext") != -1) || @@ -327,14 +346,15 @@ public class SpringXMLComponentTypeLoader { /* * 1. Each sca:service becomes a service in the component type * 2. Each sca:reference becomes a reference in the component type - * 3. IF there are no explicit service elements, each bean becomes a service - * 4. Each bean property which is a reference not pointing at another bean in the + * 3. Each sca:property becomes a property in the component type + * 4. IF there are no explicit service elements, each bean becomes a service + * 5. Each bean property which is a reference not pointing at another bean in the * application context becomes a reference unless it is pointing at one of the references - * 5. Each sca:property becomes a property in the component type * 6. Each bean property which is not a reference and which is not pointing * at another bean in the application context becomes a property in the component type */ + JavaImplementation javaImplementation = null; ComponentType componentType = implementation.getComponentType(); try { @@ -362,6 +382,24 @@ public class SpringXMLComponentTypeLoader { Reference theReference = createReference(interfaze, referenceElement.getName()); componentType.getReferences().add(theReference); } // end while + + // Next handle the properties + Iterator itsp = scaproperties.iterator(); + while (itsp.hasNext()) { + SpringSCAPropertyElement scaproperty = itsp.next(); + // Create a component type property if the SCA property element has a name + // and a type declared... + if (scaproperty.getType() != null && scaproperty.getName() != null) { + Property theProperty = assemblyFactory.createProperty(); + theProperty.setName(scaproperty.getName()); + // Get the Java class and then an XSD element type for the property + Class propType = Class.forName(scaproperty.getType()); + theProperty.setXSDType(JavaXMLMapper.getXMLType(propType)); + componentType.getProperties().add(theProperty); + // Remember the Java Class (ie the type) for this property + implementation.setPropertyClass(theProperty.getName(), propType); + } // end if + } // end while // Finally deal with the beans Iterator itb; @@ -371,11 +409,13 @@ public class SpringXMLComponentTypeLoader { // Loop through all the beans found while (itb.hasNext()) { SpringBeanElement beanElement = itb.next(); + // If its a innerBean, ignore it + if (beanElement.isInnerBean()) continue; // Load the Spring bean class Class beanClass = cl.loadClass(beanElement.getClassName()); // Introspect the bean ComponentType beanComponentType = assemblyFactory.createComponentType(); - beanIntrospector.introspectBean(beanClass, beanComponentType, implementation); + javaImplementation = beanIntrospector.introspectBean(beanClass, beanComponentType); // Get the service interface defined by this Spring Bean and add to // the component type of the Spring Assembly List beanServices = beanComponentType.getServices(); @@ -386,8 +426,93 @@ public class SpringXMLComponentTypeLoader { } } // end while } // end if - // Now check to see if there are any more references from beans that are not satisfied + itb = beans.iterator(); + while (itb.hasNext()) { + SpringBeanElement beanElement = itb.next(); + // Ignore if the bean has no properties and constructor arguments + if (beanElement.getProperties().isEmpty() && beanElement.getCustructorArgs().isEmpty()) + continue; + + Class beanClass = cl.loadClass(beanElement.getClassName()); + // Introspect the bean + ComponentType beanComponentType = assemblyFactory.createComponentType(); + javaImplementation = beanIntrospector.introspectBean(beanClass, beanComponentType); + Map propertyMap = javaImplementation.getPropertyMembers(); + JavaConstructorImpl constructor = javaImplementation.getConstructor(); + // Get the references by this Spring Bean and add the unresolved ones to + // the component type of the Spring Assembly + List beanReferences = beanComponentType.getReferences(); + List beanProperties = beanComponentType.getProperties(); + + Iterator itp = beanElement.getProperties().iterator(); + while (itp.hasNext()) { + SpringPropertyElement propertyElement = itp.next(); + if (propertyRefUnresolved(propertyElement.getRef(), beans, references, scaproperties)) { + // This means an unresolved reference from the spring bean... + for (Reference reference : beanReferences) { + if (propertyElement.getName().equals(reference.getName())) { + // The name of the reference in this case is the string in + // the @ref attribute of the Spring property element, NOT the + // name of the field in the Spring bean.... + reference.setName(propertyElement.getRef()); + componentType.getReferences().add(reference); + } // end if + } // end for + + // Store the unresolved references as unresolvedBeanRef in the Spring Implementation type + for (Property scaproperty : beanProperties) { + if (propertyElement.getName().equals(scaproperty.getName())) { + // The name of the reference in this case is the string in + // the @ref attribute of the Spring property element, NOT the + // name of the field in the Spring bean.... + Class interfaze = cl.loadClass((propertyMap.get(propertyElement.getName()).getType()).getName()); + Reference theReference = createReference(interfaze, propertyElement.getRef()); + implementation.setUnresolvedBeanRef(propertyElement.getRef(), theReference); + } // end if + } // end for + } // end if + } // end while + + Iterator itcr = beanElement.getCustructorArgs().iterator(); + while (itcr.hasNext()) { + SpringConstructorArgElement conArgElement = itcr.next(); + if (propertyRefUnresolved(conArgElement.getRef(), beans, references, scaproperties)) { + for (JavaParameterImpl parameter : constructor.getParameters()) { + String paramType = parameter.getType().getName(); + Class interfaze = cl.loadClass(paramType); + // Create a component type reference/property if the constructor-arg element has a + // type attribute declared... + if (conArgElement.getType() != null && paramType.equals(conArgElement.getType())) { + if (parameter.getClassifer().getName().equals("org.osoa.sca.annotations.Reference")) { + Reference theReference = createReference(interfaze, conArgElement.getRef()); + componentType.getReferences().add(theReference); + } + if (parameter.getClassifer().getName().equals("org.osoa.sca.annotations.Property")) { + Property theProperty = assemblyFactory.createProperty(); + theProperty.setName(conArgElement.getRef()); + theProperty.setXSDType(JavaXMLMapper.getXMLType(interfaze)); + componentType.getProperties().add(theProperty); + // Remember the Java Class (ie the type) for this property + implementation.setPropertyClass(theProperty.getName(), interfaze); + } + } + + // Store the unresolved references as unresolvedBeanRef in the Spring Implementation type + // if the type attribute is absent in the contructor-arg element... + if (conArgElement.getType() == null) { + Reference theReference = createReference(interfaze, conArgElement.getRef()); + implementation.setUnresolvedBeanRef(conArgElement.getRef(), theReference); + } + } // end for + } // end if + } // end while + + } // end while + + + // Now check to see if there are any more references from beans that are not satisfied + /*itb = beans.iterator(); while (itb.hasNext()) { SpringBeanElement beanElement = itb.next(); boolean unresolvedProperties = false; @@ -406,8 +531,8 @@ public class SpringXMLComponentTypeLoader { Class beanClass = cl.loadClass(beanElement.getClassName()); // Introspect the bean ComponentType beanComponentType = assemblyFactory.createComponentType(); - Map propertyMap = - beanIntrospector.introspectBean(beanClass, beanComponentType, implementation); + javaImplementation = beanIntrospector.introspectBean(beanClass, beanComponentType); + Map propertyMap = javaImplementation.getPropertyMembers(); // Get the references by this Spring Bean and add the unresolved ones to // the component type of the Spring Assembly List beanReferences = beanComponentType.getReferences(); @@ -441,48 +566,14 @@ public class SpringXMLComponentTypeLoader { implementation.setUnresolvedBeanRef(propertyElement.getRef(), theReference); resolved = true; } - } - - /*// If the bean property is not already resolved as a reference - // then it must be an SCA property... - for (Property scaproperty : beanProperties) { - if (propertyElement.getName().equals(scaproperty.getName())) { - // The name of the reference in this case is the string in - // the @ref attribute of the Spring property element, NOT the - // name of the field in the Spring bean.... - scaproperty.setName(propertyElement.getRef()); - componentType.getProperties().add(scaproperty); - // Fetch and store the type of the property - implementation.setPropertyClass(propertyElement.getRef(), propertyMap - .get(propertyElement.getName()).getType()); - resolved = true; - } // end if - } // end for */ + } } // end if } // end if } // end while } // end if } // end if - - } // end while - - Iterator itsp = scaproperties.iterator(); - while (itsp.hasNext()) { - SpringSCAPropertyElement scaproperty = itsp.next(); - // Create a component type property if the SCA property element has a name - // and a type declared... - if (scaproperty.getType() != null && scaproperty.getName() != null) { - Property theProperty = assemblyFactory.createProperty(); - theProperty.setName(scaproperty.getName()); - // Get the Java class and then an XSD element type for the property - Class propType = Class.forName(scaproperty.getType()); - theProperty.setXSDType(JavaXMLMapper.getXMLType(propType)); - componentType.getProperties().add(theProperty); - // Remember the Java Class (ie the type) for this property - implementation.setPropertyClass(theProperty.getName(), propType); - } // end if - } // end while + } // end while*/ } catch (ClassNotFoundException e) { // Means that either an interface class, property class or a bean was not found @@ -490,7 +581,7 @@ public class SpringXMLComponentTypeLoader { } catch (InvalidInterfaceException e) { throw new ContributionReadException(e); } catch (ContributionResolveException e) { - + } // end try // If we get here, the Spring assembly component type is resolved -- cgit v1.2.3