diff options
Diffstat (limited to '')
4 files changed, 529 insertions, 0 deletions
diff --git a/sca-java-2.x/branches/2.0-Beta1/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SCAGenericApplicationContext.java b/sca-java-2.x/branches/2.0-Beta1/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/branches/2.0-Beta1/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/branches/2.0-Beta1/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SCAParentApplicationContext.java b/sca-java-2.x/branches/2.0-Beta1/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/branches/2.0-Beta1/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/branches/2.0-Beta1/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SpringApplicationContextAccessor.java b/sca-java-2.x/branches/2.0-Beta1/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/branches/2.0-Beta1/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/branches/2.0-Beta1/modules/implementation-spring-runtime/src/main/java/org/apache/tuscany/sca/implementation/spring/context/SpringContextWrapper.java b/sca-java-2.x/branches/2.0-Beta1/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/branches/2.0-Beta1/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); + } + +} |