diff options
Diffstat (limited to 'sca-java-1.x/tags/java-M1-final/java/sca/core/src/main/java/org/apache/tuscany/core/system/builder/SystemContextFactoryBuilder.java')
-rw-r--r-- | sca-java-1.x/tags/java-M1-final/java/sca/core/src/main/java/org/apache/tuscany/core/system/builder/SystemContextFactoryBuilder.java | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/sca-java-1.x/tags/java-M1-final/java/sca/core/src/main/java/org/apache/tuscany/core/system/builder/SystemContextFactoryBuilder.java b/sca-java-1.x/tags/java-M1-final/java/sca/core/src/main/java/org/apache/tuscany/core/system/builder/SystemContextFactoryBuilder.java new file mode 100644 index 0000000000..835324c392 --- /dev/null +++ b/sca-java-1.x/tags/java-M1-final/java/sca/core/src/main/java/org/apache/tuscany/core/system/builder/SystemContextFactoryBuilder.java @@ -0,0 +1,343 @@ +/** + * + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * 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.core.system.builder; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.apache.tuscany.common.monitor.MonitorFactory; +import org.apache.tuscany.core.builder.BuilderConfigException; +import org.apache.tuscany.core.builder.BuilderException; +import org.apache.tuscany.core.builder.ContextFactoryBuilder; +import org.apache.tuscany.core.builder.ContextResolver; +import org.apache.tuscany.core.builder.NoAccessorException; +import org.apache.tuscany.core.builder.ObjectFactory; +import org.apache.tuscany.core.builder.UnknownTypeException; +import org.apache.tuscany.core.builder.impl.ArrayMultiplicityObjectFactory; +import org.apache.tuscany.core.builder.impl.ListMultiplicityObjectFactory; +import org.apache.tuscany.core.config.JavaIntrospectionHelper; +import org.apache.tuscany.core.context.impl.CompositeContextImpl; +import org.apache.tuscany.core.extension.config.InjectorExtensibilityElement; +import org.apache.tuscany.core.extension.config.extensibility.ComponentNameExtensibilityElement; +import org.apache.tuscany.core.extension.config.extensibility.ContextExtensibilityElement; +import org.apache.tuscany.core.extension.config.extensibility.DestroyInvokerExtensibilityElement; +import org.apache.tuscany.core.extension.config.extensibility.InitInvokerExtensibilityElement; +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.MethodInjector; +import org.apache.tuscany.core.injection.NonProxiedTargetFactory; +import org.apache.tuscany.core.injection.SingletonObjectFactory; +import org.apache.tuscany.core.system.assembly.SystemImplementation; +import org.apache.tuscany.core.system.assembly.SystemModule; +import org.apache.tuscany.core.system.config.SystemContextFactory; +import org.apache.tuscany.core.system.config.SystemInjectorExtensibilityElement; +import org.apache.tuscany.core.system.config.extensibility.MonitorExtensibilityElement; +import org.apache.tuscany.core.system.context.SystemCompositeContextImpl; +import org.apache.tuscany.model.assembly.AssemblyObject; +import org.apache.tuscany.model.assembly.Component; +import org.apache.tuscany.model.assembly.Composite; +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.Implementation; +import org.apache.tuscany.model.assembly.Module; +import org.apache.tuscany.model.assembly.Multiplicity; +import org.apache.tuscany.model.assembly.Scope; +import org.apache.tuscany.model.assembly.Service; + +/** + * Decorates components whose implementation type is a {@link org.apache.tuscany.core.system.assembly.SystemImplementation} + * with the appropriate runtime configuration. This builder handles both system composite components as well + * as system leaf or "simple" components. Consequently, both simple and composite component types may be + * injected and autowired. + * <p/> + * Note that system component references are not proxied. + * + * @version $Rev$ $Date$ + */ +public class SystemContextFactoryBuilder implements ContextFactoryBuilder { + + private final MonitorFactory monitorFactory; + + public SystemContextFactoryBuilder(MonitorFactory monitorFactory) { + this.monitorFactory = monitorFactory; + } + + @SuppressWarnings("unchecked") + public void build(AssemblyObject modelObject) throws BuilderException { + if (!(modelObject instanceof Component)) { + return; + } + Component component = (Component) modelObject; + + Class implClass; + Scope scope; + // Get the component implementation + Implementation componentImplementation = component.getImplementation(); + if (componentImplementation instanceof SystemImplementation + && component.getContextFactory() == null) { + + // The component is a system component, implemented by a Java class + SystemImplementation implementation = (SystemImplementation) componentImplementation; + if (componentImplementation.getComponentType().getServices() == null + || componentImplementation.getComponentType().getServices().size() < 1) { + BuilderConfigException e = new BuilderConfigException("No service configured on component type"); + e.setIdentifier(component.getName()); + throw e; + } + implClass = implementation.getImplementationClass(); + Scope previous = null; + scope = Scope.MODULE; + List<Service> services = component.getImplementation().getComponentType().getServices(); + for (Service service : services) { + // calculate and validate the scope of the component; ensure that all service scopes are the same unless + // a scope is stateless + Scope current = service.getServiceContract().getScope(); + if (previous != null && current != null && current != previous + && (current != Scope.INSTANCE && previous != Scope.INSTANCE)) { + BuilderException e = new BuilderConfigException("Incompatible scopes specified for services on component"); + e.setIdentifier(component.getName()); + throw e; + } + if (current != null && current != Scope.MODULE) { + scope = current; + } + } + + } else if (componentImplementation instanceof Composite) { + implClass = ((Composite) componentImplementation).getImplementationClass(); + if (implClass == null) { + // FIXME this is a hack + if (((Module) componentImplementation).getName().startsWith("org.apache.tuscany.core.system")) + { + // The component is a system module component, fix the implementation class to our implementation + // of system module component context + implClass = SystemCompositeContextImpl.class; + } else if (componentImplementation instanceof SystemModule) { + implClass = SystemCompositeContextImpl.class; + } else { + // The component is an app module component, fix the implementation class to our implementation + // of app module component context + //FIXME this should be extensible, i.e. the model should specify the impl class of the module + implClass = CompositeContextImpl.class; + } + //END hack + } + scope = Scope.AGGREGATE; + } else { + return; + } + Set<Field> fields; + Set<Method> methods; + SystemContextFactory contextFactory; + try { + fields = JavaIntrospectionHelper.getAllFields(implClass); + methods = JavaIntrospectionHelper.getAllUniqueMethods(implClass); + String name = component.getName(); + if (componentImplementation instanceof Module) { + Module module = (Module) componentImplementation; + contextFactory = new SystemContextFactory(name, module, JavaIntrospectionHelper.getDefaultConstructor(implClass), scope); + + } else { + contextFactory = new SystemContextFactory(name, JavaIntrospectionHelper.getDefaultConstructor(implClass), scope); + } + + //ContextObjectFactory contextObjectFactory = new ContextObjectFactory(contextFactory); + + List<Injector> injectors = new ArrayList<Injector>(); + + // handle properties + List<ConfiguredProperty> configuredProperties = component.getConfiguredProperties(); + if (configuredProperties != null) { + for (ConfiguredProperty property : configuredProperties) { + Injector injector = createPropertyInjector(property, fields, methods); + injectors.add(injector); + } + } + + // FIXME do not inject references on an application module yet + if (implClass != CompositeContextImpl.class) { + // handle references + List<ConfiguredReference> configuredReferences = component.getConfiguredReferences(); + if (configuredReferences != null) { + for (ConfiguredReference reference : configuredReferences) { + Injector injector = createReferenceInjector(reference, fields, methods, contextFactory); + injectors.add(injector); + } + } + } + List<Object> elements = componentImplementation.getComponentType().getExtensibilityElements(); + for (Object element : elements) { + if (element instanceof InitInvokerExtensibilityElement) { + InitInvokerExtensibilityElement invokerElement = (InitInvokerExtensibilityElement) element; + EventInvoker<Object> initInvoker = invokerElement.getEventInvoker(); + boolean eagerInit = invokerElement.isEager(); + contextFactory.setEagerInit(eagerInit); + contextFactory.setInitInvoker(initInvoker); + } else if (element instanceof DestroyInvokerExtensibilityElement) { + DestroyInvokerExtensibilityElement invokerElement = (DestroyInvokerExtensibilityElement) element; + EventInvoker<Object> destroyInvoker = invokerElement.getEventInvoker(); + contextFactory.setDestroyInvoker(destroyInvoker); + } else if (element instanceof ComponentNameExtensibilityElement) { + ComponentNameExtensibilityElement nameElement = (ComponentNameExtensibilityElement) element; + injectors.add(nameElement.getEventInvoker(name)); + } else if (element instanceof ContextExtensibilityElement) { + ContextExtensibilityElement contextElement = (ContextExtensibilityElement) element; + injectors.add(contextElement.getInjector(contextFactory)); + } else if (element instanceof InjectorExtensibilityElement) { + InjectorExtensibilityElement injectorElement = (InjectorExtensibilityElement) element; + injectors.add(injectorElement.getInjector(contextFactory)); + } else if (element instanceof SystemInjectorExtensibilityElement) { + SystemInjectorExtensibilityElement injectorElement = (SystemInjectorExtensibilityElement) element; + injectors.add(injectorElement.getInjector(contextFactory)); + } else if (element instanceof MonitorExtensibilityElement) { + MonitorExtensibilityElement monitorElement = (MonitorExtensibilityElement) element; + injectors.add(monitorElement.getInjector(monitorFactory)); + } + } + contextFactory.setSetters(injectors); + // decorate the logical model + component.setContextFactory(contextFactory); + } catch (BuilderConfigException e) { + e.addContextName(component.getName()); + throw e; + } catch (NoSuchMethodException e) { + BuilderConfigException ce = new BuilderConfigException("Class does not have a no-arg constructor", e); + ce.setIdentifier(implClass.getName()); + throw ce; + } catch (FactoryInitException e) { + BuilderConfigException ce = new BuilderConfigException("Error building component", e); + ce.addContextName(component.getName()); + throw ce; + } + } + + /** + * 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(); + // @FIXME is this how to get property type of object + 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; + // FIXME support types other than String + if (JavaIntrospectionHelper.isImmutable(type)) { + if (field != null) { + injector = new FieldInjector(field, new SingletonObjectFactory<Object>(value)); + } else { + injector = new MethodInjector(method, new SingletonObjectFactory<Object>(value)); + } + } else { + if (field != null) { + throw new UnknownTypeException(field.getName()); + } else { + throw new UnknownTypeException(method.getName()); + } + } + return injector; + + } + + /** + * Creates object factories that resolve target(s) of a reference and an <code>Injector</code> responsible + * for injecting them into the reference + */ + private Injector createReferenceInjector(ConfiguredReference reference, Set<Field> fields, Set<Method> methods, + ContextResolver resolver) { + + List<ObjectFactory> objectFactories = new ArrayList<ObjectFactory>(); + String refName = reference.getPort().getName(); + Class refClass = reference.getPort().getServiceContract().getInterface(); + for (ConfiguredService configuredService : reference.getTargetConfiguredServices()) { + objectFactories.add(new NonProxiedTargetFactory(configuredService, resolver)); + } + boolean multiplicity = reference.getPort().getMultiplicity() == Multiplicity.ONE_N + || reference.getPort().getMultiplicity() == Multiplicity.ZERO_N; + return createInjector(refName, refClass, multiplicity, objectFactories, fields, methods); + + } + + /** + * Creates an <code>Injector</code> for an object factories associated with a reference. + */ + private Injector createInjector(String refName, Class refClass, boolean multiplicity, List<ObjectFactory> objectFactories, + Set<Field> fields, Set<Method> methods) throws NoAccessorException, BuilderConfigException { + Field field; + Method method = null; + if (multiplicity) { + // since this is a multiplicity, we cannot match on business interface type, so scan through the fields, + // matching on name and List or Array + field = JavaIntrospectionHelper.findMultiplicityFieldByName(refName, fields); + if (field == null) { + // No fields found. Again, since this is a multiplicity, we cannot match on interface type, so + // scan through the fields, matching on name and List or Array + method = JavaIntrospectionHelper.findMultiplicityMethodByName(refName, methods); + if (method == null) { + throw new NoAccessorException(refName); + } + } + Injector injector; + if (field != null) { + // for multiplicities, we need to inject the target or targets using an object factory + // which first delegates to create the proxies and then returns them in the appropriate List or array + // type + if (field.getType().isArray()) { + injector = new FieldInjector(field, new ArrayMultiplicityObjectFactory(refClass, objectFactories)); + } else { + injector = new FieldInjector(field, new ListMultiplicityObjectFactory(objectFactories)); + } + } else { + if (method.getParameterTypes()[0].isArray()) { + injector = new MethodInjector(method, new ArrayMultiplicityObjectFactory(refClass, objectFactories)); + } else { + injector = new MethodInjector(method, new ListMultiplicityObjectFactory(objectFactories)); + } + } + return injector; + } else { + field = JavaIntrospectionHelper.findClosestMatchingField(refName, refClass, fields); + if (field == null) { + method = JavaIntrospectionHelper.findClosestMatchingMethod(refName, new Class[]{refClass}, methods); + if (method == null) { + throw new NoAccessorException(refName); + } + } + Injector injector; + if (field != null) { + injector = new FieldInjector(field, objectFactories.get(0)); + } else { + injector = new MethodInjector(method, objectFactories.get(0)); + } + return injector; + } + } + +} |