diff options
Diffstat (limited to 'sca-java-1.x/tags/java-M1-final/java/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/config/JavaContextFactory.java')
-rw-r--r-- | sca-java-1.x/tags/java-M1-final/java/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/config/JavaContextFactory.java | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/sca-java-1.x/tags/java-M1-final/java/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/config/JavaContextFactory.java b/sca-java-1.x/tags/java-M1-final/java/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/config/JavaContextFactory.java new file mode 100644 index 0000000000..ff498d851a --- /dev/null +++ b/sca-java-1.x/tags/java-M1-final/java/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/config/JavaContextFactory.java @@ -0,0 +1,341 @@ +/** + * + * 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.container.java.config; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import commonj.sdo.DataObject; +import org.apache.tuscany.container.java.context.JavaAtomicContext; +import org.apache.tuscany.core.builder.BuilderConfigException; +import org.apache.tuscany.core.builder.ContextCreationException; +import org.apache.tuscany.core.builder.ContextFactory; +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.impl.ArrayMultiplicityObjectFactory; +import org.apache.tuscany.core.builder.impl.ListMultiplicityObjectFactory; +import org.apache.tuscany.core.builder.impl.ProxyObjectFactory; +import org.apache.tuscany.core.config.JavaIntrospectionHelper; +import org.apache.tuscany.core.context.AtomicContext; +import org.apache.tuscany.core.context.CompositeContext; +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.MethodInjector; +import org.apache.tuscany.core.injection.PojoObjectFactory; +import org.apache.tuscany.core.injection.SingletonObjectFactory; +import org.apache.tuscany.core.wire.SourceWireFactory; +import org.apache.tuscany.core.wire.TargetWireFactory; +import org.apache.tuscany.databinding.sdo.SDOObjectFactory; +import org.apache.tuscany.model.assembly.Scope; +import org.osoa.sca.annotations.Property; +import org.osoa.sca.annotations.Reference; + +/** + * A ContextFactory that handles POJO component implementation types + * + * @version $Rev$ $Date$ + */ +public class JavaContextFactory implements ContextFactory<AtomicContext>, ContextResolver { + + // the component name as configured in the hosting module + private String name; + + // the parent context of the component + private CompositeContext parentContext; + + private Map<String, TargetWireFactory> targetProxyFactories = new HashMap<String, TargetWireFactory>(); + + private List<SourceWireFactory> sourceProxyFactories = new ArrayList<SourceWireFactory>(); + + // the implementation type constructor + private Constructor<Object> ctr; + + private Set<Field> fields; + + private Set<Method> methods; + + // injectors for properties, references and other metadata values such as + private List<Injector> setters; + + // an invoker for a method decorated with @Init + private EventInvoker<Object> init; + + // whether the component should be eagerly initialized when its scope starts + private boolean eagerInit; + + // an invoker for a method decorated with @Destroy + private EventInvoker<Object> destroy; + + // the scope of the implementation instance + private Scope scope; + + // whether the component is stateless + private boolean stateless; + + /** + * Creates a new context factory + * + * @param name the SCDL name of the component the context refers to + * @param ctr the implementation type constructor + * @param scope the scope of the component implementation type + */ + public JavaContextFactory(String name, Constructor<Object> ctr, Scope scope) { + assert (name != null) : "Name was null"; + assert (ctr != null) : "Constructor was null"; + this.name = name; + this.ctr = ctr; + this.scope = scope; + stateless = (scope == Scope.INSTANCE); + fields = JavaIntrospectionHelper.getAllFields(ctr.getDeclaringClass()); + methods = JavaIntrospectionHelper.getAllUniqueMethods(ctr.getDeclaringClass()); + } + + public String getName() { + return name; + } + + public Scope getScope() { + return scope; + } + + public AtomicContext createContext() throws ContextCreationException { + PojoObjectFactory<?> objectFactory = new PojoObjectFactory<Object>(ctr, null, setters); + return new JavaAtomicContext(name, objectFactory, eagerInit, init, destroy, stateless); + } + + public void addTargetWireFactory(String serviceName, TargetWireFactory factory) { + targetProxyFactories.put(serviceName, factory); + } + + public TargetWireFactory getTargetWireFactory(String serviceName) { + return targetProxyFactories.get(serviceName); + } + + public Map<String, TargetWireFactory> getTargetWireFactories() { + return targetProxyFactories; + } + + public void addProperty(String propertyName, Object value) { + setters.add(createPropertyInjector(propertyName, value)); + } + + public void addSourceWireFactory(String referenceName, SourceWireFactory factory) { + sourceProxyFactories.add(factory); + setters.add(createReferenceInjector(referenceName, factory, false)); + } + + public void addSourceWireFactories(String referenceName, Class referenceInterface, List<SourceWireFactory> factories, boolean multiplicity) { + sourceProxyFactories.addAll(factories); + setters.add(createReferenceInjector(referenceName, factories, multiplicity)); + } + + public List<SourceWireFactory> getSourceWireFactories() { + return sourceProxyFactories; + } + + public void setSetters(List<Injector> setters) { + this.setters = setters; + } + + public void setEagerInit(boolean val) { + eagerInit = val; + } + + public void setInitInvoker(EventInvoker<Object> invoker) { + init = invoker; + } + + public void setDestroyInvoker(EventInvoker<Object> invoker) { + destroy = invoker; + } + + public void prepare(CompositeContext parent) { + parentContext = parent; + } + + public CompositeContext getCurrentContext() { + return parentContext; + } + + /** + * Creates an <code>Injector</code> for component properties + */ + private Injector createPropertyInjector(String propertyName, Object value) + throws NoAccessorException { + Class type = value.getClass(); + + // There is no efficient way to do this + Method method = null; + Field field = JavaIntrospectionHelper.findClosestMatchingField(propertyName, type, fields); + if (field == null) { + // hack for TUSCANY-322 + for (Field current : fields) { + Property annot = current.getAnnotation(Property.class); + if (annot != null) { + if (propertyName.equals(annot.name())) { + field = current; + break; + } + } + } + method = JavaIntrospectionHelper.findClosestMatchingMethod(propertyName, new Class[]{type}, methods); + if (method == null) { + // hack for TUSCANY-322 + for (Method current : methods) { + Property annot = current.getAnnotation(Property.class); + if (annot != null) { + if (propertyName.equals(annot.name())) { + method = current; + break; + } + } + } + if (method == null) { + throw new NoAccessorException(propertyName); + } + } + } + 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<Object>(value)); + } else { + injector = new MethodInjector(method, new SingletonObjectFactory<Object>(value)); + } + } + return injector; + + } + + /** + * Creates proxy factories that represent target(s) of a reference and an <code>Injector</code> + * responsible for injecting them into the reference + */ + private Injector createReferenceInjector(String refName, List<SourceWireFactory> wireFactories, boolean multiplicity) { + Class refClass = wireFactories.get(0).getBusinessInterface(); //reference.getPort().getServiceContract().getInterface(); + // iterate through the targets + List<ObjectFactory> objectFactories = new ArrayList<ObjectFactory>(); + for (SourceWireFactory wireFactory : wireFactories) { + objectFactories.add(new ProxyObjectFactory(wireFactory)); + } + return createInjector(refName, refClass, multiplicity, objectFactories, fields, methods); + + } + + private Injector createReferenceInjector(String refName, SourceWireFactory wireFactory, boolean multiplicity) { + Class refClass = wireFactory.getBusinessInterface();//reference.getPort().getServiceContract().getInterface(); + List<ObjectFactory> objectFactories = new ArrayList<ObjectFactory>(); + objectFactories.add(new ProxyObjectFactory(wireFactory)); + return createInjector(refName, refClass, multiplicity, objectFactories, fields, methods); + + } + + /** + * Creates an <code>Injector</code> for a set of 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 business 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; + // for multiplicities, we need to inject the reference proxy or proxies using an object factory + // which first delegates to create the proxies and then returns them in the appropriate List or array type + if (field != null) { + 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) { + // hack for TUSCANY-300 + for (Field current : fields) { + Reference annot = current.getAnnotation(Reference.class); + if (annot != null) { + if (refName.equals(annot.name())) { + field = current; + break; + } + } + } + if (field == null) { + method = JavaIntrospectionHelper.findClosestMatchingMethod(refName, new Class[]{refClass}, methods); + if(method == null){ + // Fix for Tuscany-325 + method = JavaIntrospectionHelper.findClosestMatchingMethod("set"+refName.substring(0,1).toUpperCase()+ refName.substring(1), new Class[]{refClass}, methods); + } + if (method == null) { + // hack for TUSCANY-300 + for (Method current : methods) { + Reference annot = current.getAnnotation(Reference.class); + if (annot != null) { + if (refName.equals(annot.name())) { + method = current; + break; + } + } + } + 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; + } + } + + +} |