diff options
Diffstat (limited to 'sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca')
22 files changed, 2172 insertions, 0 deletions
diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SCAGenericApplicationContext.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SCAGenericApplicationContext.java new file mode 100644 index 0000000000..44a3ee2b88 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SCAGenericApplicationContext.java @@ -0,0 +1,145 @@ +/* + * 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.context; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.implementation.spring.SpringBeanElement; +import org.apache.tuscany.sca.implementation.spring.SpringConstructorArgElement; +import org.apache.tuscany.sca.implementation.spring.SpringPropertyElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAPropertyElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAReferenceElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAServiceElement; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanReference; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder; +import org.springframework.beans.factory.config.TypedStringValue; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericApplicationContext; + +public class SCAGenericApplicationContext extends GenericApplicationContext { + + private ClassLoader classloader = null; + private List<SpringSCAPropertyElement> propertyElements = new ArrayList<SpringSCAPropertyElement>(); + private List<SpringSCAServiceElement> serviceElements = new ArrayList<SpringSCAServiceElement>(); + private List<SpringSCAReferenceElement> referenceElements = new ArrayList<SpringSCAReferenceElement>(); + private List<SpringBeanElement> beanElements; + + public SCAGenericApplicationContext(DefaultListableBeanFactory beanFactory, + ApplicationContext parent, + ClassLoader classloader) { + super(beanFactory, parent); + this.classloader = classloader; + } + + public SCAGenericApplicationContext(ApplicationContext parent, ClassLoader classloader) { + super(parent); + this.classloader = classloader; + } + + @Override + protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { + beanFactory.setBeanClassLoader(classloader); + } + + public void addSCAPropertyElement(SpringSCAPropertyElement propertyElement) { + propertyElements.add(propertyElement); + } + + public void addSCAServiceElement(SpringSCAServiceElement serviceElement) { + serviceElements.add(serviceElement); + } + + public void addSCAReferenceElement(SpringSCAReferenceElement referenceElement) { + referenceElements.add(referenceElement); + } + + public synchronized List<SpringBeanElement> getBeanElements() { + if (beanElements == null) { + beanElements = new ArrayList<SpringBeanElement>(); + for (String name : getBeanDefinitionNames()) { + BeanDefinition def = getBeanDefinition(name); + SpringBeanElement beanElement = new SpringBeanElement(name, def.getBeanClassName()); + beanElements.add(beanElement); + beanElement.setAbstractBean(def.isAbstract()); + beanElement.setFactoryBeanAttribute(def.getFactoryBeanName() != null); + beanElement.setFactoryMethodAttribute(def.getFactoryMethodName() != null); + beanElement.setParentAttribute(def.getParentName() != null); + beanElement.setInnerBean(beanElement.getId() == null); + + ConstructorArgumentValues args = def.getConstructorArgumentValues(); + for (Map.Entry<Integer, ValueHolder> e: args.getIndexedArgumentValues().entrySet()) { + ValueHolder holder = e.getValue(); + SpringConstructorArgElement arg = new SpringConstructorArgElement(holder.getType()); + arg.setIndex(e.getKey()); + beanElement.addCustructorArgs(arg); + } + + MutablePropertyValues values = def.getPropertyValues(); + for (PropertyValue p : values.getPropertyValueList()) { + SpringPropertyElement propertyElement = new SpringPropertyElement(p.getName()); + Object value = p.getValue(); + configurePropertyElement(propertyElement, value); + beanElement.getProperties().add(propertyElement); + } + } + } + return beanElements; + } + + public void configurePropertyElement(SpringPropertyElement propertyElement, Object value) { + if (value instanceof BeanReference) { + BeanReference beanRef = (BeanReference)value; + propertyElement.addRef(beanRef.getBeanName()); + } else if (value instanceof Collection) { + Collection collection = (Collection)value; + for (Object item : collection) { + configurePropertyElement(propertyElement, item); + } + } else if (value instanceof TypedStringValue) { + TypedStringValue stringValue = (TypedStringValue)value; + propertyElement.addValue(stringValue.getValue()); + } else { + if (value != null) { + propertyElement.addValue(value.toString()); + } + } + } + + public List<SpringSCAPropertyElement> getPropertyElements() { + return propertyElements; + } + + public List<SpringSCAServiceElement> getServiceElements() { + return serviceElements; + } + + public List<SpringSCAReferenceElement> getReferenceElements() { + return referenceElements; + } + +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SCAParentApplicationContext.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SCAParentApplicationContext.java new file mode 100644 index 0000000000..cd81facc3d --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SCAParentApplicationContext.java @@ -0,0 +1,213 @@ +/* + * 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.context; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.Locale; +import java.util.Map; + +import org.apache.tuscany.sca.implementation.spring.provider.SpringImplementationWrapper; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.MessageSourceResolvable; +import org.springframework.context.NoSuchMessageException; +import org.springframework.core.io.Resource; + +/** + * A Spring ParentApplicationContext for a given Spring Implementation + * + * The Parent application context is responsible for handling those entities within a Spring + * application context that actually belong to SCA rather than to Spring. The principal things + * are Properties and References. These may be present either through explicit <sca:property/> + * and <sca:reference/> elements in the application context or they may be implicit through + * unresolved Spring bean <property.../> elements. In either case, it is the Parent application + * context that must provide Spring beans that correspond to the property or reference, as derived + * from the SCA composite in which the Spring application context is an implementation. + * + * @version $Rev$ $Date$ + */ +public class SCAParentApplicationContext implements ApplicationContext { + + // The Spring implementation for which this is the parent application context + private SpringImplementationWrapper implementation; + + private static final String[] EMPTY_ARRAY = new String[0]; + + public SCAParentApplicationContext(SpringImplementationWrapper implementation) { + this.implementation = implementation; + } // end constructor + + public Object getBean(String name) throws BeansException { + return getBean(name, (Class)null); + } + + /** + * Get a Bean for a reference or for a property. + * + * @param name - the name of the Bean required + * @param requiredType - the required type of the Bean (either a Java class or a Java interface) + * @return Object - a Bean which matches the requested bean + */ + public Object getBean(String name, Class requiredType) throws BeansException { + Object bean = implementation.getBean(name, requiredType); + if (bean == null && getParent() != null) { + bean = getParent().getBean(name, requiredType); + } + if (bean == null) { + throw new NoSuchBeanDefinitionException("Unable to find Bean with name " + name); + } else { + return bean; + } + } // end method getBean( String, Class ) + + public Object getBean(String name, Object[] args) throws BeansException { + return getBean(name, ((Class)null)); + } + + public <T> T getBean(Class<T> clazz) throws BeansException { + return clazz.cast(getBean(clazz.getName(), clazz)); + } + + public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> clazz) throws BeansException { + return null; + } + + public <A extends Annotation> A findAnnotationOnBean(String arg0, Class<A> clazz) { + return null; + } + + public boolean containsBean(String name) { + // TODO + return false; + } + + public boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + // TODO + return false; + } + + public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException { + throw new UnsupportedOperationException(); + } + + public Class getType(String name) throws NoSuchBeanDefinitionException { + return null; + } + + public String[] getAliases(String name) throws NoSuchBeanDefinitionException { + return EMPTY_ARRAY; + } + + public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException { + return null; + } + + public String getId() { + return this.toString(); + } + + public String getDisplayName() { + return implementation.getURI(); + } + + public long getStartupDate() { + return 0; + } + + public boolean containsBeanDefinition(String beanName) { + return false; + } + + public int getBeanDefinitionCount() { + return 0; + } + + public String[] getBeanDefinitionNames() { + return new String[0]; + } + + public String[] getBeanNamesForType(Class type) { + return new String[0]; + } + + public String[] getBeanNamesForType(Class type, boolean includePrototypes, boolean includeFactoryBeans) { + return new String[0]; + } + + public Map getBeansOfType(Class type) throws BeansException { + return null; + } + + public Map getBeansOfType(Class type, boolean includePrototypes, boolean includeFactoryBeans) throws BeansException { + return null; + } + + public boolean isPrototype(String theString) { + return false; + } + + public BeanFactory getParentBeanFactory() { + return null; + } + + public boolean containsLocalBean(String name) { + return false; + } + + public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) { + return null; + } + + public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException { + return null; + } + + public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException { + return null; + } + + public void publishEvent(ApplicationEvent event) { + + } + + public Resource[] getResources(String locationPattern) throws IOException { + return new Resource[0]; + } + + public Resource getResource(String location) { + return null; + } + + public ClassLoader getClassLoader() { + // REVIEW: this is almost certainly flawed, but it's not clear how the SCA runtime's + // resource loading mechanism is exposed right now. + return this.getClass().getClassLoader(); + } + + @Override + public ApplicationContext getParent() { + return implementation.getParentApplicationContext(); + } + +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SpringApplicationContextAccessor.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SpringApplicationContextAccessor.java new file mode 100644 index 0000000000..2d18b5aa6c --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SpringApplicationContextAccessor.java @@ -0,0 +1,41 @@ +/* + * 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.context; + +import org.springframework.context.ApplicationContext; + +/** + * A utility to receive the parent Spring application context + */ +public interface SpringApplicationContextAccessor { + /** + * Get the parent Spring application context for the hosting environment. This will be used as the parent + * application context for implementation.spring components + * @return The parent application context + */ + ApplicationContext getParentApplicationContext(); + + /** + * Set the root Spring application context. This is particually useful for Spring web integration where Spring + * creates WebApplicationContext and keeps it in the ServletContext + * @param parentApplicationContext The parent application context + */ + void setParentApplicationContext(ApplicationContext parentApplicationContext); +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SpringContextWrapper.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SpringContextWrapper.java new file mode 100644 index 0000000000..4b0ad72972 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SpringContextWrapper.java @@ -0,0 +1,130 @@ +/* + * 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.context; + +import java.net.URL; +import java.util.List; + +import org.apache.tuscany.sca.implementation.spring.processor.ComponentNameAnnotationProcessor; +import org.apache.tuscany.sca.implementation.spring.processor.ConstructorAnnotationProcessor; +import org.apache.tuscany.sca.implementation.spring.processor.InitDestroyAnnotationProcessor; +import org.apache.tuscany.sca.implementation.spring.processor.PropertyAnnotationProcessor; +import org.apache.tuscany.sca.implementation.spring.processor.ReferenceAnnotationProcessor; +import org.apache.tuscany.sca.implementation.spring.provider.ComponentWrapper; +import org.apache.tuscany.sca.implementation.spring.provider.PropertyValueWrapper; +import org.apache.tuscany.sca.implementation.spring.provider.SpringImplementationWrapper; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.io.UrlResource; + +/** + * This is the runtime side tie for the corresponding tuscany side stub class. + * It enables the Tuscany code to invoke methods on a Spring context without + * needing to know about any Spring classes. See the SpringContextStub class + * in the implementation-spring module for what the stub does. + */ +public class SpringContextWrapper { + + private GenericApplicationContext springContext; + private SpringImplementationWrapper implementation; + + public SpringContextWrapper(SpringImplementationWrapper implementation, List<URL> resource) { + this.implementation = implementation; + SCAParentApplicationContext scaParentContext = new SCAParentApplicationContext(implementation); + springContext = createApplicationContext(scaParentContext, resource); + } + + public ApplicationContext getApplicationContext() { + return springContext; + } + + public void start() { + // Do refresh here to ensure that Spring Beans are not touched before the SCA config process is complete... + springContext.refresh(); + springContext.start(); + } + + public void close() { + springContext.close(); + if (springContext instanceof GenericApplicationContext) { + springContext.stop(); + } + } + + /** + * Include BeanPostProcessor to deal with SCA Annotations in Spring Bean + */ + private GenericApplicationContext createApplicationContext(SCAParentApplicationContext scaParentContext, + List<URL> resources) { + + GenericApplicationContext appCtx = + new SCAGenericApplicationContext(scaParentContext, implementation.getClassLoader()); + XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(appCtx); + + // REVIEW: [rfeng] How do we control the schema validation + xmlReader.setValidating(false); + + for (URL resource : resources) { + xmlReader.loadBeanDefinitions(new UrlResource(resource)); + } + xmlReader.setBeanClassLoader(implementation.getClassLoader()); + includeAnnotationProcessors(appCtx.getBeanFactory()); + return appCtx; + + } + + public Object getBean(String id) throws BeansException { + return springContext.getBean(id); + } + + /** + * 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 + ComponentWrapper component = implementation.getComponentWrapper(); + BeanPostProcessor referenceProcessor = new ReferenceAnnotationProcessor(component); + beanFactory.addBeanPostProcessor(referenceProcessor); + + // Processor to deal with @Property SCA Annotations + PropertyValueWrapper pvs = implementation.getPropertyValueWrapper(); + BeanPostProcessor propertyProcessor = new PropertyAnnotationProcessor(pvs); + beanFactory.addBeanPostProcessor(propertyProcessor); + + // Processor to deal with @ComponentName SCA Annotations + BeanPostProcessor componentNameProcessor = + new ComponentNameAnnotationProcessor(implementation.getComponentName()); + beanFactory.addBeanPostProcessor(componentNameProcessor); + + // Processor to deal with @Constructor SCA Annotations + BeanPostProcessor constructorProcessor = new ConstructorAnnotationProcessor(); + beanFactory.addBeanPostProcessor(constructorProcessor); + } + +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/SCANamespaceHandlerResolver.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/SCANamespaceHandlerResolver.java new file mode 100644 index 0000000000..75e00007f6 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/SCANamespaceHandlerResolver.java @@ -0,0 +1,53 @@ +/* + * 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.namespace; + +import org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver; +import org.springframework.beans.factory.xml.NamespaceHandler; + +/** + * Overrides the default Spring namespace resolver to automatically register + * {@link ScaNamespaceHandler} instead of requiring a value to be supplied in a + * Spring configuration + * + * @version $Rev$ $Date$ + */ +public class SCANamespaceHandlerResolver extends DefaultNamespaceHandlerResolver { + private static final String SCA_NAMESPACE = "http://www.springframework.org/schema/sca"; + + private ScaNamespaceHandler handler; + + public SCANamespaceHandlerResolver(ClassLoader classLoader) { + super(classLoader); + handler = new ScaNamespaceHandler(/*componentType*/); + } + + public SCANamespaceHandlerResolver(String handlerMappingsLocation, ClassLoader classLoader) { + super(classLoader, handlerMappingsLocation); + handler = new ScaNamespaceHandler(/*componentType*/); + } + + @Override + public NamespaceHandler resolve(String namespaceUri) { + if (SCA_NAMESPACE.equals(namespaceUri)) { + return handler; + } + return super.resolve(namespaceUri); + } +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaNamespaceHandler.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaNamespaceHandler.java new file mode 100644 index 0000000000..66cb3c76fc --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaNamespaceHandler.java @@ -0,0 +1,93 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.tuscany.sca.implementation.spring.namespace; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import javax.xml.namespace.QName; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Handler for the <sca:> namespace in an application context + * + * @version $Rev$ $Date$ + */ +public class ScaNamespaceHandler extends NamespaceHandlerSupport { + + public ScaNamespaceHandler() { + } + + @Override + public void init() { + registerBeanDefinitionParser("reference", new ScaReferenceBeanDefinitionParser()); + registerBeanDefinitionParser("service", new ScaServiceBeanDefinitionParser()); + registerBeanDefinitionParser("property", new ScaPropertyBeanDefinitionParser()); + } + + private static String getNamespaceURI(Element element, String prefix) { + if (element == null) { + return null; + } + String name = ("".equals(prefix)) ? "xmlns" : "xmlns:" + prefix; + String ns = element.getAttribute(name); + if (ns != null && !"".equals(ns)) { + return ns; + } + Node parent = element.getParentNode(); + if (parent instanceof Element) { + return getNamespaceURI((Element)parent, prefix); + } else { + return null; + } + } + + public static List<QName> resolve(Element element, String listOfNames) { + List<QName> qnames = new ArrayList<QName>(); + StringTokenizer tokenizer = new StringTokenizer(listOfNames); + while (tokenizer.hasMoreTokens()) { + String qname = tokenizer.nextToken(); + String prefix = ""; + String local = qname; + int index = qname.indexOf(':'); + if (index != -1) { + local = qname.substring(index + 1); + prefix = qname.substring(0, index); + } + String ns = getNamespaceURI(element, prefix); + if (ns != null) { + qnames.add(new QName(ns, local, prefix)); + } else { + throw new IllegalArgumentException("Prefix " + prefix + "is not bound to a namespace"); + } + } + return qnames; + } + + public static String getAttribute(Element element, String name) { + String attr = element.getAttributeNS(null, name); + if ("".equals(attr)) { + return null; + } else { + return attr; + } + } +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaPropertyBeanDefinitionParser.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaPropertyBeanDefinitionParser.java new file mode 100644 index 0000000000..bff0aa84e0 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaPropertyBeanDefinitionParser.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.tuscany.sca.implementation.spring.namespace; + +import org.apache.tuscany.sca.implementation.spring.SpringSCAPropertyElement; +import org.apache.tuscany.sca.implementation.spring.context.SCAGenericApplicationContext; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.w3c.dom.Element; + +/** + * Parser for the <sca:reference> element + * @version $Rev$ $Date$ + */ +public class ScaPropertyBeanDefinitionParser implements BeanDefinitionParser { + + public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinitionRegistry registry = parserContext.getRegistry(); + if (registry instanceof SCAGenericApplicationContext) { + SCAGenericApplicationContext context = (SCAGenericApplicationContext)registry; + SpringSCAPropertyElement propertyElement = + new SpringSCAPropertyElement(element.getAttributeNS(null, "name"), element.getAttributeNS(null, "type")); + context.addSCAPropertyElement(propertyElement); + } + // do nothing, this is handled by Tuscany + return null; + } +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaReferenceBeanDefinitionParser.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaReferenceBeanDefinitionParser.java new file mode 100644 index 0000000000..ab797c1e52 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaReferenceBeanDefinitionParser.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.tuscany.sca.implementation.spring.namespace; + +import static org.apache.tuscany.sca.implementation.spring.namespace.ScaNamespaceHandler.getAttribute; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.implementation.spring.SpringSCAReferenceElement; +import org.apache.tuscany.sca.implementation.spring.context.SCAGenericApplicationContext; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.w3c.dom.Element; + +/** + * Parser for the <sca:reference> element + * + * @version $Rev$ $Date$ + */ +public class ScaReferenceBeanDefinitionParser implements BeanDefinitionParser { + + public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinitionRegistry registry = parserContext.getRegistry(); + if (registry instanceof SCAGenericApplicationContext) { + SCAGenericApplicationContext context = (SCAGenericApplicationContext)registry; + SpringSCAReferenceElement referenceElement = + new SpringSCAReferenceElement(getAttribute(element, "name"), getAttribute(element, "type")); + referenceElement.setDefaultBean(getAttribute(element, "default")); + + String requires = getAttribute(element, "requires"); + if (requires != null) { + List<QName> qnames = ScaNamespaceHandler.resolve(element, requires); + referenceElement.getIntentNames().addAll(qnames); + } + + String policySets = getAttribute(element, "policySets"); + if (policySets != null) { + List<QName> qnames = ScaNamespaceHandler.resolve(element, policySets); + referenceElement.getPolicySetNames().addAll(qnames); + } + + context.addSCAReferenceElement(referenceElement); + } + + // do nothing, this is handled by Tuscany + return null; + } + +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaServiceBeanDefinitionParser.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaServiceBeanDefinitionParser.java new file mode 100644 index 0000000000..6a3beebcff --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/namespace/ScaServiceBeanDefinitionParser.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.tuscany.sca.implementation.spring.namespace; + +import static org.apache.tuscany.sca.implementation.spring.namespace.ScaNamespaceHandler.getAttribute; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.implementation.spring.SpringSCAServiceElement; +import org.apache.tuscany.sca.implementation.spring.context.SCAGenericApplicationContext; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.w3c.dom.Element; + +/** + * Parser for the <sca:service/> element + * + * @version $Rev$ $Date$ + */ +public class ScaServiceBeanDefinitionParser implements BeanDefinitionParser { + + public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinitionRegistry registry = parserContext.getRegistry(); + if (registry instanceof SCAGenericApplicationContext) { + SCAGenericApplicationContext context = (SCAGenericApplicationContext)registry; + SpringSCAServiceElement serviceElement = + new SpringSCAServiceElement(getAttribute(element, "name"), getAttribute(element, "target")); + serviceElement.setType(getAttribute(element, "type")); + + String requires = getAttribute(element, "requires"); + if (requires != null) { + List<QName> qnames = ScaNamespaceHandler.resolve(element, requires); + serviceElement.getIntentNames().addAll(qnames); + } + + String policySets = getAttribute(element, "policySets"); + if (policySets != null) { + List<QName> qnames = ScaNamespaceHandler.resolve(element, policySets); + serviceElement.getPolicySetNames().addAll(qnames); + } + + context.addSCAServiceElement(serviceElement); + } + // do nothing, handled by Tuscany + return null; + } + +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ComponentNameAnnotationProcessor.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ComponentNameAnnotationProcessor.java new file mode 100644 index 0000000000..68d49bbc24 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/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.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.lang.ref.Reference; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.oasisopen.sca.annotation.ComponentName; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + +public class ComponentNameAnnotationProcessor implements BeanPostProcessor { + + private Class<? extends Annotation> componentNameAnnotationType = ComponentName.class; + + private String componentName; + + public ComponentNameAnnotationProcessor(String componentName) { + this.componentName = componentName; + } + + /** + * Gets componentName annotation type. + */ + protected Class<? extends Annotation> getComponentNameAnnotationType() { + return this.componentNameAnnotationType; + } + + /** + * Sets componentName annotation type. + */ + public void setComponentNameAnnotationType(Class<? extends Annotation> 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; + } + + /** + * <p>Processes a beans fields for injection if it has a {@link Reference} annotation.</p> + */ + 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 = componentName; + 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 = componentName; + 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/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ConstructorAnnotationProcessor.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ConstructorAnnotationProcessor.java new file mode 100644 index 0000000000..a52a85ff3a --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ConstructorAnnotationProcessor.java @@ -0,0 +1,112 @@ +/* + * 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 java.lang.reflect.Constructor; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; +import org.springframework.util.Assert; + +public class ConstructorAnnotationProcessor extends InstantiationAwareBeanPostProcessorAdapter { + + private Class<? extends Annotation> constructorAnnotationType = org.oasisopen.sca.annotation.Constructor.class; + + private Class<? extends Annotation> 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<? extends Annotation> autowiredAnnotationType) { + Assert.notNull(autowiredAnnotationType, "'autowiredAnnotationType' must not be null"); + this.autowiredAnnotationType = autowiredAnnotationType; + } + + /** + * Return the 'autowired' annotation type. + */ + protected Class<? extends Annotation> getAutowiredAnnotationType() { + return this.autowiredAnnotationType; + } + + /** + * Return the 'constructor' annotation type. + */ + protected Class<? extends Annotation> getConstructorAnnotationType() { + return this.constructorAnnotationType; + } + + /** + * Sets the 'constructor' annotation type. + */ + public void setConstructorAnnotationType(Class<? extends Annotation> 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/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/InitDestroyAnnotationProcessor.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/InitDestroyAnnotationProcessor.java new file mode 100644 index 0000000000..477582b1d3 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/InitDestroyAnnotationProcessor.java @@ -0,0 +1,75 @@ +/* + * 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.oasisopen.sca.annotation.Destroy; +import org.oasisopen.sca.annotation.Init; +import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor; + +public class InitDestroyAnnotationProcessor extends InitDestroyAnnotationBeanPostProcessor { + + private static final long serialVersionUID = 0; + + private Class<? extends Annotation> initAnnotationType = Init.class; + private Class<? extends Annotation> destroyAnnotationType = Destroy.class; + + /** + * Gets init annotation type. + */ + protected Class<? extends Annotation> getInitAnnotationType() { + return this.initAnnotationType; + } + + /** + * Sets init annotation type. + */ + /* + * public void setInitAnnotationType(Class<? extends Annotation> + * initAnnotationType) { Assert.notNull(initAnnotationType, + * "Init annotation type must not be null."); this.initAnnotationType = + * initAnnotationType; } + */ + + /** + * Gets destroy annotation type. + */ + protected Class<? extends Annotation> getDestroyAnnotationType() { + return this.destroyAnnotationType; + } + + /** + * Sets destroy annotation type. + */ + /* + * public void setDestroyAnnotationType(Class<? extends Annotation> + * 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/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/PropertyAnnotationProcessor.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/PropertyAnnotationProcessor.java new file mode 100644 index 0000000000..4763714a38 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/PropertyAnnotationProcessor.java @@ -0,0 +1,164 @@ +/* + * 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.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.tuscany.sca.implementation.spring.provider.PropertyValueWrapper; +import org.oasisopen.sca.annotation.Property; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + +public class PropertyAnnotationProcessor implements BeanPostProcessor { + + private Class<? extends Annotation> propertyAnnotationType = Property.class; + + private PropertyValueWrapper propertyValue; + + public PropertyAnnotationProcessor(PropertyValueWrapper propertyValue) { + this.propertyValue = propertyValue; + } + + /** + * Gets property annotation type. + */ + protected Class<? extends Annotation> getPropertyAnnotationType() { + return this.propertyAnnotationType; + } + + /** + * Sets property annotation type. + */ + public void setPropertyAnnotationType(Class<? extends Annotation> 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; + } + + /** + * <p>Processes a beans fields for injection if it has a {@link Property} annotation.</p> + */ + protected void processAnnotation(final Object bean) { + + final Class<?> clazz = bean.getClass(); + + ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { + public void doWith(Method method) { + + 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, propertyValue.getPropertyObj(pd.getPropertyType(), pd.getName())); + } else { + injectProperty(bean, pd, propertyValue.getPropertyObj(pd.getPropertyType(), propName)); + } + } + } + } + }); + + ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() { + public void doWith(Field field) { + + 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 = propertyValue.getPropertyObj(field.getType(), field.getName()); + } else { + propertyObj = propertyValue.getPropertyObj(field.getType(), propName); + } + + if (propertyObj != null) + ReflectionUtils.setField(field, bean, 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); + } + } + } + +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ReferenceAnnotationProcessor.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ReferenceAnnotationProcessor.java new file mode 100644 index 0000000000..ad79db840e --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/ReferenceAnnotationProcessor.java @@ -0,0 +1,168 @@ +/* + * 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.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.tuscany.sca.implementation.spring.provider.ComponentWrapper; +import org.oasisopen.sca.annotation.Reference; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.FatalBeanException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + +public class ReferenceAnnotationProcessor implements BeanPostProcessor { + + private Class<? extends Annotation> referenceAnnotationType = Reference.class; + private ComponentWrapper component; + + public ReferenceAnnotationProcessor(ComponentWrapper component) { + this.component = component; + } + + /** + * Gets referece annotation type. + */ + protected Class<? extends Annotation> getReferenceAnnotationType() { + return this.referenceAnnotationType; + } + + /** + * Sets referece annotation type. + */ + public void setReferenceAnnotationType(Class<? extends Annotation> 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; + } + + /** + * <p>Processes a beans fields for injection if it has a {@link Reference} annotation.</p> + */ + protected void processAnnotation(final Object bean) { + + final Class<?> clazz = bean.getClass(); + + ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { + public void doWith(Method method) { + + 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) { + + 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.getService(field.getType(), field.getName()); + } else { + referenceObj = component.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.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); + } + } + } +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/SpringXMLBeanDefinitionLoaderImpl.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/SpringXMLBeanDefinitionLoaderImpl.java new file mode 100644 index 0000000000..6ba2c65ef0 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/processor/SpringXMLBeanDefinitionLoaderImpl.java @@ -0,0 +1,79 @@ +/* + * 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.net.URL; +import java.util.List; + +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.implementation.spring.SpringBeanElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAPropertyElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAReferenceElement; +import org.apache.tuscany.sca.implementation.spring.SpringSCAServiceElement; +import org.apache.tuscany.sca.implementation.spring.context.SCAGenericApplicationContext; +import org.apache.tuscany.sca.implementation.spring.xml.SpringXMLBeanDefinitionLoader; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.ApplicationContext; +import org.springframework.core.io.UrlResource; + +/** + * A tie that allows Tuscany to call Spring library to load the application context for the purpose of introspection + */ +public class SpringXMLBeanDefinitionLoaderImpl implements SpringXMLBeanDefinitionLoader { + + private static SCAGenericApplicationContext createApplicationContext(Object scaParentContext, + ClassLoader classLoader, + List<URL> resources) { + if (classLoader == null) { + classLoader = Thread.currentThread().getContextClassLoader(); + } + + SCAGenericApplicationContext appCtx = + new SCAGenericApplicationContext((ApplicationContext)scaParentContext, classLoader); + XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(appCtx); + + // REVIEW: [rfeng] How do we control the schema validation + xmlReader.setValidating(false); + + for (URL resource : resources) { + xmlReader.loadBeanDefinitions(new UrlResource(resource)); + } + + return appCtx; + + } + + @Override + public Object load(List<URL> resources, + List<SpringSCAServiceElement> serviceElements, + List<SpringSCAReferenceElement> referenceElements, + List<SpringSCAPropertyElement> propertyElements, + List<SpringBeanElement> beanElements, + ProcessorContext context) { + // FIXME: [rfeng] We should try to avoid parsing the Spring xml twice for the deployment and runtime + SCAGenericApplicationContext applicationContext = createApplicationContext(null, null, resources); + serviceElements.addAll(applicationContext.getServiceElements()); + referenceElements.addAll(applicationContext.getReferenceElements()); + propertyElements.addAll(applicationContext.getPropertyElements()); + beanElements.addAll(applicationContext.getBeanElements()); + return applicationContext; + } + +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/ComponentWrapper.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/ComponentWrapper.java new file mode 100644 index 0000000000..5bddd8a006 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/ComponentWrapper.java @@ -0,0 +1,38 @@ +/* + * 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.provider; + +/** + * Wrapper for the Component + */ +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +public class ComponentWrapper { + + private RuntimeComponent component; + + public ComponentWrapper(RuntimeComponent component) { + this.component = component; + } + + public Object getService(Class<?> type, String name) { + return component.getComponentContext().getService(type, name); + } +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/PropertyValueWrapper.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/PropertyValueWrapper.java new file mode 100644 index 0000000000..eca1492081 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/PropertyValueWrapper.java @@ -0,0 +1,50 @@ +/* + * 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.provider; + +import java.util.List; + +import org.apache.tuscany.sca.assembly.ComponentProperty; +import org.apache.tuscany.sca.context.PropertyValueFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; + +/** + * Wrapper for PropertyValue + */ +public class PropertyValueWrapper { + + private RuntimeComponent component; + private PropertyValueFactory propertyFactory; + + public PropertyValueWrapper(RuntimeComponent component, PropertyValueFactory propertyFactory) { + this.component = component; + this.propertyFactory = propertyFactory; + } + + public Object getPropertyObj(Class<?> type, String name) { + List<ComponentProperty> props = component.getProperties(); + for (ComponentProperty prop : props) { + if (prop.getName().equals(name)) { + return propertyFactory.createPropertyValue(prop, type); + } + } + return null; // property name not found + } +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringImplementationProvider.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringImplementationProvider.java new file mode 100644 index 0000000000..db7831322a --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringImplementationProvider.java @@ -0,0 +1,81 @@ +/* + * 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.provider; + +import org.apache.tuscany.sca.context.PropertyValueFactory; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.implementation.spring.context.SpringContextWrapper; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.springframework.context.ApplicationContext; + +/** + * A provider class for runtime Spring implementation instances + * @version $Rev$ $Date$ + */ +public class SpringImplementationProvider implements ImplementationProvider { + private RuntimeComponent component; + + // A Spring application context object + private SpringContextWrapper springContext; + + /** + * Constructor for the provider - takes a component definition and a Spring implementation + * description + * @param component - the component in the assembly + * @param implementation - the implementation + */ + public SpringImplementationProvider(RuntimeComponent component, + SpringImplementationWrapper implementation, + ApplicationContext parentApplicationContext, + ProxyFactory proxyService, + PropertyValueFactory propertyValueObjectFactory) { + super(); + this.component = component; + + springContext = new SpringContextWrapper(implementation, implementation.getResource()); + + } // end constructor + + public Invoker createInvoker(RuntimeComponentService service, Operation operation) { + return new SpringInvoker(component, springContext, service, operation); + } + + public boolean supportsOneWayInvocation() { + return false; + } + + /** + * Start this Spring implementation instance + */ + public void start() { + springContext.start(); + } + + /** + * Stop this implementation instance + */ + public void stop() { + springContext.close(); + } + +} // end class SpringImplementationProvider diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringImplementationProviderFactory.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringImplementationProviderFactory.java new file mode 100644 index 0000000000..be16fb3251 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringImplementationProviderFactory.java @@ -0,0 +1,78 @@ +/* + * 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.provider; + +import org.apache.tuscany.sca.context.PropertyValueFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.core.invocation.ExtensibleProxyFactory; +import org.apache.tuscany.sca.core.invocation.ProxyFactory; +import org.apache.tuscany.sca.implementation.spring.SpringImplementation; +import org.apache.tuscany.sca.implementation.spring.context.SpringApplicationContextAccessor; +import org.apache.tuscany.sca.provider.ImplementationProvider; +import org.apache.tuscany.sca.provider.ImplementationProviderFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.springframework.context.ApplicationContext; + +/** + * ImplementationProviderFactory for Spring implementation type + * @version $Rev$ $Date$ + * + */ +public class SpringImplementationProviderFactory implements ImplementationProviderFactory<SpringImplementation> { + private ProxyFactory proxyFactory; + private PropertyValueFactory propertyFactory; + private SpringApplicationContextAccessor contextAccessor; + + /** + * Simple constructor + * + */ + public SpringImplementationProviderFactory(ExtensionPointRegistry registry) { + super(); + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + contextAccessor = utilities.getUtility(SpringApplicationContextAccessor.class); + proxyFactory = ExtensibleProxyFactory.getInstance(registry); + propertyFactory = utilities.getUtility(PropertyValueFactory.class); + } + + /** + * Returns a SpringImplementationProvider for a given component and Spring implementation + * @param component the component for which implementation instances are required + * @param implementation the Spring implementation with details of the component + * implementation + * @return the SpringImplementationProvider for the specified component + */ + public ImplementationProvider createImplementationProvider(RuntimeComponent component, + SpringImplementation implementation) { + ApplicationContext parentApplicationContext = + (contextAccessor != null) ? contextAccessor.getParentApplicationContext() : null; + SpringImplementationWrapper tie = + new SpringImplementationWrapper(implementation, parentApplicationContext, component, propertyFactory); + return new SpringImplementationProvider(component, tie, parentApplicationContext, proxyFactory, propertyFactory); + } + + /** + * Returns the class of the Spring implementation + */ + public Class<SpringImplementation> getModelType() { + return SpringImplementation.class; + } + +} // end class SpringImplementationProviderFactory diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringImplementationWrapper.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringImplementationWrapper.java new file mode 100644 index 0000000000..e5593f5eaa --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringImplementationWrapper.java @@ -0,0 +1,158 @@ +/* + * 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.provider; + +import java.net.URL; +import java.util.List; + +import org.apache.tuscany.sca.assembly.ComponentProperty; +import org.apache.tuscany.sca.assembly.Property; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.context.PropertyValueFactory; +import org.apache.tuscany.sca.implementation.spring.SpringImplementation; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.springframework.context.ApplicationContext; + +/** + * Wrapper for SpringImplementation + */ +public class SpringImplementationWrapper { + + private SpringImplementation implementation; + private ApplicationContext parentApplicationContext; + private RuntimeComponent component; + private PropertyValueFactory propertyFactory; + + public SpringImplementationWrapper(SpringImplementation implementation, + ApplicationContext parentApplicationContext, + RuntimeComponent component, + PropertyValueFactory propertyFactory) { + this.implementation = implementation; + this.component = component; + this.propertyFactory = propertyFactory; + this.parentApplicationContext = parentApplicationContext; + } + + public String getURI() { + return implementation.getURI(); + } + + public List<URL> getResource() { + return implementation.getResource(); + } + + public String getComponentName() { + return component.getName(); + } + + /** + * Method to create a Java Bean for a Property value + * @param <B> the class type of the Bean + * @param requiredType - a Class object for the required type + * @param name - the Property name + * @return - a Bean of the specified property, with value set + */ + private <B> B getPropertyBean(Class<?> requiredType, String name) { + B propertyObject = null; + // Get the component's list of properties + List<ComponentProperty> 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 + propertyObject = (B)propertyFactory.createPropertyValue(prop, requiredType); + } // end if + } // end for + + return propertyObject; + } + + /** + * Creates a proxy Bean for a reference + * @param <B> the Business interface type for the reference + * @param businessInterface - the business interface as a Class + * @param referenceName - the name of the Reference + * @return an Bean of the type defined by <B> + */ + private <B> B getService(Class<B> businessInterface, String referenceName) { + return component.getComponentContext().getService(businessInterface, referenceName); + } + + /** + * Get a Bean for a reference or for a property. + * + * @param name - the name of the Bean required + * @param requiredType - the required type of the Bean (either a Java class or a Java interface) + * @return Object - a Bean which matches the requested bean + */ + public Object getBean(String name, Class<?> requiredType) { + // The expectation is that the requested Bean is either a reference or a property + // from the Spring context + for (Reference reference : implementation.getReferences()) { + if (reference.getName().equals(name)) { + // Extract the Java interface for the reference (it can't be any other interface type + // for a Spring application context) + if (requiredType == null) { + JavaInterface javaInterface = (JavaInterface)reference.getInterfaceContract().getInterface(); + requiredType = javaInterface.getJavaClass(); + } + // Create and return the proxy for the reference + return getService(requiredType, reference.getName()); + } // end if + } // end for + + // For a property, get the name and the required Java type and create a Bean + // of that type with the value inserted. + for (Property property : implementation.getProperties()) { + if (property.getName().equals(name)) { + if (requiredType == null) { + // The following code only deals with a subset of types and was superceded + // by the information from the implementation (which uses Classes as found + // in the Spring implementation itself. + //requiredType = JavaXMLMapper.getJavaType( property.getXSDType() ); + requiredType = implementation.getPropertyClass(name); + } + return getPropertyBean(requiredType, property.getName()); + } // end if + } // end for + // TODO: NoSuchBeanException + // throw new RuntimeException("Unable to find Bean with name " + name); + return null; + + } // end method getBean( String, Class ) + + public ComponentWrapper getComponentWrapper() { + return new ComponentWrapper(component); + } + + public PropertyValueWrapper getPropertyValueWrapper() { + return new PropertyValueWrapper(component, propertyFactory); + } + + public ClassLoader getClassLoader() { + return implementation.getClassLoader(); + } + + public ApplicationContext getParentApplicationContext() { + return parentApplicationContext; + } + +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringInvocationException.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringInvocationException.java new file mode 100644 index 0000000000..0e1d3f5b5a --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringInvocationException.java @@ -0,0 +1,40 @@ +/* + * 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.provider; + +/** + * @version $Rev$ $Date$ + */ +public class SpringInvocationException extends Exception { + + private static final long serialVersionUID = -1157790036638157513L; + + public SpringInvocationException(String msg) { + super(msg); + } + + public SpringInvocationException(Throwable e) { + super(e); + } + + public SpringInvocationException(String msg, Throwable e) { + super(msg, e); + } + +} diff --git a/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringInvoker.java b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringInvoker.java new file mode 100644 index 0000000000..ea1d6e6755 --- /dev/null +++ b/sca-java-2.x/tags/2.0-Beta1-RC2/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/provider/SpringInvoker.java @@ -0,0 +1,126 @@ +/* + * 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.provider; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.implementation.spring.SpringBeanElement; +import org.apache.tuscany.sca.implementation.spring.SpringImplementation; +import org.apache.tuscany.sca.implementation.spring.context.SpringContextWrapper; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.java.impl.JavaInterfaceUtil; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; + +/** + * Initial implementation of a Spring bean invoker + * @version $Rev$ $Date$ + */ +public class SpringInvoker implements Invoker { + + private Method theMethod = null; + private Object bean; + private SpringBeanElement beanElement; + private boolean badInvoker = false; + + private SpringContextWrapper springContext; + private Operation operation; + + /** + * SpringInvoker constructor + * @param component - the Spring component to invoke + * @param service - the service to invoke + * @param operation - the operation to invoke + */ + public SpringInvoker(RuntimeComponent component, + SpringContextWrapper springContext, + RuntimeComponentService service, + Operation operation) { + + this.springContext = springContext; + this.operation = operation; + + // From the component and the service, identify the Spring Bean which is the target + SpringImplementation theImplementation = (SpringImplementation)component.getImplementation(); + beanElement = theImplementation.getBeanFromService(service.getService()); + + if (beanElement == null) { + badInvoker = true; + return; + } + + } // end constructor SpringInvoker + + // Lazy-load the method to avoid timing problems with the Spring Context + private void setupMethod() throws SpringInvocationException { + try { + bean = springContext.getBean(beanElement.getId()); + Class<?> beanClass = bean.getClass(); + theMethod = JavaInterfaceUtil.findMethod(beanClass, operation); + //System.out.println("SpringInvoker - found method " + theMethod.getName() ); + } catch (NoSuchMethodException e) { + throw new SpringInvocationException(e); + } + } + + private Object doInvoke(Object payload) throws SpringInvocationException { + if (theMethod == null) + setupMethod(); + + if (badInvoker) + throw new SpringInvocationException("Spring invoker incorrectly configured"); + // Invoke the method on the Spring bean using the payload, returning the results + try { + Object ret; + + if (payload != null && !payload.getClass().isArray()) { + ret = theMethod.invoke(bean, payload); + } else { + ret = theMethod.invoke(bean, (Object[])payload); + } + return ret; + } catch (InvocationTargetException e) { + throw new SpringInvocationException("Spring invoker invoke method '" + theMethod.getName() + "' error.", + e.getCause()); + } catch (Exception e) { + throw new SpringInvocationException("Spring invoker invoke method '" + theMethod.getName() + "' error.", e); + } + + } // end method doInvoke + + /** + * @param msg the message to invoke on the target bean + */ + public Message invoke(Message msg) { + try { + Object resp = doInvoke(msg.getBody()); + msg.setBody(resp); + } catch (SpringInvocationException e) { + msg.setFaultBody(e.getCause()); + } catch (Throwable e) { + msg.setFaultBody(e); + } + //System.out.println("Spring Invoker - invoke called"); + return msg; + } // end method invoke + +} // end class SpringInvoker |