diff options
Diffstat (limited to 'sca-java-1.x/tags/java-stable-20060304/sca/container.java/src/main/java/org/apache/tuscany/container/java/builder/JavaComponentContextBuilder.java')
-rw-r--r-- | sca-java-1.x/tags/java-stable-20060304/sca/container.java/src/main/java/org/apache/tuscany/container/java/builder/JavaComponentContextBuilder.java | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/sca-java-1.x/tags/java-stable-20060304/sca/container.java/src/main/java/org/apache/tuscany/container/java/builder/JavaComponentContextBuilder.java b/sca-java-1.x/tags/java-stable-20060304/sca/container.java/src/main/java/org/apache/tuscany/container/java/builder/JavaComponentContextBuilder.java new file mode 100644 index 0000000000..9ac030dfb9 --- /dev/null +++ b/sca-java-1.x/tags/java-stable-20060304/sca/container.java/src/main/java/org/apache/tuscany/container/java/builder/JavaComponentContextBuilder.java @@ -0,0 +1,348 @@ +package org.apache.tuscany.container.java.builder; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.tuscany.container.java.assembly.JavaImplementation; +import org.apache.tuscany.container.java.config.JavaComponentRuntimeConfiguration; +import org.apache.tuscany.core.builder.BuilderConfigException; +import org.apache.tuscany.core.builder.BuilderException; +import org.apache.tuscany.core.builder.NoAccessorException; +import org.apache.tuscany.core.builder.RuntimeConfigurationBuilder; +import org.apache.tuscany.core.builder.impl.HierarchicalBuilder; +import org.apache.tuscany.core.builder.impl.ProxyObjectFactory; +import org.apache.tuscany.core.config.JavaIntrospectionHelper; +import org.apache.tuscany.core.context.AggregateContext; +import org.apache.tuscany.core.context.QualifiedName; +import org.apache.tuscany.core.injection.EventInvoker; +import org.apache.tuscany.core.injection.FactoryInitException; +import org.apache.tuscany.core.injection.FieldInjector; +import org.apache.tuscany.core.injection.Injector; +import org.apache.tuscany.core.injection.MethodEventInvoker; +import org.apache.tuscany.core.injection.MethodInjector; +import org.apache.tuscany.core.injection.SDOObjectFactory; +import org.apache.tuscany.core.injection.SingletonObjectFactory; +import org.apache.tuscany.core.invocation.InvocationConfiguration; +import org.apache.tuscany.core.invocation.MethodHashMap; +import org.apache.tuscany.core.invocation.ProxyConfiguration; +import org.apache.tuscany.core.invocation.impl.InvokerInterceptor; +import org.apache.tuscany.core.invocation.spi.ProxyFactory; +import org.apache.tuscany.core.invocation.spi.ProxyFactoryFactory; +import org.apache.tuscany.core.message.MessageFactory; +import org.apache.tuscany.core.runtime.RuntimeContext; +import org.apache.tuscany.core.system.annotation.Autowire; +import org.apache.tuscany.model.assembly.AssemblyModelObject; +import org.apache.tuscany.model.assembly.ConfiguredProperty; +import org.apache.tuscany.model.assembly.ConfiguredReference; +import org.apache.tuscany.model.assembly.ConfiguredService; +import org.apache.tuscany.model.assembly.Scope; +import org.apache.tuscany.model.assembly.Service; +import org.apache.tuscany.model.assembly.ServiceContract; +import org.apache.tuscany.model.assembly.SimpleComponent; +import org.osoa.sca.annotations.ComponentName; +import org.osoa.sca.annotations.Context; +import org.osoa.sca.annotations.Destroy; +import org.osoa.sca.annotations.Init; + +import commonj.sdo.DataObject; + +/** + * Builds runtime configurations for component implementations that map to + * {@link org.apache.tuscany.container.java.assembly.JavaImplementation}. The logical model is then decorated with the + * runtime configuration. + * + * @see org.apache.tuscany.core.builder.RuntimeConfiguration + * + * @version $Rev: 368822 $ $Date: 2006-01-13 10:54:38 -0800 (Fri, 13 Jan 2006) $ + */ +@org.osoa.sca.annotations.Scope("MODULE") +public class JavaComponentContextBuilder implements RuntimeConfigurationBuilder<AggregateContext> { + + private RuntimeContext runtimeContext; + + private ProxyFactoryFactory proxyFactoryFactory; + + private MessageFactory messageFactory; + + /* the top-level builder responsible for evaluating policies */ + private HierarchicalBuilder policyBuilder = new HierarchicalBuilder(); + + @Init(eager = true) + public void init() { + runtimeContext.addBuilder(this); + } + + /** + * @param runtimeContext The runtimeContext to set. + */ + @Autowire + public void setRuntimeContext(RuntimeContext runtimeContext) { + this.runtimeContext = runtimeContext; + } + + /** + * Sets the factory used to construct proxies implmementing the business interface required by a reference + */ + @Autowire + public void setProxyFactoryFactory(ProxyFactoryFactory factory) { + this.proxyFactoryFactory = factory; + } + + /** + * Sets the factory used to construct invocation messages + * + * @param msgFactory + */ + @Autowire + public void setMessageFactory(MessageFactory msgFactory) { + this.messageFactory = msgFactory; + } + + /** + * Adds a builder responsible for creating source-side and target-side invocation chains for a reference. The + * reference builder may be hierarchical, containing other child reference builders that operate on specific + * metadata used to construct and invocation chain. + */ + public void addPolicyBuilder(RuntimeConfigurationBuilder builder) { + policyBuilder.addBuilder(builder); + } + + // ---------------------------------- + // Constructors + // ---------------------------------- + + public JavaComponentContextBuilder() { + } + + // ---------------------------------- + // Methods + // ---------------------------------- + + public void build(AssemblyModelObject modelObject, AggregateContext parentContext) throws BuilderException { + if (!(modelObject instanceof SimpleComponent)) { + return; + } + SimpleComponent component = (SimpleComponent) modelObject; + if (component.getComponentImplementation() instanceof JavaImplementation) { + JavaImplementation javaImpl = (JavaImplementation) component.getComponentImplementation(); + // FIXME scope + Scope scope = component.getComponentImplementation().getComponentType().getServices().get(0).getServiceContract() + .getScope(); + Class implClass = null; + Set<Field> fields; + Set<Method> methods; + try { + implClass = javaImpl.getImplementationClass(); + fields = JavaIntrospectionHelper.getAllFields(implClass); + methods = JavaIntrospectionHelper.getAllUniqueMethods(implClass); + String name = component.getName(); + Constructor ctr = implClass.getConstructor((Class[]) null); + + List<Injector> injectors = new ArrayList(); + + EventInvoker initInvoker = null; + boolean eagerInit = false; + EventInvoker destroyInvoker = null; + for (Field field : fields) { + ComponentName compName = field.getAnnotation(ComponentName.class); + if (compName != null) { + Injector injector = new FieldInjector(field, new SingletonObjectFactory(name)); + injectors.add(injector); + } + Context context = field.getAnnotation(Context.class); + if (context != null) { + Injector injector = new FieldInjector(field, new SingletonObjectFactory(parentContext)); + injectors.add(injector); + } + } + for (Method method : methods) { + Init init = method.getAnnotation(Init.class); + if (init != null && initInvoker == null) { + initInvoker = new MethodEventInvoker(method); + eagerInit = init.eager(); + continue; + } + // @spec - should we allow the same method to have @init and + // @destroy? + Destroy destroy = method.getAnnotation(Destroy.class); + if (destroy != null && destroyInvoker == null) { + destroyInvoker = new MethodEventInvoker(method); + continue; + } + ComponentName compName = method.getAnnotation(ComponentName.class); + if (compName != null) { + Injector injector = new MethodInjector(method, new SingletonObjectFactory(name)); + injectors.add(injector); + } + Context context = method.getAnnotation(Context.class); + if (context != null) { + Injector injector = new MethodInjector(method, new SingletonObjectFactory(parentContext)); + injectors.add(injector); + } + } + // handle properties + List<ConfiguredProperty> configuredProperties = component.getConfiguredProperties(); + if (configuredProperties != null) { + for (ConfiguredProperty property : configuredProperties) { + Injector injector = createPropertyInjector(property, fields, methods); + injectors.add(injector); + } + } + JavaComponentRuntimeConfiguration config = new JavaComponentRuntimeConfiguration(name, JavaIntrospectionHelper + .getDefaultConstructor(implClass), eagerInit, initInvoker, destroyInvoker, scope); + component.getComponentImplementation().setRuntimeConfiguration(config); + + // create target-side invocation chains for each service offered by the implementation + for (ConfiguredService configuredService : component.getConfiguredServices()) { + Service service = configuredService.getService(); + ServiceContract serviceContract = service.getServiceContract(); + Map<Method, InvocationConfiguration> iConfigMap = new MethodHashMap(); + ProxyFactory proxyFactory = proxyFactoryFactory.createProxyFactory(); + Set<Method> javaMethods = JavaIntrospectionHelper.getAllUniqueMethods(serviceContract.getInterface()); + for (Method method : javaMethods) { + InvocationConfiguration iConfig = new InvocationConfiguration(method); + iConfigMap.put(method, iConfig); + } + QualifiedName qName = new QualifiedName(component.getName() + QualifiedName.NAME_SEPARATOR + service.getName()); + ProxyConfiguration pConfiguration = new ProxyConfiguration(qName, iConfigMap, serviceContract.getInterface() + .getClassLoader(), messageFactory); + proxyFactory.setBusinessInterface(serviceContract.getInterface()); + proxyFactory.setProxyConfiguration(pConfiguration); + config.addTargetProxyFactory(service.getName(), proxyFactory); + configuredService.setProxyFactory(proxyFactory); + if (policyBuilder != null) { + // invoke the reference builder to handle target-side metadata + policyBuilder.build(configuredService, parentContext); + } + // add tail interceptor + for (InvocationConfiguration iConfig : (Collection<InvocationConfiguration>) iConfigMap.values()) { + iConfig.addTargetInterceptor(new InvokerInterceptor()); + } + + } + + // handle references + List<ConfiguredReference> configuredReferences = component.getConfiguredReferences(); + if (configuredReferences != null) { + for (ConfiguredReference reference : configuredReferences) { + ProxyFactory proxyFactory = proxyFactoryFactory.createProxyFactory(); + ServiceContract serviceContract = reference.getReference().getServiceContract(); + Map<Method, InvocationConfiguration> iConfigMap = new HashMap(); + Set<Method> javaMethods = JavaIntrospectionHelper.getAllUniqueMethods(serviceContract.getInterface()); + for (Method method : javaMethods) { + InvocationConfiguration iConfig = new InvocationConfiguration(method); + iConfigMap.put(method, iConfig); + } + String targetCompName = reference.getTargetConfiguredServices().get(0).getAggregatePart().getName(); + String targetSerivceName = reference.getTargetConfiguredServices().get(0).getService().getName(); + + QualifiedName qName = new QualifiedName(targetCompName + "/" + targetSerivceName); + // QualifiedName qName = new QualifiedName(reference.getAggregatePart().getName() + "/" + // + reference.getPort().getName()); + ProxyConfiguration pConfiguration = new ProxyConfiguration(qName, iConfigMap, serviceContract.getInterface().getClassLoader(), messageFactory); + proxyFactory.setBusinessInterface(serviceContract.getInterface()); + proxyFactory.setProxyConfiguration(pConfiguration); + config.addSourceProxyFactory(reference.getReference().getName(), proxyFactory); + reference.setProxyFactory(proxyFactory); + if (policyBuilder != null) { + // invoke the reference builder to handle metadata associated with the reference + policyBuilder.build(reference, parentContext); + } + Injector injector = createReferenceInjector(reference.getReference().getName(), proxyFactory, fields, + methods); + injectors.add(injector); + } + } + config.setSetters(injectors); + } catch (BuilderException e) { + e.addContextName(component.getName()); + e.addContextName(parentContext.getName()); + throw e; + } catch (NoSuchMethodException e) { + BuilderConfigException ce = new BuilderConfigException("Class does not have a no-arg constructor", e); + ce.setIdentifier(implClass.getName()); + ce.addContextName(component.getName()); + ce.addContextName(parentContext.getName()); + throw ce; + } + } + } + + // ---------------------------------- + // Private methods + // ---------------------------------- + + /** + * Creates an <code>Injector</code> for component properties + */ + private Injector createPropertyInjector(ConfiguredProperty property, Set<Field> fields, Set<Method> methods) + throws NoAccessorException { + Object value = property.getValue(); + String propName = property.getProperty().getName(); + Class type = value.getClass(); + + // There is no efficient way to do this + Method method = null; + Field field = JavaIntrospectionHelper.findClosestMatchingField(propName, type, fields); + if (field == null) { + method = JavaIntrospectionHelper.findClosestMatchingMethod(propName, new Class[] { type }, methods); + if (method == null) { + throw new NoAccessorException(propName); + } + } + Injector injector = null; + if (value instanceof DataObject) { + if (field != null) { + injector = new FieldInjector(field, new SDOObjectFactory((DataObject) value)); + } else { + injector = new MethodInjector(method, new SDOObjectFactory((DataObject) value)); + } + } else if (JavaIntrospectionHelper.isImmutable(type)) { + if (field != null) { + injector = new FieldInjector(field, new SingletonObjectFactory(value)); + } else { + injector = new MethodInjector(method, new SingletonObjectFactory(value)); + } + } + return injector; + + } + + /** + * Creates an <code>Injector</code> for service references + */ + private Injector createReferenceInjector(String refName, ProxyFactory proxyFactory, Set<Field> fields, Set<Method> methods) + throws NoAccessorException, BuilderConfigException { + Method method = null; + Field field = JavaIntrospectionHelper.findClosestMatchingField(refName, proxyFactory.getBusinessInterface(), fields); + if (field == null) { + method = JavaIntrospectionHelper.findClosestMatchingMethod(refName, + new Class[] { proxyFactory.getBusinessInterface() }, methods); + if (method == null) { + throw new NoAccessorException(refName); + } + } + Injector injector; + try { + if (field != null) { + injector = new FieldInjector(field, new ProxyObjectFactory(proxyFactory)); + } else { + injector = new MethodInjector(method, new ProxyObjectFactory(proxyFactory)); + } + } catch (FactoryInitException e) { + BuilderConfigException ce = new BuilderConfigException("Error configuring reference", e); + ce.setIdentifier(refName); + throw ce; + } + return injector; + + } + +} |