diff options
Diffstat (limited to '')
59 files changed, 4119 insertions, 0 deletions
diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/config/SCANamespaceHandlerResolver.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/config/SCANamespaceHandlerResolver.java new file mode 100644 index 0000000000..047d2b4ad1 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/config/SCANamespaceHandlerResolver.java @@ -0,0 +1,59 @@ +/* + * 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.container.spring.config; + +import org.apache.tuscany.spi.model.CompositeComponentType; + +import org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver; +import org.springframework.beans.factory.xml.NamespaceHandler; +import org.springframework.sca.config.ScaNamespaceHandler; + +/** + * Overrides the default Spring namespace resolver to automatically register {@link SCANamespaceHandler} instead of + * requiring a value to be supplied in a Spring configuration + * <p/> + * TODO: Figure out how to activate this impl + * + * @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, CompositeComponentType componentType) { + super(classLoader); + handler = new ScaNamespaceHandler(/*componentType*/); + } + + public SCANamespaceHandlerResolver(String handlerMappingsLocation, + ClassLoader classLoader, + CompositeComponentType componentType) { + super(classLoader, handlerMappingsLocation); + handler = new ScaNamespaceHandler(/*componentType*/); + } + + public NamespaceHandler resolve(String namespaceUri) { + if (SCA_NAMESPACE.equals(namespaceUri)) { + return handler; + } + return super.resolve(namespaceUri); + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/config/ScaApplicationContext.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/config/ScaApplicationContext.java new file mode 100644 index 0000000000..cdf33b0ea1 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/config/ScaApplicationContext.java @@ -0,0 +1,68 @@ +/* + * 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.container.spring.config; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.AbstractXmlApplicationContext; +import org.springframework.core.io.Resource; +import org.springframework.sca.ScaAdapterAware; +import org.springframework.sca.ScaAdapterPostProcessor; + +import org.apache.tuscany.container.spring.impl.SpringScaAdapter; +import org.apache.tuscany.container.spring.model.SpringComponentType; + +/** + * @author Andy Piper + * @since 2.1 + */ +public class ScaApplicationContext extends AbstractXmlApplicationContext { + public static final String APP_CONTEXT_PROP = "org.springframework.sca.application.context"; + private Resource appXml; + private SpringComponentType componentType; + + public ScaApplicationContext(Resource appXml, SpringComponentType componentType) { + this(null, appXml, componentType); + } + + public ScaApplicationContext(ApplicationContext parent, Resource appXml, SpringComponentType componentType) { + super(parent); + this.appXml = appXml; + this.componentType = componentType; + refresh(); + } + + protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { + // beanDefinitionReader.setEntityResolver(null); + beanDefinitionReader + .setNamespaceHandlerResolver(new SCANamespaceHandlerResolver(getClassLoader(), componentType)); + } + + protected Resource[] getConfigResources() { + return new Resource[]{appXml}; + } + + protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + super.postProcessBeanFactory(beanFactory); + beanFactory.addBeanPostProcessor(new ScaAdapterPostProcessor(new SpringScaAdapter(componentType))); + beanFactory.ignoreDependencyInterface(ScaAdapterAware.class); + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringComponentTypeLoader.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringComponentTypeLoader.java new file mode 100644 index 0000000000..fa815eee78 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringComponentTypeLoader.java @@ -0,0 +1,109 @@ +/* + * 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.container.spring.impl; + +import org.springframework.context.support.AbstractRefreshableApplicationContext; +import org.springframework.core.io.Resource; +import org.springframework.sca.ScaServiceExporter; + +import org.apache.tuscany.container.spring.config.ScaApplicationContext; +import org.apache.tuscany.container.spring.model.SpringComponentType; +import org.apache.tuscany.container.spring.model.SpringImplementation; +import org.apache.tuscany.spi.annotation.Autowire; +import org.apache.tuscany.spi.component.CompositeComponent; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.extension.ComponentTypeLoaderExtension; +import org.apache.tuscany.spi.loader.LoaderException; +import org.apache.tuscany.spi.loader.LoaderRegistry; +import org.apache.tuscany.host.RuntimeInfo; + +/** + * Loads a component type for a Spring <code>ApplicationContext</code>. The implementation creates a new instance of a + * Spring application context which is configured with SCA namespace handlers for generating component type information + * + * @version $$Rev$$ $$Date$$ + */ + +public class SpringComponentTypeLoader extends ComponentTypeLoaderExtension<SpringImplementation> { + public static final String SERVICE_BEAN_SUFFIX = ".SCAService"; + + private org.apache.tuscany.host.RuntimeInfo runtimeInfo; + + public SpringComponentTypeLoader(@Autowire LoaderRegistry loaderRegistry, @Autowire RuntimeInfo runtimeInfo) { + super(loaderRegistry); + this.runtimeInfo = runtimeInfo; + } + + @Override + protected Class<SpringImplementation> getImplementationClass() { + return SpringImplementation.class; + } + + /** + * Responsible for loading the Spring composite component type. The the application context is instantiated here as + * it is needed to derive component type information. Since the component type is loaded per SCDL entry (i.e. + * composite use) one application context instance will be created per Spring composite instance. + */ + @SuppressWarnings("unchecked") + public void load(CompositeComponent parent, + SpringImplementation implementation, + DeploymentContext deploymentContext) throws LoaderException { + if (implementation.getComponentType() != null) { + // FIXME hack since the builder registry loads the implementation type and the Spring implementation loader + // needs to as well. The second call is done by the builder registry and we just ignore it. + return; + } + Resource resource = implementation.getApplicationResource(); + SpringComponentType componentType = new SpringComponentType(); + // REVIEW andyp -- pass in deploymentContext.getClassLoader()? + AbstractRefreshableApplicationContext ctx; + if (runtimeInfo instanceof SpringRuntimeInfo) { + ctx = ((SpringRuntimeInfo) runtimeInfo).getApplicationContext(); + } else { + ctx = new ScaApplicationContext(resource, componentType); + } + componentType.setApplicationContext(ctx); // FIXME andyp@bea.com -- don't do this! + + // If there are <sca:service> elements, they define (and limit) the services exposed + // in the componentType. + String [] serviceBeanNames = ctx.getBeanNamesForType(ScaServiceExporter.class); + for (String serviceBeanName : serviceBeanNames) { + int nSuffix = serviceBeanName.indexOf(SERVICE_BEAN_SUFFIX); + if (nSuffix == -1) { + continue; + } + + String serviceName = serviceBeanName.substring(0, nSuffix); + ScaServiceExporter serviceBean = (ScaServiceExporter) ctx.getBean(serviceName); + // REVIEW andyp -- use the class directly? + String serviceTypeName = serviceBean.getServiceType().getName(); + try { + Class serviceInterface = Class.forName(serviceTypeName, true, deploymentContext.getClassLoader()); + componentType.addServiceType(serviceName, serviceInterface); + //ServiceDefinition service = createService(serviceInterface); + //componentType.getServices().put(serviceName, service); + } catch (ClassNotFoundException e) { + throw new LoaderException(e); + } + } + // if no service tags are specified, expose all beans + componentType.setExposeAllBeans(componentType.getServiceTypes().isEmpty()); + implementation.setComponentType(componentType); + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringCompositeBuilder.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringCompositeBuilder.java new file mode 100644 index 0000000000..6ec5d8fdd7 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringCompositeBuilder.java @@ -0,0 +1,88 @@ +/* + * 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.container.spring.impl; + +import org.apache.tuscany.spi.QualifiedName; +import org.apache.tuscany.spi.builder.BuilderConfigException; +import org.apache.tuscany.spi.component.Component; +import org.apache.tuscany.spi.component.CompositeComponent; +import org.apache.tuscany.spi.component.Reference; +import org.apache.tuscany.spi.component.Service; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.extension.ComponentBuilderExtension; +import org.apache.tuscany.spi.model.Binding; +import org.apache.tuscany.spi.model.BoundReferenceDefinition; +import org.apache.tuscany.spi.model.BoundServiceDefinition; +import org.apache.tuscany.spi.model.ComponentDefinition; +import org.apache.tuscany.spi.model.CompositeComponentType; +import org.apache.tuscany.spi.model.Property; +import org.apache.tuscany.spi.wire.InboundInvocationChain; +import org.apache.tuscany.spi.wire.InboundWire; + +import org.apache.tuscany.container.spring.model.SpringImplementation; +import org.springframework.context.support.AbstractApplicationContext; + +/** + * Creates a {@link org.apache.tuscany.container.spring.impl.SpringCompositeComponent} from an assembly model + * + * @version $$Rev$$ $$Date$$ + */ +public class SpringCompositeBuilder extends ComponentBuilderExtension<SpringImplementation> { + + public Component build(CompositeComponent parent, + ComponentDefinition<SpringImplementation> componentDefinition, + DeploymentContext deploymentContext) throws BuilderConfigException { + String name = componentDefinition.getName(); + SpringImplementation implementation = componentDefinition.getImplementation(); + AbstractApplicationContext applicationContext = implementation.getComponentType().getApplicationContext(); + SpringCompositeComponent component = + new SpringCompositeComponent(name, applicationContext, parent, connector, null); + CompositeComponentType<BoundServiceDefinition<? extends Binding>, + BoundReferenceDefinition<? extends Binding>, + ? extends Property> componentType = implementation.getComponentType(); + + // We still need to set the target invoker as opposed to having the connector do it since the + // Spring context is "opaque" to the wiring fabric. In other words, the Spring context does not expose + // its beans as SCA components to the connector to wire the services to + for (BoundServiceDefinition<? extends Binding> serviceDefinition : componentType.getServices().values()) { + // call back into builder registry to handle building of services + Service service = (Service) builderRegistry.build(parent, serviceDefinition, deploymentContext); + // wire serviceDefinition to bean invokers + InboundWire wire = service.getInboundWire(); + QualifiedName targetName = new QualifiedName(serviceDefinition.getTarget().getPath()); + for (InboundInvocationChain chain : wire.getInvocationChains().values()) { + // FIXME this should go to the connector and get policy and be invoked from SpringComposite.prepare() + chain.addInterceptor(new SpringInterceptor()); + chain.setTargetInvoker(component.createTargetInvoker(targetName.getPartName(), chain.getOperation())); + } + component.register(service); + } + for (BoundReferenceDefinition<?> referenceDefinition : componentType.getReferences().values()) { + // call back into builder registry to handle building of references + Reference reference = (Reference) builderRegistry.build(parent, referenceDefinition, deploymentContext); + connector.connect(reference); + component.register(reference); + } + return component; + } + + protected Class<SpringImplementation> getImplementationType() { + return SpringImplementation.class; + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringCompositeComponent.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringCompositeComponent.java new file mode 100644 index 0000000000..b30202cb96 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringCompositeComponent.java @@ -0,0 +1,252 @@ +/* + * 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.container.spring.impl; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Locale; +import java.util.Map; + +import org.w3c.dom.Document; + +import org.apache.tuscany.spi.builder.Connector; +import org.apache.tuscany.spi.component.CompositeComponent; +import org.apache.tuscany.spi.component.Reference; +import org.apache.tuscany.spi.component.SCAObject; +import org.apache.tuscany.spi.component.ScopeContainer; +import org.apache.tuscany.spi.component.Service; +import org.apache.tuscany.spi.extension.CompositeComponentExtension; +import static org.apache.tuscany.spi.idl.java.JavaIDLUtils.findMethod; +import org.apache.tuscany.spi.model.Operation; +import org.apache.tuscany.spi.model.ServiceContract; +import org.apache.tuscany.spi.wire.TargetInvoker; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanNotOfRequiredTypeException; +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.ConfigurableApplicationContext; +import org.springframework.context.MessageSourceResolvable; +import org.springframework.context.NoSuchMessageException; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.core.io.Resource; + +/** + * A composite implementation responsible for managing Spring application contexts. + * + * @version $$Rev$$ $$Date$$ + */ +public class SpringCompositeComponent extends CompositeComponentExtension { + private static final String[] EMPTY_ARRAY = new String[0]; + private AbstractApplicationContext springContext; + + /** + * Creates a new composite + * + * @param name the name of the SCA composite + * @param springContext the pre-instantiated Spring applicaiton context + * @param parent the SCA composite parent + * @param connector the connector to use for wiring children + * @param propertyValues the values of this composite's Properties + */ + public SpringCompositeComponent(String name, + AbstractApplicationContext springContext, + CompositeComponent parent, + Connector connector, + Map<String, Document> propertyValues) { + super(name, parent, connector, propertyValues); + SCAApplicationContext scaApplicationContext = new SCAApplicationContext(); + springContext.setParent(scaApplicationContext); + // REVIEW we need to refresh to pick up the parent but this is not optimal + springContext.refresh(); + this.springContext = springContext; + } + + public TargetInvoker createTargetInvoker(String targetName, Operation operation) { + ServiceContract contract = operation.getServiceContract(); + Method[] methods = contract.getInterfaceClass().getMethods(); + Method method = findMethod(operation, methods); + // FIXME test m == null + // Treat the serviceName as the Spring bean name to look up + return new SpringInvoker(targetName, method, springContext); + } + + public void setScopeContainer(ScopeContainer scopeContainer) { + // not needed + } + + public ConfigurableApplicationContext getApplicationContext() { + return springContext; + } + + public void prepare() { + // TODO handle only references with a composite binding + } + + public void start() { + super.start(); + for (SCAObject child : children.values()) { + child.start(); + } + springContext.start(); + } + + public void stop() { + super.stop(); + springContext.stop(); + } + + public <T> T locateService(Class<T> serviceInterface, String name) { + return serviceInterface.cast(springContext.getBean(name)); + } + + /** + * An inner class is required to act as the Spring application context parent as opposed to implementing the + * interface since the return types for {@link org.springframework.context.ApplicationContext#getParent()} and + * {@link org.apache.tuscany.spi.component.CompositeComponent#getParent()} clash + */ + private class SCAApplicationContext implements ApplicationContext { + + public Object getBean(String name) throws BeansException { + return getBean(name, null); + } + + public Object getBean(String name, Class requiredType) throws BeansException { + SCAObject object = children.get(name); // keep cast due to compiler error + if (object == null) { + return null; + } + Class<?> type; + if (object instanceof Reference) { + type = ((Reference) object).getInterface(); + } else if (object instanceof Service) { + type = ((Service) object).getInterface(); + } else { + throw new AssertionError("Illegal object type [" + name + "]"); + } + if (requiredType != null && requiredType.isAssignableFrom(type)) { + // need null check since Spring may pass in a null + throw new BeanNotOfRequiredTypeException(name, requiredType, type); + } + return object.getServiceInstance(); + } + + public boolean containsBean(String name) { + return children.get(name) != null; + } + + public boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + return children.get(name) != null; + } + + public Class getType(String name) throws NoSuchBeanDefinitionException { + return null; + } + + public String[] getAliases(String name) throws NoSuchBeanDefinitionException { + return EMPTY_ARRAY; + } + + public ApplicationContext getParent() { + return null; + } + + public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException { + return null; + } + + public String getDisplayName() { + return getName(); + } + + 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 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(); + } + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringImplementationLoader.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringImplementationLoader.java new file mode 100644 index 0000000000..c95375cad2 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringImplementationLoader.java @@ -0,0 +1,196 @@ +/* + * 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.container.spring.impl; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import javax.xml.namespace.QName; +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import static org.osoa.sca.Version.XML_NAMESPACE_1_0; + +import org.apache.tuscany.spi.annotation.Autowire; +import org.apache.tuscany.spi.component.CompositeComponent; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.extension.LoaderExtension; +import org.apache.tuscany.spi.loader.LoaderException; +import org.apache.tuscany.spi.loader.LoaderRegistry; +import org.apache.tuscany.spi.loader.MissingResourceException; +import org.apache.tuscany.spi.model.BoundReferenceDefinition; +import org.apache.tuscany.spi.model.BoundServiceDefinition; + +import org.apache.tuscany.container.spring.model.SpringComponentType; +import org.apache.tuscany.container.spring.model.SpringImplementation; +import org.apache.tuscany.host.RuntimeInfo; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; + +/** + * Loader for handling Spring <spring:implementation.spring> elements. + */ +public class SpringImplementationLoader extends LoaderExtension<SpringImplementation> { + private static final QName IMPLEMENTATION_SPRING = new QName("http://www.osoa.org/xmlns/sca/1.0", + "implementation.spring"); + + private static final String APPLICATION_CONTEXT = "application-context.xml"; + + private static final QName SERVICE_ELEMENT = new QName(XML_NAMESPACE_1_0, "service"); + private static final QName REFERENCE_ELEMENT = new QName(XML_NAMESPACE_1_0, "reference"); + + private final RuntimeInfo runtimeInfo; + + public SpringImplementationLoader(@Autowire LoaderRegistry registry, @Autowire RuntimeInfo runtimeInfo) { + super(registry); + this.runtimeInfo = runtimeInfo; + } + + public QName getXMLType() { + return IMPLEMENTATION_SPRING; + } + + @SuppressWarnings("unchecked") + public SpringImplementation load(CompositeComponent parent, + XMLStreamReader reader, + DeploymentContext deploymentContext) + throws XMLStreamException, LoaderException { + + String locationAttr = reader.getAttributeValue(null, "location"); + if (locationAttr == null && !contextProvided()) { + throw new MissingResourceException("No location supplied"); + } + + SpringImplementation implementation = new SpringImplementation(); + ClassLoader classLoader = deploymentContext.getClassLoader(); + if (!contextProvided()) { + implementation.setApplicationResource(getApplicationContextResource(locationAttr, classLoader)); + } + registry.loadComponentType(parent, implementation, deploymentContext); + SpringComponentType type = implementation.getComponentType(); + while (true) { + switch (reader.next()) { + case START_ELEMENT: + QName qname = reader.getName(); + if (SERVICE_ELEMENT.equals(qname)) { + BoundServiceDefinition service = + (BoundServiceDefinition) registry.load(parent, reader, deploymentContext); + if (!type.isExposeAllBeans()) { + String name = service.getName(); + if (!type.getServiceTypes().containsKey(name)) { + LoaderException e = new LoaderException("No service defined in Spring context for "); + e.setIdentifier(name); + throw e; + } + } + type.getDeclaredServices().put(service.getName(), service); + } else if (REFERENCE_ELEMENT.equals(qname)) { + BoundReferenceDefinition reference = + (BoundReferenceDefinition) registry.load(parent, reader, deploymentContext); + type.getDeclaredReferences().put(reference.getName(), reference); + } + break; + case END_ELEMENT: + if (IMPLEMENTATION_SPRING.equals(reader.getName())) { + return implementation; + } + } + } + } + + protected Resource getApplicationContextResource(String locationAttr, ClassLoader cl) throws LoaderException { + assert runtimeInfo != null; + File manifestFile = null; + File appXmlFile; + File locationFile = new File(locationAttr); + + if (!locationFile.isAbsolute()) { + locationFile = new File(runtimeInfo.getApplicationRootDirectory(), locationAttr); + } + if (!locationFile.exists()) { + // FIXME hack + URL url = cl.getResource(locationAttr); + if (url != null) { + return new UrlResource(url); + } + throw new MissingResourceException(locationFile.toString()); + } + + if (locationFile.isDirectory()) { + try { + manifestFile = new File(locationFile, "META-INF/MANIFEST.MF"); + if (manifestFile.exists()) { + Manifest mf = new Manifest(new FileInputStream(manifestFile)); + Attributes mainAttrs = mf.getMainAttributes(); + String appCtxPath = mainAttrs.getValue("Spring-Context"); + if (appCtxPath != null) { + appXmlFile = new File(locationFile, appCtxPath); + if (appXmlFile.exists()) { + return new UrlResource(appXmlFile.toURL()); + } + } + } + // no manifest-specified Spring context, use default + appXmlFile = new File(locationFile, APPLICATION_CONTEXT); + if (appXmlFile.exists()) { + return new UrlResource(appXmlFile.toURL()); + } + } catch (IOException e) { + throw new LoaderException("Error reading manifest " + manifestFile); + } + } else { + try { + JarFile jf = new JarFile(locationFile); + JarEntry je; + Manifest mf = jf.getManifest(); + if (mf != null) { + Attributes mainAttrs = mf.getMainAttributes(); + String appCtxPath = mainAttrs.getValue("Spring-Context"); + if (appCtxPath != null) { + je = jf.getJarEntry(appCtxPath); + if (je != null) { + // TODO return a Spring specific Resouce type for jars + return new UrlResource(new URL("jar:" + locationFile.toURL() + "!/" + appCtxPath)); + } + } + } + je = jf.getJarEntry(APPLICATION_CONTEXT); + if (je != null) { + return new UrlResource(new URL("jar:" + locationFile.toURI().toURL() + "!" + APPLICATION_CONTEXT)); + } + } catch (IOException e) { + // bad archive + // TODO: create a more appropriate exception type + throw new MissingResourceException(locationAttr, e); + } + } + throw new MissingResourceException(APPLICATION_CONTEXT); + } + + private boolean contextProvided() { + return runtimeInfo instanceof SpringRuntimeInfo; + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringInterceptor.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringInterceptor.java new file mode 100644 index 0000000000..fb7f0bd99c --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringInterceptor.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.container.spring.impl; + +import org.apache.tuscany.spi.wire.Interceptor; +import org.apache.tuscany.spi.wire.InvocationRuntimeException; +import org.apache.tuscany.spi.wire.Message; +import org.apache.tuscany.spi.wire.TargetInvoker; + +/** + * A temporary interceptor until the connector is updated + * + * @version $Rev$ $Date$ + */ +public class SpringInterceptor implements Interceptor { + + public Message invoke(Message msg) throws InvocationRuntimeException { + TargetInvoker invoker = msg.getTargetInvoker(); + if (invoker == null) { + throw new InvocationRuntimeException("No target invoker specified on message"); + } + return invoker.invoke(msg); + } + + public void setNext(Interceptor next) { + throw new IllegalStateException("This interceptor must be the last one in an target interceptor chain"); + } + + public Interceptor getNext() { + return null; + } + + public boolean isOptimizable() { + return true; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringInvoker.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringInvoker.java new file mode 100644 index 0000000000..6e05c888ae --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringInvoker.java @@ -0,0 +1,104 @@ +/* + * 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.container.spring.impl; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.tuscany.spi.component.TargetException; +import org.apache.tuscany.spi.wire.InvocationRuntimeException; +import org.apache.tuscany.spi.wire.Message; +import org.apache.tuscany.spi.wire.TargetInvoker; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; + +/** + * Dispatches to an operation on a Spring bean. Since Spring manages bean lifecycle and scope through resolution in the + * target proxy, the invoker can safely cache the target proxy. + * + * @version $$Rev$$ $$Date$$ + */ +public class SpringInvoker implements TargetInvoker { + private ApplicationContext springContext; + // default to true since Spring handles resolution + private boolean cacheable = true; + private String beanName; + private Method method; + // caching is thread-safe since Spring handles resolution + private Object bean; + + public SpringInvoker(String beanName, Method method, ApplicationContext context) { + this.beanName = beanName; + this.method = method; + springContext = context; + } + + public Object invokeTarget(final Object object) throws InvocationTargetException { + if (bean == null) { + try { + bean = springContext.getBean(beanName); + } catch (BeansException e) { + throw new TargetException(e); + } + } + try { + if (object != null && !object.getClass().isArray()) { + return method.invoke(bean, object); + } else { + return method.invoke(bean, (Object[]) object); + } + } catch (IllegalAccessException e) { + throw new InvocationTargetException(e); + } + } + + public Message invoke(Message msg) throws InvocationRuntimeException { + try { + Object resp = invokeTarget(msg.getBody()); + msg.setBody(resp); + } catch (InvocationTargetException e) { + msg.setBodyWithFault(e.getCause()); + } catch (Throwable e) { + msg.setBodyWithFault(e); + } + return msg; + } + + public boolean isCacheable() { + return cacheable; + } + + public void setCacheable(boolean cacheable) { + this.cacheable = cacheable; + } + + public boolean isOptimizable() { + return false; + } + + + public SpringInvoker clone() throws CloneNotSupportedException { + SpringInvoker invoker = (SpringInvoker) super.clone(); + invoker.bean = null; + return invoker; + } + + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringRuntimeInfo.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringRuntimeInfo.java new file mode 100644 index 0000000000..8b4f0ac905 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringRuntimeInfo.java @@ -0,0 +1,63 @@ +/* + * 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.container.spring.impl; + +import java.io.File; +import java.net.URL; + +import org.apache.tuscany.host.RuntimeInfo; +import org.springframework.context.support.AbstractRefreshableApplicationContext; + +/** + * @author Andy Piper + * @since 2.1 + */ +public class SpringRuntimeInfo implements RuntimeInfo { + private AbstractRefreshableApplicationContext applicationContext; + private File appRootDir; + + public SpringRuntimeInfo(File appRootDir, AbstractRefreshableApplicationContext applicationContext) { + this.appRootDir = appRootDir; + this.applicationContext = applicationContext; + } + + public AbstractRefreshableApplicationContext getApplicationContext() { + return applicationContext; + } + + public void setApplicationContext(AbstractRefreshableApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + public File getInstallDirectory() { + return null; + } + + public File getApplicationRootDirectory() { + return appRootDir; + } + + public URL getBaseURL() { + return null; + } + + public boolean isOnline() { + return true; + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringScaAdapter.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringScaAdapter.java new file mode 100644 index 0000000000..ca645db823 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/impl/SpringScaAdapter.java @@ -0,0 +1,54 @@ +/* + * 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.container.spring.impl; + +import org.apache.tuscany.container.spring.model.SpringComponentType; +import org.springframework.sca.ScaAdapter; + +/** + * @author Andy Piper + * @since 2.1 + */ +public class SpringScaAdapter implements ScaAdapter { + //private final SpringComponentType componentType; + + public SpringScaAdapter(SpringComponentType componentType) { + //this.componentType = componentType; + } + + public Object getServiceReference(String referenceName, Class referenceType, String moduleName, + String defaultServiceName) { + /* + ReferenceDefinition reference = null; + componentType.getReferences().put(referenceName, reference); + */ + return null; + } + + public Object getPropertyReference(String propertyName, Class propertyType, String moduleName) { + return null; + } + + public void publishAsService(Object serviceImplementation, Class serviceInterface, String serviceName, + String moduleName) { + /* + componentType.addServiceType(serviceName, serviceInterface); + ServiceDefinition service = null; + componentType.getServices().put(serviceName, service); + */ + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/model/SpringComponentType.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/model/SpringComponentType.java new file mode 100644 index 0000000000..d8758ffdb7 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/model/SpringComponentType.java @@ -0,0 +1,101 @@ +/* + * 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.container.spring.model; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.tuscany.spi.model.CompositeComponentType; +import org.apache.tuscany.spi.model.Property; +import org.apache.tuscany.spi.model.ReferenceDefinition; +import org.apache.tuscany.spi.model.ServiceDefinition; + +import org.springframework.context.support.AbstractApplicationContext; + +/** + * Component type information for a Spring composite component implementation type. A component type is associated with + * a Spring application context + * + * @version $Rev$ $Date$ + */ +public class SpringComponentType<S extends ServiceDefinition, + R extends ReferenceDefinition, + P extends Property<?>> extends CompositeComponentType<S, R, P> { + + private AbstractApplicationContext applicationContext; + private Map<String, Class<?>> serviceTypes = new HashMap<String, Class<?>>(); + private boolean exposeAllBeans; + + public SpringComponentType(AbstractApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + public SpringComponentType() { + } + + // FIXME andyp@bea.com -- this is a component type it should NOT contain bean instances! + + /** + * Returns the application context for the component type + */ + public AbstractApplicationContext getApplicationContext() { + return applicationContext; + } + + public void setApplicationContext(AbstractApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + /** + * Returns a collection of service types defined by <code>sca:service</code> elements in a Spring configuration. + * Service types define beans that can be targets of services defined in the SCDL Spring composite declaration. For + * each service type, there must be a corresponding service definition as part of the Spring composite declaration + * per the SCA specification. + */ + public Map<String, Class<?>> getServiceTypes() { + return serviceTypes; + } + + /** + * Adds a service type to the component declaration defined by <code>sca:service</code> elements in a Spring + * configuration. + * + * @param name the name of the service + * @param type the interface type of the target bean + */ + public void addServiceType(String name, Class<?> type) { + this.serviceTypes.put(name, type); + } + + /** + * Returns true if all beans in the Spring application context may be service targets or false if service types are + * defined + */ + public boolean isExposeAllBeans() { + return exposeAllBeans; + } + + /** + * Sets if all beans in the Spring application context may be service targets or false if service types are defined + */ + public void setExposeAllBeans(boolean exposeAllBeans) { + this.exposeAllBeans = exposeAllBeans; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/model/SpringImplementation.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/model/SpringImplementation.java new file mode 100644 index 0000000000..7780894f56 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/model/SpringImplementation.java @@ -0,0 +1,77 @@ +/* + * 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.container.spring.model; + +import org.apache.tuscany.spi.model.Binding; +import org.apache.tuscany.spi.model.BoundReferenceDefinition; +import org.apache.tuscany.spi.model.BoundServiceDefinition; +import org.apache.tuscany.spi.model.Implementation; +import org.apache.tuscany.spi.model.Property; + +import org.springframework.core.io.Resource; + +/** + * Represents a composite whose implementation type is a Spring application context. + * + * @version $$Rev$$ $$Date$$ + */ +public class SpringImplementation extends Implementation<SpringComponentType<BoundServiceDefinition<? extends Binding>, + BoundReferenceDefinition<? extends Binding>, ? extends Property>> { + + private String location; + private Resource applicationResource; + + public SpringImplementation() { + } + + public SpringImplementation(SpringComponentType< + BoundServiceDefinition<? extends Binding>, + BoundReferenceDefinition<? extends Binding>, + ? extends Property> componentType) { + super(componentType); + } + + /** + * Returns the path of the Spring application context configuration + */ + public String getLocation() { + return location; + } + + /** + * Sets the path of the Spring application context configuration + */ + public void setLocation(String location) { + this.location = location; + } + + /** + * Returns the Spring configuration resource for the application context + */ + public Resource getApplicationResource() { + return applicationResource; + } + + /** + * Sets the Spring configuration resource for the application context + */ + public void setApplicationResource(Resource applicationXml) { + this.applicationResource = applicationXml; + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/model/SpringServiceContract.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/model/SpringServiceContract.java new file mode 100644 index 0000000000..3a88991e4b --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/model/SpringServiceContract.java @@ -0,0 +1,31 @@ +/* + * 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.container.spring.model; + +import org.apache.tuscany.spi.model.ServiceContract; + +/** + * @version $Rev$ $Date$ + */ +public class SpringServiceContract extends ServiceContract { + + public SpringServiceContract(String interfaceName) { + super(interfaceName); + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/webapp/ScaWebApplicationContext.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/webapp/ScaWebApplicationContext.java new file mode 100644 index 0000000000..2284d32201 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/webapp/ScaWebApplicationContext.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.container.spring.webapp; + +import java.io.File; +import java.net.URL; + +import javax.servlet.ServletContext; + +import org.apache.tuscany.api.TuscanyRuntimeException; +import org.apache.tuscany.container.spring.config.SCANamespaceHandlerResolver; +import org.apache.tuscany.container.spring.impl.SpringScaAdapter; +import org.apache.tuscany.container.spring.model.SpringComponentType; +import org.apache.tuscany.runtime.webapp.WebappRuntime; +import org.apache.tuscany.runtime.webapp.WebappUtil; +import org.apache.tuscany.runtime.webapp.WebappUtilImpl; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.Resource; +import org.springframework.sca.ScaAdapterAware; +import org.springframework.sca.ScaAdapterPostProcessor; +import org.springframework.util.Assert; +import org.springframework.web.context.ConfigurableWebApplicationContext; +import org.springframework.web.context.support.XmlWebApplicationContext; + +/** + * WebApplicationContext implementation that understands SCA extensions. + * This class is not very complicated, the key issue is getting hold of a reference + * to the Tuscany runtime which the webapp is using. + * + * @author Andy Piper + */ +public class ScaWebApplicationContext extends XmlWebApplicationContext + implements ConfigurableWebApplicationContext { + private WebappRuntime runtime; + private SpringComponentType componentType; + + public ScaWebApplicationContext() { + } + + protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { +// beanDefinitionReader.setEntityResolver(null); + beanDefinitionReader + .setNamespaceHandlerResolver(new SCANamespaceHandlerResolver(getClassLoader(), componentType)); + } + + public Resource getResource(String location) { + Assert.notNull(location, "location is required"); + return super.getResource(location); + } + + /* (non-Javadoc) + * @see org.springframework.context.support.AbstractApplicationContext#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) + */ + protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + super.postProcessBeanFactory(beanFactory); + beanFactory.addBeanPostProcessor(new ScaAdapterPostProcessor + (new SpringScaAdapter(componentType))); + beanFactory.ignoreDependencyInterface(ScaAdapterAware.class); + } + + protected void onRefresh() { + if (runtime != null) { // egregious hack to prevent recursion in refresh() + return; + } + ServletContext servletContext = getServletContext(); + WebappUtil utils = getUtils(servletContext); + + try { + ClassLoader webappClassLoader = Thread.currentThread().getContextClassLoader(); + ClassLoader bootClassLoader = utils.getBootClassLoader(webappClassLoader); + runtime = utils.getRuntime(bootClassLoader); + URL systemScdl = utils.getSystemScdl(bootClassLoader); + URL applicationScdl = utils.getApplicationScdl(webappClassLoader); + + runtime.setMonitorFactory(runtime.createDefaultMonitorFactory()); + runtime.setApplicationName(utils.getApplicationName()); + runtime.setServletContext(servletContext); + runtime.setHostClassLoader(webappClassLoader); + runtime.setSystemScdl(systemScdl); + runtime.setApplicationScdl(applicationScdl); + runtime.setRuntimeInfo(new SpringWebappRuntimeInfo(getApplicationRootDirectory(), this)); + runtime.initialize(); + } catch (TuscanyRuntimeException e) { + servletContext.log(e.getMessage(), e); + throw e; + } + } + + protected WebappUtil getUtils(ServletContext servletContext) { + return new WebappUtilImpl(servletContext); + } + + protected void onClose() { + if (runtime != null) { + runtime.destroy(); + runtime = null; + } + } + + /** + * What does this do and why to we need it? + * @return + */ + private File getApplicationRootDirectory() { + String property = System.getProperty("tuscany.applicationRootDir"); + if (property != null) { + return new File(property); + } + + return new File(System.getProperty("user.dir")); + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/webapp/SpringWebappRuntimeInfo.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/webapp/SpringWebappRuntimeInfo.java new file mode 100644 index 0000000000..a860049462 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/apache/tuscany/container/spring/webapp/SpringWebappRuntimeInfo.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.container.spring.webapp; + +import java.io.File; +import javax.servlet.ServletContext; + +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.XmlWebApplicationContext; + +import org.apache.tuscany.container.spring.impl.SpringRuntimeInfo; +import org.apache.tuscany.runtime.webapp.WebappRuntimeInfo; + +/** + * @author Andy Piper + */ +public class SpringWebappRuntimeInfo extends SpringRuntimeInfo implements WebappRuntimeInfo { + public SpringWebappRuntimeInfo(File appRootDir, XmlWebApplicationContext applicationContext) { + super(appRootDir, applicationContext); + } + + public ServletContext getServletContext() { + return ((WebApplicationContext) getApplicationContext()).getServletContext(); + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/DefaultScaAdapter.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/DefaultScaAdapter.java new file mode 100644 index 0000000000..e2071e27c3 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/DefaultScaAdapter.java @@ -0,0 +1,46 @@ +/* + * 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. + * + * Created on 11-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +public class DefaultScaAdapter implements ScaAdapter { + + public Object getServiceReference(String referenceName, + Class referenceType, + String moduleName, + String defaultServiceName) { + // TODO + return new Object(); + } + + public Object getPropertyReference(String propertyName, Class propertyType, String moduleName) { + // TODO + return new Object(); + } + + public void publishAsService(Object serviceImplementation, + Class serviceInterface, + String serviceName, + String moduleName) { + // TODO + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaAdapter.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaAdapter.java new file mode 100644 index 0000000000..e5aae6f0a2 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaAdapter.java @@ -0,0 +1,45 @@ +/* + * 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. + * + * Created on 11-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca; + +/** + * Encapsulates interaction with an SCA runtime + * + * @author Adrian Colyer + * @since 2.0 + */ +public interface ScaAdapter { + + Object getServiceReference( + String referenceName, + Class referenceType, + String moduleName, + String defaultServiceName); + + Object getPropertyReference( + String propertyName, + Class propertyType, + String moduleName); + + void publishAsService( + Object serviceImplementation, + Class serviceInterface, + String serviceName, + String moduleName); + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaAdapterAware.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaAdapterAware.java new file mode 100644 index 0000000000..abe975c936 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaAdapterAware.java @@ -0,0 +1,31 @@ +/* + * 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.springframework.sca; + +/** + * /** Interface that enables beans to find the ScaAdapter they are defined with. + * <p/> + * Note that in most circumstances there is no need for a bean to implement this interface. + * + * @author Andy Piper + * @since 2.1 + */ +public interface ScaAdapterAware { + void setScaAdapter(ScaAdapter adapter); +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaAdapterPostProcessor.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaAdapterPostProcessor.java new file mode 100644 index 0000000000..b07be8f452 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaAdapterPostProcessor.java @@ -0,0 +1,52 @@ +/* + * 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.springframework.sca; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +/** + * @author Andy Piper + * @since 2.1 + */ +public class ScaAdapterPostProcessor implements BeanPostProcessor { + private ScaAdapter scaAdapter; + + public ScaAdapterPostProcessor(ScaAdapter adapter) { + this.scaAdapter = adapter; + } + + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof ScaAdapterAware) { + if (this.scaAdapter == null) { + throw new IllegalStateException("Cannot satisfy ScaAdapterAware for bean '" + + beanName + "' without ScaAdapater"); + } + ((ScaAdapterAware) bean).setScaAdapter(scaAdapter); + } + return bean; + } + + public Object postProcessAfterInitialization(Object object, String string) throws BeansException { + return object; + } + + public ScaAdapter getScaAdapter() { + return scaAdapter; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaComposite.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaComposite.java new file mode 100644 index 0000000000..e12e763d9f --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaComposite.java @@ -0,0 +1,77 @@ +/* + * 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. + * + * Created on 10-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca; + +import org.springframework.beans.factory.InitializingBean; + +/** + * Bean that represents an Sca composite component. An instance of this bean is created when the <sca:composite + * module-id="xxx"/> element is declared. + * + * @author Adrian Colyer + * @since 2.0 + */ +public class ScaComposite implements InitializingBean { + + private String component; + private ScaAdapter scaAdapter = new DefaultScaAdapter(); + + public String getComponent() { + return this.component; + } + + public void setComponent(String component) { + this.component = component; + } + + public void setScaAdapter(ScaAdapter scaAdapter) { + this.scaAdapter = scaAdapter; + } + + public void setScaAdapterClass(Class adapterClass) { + if (!ScaAdapter.class.isAssignableFrom(adapterClass)) { + throw new IllegalArgumentException( + "Adapter class '" + adapterClass + "' specified for ScaComposite bean " + + "does not implement the ScaApapter interface" + ); + } + try { + this.scaAdapter = (ScaAdapter) adapterClass.newInstance(); + } catch (Exception ex) { + // many exceptions may be thrown by the above, we treat them all + // the same + throw new IllegalStateException("Unable to create instance of ScaAdapter class '" + + adapterClass.getName() + "'", ex); + } + } + + public ScaAdapter getScaAdapter() { + return this.scaAdapter; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception { + if (this.component == null) { + throw new IllegalArgumentException("Required property moduleId was not set"); + } + } + + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaPostProcessor.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaPostProcessor.java new file mode 100644 index 0000000000..f96af00584 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaPostProcessor.java @@ -0,0 +1,147 @@ +/* + * 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.springframework.sca; + +import java.beans.PropertyDescriptor; + +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.core.task.TaskExecutor; +import org.springframework.sca.intercept.OneWayAdvisor; +import org.springframework.sca.metadata.DeploymentMetadata; +import org.springframework.sca.metadata.Injection; +import org.springframework.sca.metadata.NoSuchServiceException; +import org.springframework.sca.metadata.ServiceMetadata; + +/** + * Spring bean post processor that looks up service metadata by name for each bean definition and performs SCA + * injection. + * <p/> + * Also performs proxying for OneWay. + * + * @author Rod Johnson + */ +public class ScaPostProcessor implements InstantiationAwareBeanPostProcessor, ApplicationContextAware { + + private DeploymentMetadata deploymentMetadata; + + private ApplicationContext applicationContext; + + private TaskExecutor taskExecutor; + + //private ScaAdapter scaAdapter; + + + /** + * @param taskExecutor The taskExecutor to set. + */ + public void setTaskExecutor(TaskExecutor taskExecutor) { + this.taskExecutor = taskExecutor; + } + + // TODO would process side files when container starts up + + public void setDeploymentMetadata(DeploymentMetadata deploymentMetadata) { + this.deploymentMetadata = deploymentMetadata; + } + + /** + * @param scaAdapter the ScaAdapter for use to export services if necessary + */ + public void setScaAdapter(ScaAdapter scaAdapter) { + //this.scaAdapter = scaAdapter; + } + + + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + public Object postProcessBeforeInstantiation(Class beanClass, + String beanName) throws BeansException { + return null; + } + + public boolean postProcessAfterInstantiation(Object bean, String beanName) + throws BeansException { + try { + ServiceMetadata smd = deploymentMetadata.getServiceMetadata(beanName); + doScaInjection(bean, smd); + } catch (NoSuchServiceException ex) { + // + } + return true; + } + + public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, + String beanName) throws BeansException { + return pvs; + } + + public PropertyValues postProcessPropertyValues(PropertyValues propertyValues, Object object, String string) + throws BeansException { + return propertyValues; + } + + protected void doScaInjection(Object bean, ServiceMetadata smd) { + for (Injection injection : smd.getInjections()) { + injection.apply(applicationContext, bean); + } + } + + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + try { + ServiceMetadata smd = deploymentMetadata.getServiceMetadata(beanName); + return createScaProxy(bean, smd); + } catch (NoSuchServiceException ex) { + return bean; + } + + // TODO validate required injections here or earlier + + // TODO publish if necessary, using adapter + } + + protected Object createScaProxy(Object bean, ServiceMetadata smd) { + ProxyFactory pf = new ProxyFactory(bean); + for (Class intf : smd.getServiceInterfaces()) { + pf.addInterface(intf); + } + +//pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR); +//pf.addAdvisor(new ExposeBeanNameAdvisor(smd.getServiceName())); + // TODO enforce call by value + + if (!smd.getOneWayMethods().isEmpty()) { + pf.addAdvisor(new OneWayAdvisor(smd, this.taskExecutor)); + } + + return pf.getProxy(); + } + + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaPropertyProxyFactoryBean.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaPropertyProxyFactoryBean.java new file mode 100644 index 0000000000..e89072466a --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaPropertyProxyFactoryBean.java @@ -0,0 +1,123 @@ +/* + * 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. + * + * Created on 10-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; + +/** + * Factory bean that returns a reference to an SCA property obtained by asking the SCA runtime for the property with the + * given name for the given component. + * + * @author Adrian Colyer + * @since 2.0 + */ +public class ScaPropertyProxyFactoryBean implements InitializingBean, FactoryBean { + + /** + * the type of the property + */ + private Class propertyType; + + /** + * the name of the property to look up + */ + private String propertyName; + + /** + * the SCA component we should present ourselves as when asking for a service reference + */ + private ScaComposite scaComposite; + + private Object resolvedPropertyVal; + + public void setPropertyType(Class serviceType) { + this.propertyType = serviceType; + } + + public Class getPropertyType() { + return this.propertyType; + } + + public void setPropertyName(String name) { + this.propertyName = name; + } + + public String getPropertyName() { + return this.propertyName; + } + + public void setScaComposite(ScaComposite scaComposite) { + this.scaComposite = scaComposite; + } + + public ScaComposite getScaComposite() { + return this.scaComposite; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception { + if (this.propertyType == null) { + throw new IllegalArgumentException("Required property serviceType was not set"); + } + if (this.scaComposite == null) { + throw new IllegalArgumentException("Required property scaComposite was not set"); + } + if (this.propertyName == null) { + throw new IllegalArgumentException("Required property referenceName was not set"); + } + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#getObject() + */ + public Object getObject() throws Exception { + if (this.resolvedPropertyVal != null) { + return this.resolvedPropertyVal; + } + + String moduleName = this.scaComposite.getComponent(); + // TODO: AMC is there any merit in proxying this with a lazy target source? + Object propertyVal = + this.scaComposite.getScaAdapter().getPropertyReference(this.propertyName, this.propertyType, moduleName); + if (!this.propertyType.isAssignableFrom(propertyVal.getClass())) { + throw new IllegalStateException("Property value '" + propertyVal.toString() + "'" + + " of type '" + propertyVal.getClass().getName() + "' " + + " is not of expected type '" + this.propertyType.getName() + "'"); + } + this.resolvedPropertyVal = propertyVal; + return this.resolvedPropertyVal; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#getObjectType() + */ + public Class getObjectType() { + return this.propertyType; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#isSingleton() + */ + public boolean isSingleton() { + return true; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaServiceExporter.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaServiceExporter.java new file mode 100644 index 0000000000..0155dd9646 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaServiceExporter.java @@ -0,0 +1,105 @@ +/* + * 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. + * + * Created on 10-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.InitializingBean; + +/** + * Exposes a bean instance to SCA to using the given service name. + * + * @author Adrian Colyer + * @since 2.0 + */ +public class ScaServiceExporter implements InitializingBean, BeanFactoryAware, ScaAdapterAware { + + /** + * the name of the service we want to advertise + */ + private String serviceName; + + /** + * the type the service should be published with + */ + private Class serviceType; + + /** + * the bean to be published + */ + private Object target; + + /** + * for resolving the bean name + */ + private BeanFactory beanFactory; + private ScaAdapter scaAdapter; + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public String getServiceName() { + return this.serviceName; + } + + public void setServiceType(Class serviceType) { + this.serviceType = serviceType; + } + + public Class getServiceType() { + return this.serviceType; + } + + public void setTarget(Object targetBean) { + this.target = targetBean; + } + + public Object getTarget() { + return this.target; + } + + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + + public void afterPropertiesSet() throws Exception { + if (this.serviceType == null) { + throw new IllegalArgumentException("Required property serviceType was not set"); + } + if (this.target == null) { + throw new IllegalArgumentException("Required property target was not set"); + } + if (this.beanFactory == null) { + throw new IllegalArgumentException("Required property beanFactory was not set"); + } + if (this.serviceName == null) { + throw new IllegalArgumentException("Required property serviceName was not set"); + } + publishScaService(); + } + + private void publishScaService() { + scaAdapter.publishAsService(target, serviceType, serviceName, null); + } + + public void setScaAdapter(ScaAdapter adapter) { + this.scaAdapter = adapter; + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaServiceProxyFactoryBean.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaServiceProxyFactoryBean.java new file mode 100644 index 0000000000..01ca5671d4 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/ScaServiceProxyFactoryBean.java @@ -0,0 +1,144 @@ +/* + * 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. + * + * Created on 10-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * Factory bean that returns a reference to an SCA service obtained by asking the SCA runtime for the service with the + * given name for the given component. + * + * @author Adrian Colyer + * @since 2.0 + */ +public class ScaServiceProxyFactoryBean + implements InitializingBean, FactoryBean, ApplicationContextAware, ScaAdapterAware { + + /** + * the public interface type of the service (may be a class...) + */ + private Class serviceType; + + /** + * the name of the reference to look up + */ + private String referenceName; + + /** + * the default service name to resolve the reference too + */ + private String defaultServiceName; + + private Object resolvedServiceReference; + private ApplicationContext applicationContext; + //private ScaAdapter scaAdapter; + + public void setServiceType(Class serviceType) { + this.serviceType = serviceType; + } + + public Class getServiceType() { + return this.serviceType; + } + + public void setReferenceName(String name) { + this.referenceName = name; + } + + public String getReferenceName() { + return this.referenceName; + } + + public void setDefaultServiceName(String defaultService) { + this.defaultServiceName = defaultService; + } + + public String getDefaultServiceName() { + return this.defaultServiceName; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception { + if (this.serviceType == null) { + throw new IllegalArgumentException("Required property serviceType was not set"); + } + if (this.referenceName == null) { + throw new IllegalArgumentException("Required property referenceName was not set"); + } + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#getObject() + */ + public Object getObject() throws Exception { + if (this.resolvedServiceReference != null) { + return this.resolvedServiceReference; + } + + // TODO: AMC is there any merit in proxying this with a lazy target source? + // should the returned service ref be proxied? Only seems to add value + // if SCA gives us any lifecycle events we can subscribe to and take + // meaningful action on... + // See OsgiServiceProxyFactoryBean for an example of how to do the + // proxying if needed. + Object scaServiceRef; + if (this.applicationContext.getParent() == null) { + return null; + } + + if (!this.applicationContext.getParent().containsBean(this.referenceName)) { + return new Object(); + //scaServiceRef = this.applicationContext.getParent().getBean(this.defaultServiceName); + } else { + scaServiceRef = this.applicationContext.getParent().getBean(this.referenceName); + } + if (!this.serviceType.isAssignableFrom(scaServiceRef.getClass())) { + throw new IllegalStateException("..."); + } + this.resolvedServiceReference = scaServiceRef; + return this.resolvedServiceReference; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#getObjectType() + */ + public Class getObjectType() { + return this.serviceType; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#isSingleton() + */ + public boolean isSingleton() { + return false; + } + + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + public void setScaAdapter(ScaAdapter adapter) { + // this.scaAdapter = adapter; + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaCompositeBeanDefinitionParser.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaCompositeBeanDefinitionParser.java new file mode 100644 index 0000000000..9c6ac633f7 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaCompositeBeanDefinitionParser.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. + * + * Created on 10-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.sca.ScaComposite; + +/** + * Parser for <sca:composite> elements + * + * @author Adrian Colyer + * @since 2.0 + */ +public class ScaCompositeBeanDefinitionParser implements BeanDefinitionParser { + + static final String SCA_COMPOSITE_BEAN_NAME = "scaComposite"; + private static final String MODULE_ATTRIBUTE_NAME = "component"; + private static final String MODULE_ID = "component"; + private static final String ADAPTER_ATTRIBUTE = "sca-adapter-class"; + private static final String ADAPTER_CLASS_PROPERTY = "scaAdapterClass"; + + public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinitionRegistry registry = parserContext.getRegistry(); + if (registry.containsBeanDefinition(SCA_COMPOSITE_BEAN_NAME)) { + throw new IllegalArgumentException( + "At most one <sca:composite> element can be declared in a bean factory"); + } + BeanDefinition beanDef = createScaCompositeBeanDefinition(element); + registry.registerBeanDefinition(SCA_COMPOSITE_BEAN_NAME, beanDef); + return beanDef; + } + + private BeanDefinition createScaCompositeBeanDefinition(Element element) { + RootBeanDefinition beanDefinition = new RootBeanDefinition(); + beanDefinition.setBeanClass(ScaComposite.class); + MutablePropertyValues props = new MutablePropertyValues(); + props.addPropertyValue(MODULE_ID, element.getAttribute(MODULE_ATTRIBUTE_NAME)); + if (element.hasAttribute(ADAPTER_ATTRIBUTE)) { + props.addPropertyValue(ADAPTER_CLASS_PROPERTY, element.getAttribute(ADAPTER_ATTRIBUTE)); + } + beanDefinition.setPropertyValues(props); + return beanDefinition; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaContextBuilder.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaContextBuilder.java new file mode 100644 index 0000000000..3446aaf462 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaContextBuilder.java @@ -0,0 +1,68 @@ +/* + * 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. + * + * Created on 10-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca.config; + +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.sca.ScaAdapter; +import org.springframework.sca.ScaComposite; + +/** + * @author Hal Hildebrand Date: Apr 11, 2006 Time: 4:33:33 PM + */ +public class ScaContextBuilder { + private static final String MODULE_ID = "moduleId"; + + private static final String SCA_ADAPTER = "scaAdapter"; + + private static final String SCA_COMPOSITE_BEAN_NAME = "scaComposite"; + + private String moduleId; + + private ScaAdapter scaAdapter; + + public String getModuleId() { + return this.moduleId; + } + + public void setModuleId(String moduleId) { + this.moduleId = moduleId; + } + + public void setScaAdapter(ScaAdapter scaAdapter) { + this.scaAdapter = scaAdapter; + } + + public ScaAdapter getScaAdapter() { + return this.scaAdapter; + } + + public ApplicationContext construct() { + GenericApplicationContext parent = new GenericApplicationContext(); + BeanDefinition bd = new RootBeanDefinition(ScaComposite.class, true); + + bd.getPropertyValues().addPropertyValue(new PropertyValue(MODULE_ID, moduleId)); + bd.getPropertyValues().addPropertyValue(new PropertyValue(SCA_ADAPTER, scaAdapter)); + parent.registerBeanDefinition(SCA_COMPOSITE_BEAN_NAME, bd); + parent.refresh(); + return parent; + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaNamespaceHandler.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaNamespaceHandler.java new file mode 100644 index 0000000000..878267813a --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaNamespaceHandler.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. + * + * Created on 10-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca.config; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +/** + * Handler for the <sca:> namespace. Handles: <ul> <li><sca:composite module="xxxxx"/></li> + * <li><sca:reference name="xxx" type="yyy" default-service="zzz"/></li> <li><sca:property name="xxx" + * type="yyy"/></li> <li><sca:service name="xxx" type="yyyy" target="zzz"/> </ul> + * + * @author Adrian Colyer + * @since 2.0 + */ +public class ScaNamespaceHandler extends NamespaceHandlerSupport { + + public ScaNamespaceHandler() { + // FIXME JFM + init(); + } + + public final void init() { + registerBeanDefinitionParser("composite", new ScaCompositeBeanDefinitionParser()); + registerBeanDefinitionParser("reference", new ScaReferenceBeanDefinitionParser()); + registerBeanDefinitionParser("property", new ScaPropertyBeanDefinitionParser()); + registerBeanDefinitionParser("service", new ScaServiceBeanDefinitionParser()); + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaPropertyBeanDefinitionParser.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaPropertyBeanDefinitionParser.java new file mode 100644 index 0000000000..55413b69da --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaPropertyBeanDefinitionParser.java @@ -0,0 +1,63 @@ +/* + * 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. + * + * Created on 10-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.sca.ScaPropertyProxyFactoryBean; + +/** + * Parser for the <sca:property/> element + * + * @author Adrian Colyer + * @since 2.0 + */ +public class ScaPropertyBeanDefinitionParser implements BeanDefinitionParser { + + private static final String PROPERTY_NAME_ATTRIBUTE = "name"; + private static final String PROPERTY_NAME_PROPERTY = "propertyName"; + private static final String PROPERTY_TYPE_PROPERTY = "propertyType"; + private static final String TYPE_ATTRIBUTE = "type"; + private static final String ID_ATTRIBUTE = "id"; + + public BeanDefinition parse(Element element, ParserContext parserContext) { + // needs service type, reference name, sca component, and optionally default service name + BeanDefinitionRegistry registry = parserContext.getRegistry(); + String beanName = element.getAttribute(ID_ATTRIBUTE); + BeanDefinition beanDef = createBeanDefinition(element); + registry.registerBeanDefinition(beanName, beanDef); + return beanDef; + } + + private BeanDefinition createBeanDefinition(Element element) { + RootBeanDefinition beanDefinition = new RootBeanDefinition(); + beanDefinition.setBeanClass(ScaPropertyProxyFactoryBean.class); + MutablePropertyValues props = new MutablePropertyValues(); + props.addPropertyValue(PROPERTY_NAME_PROPERTY, element.getAttribute(PROPERTY_NAME_ATTRIBUTE)); + props.addPropertyValue(PROPERTY_TYPE_PROPERTY, element.getAttribute(TYPE_ATTRIBUTE)); + beanDefinition.setPropertyValues(props); + return beanDefinition; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaReferenceBeanDefinitionParser.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaReferenceBeanDefinitionParser.java new file mode 100644 index 0000000000..4f4d196571 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaReferenceBeanDefinitionParser.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. + * + * Created on 10-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.sca.ScaServiceProxyFactoryBean; + +/** + * Parser for the <sca:reference> element + * + * @author Adrian Colyer + * @since 2.0 + */ +public class ScaReferenceBeanDefinitionParser implements BeanDefinitionParser { + + private static final String REFERENCE_NAME_ATTRIBUTE = "name"; + private static final String REFERENCE_NAME_PROPERTY = "referenceName"; + private static final String TYPE_ATTRIBUTE = "type"; + private static final String SERVICE_TYPE_PROPERTY = "serviceType"; + private static final String DEFAULT_SERVICE_ATTRIBUTE = "default"; + private static final String DEFAULT_SERVICE_PROPERTY = "defaultServiceName"; + + public BeanDefinition parse(Element element, ParserContext parserContext) { + // needs service type, reference name, sca component, and optionally default service name + BeanDefinitionRegistry registry = parserContext.getRegistry(); + String referenceName = element.getAttribute(REFERENCE_NAME_ATTRIBUTE); + BeanDefinition beanDef = createBeanDefinition(element); + registry.registerBeanDefinition(referenceName, beanDef); + return beanDef; + } + + private BeanDefinition createBeanDefinition(Element element) { + RootBeanDefinition beanDefinition = new RootBeanDefinition(); + beanDefinition.setBeanClass(ScaServiceProxyFactoryBean.class); + MutablePropertyValues props = new MutablePropertyValues(); + props.addPropertyValue(REFERENCE_NAME_PROPERTY, element.getAttribute(REFERENCE_NAME_ATTRIBUTE)); + props.addPropertyValue(SERVICE_TYPE_PROPERTY, element.getAttribute(TYPE_ATTRIBUTE)); + if (element.hasAttribute(DEFAULT_SERVICE_ATTRIBUTE)) { + props.addPropertyValue(DEFAULT_SERVICE_PROPERTY, element.getAttribute(DEFAULT_SERVICE_ATTRIBUTE)); + } + beanDefinition.setPropertyValues(props); + return beanDefinition; + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaServiceBeanDefinitionParser.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaServiceBeanDefinitionParser.java new file mode 100644 index 0000000000..5867236faa --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/config/ScaServiceBeanDefinitionParser.java @@ -0,0 +1,65 @@ +/* + * 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. + * + * Created on 10-Apr-2006 by Adrian Colyer + */ +package org.springframework.sca.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.sca.ScaServiceExporter; + +/** + * Parser for the <sca:service/> element + * + * @author Adrian Colyer + * @since 2.0 + */ +public class ScaServiceBeanDefinitionParser implements BeanDefinitionParser { + + private static final String SERVICE_NAME_ATTRIBUTE = "name"; + private static final String TYPE_ATTRIBUTE = "type"; + private static final String TARGET_ATTRIBUTE = "target"; + private static final String SERVICE_NAME_PROPERTY = "serviceName"; + private static final String SERVICE_TYPE_PROPERTY = "serviceType"; + private static final String TARGET_PROPERTY = "target"; + + public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinitionRegistry registry = parserContext.getRegistry(); + String serviceName = element.getAttribute(SERVICE_NAME_ATTRIBUTE); + BeanDefinition beanDef = createBeanDefinition(element); + registry.registerBeanDefinition(serviceName, beanDef); + return beanDef; + } + + private BeanDefinition createBeanDefinition(Element element) { + RootBeanDefinition beanDefinition = new RootBeanDefinition(); + beanDefinition.setBeanClass(ScaServiceExporter.class); + MutablePropertyValues props = new MutablePropertyValues(); + props.addPropertyValue(SERVICE_TYPE_PROPERTY, element.getAttribute(TYPE_ATTRIBUTE)); + props.addPropertyValue(TARGET_PROPERTY, new RuntimeBeanReference(element.getAttribute(TARGET_ATTRIBUTE))); + props.addPropertyValue(SERVICE_NAME_PROPERTY, element.getAttribute(SERVICE_NAME_ATTRIBUTE)); + beanDefinition.setPropertyValues(props); + return beanDefinition; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/intercept/OneWayAdvisor.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/intercept/OneWayAdvisor.java new file mode 100644 index 0000000000..60bf2a344d --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/intercept/OneWayAdvisor.java @@ -0,0 +1,82 @@ +/* + * 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.springframework.sca.intercept; + +import java.lang.reflect.Method; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.aop.framework.ReflectiveMethodInvocation; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.aop.support.StaticMethodMatcherPointcut; +import org.springframework.core.task.TaskExecutor; +import org.springframework.sca.metadata.ServiceMetadata; + +/** + * An AOP Alliance MethodInterceptor, rather than AspectJ aspect, as there's no value in typed pointcuts. Oh, if it were + * only annotations... + * + * @author Rod Johnson + */ + +public class OneWayAdvisor extends DefaultPointcutAdvisor { + + private TaskExecutor taskExecutor; + + private final ServiceMetadata smd; + + public OneWayAdvisor(final ServiceMetadata aSmd, TaskExecutor taskExecutor) { + this.smd = aSmd; + setPointcut(new StaticMethodMatcherPointcut() { + public boolean matches(Method method, Class targetClass) { + for (Method m : smd.getOneWayMethods()) { + if (m.getName().equals(method.getName())) { + return true; + } + } + return false; + } + }); + setAdvice(new OneWayInterceptor()); + this.taskExecutor = taskExecutor; + } + + + private class OneWayInterceptor implements MethodInterceptor { + public Object invoke(MethodInvocation mi) throws Throwable { + try { + // TODO this is not right + ReflectiveMethodInvocation rmi = (ReflectiveMethodInvocation) mi; + final MethodInvocation clone = rmi.invocableClone(); + System.out.println("EXECUTE DEFERRED"); + taskExecutor.execute(new Runnable() { + public void run() { + try { + clone.proceed(); + } catch (Throwable ex) { + // TODO + throw new UnsupportedOperationException(); + } + } + }); + } catch (Throwable t) { + t.printStackTrace(); + } + return null; + } + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/AnnotationServiceMetadata.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/AnnotationServiceMetadata.java new file mode 100644 index 0000000000..9a04831ab8 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/AnnotationServiceMetadata.java @@ -0,0 +1,95 @@ +/* + * 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.springframework.sca.metadata; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; + +import org.osoa.sca.annotations.ComponentName; +import org.osoa.sca.annotations.OneWay; +import org.osoa.sca.annotations.Property; +import org.osoa.sca.annotations.Service; + +import org.springframework.util.ReflectionUtils; + +/** + * TODO not the way to get this + * + * @author Rod Johnson + */ +public class AnnotationServiceMetadata implements ServiceMetadata { + + private final String name; + + private final Class<?> serviceClass; + + public AnnotationServiceMetadata(String name, Class<?> serviceClass) throws NoSuchServiceException { + if (!serviceClass.isAnnotationPresent(Service.class)) { + throw new NoSuchServiceException(); + } + this.name = name; + this.serviceClass = serviceClass; + } + + public String getServiceName() { + return name; + } + + public Class<?>[] getServiceInterfaces() { + return serviceClass.getAnnotation(Service.class).interfaces(); + } + + public List<Method> getOneWayMethods() { + List<Method> oneWayMethods = new LinkedList<Method>(); + for (Method m : serviceClass.getMethods()) { + if (m.isAnnotationPresent(OneWay.class)) { + oneWayMethods.add(m); + } + } + + // TODO fields + + return oneWayMethods; + } + + public List<Injection> getInjections() { + final List<Injection> injections = new LinkedList<Injection>(); + for (Method m : serviceClass.getMethods()) { + if (m.isAnnotationPresent(Property.class)) { + injections.add(new MethodInjection(m)); + } + } + + // TODO fields propertly + + ReflectionUtils.doWithFields(serviceClass, new ReflectionUtils.FieldCallback() { + public void doWith(Field f) throws IllegalArgumentException { + if (f.isAnnotationPresent(ComponentName.class)) { + Injection componentNameInjection = new FieldInjection(f); + componentNameInjection.setLiteralValue(name); + injections.add(componentNameInjection); + } + } + }); + + return injections; + } + + // TODO reference + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/BeanFactoryDeploymentMetadata.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/BeanFactoryDeploymentMetadata.java new file mode 100644 index 0000000000..b819ad8f8d --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/BeanFactoryDeploymentMetadata.java @@ -0,0 +1,55 @@ +/* + * 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.springframework.sca.metadata; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; + +/** + * DeploymentMetadata implementation backed by Spring BeanFactory metadata + * + * @author Rod Johnson + */ +public class BeanFactoryDeploymentMetadata implements BeanFactoryAware, DeploymentMetadata { + + private BeanFactory beanFactory; + + private Map<String, ServiceMetadata> serviceNameToMetadataMap = new HashMap<String, ServiceMetadata>(); + + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + + + /* (non-Javadoc) + * @see org.springframework.sca.metadata.DeploymentMetadata#getServiceMetadata(java.lang.String) + */ + public synchronized ServiceMetadata getServiceMetadata(String serviceName) throws NoSuchServiceException { + ServiceMetadata sm = serviceNameToMetadataMap.get(serviceName); + if (sm == null) { + Class clazz = beanFactory.getType(serviceName); + sm = new AnnotationServiceMetadata(serviceName, clazz); + serviceNameToMetadataMap.put(serviceName, sm); + } + return sm; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/DeploymentMetadata.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/DeploymentMetadata.java new file mode 100644 index 0000000000..950e5e3786 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/DeploymentMetadata.java @@ -0,0 +1,28 @@ +/* + * 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.springframework.sca.metadata; + +/** + * Source of ServiceMetadata by name + * + * @author Rod Johnson + */ +public interface DeploymentMetadata { + + ServiceMetadata getServiceMetadata(String serviceName) throws NoSuchServiceException; + +}
\ No newline at end of file diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/FieldInjection.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/FieldInjection.java new file mode 100644 index 0000000000..3d9f1b6e79 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/FieldInjection.java @@ -0,0 +1,68 @@ +/* + * 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.springframework.sca.metadata; + +import java.lang.reflect.Field; + +import org.osoa.sca.annotations.Reference; + +/** + * @author Rod Johnson + */ +public class FieldInjection extends Injection { + + private final Field field; + + public FieldInjection(Field field, String lookupName) { + super(lookupName); + this.field = field; + } + + public FieldInjection(Field field) { + Reference annotation = field.getAnnotation(Reference.class); + + this.field = field; + + if (annotation == null) { + //throw new IllegalArgumentException("Field " + field + " not annotated"); + return; + } + + if ("".equals(annotation.name())) { + setLookupName(field.getName()); + } else { + setLookupName(annotation.name()); + } + } + + @Override + protected void injectValue(Object target, Object value) { + try { + if (!field.isAccessible()) { + field.setAccessible(true); + } + field.set(target, value); + } catch (IllegalArgumentException ex) { + // TODO + throw new UnsupportedOperationException(); + } catch (IllegalAccessException ex) { + // TODO + ex.printStackTrace(); + throw new UnsupportedOperationException(); + } + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/Injection.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/Injection.java new file mode 100644 index 0000000000..2e81516d56 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/Injection.java @@ -0,0 +1,76 @@ +/* + * 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.springframework.sca.metadata; + +import org.springframework.beans.factory.BeanFactory; + +/** + * @author Rod Johnson + */ +public abstract class Injection { + + private String lookupName; + + /** + * Is it a literal value? + */ + private boolean literal; + + /** + * Literal value if it's a literal + */ + private Object literalValue; + + protected Injection() { + + } + + protected Injection(String lookupName) { + this.lookupName = lookupName; + } + + public Object getLiteralValue() { + return literalValue; + } + + public void setLiteralValue(Object literalValue) { + this.literal = true; + this.literalValue = literalValue; + } + + public boolean isLiteral() { + return literal; + } + + protected void setLookupName(String lookupName) { + this.lookupName = lookupName; + } + + public String getLookupName() { + return lookupName; + } + + public void apply(BeanFactory owner, Object target) { + Object value = literalValue; + if (!isLiteral()) { + value = owner.getBean(lookupName); + } + injectValue(target, value); + } + + protected abstract void injectValue(Object target, Object value); + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/MethodInjection.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/MethodInjection.java new file mode 100644 index 0000000000..df01d1428d --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/MethodInjection.java @@ -0,0 +1,65 @@ +/* + * 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.springframework.sca.metadata; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.osoa.sca.annotations.Property; + +/** + * @author Rod Johnson + */ +public class MethodInjection extends Injection { + + private final Method method; + + public MethodInjection(Method method, String lookupName) { + super(lookupName); + this.method = method; + } + + public MethodInjection(Method method) { + // TODO reference also + Property annotation = method.getAnnotation(Property.class); + if (annotation == null) { + throw new IllegalArgumentException("Method " + method + " not annotated"); + } + this.method = method; + if ("".equals(annotation.name())) { + setLookupName(method.getName()); + } else { + setLookupName(annotation.name()); + } + } + + @Override + protected void injectValue(Object target, Object value) { + try { + method.invoke(target, value); + } catch (IllegalArgumentException ex) { + // TODO + throw new UnsupportedOperationException(); + } catch (IllegalAccessException ex) { + // TODO + throw new UnsupportedOperationException(); + } catch (InvocationTargetException ex) { + // TODO + throw new UnsupportedOperationException(); + } + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/NoSuchServiceException.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/NoSuchServiceException.java new file mode 100644 index 0000000000..b7ffdfeee6 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/NoSuchServiceException.java @@ -0,0 +1,24 @@ +/* + * 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.springframework.sca.metadata; + +/** + * @author Rod Johnson + */ +public class NoSuchServiceException extends Exception { + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/ServiceMetadata.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/ServiceMetadata.java new file mode 100644 index 0000000000..5d23c499e4 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/java/org/springframework/sca/metadata/ServiceMetadata.java @@ -0,0 +1,56 @@ +/* + * 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.springframework.sca.metadata; + +import java.lang.reflect.Method; +import java.util.List; + +/** + * Metadata for an SCA component. + * + * @author Rod Johnson + */ +public interface ServiceMetadata { + + /** + * Return the service name + * + * @return the service name of the component + */ + String getServiceName(); + + /** + * Return the service interfaces implemented by the component + * + * @return interfaces implemented by the component + */ + Class<?>[] getServiceInterfaces(); + + /** + * Return a list of OneWay methods + * + * @return never returns null + */ + List<Method> getOneWayMethods(); + + /** + * Return a list of SCA injections + * @return a list of SCA injections. Never returns null. + */ + List<Injection> getInjections(); + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/META-INF/sca/spring.system.scdl b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/META-INF/sca/spring.system.scdl new file mode 100644 index 0000000000..cbd7138f0d --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/META-INF/sca/spring.system.scdl @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. + --> +<!-- + Spring implementation extension configuration for the launcher environment. +--> +<composite xmlns="http://www.osoa.org/xmlns/sca/1.0" + xmlns:system="http://incubator.apache.org/tuscany/xmlns/system/1.0-incubator-M2" + + name="org.apache.tuscany.launcher.SpringImplementation"> + + <component name="spring.implementationLoader"> + <system:implementation.system class="org.apache.tuscany.container.spring.impl.SpringImplementationLoader"/> + </component> + + <component name="spring.componentTypeLoader"> + <system:implementation.system class="org.apache.tuscany.container.spring.impl.SpringComponentTypeLoader"/> + </component> + + <component name="spring.componentBuilder"> + <system:implementation.system class="org.apache.tuscany.container.spring.impl.SpringCompositeBuilder"/> + </component> + +</composite>
\ No newline at end of file diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/META-INF/spring.handlers b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/META-INF/spring.handlers new file mode 100644 index 0000000000..689b49e2ae --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/META-INF/spring.handlers @@ -0,0 +1,3 @@ +http\://www.springframework.org/schema/sca=org.springframework.sca.config.ScaNamespaceHandler + + diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/META-INF/spring.schemas b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/META-INF/spring.schemas new file mode 100644 index 0000000000..33f7004be9 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/META-INF/spring.schemas @@ -0,0 +1 @@ +http\://www.springframework.org/schema/sca/spring-sca.xsd=org/springframework/sca/xml/spring-sca.xsd diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/org/springframework/sca/xml/spring-sca.xsd b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/org/springframework/sca/xml/spring-sca.xsd new file mode 100644 index 0000000000..b4eeadbb74 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/main/resources/org/springframework/sca/xml/spring-sca.xsd @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<xsd:schema xmlns="http://www.springframework.org/schema/sca" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + attributeFormDefault="unqualified" + elementFormDefault="qualified" + targetNamespace="http://www.springframework.org/schema/sca"> + + <xsd:element name="composite"> + <xsd:complexType> + <xsd:attribute name="component" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="sca-adapter-class" use="optional"> + <xsd:simpleType> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + </xsd:attribute> + </xsd:complexType> + </xsd:element> + + <xsd:element name="reference"> + <xsd:complexType> + <xsd:attribute name="name" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="type" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="default" use="optional"> + <xsd:simpleType> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + </xsd:attribute> + </xsd:complexType> + </xsd:element> + + <xsd:element name="property"> + <xsd:complexType> + <xsd:attribute name="id" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="name" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="type" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + </xsd:attribute> + </xsd:complexType> + </xsd:element> + + <xsd:element name="service"> + <xsd:complexType> + <xsd:attribute name="name" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="type" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + </xsd:attribute> + <xsd:attribute name="target" use="required"> + <xsd:simpleType> + <xsd:restriction base="xsd:string"/> + </xsd:simpleType> + </xsd:attribute> + </xsd:complexType> + </xsd:element> + +</xsd:schema> diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/SpringConfigSchemaTestCase.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/SpringConfigSchemaTestCase.java new file mode 100644 index 0000000000..80b22d6784 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/SpringConfigSchemaTestCase.java @@ -0,0 +1,58 @@ +/* + * 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.container.spring; + +import junit.framework.TestCase; +import org.apache.tuscany.container.spring.config.ScaApplicationContext; +import org.apache.tuscany.container.spring.mock.TestReference; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.io.ClassPathResource; +import org.springframework.sca.ScaServiceExporter; +import org.springframework.sca.ScaServiceProxyFactoryBean; + +/** + * Tests the SCA extensible schema elements for Spring's XML configuration files + * + * @version $$Rev$$ $$Date$$ + */ + +public class SpringConfigSchemaTestCase extends TestCase { + + private ConfigurableApplicationContext applicationContext; + + public void setUp() { + applicationContext = + new ScaApplicationContext(null, + new ClassPathResource("org/apache/tuscany/container/spring/SpringConfigSchemaTest.xml"), null); + } + + public void testSCAService() { + ScaServiceExporter service = (ScaServiceExporter) applicationContext.getBean("fooService"); + // FIXME andyp -- this is not really right. +// TestBean service = (TestBean) applicationContext.getBean("fooService"); +// assertEquals("call me", service.echo("call me")); + } + + public void testSCAReference() { + ScaServiceProxyFactoryBean pf = (ScaServiceProxyFactoryBean) applicationContext.getBean("&fooReference"); + assertEquals("fooReference", pf.getReferenceName()); + TestReference ref = (TestReference) applicationContext.getBean("fooReference"); +// assertNotNull(ref); + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/SpringTestUtils.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/SpringTestUtils.java new file mode 100644 index 0000000000..3d07c753de --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/SpringTestUtils.java @@ -0,0 +1,70 @@ +/* + * 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.container.spring; + +import org.apache.tuscany.spi.QualifiedName; +import org.apache.tuscany.spi.idl.InvalidServiceContractException; +import org.apache.tuscany.spi.builder.Connector; +import org.apache.tuscany.spi.component.CompositeComponent; +import org.apache.tuscany.spi.component.Service; +import org.apache.tuscany.spi.extension.ServiceExtension; +import org.apache.tuscany.spi.wire.InboundWire; +import org.apache.tuscany.spi.wire.OutboundWire; +import org.apache.tuscany.spi.wire.WireService; + +import org.apache.tuscany.container.spring.mock.TestBeanImpl; +import org.apache.tuscany.test.ArtifactFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.GenericApplicationContext; + +/** + * @version $$Rev$$ $$Date$$ + */ + +public final class SpringTestUtils { + private SpringTestUtils() { + } + + public static <T> Service createService(String name, + Class<T> serviceInterface, + CompositeComponent parent, + WireService wireService) throws InvalidServiceContractException { + Service service = new ServiceExtension(name, serviceInterface, parent, wireService); + InboundWire inboundWire = ArtifactFactory.createInboundWire(name, serviceInterface); + OutboundWire outboundWire = ArtifactFactory.createOutboundWire(name, serviceInterface); + ArtifactFactory.terminateWire(outboundWire); + service.setInboundWire(inboundWire); + service.setOutboundWire(outboundWire); + outboundWire.setTargetName(new QualifiedName("foo")); + Connector connector = ArtifactFactory.createConnector(); + connector.connect(service); + ArtifactFactory.terminateWire(inboundWire); + return service; + } + + + public static GenericApplicationContext createContext() { + GenericApplicationContext ctx = new GenericApplicationContext(); + BeanDefinition definition = new RootBeanDefinition(TestBeanImpl.class); + ctx.registerBeanDefinition("foo", definition); + return ctx; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/ReferenceInvocationTestCase.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/ReferenceInvocationTestCase.java new file mode 100644 index 0000000000..ff5a564ee8 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/ReferenceInvocationTestCase.java @@ -0,0 +1,68 @@ +/* + * 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.container.spring.impl; + +import org.apache.tuscany.spi.component.Reference; + +import junit.framework.TestCase; +import org.apache.tuscany.container.spring.mock.TestBean; +import org.apache.tuscany.container.spring.mock.TestBeanImpl; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.StaticApplicationContext; + +/** + * Verifies wiring from a Spring bean to an SCA composite reference + * + * @version $$Rev$$ $$Date$$ + */ +public class ReferenceInvocationTestCase extends TestCase { + + public void testInvocation() throws Exception { + AbstractApplicationContext ctx = createSpringContext(); + SpringCompositeComponent parent = new SpringCompositeComponent("spring", ctx, null, null, null); + parent.start(); + TestBean referenceTarget = new TestBeanImpl(); + Reference reference = createMock(Reference.class); + expect(reference.getName()).andReturn("bar").anyTimes(); + expect(reference.isSystem()).andReturn(false).atLeastOnce(); + expect(reference.getInterface()).andStubReturn(TestBean.class); + expect(reference.getServiceInstance()).andStubReturn(referenceTarget); + replay(reference); + parent.register(reference); + ctx.getBean("foo"); + } + + private AbstractApplicationContext createSpringContext() { + StaticApplicationContext beanFactory = new StaticApplicationContext(); + RootBeanDefinition definition = new RootBeanDefinition(TestBeanImpl.class); + //REVIEW we need to figure out how to handle eager init components + definition.setLazyInit(true); + RuntimeBeanReference ref = new RuntimeBeanReference("bar"); + PropertyValue val = new PropertyValue("bean", ref); + definition.getPropertyValues().addPropertyValue(val); + beanFactory.registerBeanDefinition("foo", definition); + return beanFactory; + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/ServiceInvocationTestCase.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/ServiceInvocationTestCase.java new file mode 100644 index 0000000000..596d9f1181 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/ServiceInvocationTestCase.java @@ -0,0 +1,76 @@ +/* + * 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.container.spring.impl; + +import org.apache.tuscany.spi.builder.Connector; +import org.apache.tuscany.spi.component.Service; +import org.apache.tuscany.spi.extension.ServiceExtension; +import org.apache.tuscany.spi.idl.InvalidServiceContractException; +import org.apache.tuscany.spi.wire.InboundInvocationChain; +import org.apache.tuscany.spi.wire.InboundWire; +import org.apache.tuscany.spi.wire.OutboundWire; +import org.apache.tuscany.spi.QualifiedName; + +import junit.framework.TestCase; +import org.apache.tuscany.container.spring.mock.TestBean; +import org.apache.tuscany.container.spring.mock.TestBeanImpl; +import org.apache.tuscany.test.ArtifactFactory; +import static org.apache.tuscany.test.ArtifactFactory.createWireService; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.StaticApplicationContext; + +/** + * Tests a simple invocation through a service to a Spring bean + * + * @version $$Rev$$ $$Date$$ + */ +public class ServiceInvocationTestCase extends TestCase { + + public void testInvocation() throws InvalidServiceContractException { + AbstractApplicationContext springContext = createSpringContext(); + SpringCompositeComponent composite = new SpringCompositeComponent("parent", springContext, null, null, null); + InboundWire inboundWire = ArtifactFactory.createInboundWire("fooService", TestBean.class); + OutboundWire outboundWire = ArtifactFactory.createOutboundWire("fooService", TestBean.class); + outboundWire.setTargetName(new QualifiedName("foo")); + ArtifactFactory.terminateWire(outboundWire); + Service service = + new ServiceExtension("fooService", TestBean.class, composite, createWireService()); + service.setInboundWire(inboundWire); + service.setOutboundWire(outboundWire); + Connector connector = ArtifactFactory.createConnector(); + connector.connect(inboundWire, outboundWire, true); + for (InboundInvocationChain chain : inboundWire.getInvocationChains().values()) { + chain.setTargetInvoker(composite.createTargetInvoker("foo", chain.getOperation())); + } + composite.register(service); + TestBean serviceInstance = (TestBean) composite.getService("fooService").getServiceInstance(); + assertEquals("bar", serviceInstance.echo("bar")); + } + + + private AbstractApplicationContext createSpringContext() { + StaticApplicationContext beanFactory = new StaticApplicationContext(); + RootBeanDefinition definition = new RootBeanDefinition(TestBeanImpl.class); + definition.setLazyInit(true); + beanFactory.registerBeanDefinition("foo", definition); + return beanFactory; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/SpringCompositeBuilderTestCase.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/SpringCompositeBuilderTestCase.java new file mode 100644 index 0000000000..50ce9a7b75 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/SpringCompositeBuilderTestCase.java @@ -0,0 +1,137 @@ +/* + * 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.container.spring.impl; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.apache.tuscany.spi.builder.BuilderRegistry; +import org.apache.tuscany.spi.builder.Connector; +import org.apache.tuscany.spi.component.CompositeComponent; +import org.apache.tuscany.spi.component.Service; +import org.apache.tuscany.spi.deployer.DeploymentContext; +import org.apache.tuscany.spi.extension.ServiceExtension; +import org.apache.tuscany.spi.model.BoundServiceDefinition; +import org.apache.tuscany.spi.model.ComponentDefinition; +import org.apache.tuscany.spi.wire.InboundWire; +import org.apache.tuscany.spi.wire.OutboundWire; +import org.apache.tuscany.spi.wire.WireService; + +import junit.framework.TestCase; +import static org.apache.tuscany.container.spring.SpringTestUtils.createContext; +import org.apache.tuscany.container.spring.mock.TestBean; +import org.apache.tuscany.container.spring.model.SpringComponentType; +import org.apache.tuscany.container.spring.model.SpringImplementation; +import org.apache.tuscany.test.ArtifactFactory; +import org.apache.tuscany.test.binding.TestBinding; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.createNiceMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.isA; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; + +/** + * @version $$Rev$$ $$Date$$ + */ +public class SpringCompositeBuilderTestCase extends TestCase { + + /** + * Verfies basic build of a spring context + */ + @SuppressWarnings("unchecked") + public void testBuild() throws Exception { + // Create an assembly model consisting of a component implemented by Spring + SpringImplementation impl = new SpringImplementation(new SpringComponentType(createContext())); + ComponentDefinition<SpringImplementation> componentDefinition = + new ComponentDefinition<SpringImplementation>("spring", impl); + + // Configure the mock builder registry + BuilderRegistry registry = createNiceMock(BuilderRegistry.class); + + // Test the SpringCompositeBuilder + SpringCompositeBuilder builder = new SpringCompositeBuilder(); + builder.setBuilderRegistry(registry); + CompositeComponent parent = createNiceMock(CompositeComponent.class); + DeploymentContext context = createNiceMock(DeploymentContext.class); + SpringCompositeComponent component = + (SpringCompositeComponent) builder.build(parent, componentDefinition, context); + TestBean bean = (TestBean) component.getApplicationContext().getBean("foo"); + assertEquals("call foo", bean.echo("call foo")); + } + + /** + * Verifies that the builder calls back into the registry to load services and wires them to bean targets when no + * <code>sca:service</code> tag is specified in the Spring application.xml + */ + @SuppressWarnings("unchecked") + public void testImplicitServiceWiring() throws Exception { + // Create an assembly model consisting of a component implemented by Spring + SpringImplementation impl = new SpringImplementation(createComponentType()); + ComponentDefinition<SpringImplementation> componentDefinition = + new ComponentDefinition<SpringImplementation>("spring", impl); + + // Create a service instance that the mock builder registry will return + WireService wireService = ArtifactFactory.createWireService(); + ServiceExtension serviceContext = + new ServiceExtension("fooService", TestBean.class, null, wireService); + InboundWire inboundWire = ArtifactFactory.createInboundWire("fooService", TestBean.class); + OutboundWire outboundWire = ArtifactFactory.createOutboundWire("fooService", TestBean.class); + ArtifactFactory.terminateWire(outboundWire); + serviceContext.setInboundWire(inboundWire); + serviceContext.setOutboundWire(outboundWire); + Connector connector = ArtifactFactory.createConnector(); + connector.connect(inboundWire, outboundWire, true); + + // Configure the mock builder registry + BuilderRegistry registry = createMock(BuilderRegistry.class); + expect(registry.build(isA(CompositeComponent.class), + isA(BoundServiceDefinition.class), + isA(DeploymentContext.class))).andStubReturn(serviceContext); + replay(registry); + + // Test the SpringCompositeBuilder + SpringCompositeBuilder builder = new SpringCompositeBuilder(); + builder.setWireService(wireService); + builder.setBuilderRegistry(registry); + CompositeComponent parent = createNiceMock(CompositeComponent.class); + DeploymentContext context = createNiceMock(DeploymentContext.class); + CompositeComponent component = (CompositeComponent) builder.build(parent, componentDefinition, context); + Service service = component.getService("fooService"); + TestBean bean = (TestBean) service.getServiceInstance(); + assertEquals("call foo", bean.echo("call foo")); + verify(registry); + } + + @SuppressWarnings("unchecked") + private SpringComponentType createComponentType() { + SpringComponentType componentType = new SpringComponentType(createContext()); + BoundServiceDefinition<TestBinding> serviceDefinition = new BoundServiceDefinition<TestBinding>(); + serviceDefinition.setName("fooService"); + serviceDefinition.setBinding(new TestBinding()); + try { + serviceDefinition.setTarget(new URI("foo")); + } catch (URISyntaxException e) { + throw new AssertionError(); + } + componentType.add(serviceDefinition); + return componentType; + } + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/SpringCompositeComponentTestCase.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/SpringCompositeComponentTestCase.java new file mode 100644 index 0000000000..f3ac13d030 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/SpringCompositeComponentTestCase.java @@ -0,0 +1,64 @@ +/* + * 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.container.spring.impl; + +import org.apache.tuscany.spi.component.Service; + +import junit.framework.TestCase; +import static org.easymock.EasyMock.expect; +import org.easymock.classextension.EasyMock; +import static org.easymock.classextension.EasyMock.replay; +import static org.easymock.classextension.EasyMock.verify; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.AbstractApplicationContext; + +/** + * @version $Rev$ $Date$ + */ +public class SpringCompositeComponentTestCase extends TestCase { + + public void testAppContextStart() { + AbstractApplicationContext appContext = EasyMock.createMock(AbstractApplicationContext.class); + appContext.refresh(); + appContext.setParent(EasyMock.isA(ApplicationContext.class)); + appContext.start(); + replay(appContext); + SpringCompositeComponent component = new SpringCompositeComponent("spring", appContext, null, null, null); + component.start(); + verify(appContext); + } + + public void testChildStart() { + AbstractApplicationContext appContext = EasyMock.createNiceMock(AbstractApplicationContext.class); + replay(appContext); + Service service = EasyMock.createMock(Service.class); + EasyMock.expect(service.getName()).andReturn("foo").anyTimes(); + service.start(); + service.getInterface(); + EasyMock.expectLastCall().andReturn(Object.class); + expect(service.isSystem()).andReturn(false).atLeastOnce(); + replay(service); + SpringCompositeComponent component = new SpringCompositeComponent("spring", appContext, null, null, null); + component.register(service); + component.start(); + verify(service); + } + + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/SpringInvocationTestCase.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/SpringInvocationTestCase.java new file mode 100644 index 0000000000..b110852a54 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/impl/SpringInvocationTestCase.java @@ -0,0 +1,62 @@ +/* + * 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.container.spring.impl; + +import org.apache.tuscany.spi.wire.Message; +import org.apache.tuscany.spi.wire.MessageImpl; + +import junit.framework.TestCase; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import org.springframework.context.ApplicationContext; + +/** + * Verifies a simple invocation on a Spring bean + * + * @version $$Rev$$ $$Date$$ + */ +public class SpringInvocationTestCase extends TestCase { + + /** + * Verifies the invoker can resolve a bean in an application context and call a method l + */ + public void testInvocation() throws Exception { + TestBean bean = createMock(TestBean.class); + bean.test("bar"); + expectLastCall(); + replay(bean); + ApplicationContext context = createMock(ApplicationContext.class); + expect(context.getBean("foo")).andReturn(bean); + replay(context); + SpringInvoker invoker = new SpringInvoker("foo", TestBean.class.getMethod("test", String.class), context); + Message msg = new MessageImpl(); + msg.setBody(new String[]{"bar"}); + invoker.invoke(msg); + verify(context); + verify(bean); + } + + + private interface TestBean { + void test(String msg); + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/integration/BootstrapTestCase.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/integration/BootstrapTestCase.java new file mode 100644 index 0000000000..c5758cb2ac --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/integration/BootstrapTestCase.java @@ -0,0 +1,57 @@ +/* + * 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.container.spring.integration; + +import org.osoa.sca.CompositeContext; +import org.osoa.sca.CurrentCompositeContext; + +import org.apache.tuscany.spi.component.Service; + +import org.apache.tuscany.container.spring.impl.SpringCompositeComponent; +import org.apache.tuscany.container.spring.mock.TestBean; +import org.apache.tuscany.test.Bootstrapper; + +/** + * Bootstraps a simple scenario where a service can invoke a Spring bean. This test case is intended to be temporary and + * replaced when the SPI test harness is finished. + * <p/> + * <bold>PLEASE DO NOT EMULATE</bold> + * + * @version $Rev$ $Date$ + */ +public class BootstrapTestCase extends Bootstrapper { + + private CompositeContext context; + + public void testDemoBoot() { + SpringCompositeComponent comp = (SpringCompositeComponent) component.getChild("Spring"); + Service service = (Service) comp.getChild("fooService"); + TestBean bean = (TestBean) service.getServiceInstance(); + bean.echo("foo"); + bean.getBean().echo("foo"); + } + + protected void setUp() throws Exception { + addExtension("spring.extension", getClass().getClassLoader().getResource("META-INF/sca/spring.system.scdl")); + super.setUp(); + context = CurrentCompositeContext.getContext(); + } + + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/mock/TestBean.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/mock/TestBean.java new file mode 100644 index 0000000000..1c768e53cc --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/mock/TestBean.java @@ -0,0 +1,31 @@ +/* + * 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.container.spring.mock; + +/** + * @version $$Rev$$ $$Date$$ + */ +public interface TestBean { + String echo(String msg); + + TestBean getBean(); + + void setBean(TestBean bean); + +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/mock/TestBeanImpl.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/mock/TestBeanImpl.java new file mode 100644 index 0000000000..db04d8bcad --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/mock/TestBeanImpl.java @@ -0,0 +1,42 @@ +/* + * 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.container.spring.mock; + +/** + * @version $$Rev$$ $$Date$$ + */ +public class TestBeanImpl implements TestBean { + + private TestBean bean; + + public TestBeanImpl() { + } + + public String echo(String msg) { + return msg; + } + + public TestBean getBean() { + return bean; + } + + public void setBean(TestBean bean) { + this.bean = bean; + } +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/mock/TestReference.java b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/mock/TestReference.java new file mode 100644 index 0000000000..7d1a519be6 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/java/org/apache/tuscany/container/spring/mock/TestReference.java @@ -0,0 +1,26 @@ +/* + * 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.container.spring.mock; + +/** + * @version $$Rev$$ $$Date$$ + */ +public interface TestReference { + String echo(String msg); +} diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/META-INF/sca/application-context.xml b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/META-INF/sca/application-context.xml new file mode 100644 index 0000000000..6ccd3963a9 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/META-INF/sca/application-context.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:sca="http://www.springframework.org/schema/sca" + xsi:schemaLocation=" +http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd +http://www.springframework.org/schema/sca http://www.springframework.org/schema/sca/spring-sca.xsd"> + + <bean id="testBean" class="org.apache.tuscany.container.spring.mock.TestBeanImpl" lazy-init="true"> + <property name="bean" ref="testReference"/> + </bean> + <!-- <sca:reference name="testReference" type="org.apache.tuscany.container.spring.mock.TestReference"/> --> + +</beans> diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/META-INF/sca/default.scdl b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/META-INF/sca/default.scdl new file mode 100644 index 0000000000..0b2c92c667 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/META-INF/sca/default.scdl @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. + --> +<composite xmlns="http://www.osoa.org/xmlns/sca/1.0" + name="spring.test"> + + <component name="Spring"> + <implementation.spring location="META-INF/sca/application-context.xml"> + <service name="fooService"> + <binding.test/> + <interface.java class="org.apache.tuscany.container.spring.mock.TestBean"/> + <reference>testBean</reference> + </service> + <reference name="testReference"> + <interface.java class="org.apache.tuscany.container.spring.mock.TestBean"/> + <binding.test/> + </reference> + </implementation.spring> + </component> + +</composite> diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/org/apache/tuscany/container/spring/ExplicitSpring.xml b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/org/apache/tuscany/container/spring/ExplicitSpring.xml new file mode 100644 index 0000000000..211211511b --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/org/apache/tuscany/container/spring/ExplicitSpring.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:sca="http://www.springframework.org/schema/sca" + xsi:schemaLocation=" +http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd +http://www.springframework.org/schema/sca http://www.springframework.org/schema/sca/spring-sca.xsd"> + + <sca:service name="fooBean" type="org.apache.tuscany.container.spring.mock.TestBeanImpl" target="testBean"/> + + <bean id="testBean" class="org.apache.tuscany.container.spring.mock.TestBeanImpl"> + </bean> + +</beans> diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/org/apache/tuscany/container/spring/SpringConfigSchemaTest.xml b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/org/apache/tuscany/container/spring/SpringConfigSchemaTest.xml new file mode 100644 index 0000000000..96a3e1ed46 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/org/apache/tuscany/container/spring/SpringConfigSchemaTest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:sca="http://www.springframework.org/schema/sca" + xsi:schemaLocation=" +http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd +http://www.springframework.org/schema/sca http://www.springframework.org/schema/sca/spring-sca.xsd"> + + <bean id="testBean" class="org.apache.tuscany.container.spring.mock.TestBeanImpl"> + </bean> + + <sca:service name="fooService" type="org.apache.tuscany.container.spring.mock.TestBean" target="testBean"/> + + <sca:reference name="fooReference" type="org.apache.tuscany.container.spring.mock.TestReference"/> + + +</beans> diff --git a/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/test.xml b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/test.xml new file mode 100644 index 0000000000..d438b88577 --- /dev/null +++ b/branches/sca-java-M2/sca/services/containers/container.spring/src/test/resources/test.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:sca="http://www.springframework.org/schema/sca" + xsi:schemaLocation=" +http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd +http://www.springframework.org/schema/sca http://www.springframework.org/schema/sca/spring-sca.xsd"> + + <bean id="testBean" class="org.apache.tuscany.container.spring.mock.TestBeanImpl"/> + +</beans> |