summaryrefslogtreecommitdiffstats
path: root/sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/system/builder/SystemComponentContextBuilder.java
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/system/builder/SystemComponentContextBuilder.java')
-rw-r--r--sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/system/builder/SystemComponentContextBuilder.java383
1 files changed, 383 insertions, 0 deletions
diff --git a/sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/system/builder/SystemComponentContextBuilder.java b/sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/system/builder/SystemComponentContextBuilder.java
new file mode 100644
index 0000000000..ac65a3de49
--- /dev/null
+++ b/sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/system/builder/SystemComponentContextBuilder.java
@@ -0,0 +1,383 @@
+/**
+ *
+ * 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.Constructor;
+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.NoAccessorException;
+import org.apache.tuscany.core.builder.RuntimeConfigurationBuilder;
+import org.apache.tuscany.core.builder.UnknownTypeException;
+import org.apache.tuscany.core.config.JavaIntrospectionHelper;
+import org.apache.tuscany.core.context.AggregateContext;
+import org.apache.tuscany.core.context.AutowireContext;
+import org.apache.tuscany.core.context.ConfigurationContext;
+import org.apache.tuscany.core.context.SystemAggregateContext;
+import org.apache.tuscany.core.context.impl.AggregateContextImpl;
+import org.apache.tuscany.core.injection.EventInvoker;
+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.ObjectCreationException;
+import org.apache.tuscany.core.injection.ReferenceTargetFactory;
+import org.apache.tuscany.core.injection.SDOObjectFactory;
+import org.apache.tuscany.core.injection.SingletonObjectFactory;
+import org.apache.tuscany.core.runtime.RuntimeContext;
+import org.apache.tuscany.core.system.annotation.Autowire;
+import org.apache.tuscany.core.system.annotation.ParentContext;
+import org.apache.tuscany.core.system.assembly.SystemImplementation;
+import org.apache.tuscany.core.system.config.SystemComponentRuntimeConfiguration;
+import org.apache.tuscany.core.system.context.SystemAggregateContextImpl;
+import org.apache.tuscany.model.assembly.AssemblyModelObject;
+import org.apache.tuscany.model.assembly.Component;
+import org.apache.tuscany.model.assembly.ComponentImplementation;
+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.Module;
+import org.apache.tuscany.model.assembly.Scope;
+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;
+
+/**
+ * Decorates components whose implementation type is a
+ * {@link org.apache.tuscany.core.system.assembly.SystemImplementation} with the appropriate runtime configuration.
+ * System components are not proxied.
+ *
+ * @version $Rev$ $Date$
+ */
+public class SystemComponentContextBuilder implements RuntimeConfigurationBuilder<AggregateContext> {
+ // ----------------------------------
+ // Constructors
+ // ----------------------------------
+
+ public SystemComponentContextBuilder() {
+ }
+
+ // ----------------------------------
+ // Methods
+ // ----------------------------------
+
+ public void build(AssemblyModelObject modelObject, AggregateContext parentContext) throws BuilderException {
+ if (!(modelObject instanceof Component)) {
+ return;
+ }
+ Component component = (Component) modelObject;
+
+ Class implClass = null;
+ Scope scope = null;
+
+ // Get the component implementation
+ ComponentImplementation componentImplementation = component.getComponentImplementation();
+ if (componentImplementation instanceof SystemImplementation
+ && componentImplementation.getRuntimeConfiguration() == null) {
+
+ // The component is a system component, implemented by a Java class
+ SystemImplementation javaImpl = (SystemImplementation) componentImplementation;
+ scope = componentImplementation.getComponentType().getServices().get(0).getServiceContract().getScope();
+ implClass = javaImpl.getImplementationClass();
+
+ } else if (componentImplementation instanceof Module) {
+ 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=SystemAggregateContextImpl.class;
+ scope = Scope.AGGREGATE;
+
+ } else {
+
+ // The component is an app module component, fix the implementation class to our implementation
+ // of app module component context
+ implClass=AggregateContextImpl.class;
+ scope = Scope.AGGREGATE;
+
+ }
+
+ } else {
+ return;
+ }
+
+ // FIXME scope
+ Set<Field> fields;
+ Set<Method> methods;
+ try {
+ fields = JavaIntrospectionHelper.getAllFields(implClass);
+ methods = JavaIntrospectionHelper.getAllUniqueMethods(implClass);
+ String name = component.getName();
+ Constructor ctr = implClass.getConstructor((Class[]) null);
+
+ List<Injector> injectors = new ArrayList();
+
+ // 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!=AggregateContextImpl.class) {
+ // handle references
+ List<ConfiguredReference> configuredReferences = component.getConfiguredReferences();
+ if (configuredReferences != null) {
+ for (ConfiguredReference reference : configuredReferences) {
+ Injector injector = createReferenceInjector(parentContext.getName(), component.getName(), parentContext,
+ reference, fields, methods);
+ injectors.add(injector);
+ }
+ }
+ }
+
+ // create factory for the component implementation type
+ 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);
+ }
+ ParentContext parentField = field.getAnnotation(ParentContext.class);
+ if (parentField != null) {
+ if (!(parentContext instanceof AggregateContext)) {
+ BuilderConfigException e = new BuilderConfigException("Component must be a child of");
+ e.setIdentifier(AggregateContext.class.getName());
+ throw e;
+ }
+ Injector injector = new FieldInjector(field, new SingletonObjectFactory((parentContext)));
+ injectors.add(injector);
+ }
+ Autowire autowire = field.getAnnotation(Autowire.class);
+ if (autowire != null) {
+ if (!(parentContext instanceof AutowireContext)) {
+ BuilderConfigException e = new BuilderConfigException("Parent context must implement");
+ e.setIdentifier(AutowireContext.class.getName());
+ throw e;
+ }
+ AutowireContext ctx = (AutowireContext) parentContext;
+ // for system aggregate context types, only allow autowire of certain types, otherwise we have a
+ // chicken-and-egg problem
+ if (SystemAggregateContext.class.isAssignableFrom(implClass)
+ && !(field.getType().equals(ConfigurationContext.class)
+ || field.getType().equals(MonitorFactory.class)
+ || field.getType().equals(RuntimeContext.class) || field.getType().equals(
+ AutowireContext.class))) {
+ BuilderConfigException e = new BuilderConfigException("Illegal autowire type for system context");
+ e.setIdentifier(field.getType().getName());
+ throw e;
+ }
+
+ Object o = ctx.resolveInstance(field.getType());
+ if (autowire.required() && o == null) {
+ BuilderConfigException e = new BuilderConfigException("No autowire found for field");
+ e.setIdentifier(field.getName());
+ throw e;
+ }
+ Injector injector = new FieldInjector(field, new SingletonObjectFactory(o));
+ 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;
+ }
+ 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);
+ }
+ ParentContext parentMethod = method.getAnnotation(ParentContext.class);
+ if (parentMethod != null) {
+ if (!(parentContext instanceof AggregateContext)) {
+ BuilderConfigException e = new BuilderConfigException("Component must be a child of ");
+ e.setIdentifier(AggregateContext.class.getName());
+ throw e;
+ }
+ Injector injector = new MethodInjector(method, new SingletonObjectFactory((parentContext)));
+ injectors.add(injector);
+ }
+ Autowire autowire = method.getAnnotation(Autowire.class);
+ if (autowire != null) {
+ if (!(parentContext instanceof AutowireContext)) {
+ BuilderConfigException e = new BuilderConfigException("Parent context must implement)");
+ e.setIdentifier(AutowireContext.class.getName());
+ throw e;
+ }
+ if (method.getParameterTypes() == null || method.getParameterTypes().length != 1) {
+ BuilderConfigException e = new BuilderConfigException(
+ "Autowire setter methods must take one parameter");
+ e.setIdentifier(method.getName());
+ throw e;
+ }
+ AutowireContext ctx = (AutowireContext) parentContext;
+ Class paramType = method.getParameterTypes()[0];
+ // for system aggregate context types, only allow autowire of certain types, otherwise we have a
+ // chicken-and-egg problem
+ if (SystemAggregateContext.class.isAssignableFrom(implClass)
+ && !(paramType.equals(ConfigurationContext.class) || paramType.equals(MonitorFactory.class)
+ || paramType.equals(RuntimeContext.class) || paramType.equals(AutowireContext.class))) {
+ BuilderConfigException e = new BuilderConfigException("Illegal autowire type for system context");
+ e.setIdentifier(paramType.getName());
+ throw e;
+ }
+ Object o = ctx.resolveInstance(paramType);
+ if (autowire.required() && o == null) {
+ BuilderConfigException e = new BuilderConfigException("No autowire found for method ");
+ e.setIdentifier(method.getName());
+ throw e;
+ }
+
+ Injector injector = new MethodInjector(method, new SingletonObjectFactory(o));
+ injectors.add(injector);
+ }
+ }
+ // decorate the logical model
+ SystemComponentRuntimeConfiguration config = new SystemComponentRuntimeConfiguration(name,
+ JavaIntrospectionHelper.getDefaultConstructor(implClass), injectors, eagerInit, initInvoker,
+ destroyInvoker, scope);
+ componentImplementation.setRuntimeConfiguration(config);
+ } catch (BuilderConfigException 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());
+ 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();
+ // @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 = null;
+ // FIXME support types other than String
+ 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));
+ }
+ } else {
+ if (field != null) {
+ throw new UnknownTypeException(field.getName());
+ } else {
+ throw new UnknownTypeException(method.getName());
+ }
+ }
+ return injector;
+
+ }
+
+ /**
+ * Creates an <code>Injector</code> for service references
+ */
+ private Injector createReferenceInjector(String moduleName, String componentName, AggregateContext parentContext,
+ ConfiguredReference reference, Set<Field> fields, Set<Method> methods) throws NoAccessorException,
+ BuilderConfigException {
+ String refName = reference.getReference().getName();
+ List<ConfiguredService> services = reference.getTargetConfiguredServices();
+ Class type;
+ if (services.size() == 1) {
+ // get the interface
+ type = reference.getReference().getServiceContract().getInterface();
+ } else {
+ // FIXME do we support arrays?
+ type = List.class;
+ }
+ Method method = null;
+ Field field = JavaIntrospectionHelper.findClosestMatchingField(refName, type, fields);
+ if (field == null) {
+ method = JavaIntrospectionHelper.findClosestMatchingMethod(refName, new Class[] { type }, methods);
+ if (method == null) {
+ throw new NoAccessorException(refName);
+ }
+ }
+ Injector injector;
+ try {
+ if (field != null) {
+ injector = new FieldInjector(field, new ReferenceTargetFactory(reference, parentContext));
+ } else {
+ injector = new MethodInjector(method, new ReferenceTargetFactory(reference, parentContext));
+ }
+ } catch (ObjectCreationException e) {
+ BuilderConfigException ce = new BuilderConfigException("Error configuring reference", e);
+ ce.setIdentifier(refName);
+ throw ce;
+ }
+ return injector;
+
+ }
+
+}