diff options
Diffstat (limited to 'branches/java-post-M1/sca/containers/container.java/src/main/java')
12 files changed, 1215 insertions, 0 deletions
diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/JavaAssemblyFactory.java b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/JavaAssemblyFactory.java new file mode 100644 index 0000000000..90271179d1 --- /dev/null +++ b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/JavaAssemblyFactory.java @@ -0,0 +1,30 @@ +/** + * + * 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.assembly; + +import org.apache.tuscany.model.assembly.AssemblyFactory; + + +/** + * The Factory for the model. + */ +public interface JavaAssemblyFactory extends AssemblyFactory { + /** + * Returns a new JavaImplementation. + */ + JavaImplementation createJavaImplementation(); +} diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/JavaImplementation.java b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/JavaImplementation.java new file mode 100644 index 0000000000..a87b8ea1bb --- /dev/null +++ b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/JavaImplementation.java @@ -0,0 +1,39 @@ +/** + * + * 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.assembly; + +import org.apache.tuscany.model.assembly.AtomicImplementation; + + +/** + * Represents a java implementation. + * + * @version $Rev$ $Date$ + */ +public interface JavaImplementation extends AtomicImplementation { + + /** + * Returns the implementation class. + */ + Class<?> getImplementationClass(); + + /** + * Sets the implementation class. + */ + void setImplementationClass(Class<?> value); + +} diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/impl/JavaAssemblyFactoryImpl.java b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/impl/JavaAssemblyFactoryImpl.java new file mode 100644 index 0000000000..3337c287ac --- /dev/null +++ b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/impl/JavaAssemblyFactoryImpl.java @@ -0,0 +1,45 @@ +/** + * + * 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.assembly.impl; + +import org.osoa.sca.annotations.Service; + +import org.apache.tuscany.container.java.assembly.JavaAssemblyFactory; +import org.apache.tuscany.container.java.assembly.JavaImplementation; +import org.apache.tuscany.model.assembly.impl.AssemblyFactoryImpl; + +/** + * A factory for the model. + */ +@Service(interfaces = {JavaAssemblyFactory.class}) +public class JavaAssemblyFactoryImpl extends AssemblyFactoryImpl implements JavaAssemblyFactory { + + /** + * Constructor + */ + public JavaAssemblyFactoryImpl() { + super(); + } + + /** + * @see org.apache.tuscany.container.java.assembly.JavaAssemblyFactory#createJavaImplementation() + */ + public JavaImplementation createJavaImplementation() { + return new JavaImplementationImpl(); + } + +} diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/impl/JavaImplementationImpl.java b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/impl/JavaImplementationImpl.java new file mode 100644 index 0000000000..57a98f4ad6 --- /dev/null +++ b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/assembly/impl/JavaImplementationImpl.java @@ -0,0 +1,44 @@ +/** + * + * 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.assembly.impl; + +import org.apache.tuscany.container.java.assembly.JavaImplementation; +import org.apache.tuscany.model.assembly.impl.AtomicImplementationImpl; + +/** + * An implementation of JavaImplementation. + * + * @version $Rev$ $Date$ + */ +public class JavaImplementationImpl extends AtomicImplementationImpl implements JavaImplementation { + private Class<?> implementationClass; + + /** + * Default constructor. + */ + protected JavaImplementationImpl() { + } + + public Class<?> getImplementationClass() { + return implementationClass; + } + + public void setImplementationClass(Class<?> value) { + checkNotFrozen(); + implementationClass = value; + } +} diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/builder/JavaContextFactoryBuilder.java b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/builder/JavaContextFactoryBuilder.java new file mode 100644 index 0000000000..de915738f9 --- /dev/null +++ b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/builder/JavaContextFactoryBuilder.java @@ -0,0 +1,113 @@ +/** + * + * 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.builder; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.tuscany.container.java.assembly.JavaImplementation; +import org.apache.tuscany.container.java.config.JavaContextFactory; +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.extension.config.InjectorExtensibilityElement; +import org.apache.tuscany.core.builder.BuilderConfigException; +import org.apache.tuscany.core.builder.BuilderException; +import org.apache.tuscany.core.builder.ContextFactory; +import org.apache.tuscany.core.config.JavaIntrospectionHelper; +import org.apache.tuscany.core.extension.ContextFactoryBuilderSupport; +import org.apache.tuscany.core.injection.EventInvoker; +import org.apache.tuscany.core.injection.Injector; +import org.apache.tuscany.core.wire.service.WireFactoryService; +import org.apache.tuscany.model.assembly.Scope; + +/** + * Builds context factories for component implementations that map to {@link + * org.apache.tuscany.container.java.assembly.JavaImplementation}. The logical model is then decorated with + * the runtime configuration. + * + * @version $Rev: 368822 $ $Date: 2006-01-13 10:54:38 -0800 (Fri, 13 Jan 2006) $ + * @see org.apache.tuscany.core.builder.ContextFactory + */ +@org.osoa.sca.annotations.Scope("MODULE") +public class JavaContextFactoryBuilder extends ContextFactoryBuilderSupport<JavaImplementation> { + + /** + * Default constructor + */ + public JavaContextFactoryBuilder() { + super(); + } + + /** + * Constructs a new instance + * + * @param wireFactoryService the system service responsible for creating wire factories + */ + public JavaContextFactoryBuilder(WireFactoryService wireFactoryService) { + super(wireFactoryService); + } + + @SuppressWarnings("unchecked") + protected ContextFactory createContextFactory(String name, JavaImplementation javaImpl, Scope scope) { + Class implClass = null; + JavaContextFactory contextFactory; + try { + implClass = javaImpl.getImplementationClass(); + + contextFactory = new JavaContextFactory(name, JavaIntrospectionHelper + .getDefaultConstructor(implClass), scope); + + List<Injector> injectors = new ArrayList<Injector>(); + List<Object> elements = javaImpl.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)); + } + } + contextFactory.setSetters(injectors); + return contextFactory; + } catch (BuilderException e) { + e.addContextName(name); + throw e; + } catch (NoSuchMethodException e) { + BuilderConfigException ce = new BuilderConfigException("Class does not have a no-arg constructor", e); + ce.setIdentifier(implClass.getName()); + ce.addContextName(name); + throw ce; + } + } + +} diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/builder/JavaTargetWireBuilder.java b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/builder/JavaTargetWireBuilder.java new file mode 100644 index 0000000000..cc66fa54f6 --- /dev/null +++ b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/builder/JavaTargetWireBuilder.java @@ -0,0 +1,38 @@ +/** + * + * 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.builder; + +import org.apache.tuscany.container.java.config.JavaContextFactory; +import org.apache.tuscany.container.java.invocation.ScopedJavaComponentInvoker; +import org.apache.tuscany.core.context.QualifiedName; +import org.apache.tuscany.core.context.ScopeContext; +import org.apache.tuscany.core.extension.WireBuilderSupport; +import org.apache.tuscany.core.wire.TargetInvoker; +import org.osoa.sca.annotations.Scope; + +import java.lang.reflect.Method; + +/** + * Completes a wire to a Java-based target component by adding a scoped java invoker to the source chain + * + * @version $Rev$ $Date$ + */ +@Scope("MODULE") +public class JavaTargetWireBuilder extends WireBuilderSupport<JavaContextFactory> { + + protected TargetInvoker createInvoker(QualifiedName targetName, Method operation, ScopeContext context, boolean downScope) { + boolean cacheable = !downScope; + return new ScopedJavaComponentInvoker(targetName, operation, context,cacheable); + } +} diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/config/JavaContextFactory.java b/branches/java-post-M1/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/branches/java-post-M1/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; + } + } + + +} diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/context/JavaAtomicContext.java b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/context/JavaAtomicContext.java new file mode 100644 index 0000000000..27581198aa --- /dev/null +++ b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/context/JavaAtomicContext.java @@ -0,0 +1,165 @@ +/** + * + * 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.context; + +import org.apache.tuscany.core.builder.ObjectFactory; +import org.apache.tuscany.core.context.AtomicContext; +import org.apache.tuscany.core.context.ContextInitException; +import org.apache.tuscany.core.context.QualifiedName; +import org.apache.tuscany.core.context.TargetException; +import org.apache.tuscany.core.context.event.InstanceCreated; +import org.apache.tuscany.core.context.impl.AbstractContext; +import org.apache.tuscany.core.injection.EventInvoker; +import org.apache.tuscany.core.injection.ObjectCallbackException; +import org.apache.tuscany.core.injection.ObjectCreationException; + +/** + * Manages Java component implementation instances + * + * @version $Rev$ $Date$ + */ +public class JavaAtomicContext extends AbstractContext implements AtomicContext { + + private boolean eagerInit; + + private EventInvoker<Object> initInvoker; + + private EventInvoker<Object> destroyInvoker; + + private boolean stateless; + + // the cached target instance + private Object cachedTargetInstance; + + // creates a new implementation instance with injected references and properties + private ObjectFactory objectFactory; + + public JavaAtomicContext(String name, ObjectFactory objectFactory, boolean eagerInit, EventInvoker<Object> initInvoker, + EventInvoker<Object> destroyInvoker, boolean stateless) { + super(name); + assert (objectFactory != null) : "Object factory was null"; + if (eagerInit && initInvoker == null) { + ContextInitException e = new ContextInitException("No intialization method found for implementation"); + e.setIdentifier(getName()); + throw e; + } + this.objectFactory = objectFactory; + + this.eagerInit = eagerInit; + this.initInvoker = initInvoker; + this.destroyInvoker = destroyInvoker; + this.stateless = stateless; + } + + public void setName(String name) { + super.setName(name); + } + + protected int type; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public void init() throws TargetException { + getInstance(null); + } + + public void destroy() throws TargetException { + if (cachedTargetInstance != null) { + if (destroyInvoker != null) { + try { + destroyInvoker.invokeEvent(cachedTargetInstance); + } catch (ObjectCallbackException e) { + TargetException te = new TargetException(e.getCause()); + te.setIdentifier(getName()); + throw te; + } + } + } + lifecycleState = STARTED; + } + + public synchronized Object getInstance(QualifiedName qName) throws TargetException { + //TODO implement returning of proxy and wire chain for service + if (cachedTargetInstance != null) { + return cachedTargetInstance; // already cached, just return + } + + if (getLifecycleState() == ERROR || getLifecycleState() == CONFIG_ERROR) { + return null; + } + synchronized (this) { + try { + Object instance = objectFactory.getInstance(); + // handle @Init + if (initInvoker != null) { + initInvoker.invokeEvent(instance); + } + publish(new InstanceCreated(this)); + lifecycleState = RUNNING; + if (stateless) { + return instance; + } else { + cachedTargetInstance = instance; // cache the instance + return cachedTargetInstance; + } + } catch (ObjectCreationException e) { + lifecycleState = ERROR; + TargetException te = new TargetException("Error creating component instance", e); + te.setIdentifier(getName()); + throw te; + } + } + + } + + public Object getTargetInstance() throws TargetException { + //TODO refactor when getInstance() returns a proxy + return getInstance(null); + } + + public boolean isEagerInit() { + return eagerInit; + } + + public boolean isDestroyable() { + return (destroyInvoker != null); + } + + public void start() throws ContextInitException { + if (getLifecycleState() != UNINITIALIZED && getLifecycleState() != STOPPED) { + throw new IllegalStateException("Context must be in UNINITIALIZED state [" + getLifecycleState() + "]"); + } + if (objectFactory == null) { + lifecycleState = ERROR; + ContextInitException e = new ContextInitException("Object factory not found"); + e.setIdentifier(getName()); + throw e; + } + lifecycleState = INITIALIZED; + } + + public void stop() { + lifecycleState = STOPPED; + } + +} diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/invocation/AbstractJavaComponentInvoker.java b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/invocation/AbstractJavaComponentInvoker.java new file mode 100644 index 0000000000..33fa9238b6 --- /dev/null +++ b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/invocation/AbstractJavaComponentInvoker.java @@ -0,0 +1,93 @@ +/** + * + * 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.invocation; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Set; + +import org.apache.tuscany.core.config.JavaIntrospectionHelper; +import org.apache.tuscany.core.context.TargetException; +import org.apache.tuscany.core.wire.Interceptor; +import org.apache.tuscany.core.wire.InvocationRuntimeException; +import org.apache.tuscany.core.wire.TargetInvoker; +import org.apache.tuscany.core.message.Message; + +/** + * Base class for dispatching to a Java based component implementation. Subclasses implement a strategy for resolving + * implementation instances. + * + * @version $Rev$ $Date$ + */ +public abstract class AbstractJavaComponentInvoker implements TargetInvoker { + + protected Method operation; + + public AbstractJavaComponentInvoker(Method operation) { + assert (operation != null) : "Operation method cannot be null"; + this.operation = operation; + } + + public Object invokeTarget(Object payload) throws InvocationTargetException { + try { + Object instance = getInstance(); + if (!operation.getDeclaringClass().isInstance(instance)) { + Set<Method> methods = JavaIntrospectionHelper.getAllUniqueMethods(instance.getClass()); + Method newOperation = JavaIntrospectionHelper.findClosestMatchingMethod(operation.getName(), operation + .getParameterTypes(), methods); + if (newOperation != null) + operation = newOperation; + } + if (payload != null && !payload.getClass().isArray()) { + return operation.invoke(instance, payload); + } else { + return operation.invoke(instance, (Object[]) payload); + } + } catch (IllegalAccessException e) { + throw new InvocationRuntimeException(e); + } + } + + public Message invoke(Message msg) { + try { + Object resp = invokeTarget(msg.getBody()); + msg.setBody(resp); + } catch (InvocationTargetException e) { + msg.setBody(e.getCause()); + } catch (Throwable e) { + msg.setBody(e); + } + return msg; + } + + protected abstract Object getInstance() throws TargetException; + + public void setNext(Interceptor next) { + throw new IllegalStateException("This interceptor must be the last interceptor in an interceptor chain"); + } + + @Override + public Object clone() throws CloneNotSupportedException { + try { + AbstractJavaComponentInvoker clone = (AbstractJavaComponentInvoker) super.clone(); + clone.operation = this.operation; + return clone; + } catch (CloneNotSupportedException e) { + return null; // will not happen + } + } +} diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/invocation/ScopedJavaComponentInvoker.java b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/invocation/ScopedJavaComponentInvoker.java new file mode 100644 index 0000000000..85d72b4b0d --- /dev/null +++ b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/invocation/ScopedJavaComponentInvoker.java @@ -0,0 +1,89 @@ +/** + * + * 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.invocation; + +import org.apache.tuscany.core.context.QualifiedName; +import org.apache.tuscany.core.context.ScopeContext; +import org.apache.tuscany.core.context.TargetException; + +import java.lang.reflect.Method; + +/** + * Uses a scope container to resolve an implementation instance based on the current thread context + * + * @version $Rev$ $Date$ + */ +public class ScopedJavaComponentInvoker extends AbstractJavaComponentInvoker { + + private ScopeContext container; + + private QualifiedName name; + + private Object target; + + public boolean cacheable; + + + /** + * Creates a new invoker + * + * @param serviceName the name of the component/service pair to invoke + * @param operation the operation the invoker is associated with + * @param scopeContext the scope context the component is resolved in + * @param cacheable Sets whether the target service instance may be cached by the invoker. This is a possible optimization + * when a wire is configured for a "down-scope" reference, i.e. a reference from a source of a shorter + * lifetime to a source of greater lifetime. + */ + public ScopedJavaComponentInvoker(QualifiedName serviceName, Method operation, ScopeContext scopeContext, boolean cacheable) { + super(operation); + assert (serviceName != null) : "No service name specified"; + assert (scopeContext != null) : "No scope scopeContext specified"; + name = serviceName; + this.container = scopeContext; + this.cacheable = cacheable; + } + + /** + * Returns whether the target is cacheable. + */ + public boolean isCacheable() { + return cacheable; + } + + /** + * Resolves the target service instance or returns a cached one + */ + protected Object getInstance() throws TargetException { + if (!cacheable) { + return container.getInstance(name); + } else { + if (target == null) { + target = container.getInstance(name); + } + return target; + } + } + + public Object clone() throws CloneNotSupportedException { + ScopedJavaComponentInvoker invoker = (ScopedJavaComponentInvoker) super.clone(); + invoker.target = null; + invoker.cacheable = this.cacheable; + invoker.container = this.container; + invoker.name = this.name; + return invoker; + } +} diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/invocation/StaticJavaComponentTargetInvoker.java b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/invocation/StaticJavaComponentTargetInvoker.java new file mode 100644 index 0000000000..dd757137cf --- /dev/null +++ b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/invocation/StaticJavaComponentTargetInvoker.java @@ -0,0 +1,50 @@ +/** + * + * 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.invocation; + +import java.lang.reflect.Method; + +/** + * Caches component instances that do not need to be resolved for every wire, e.g. an wire originating from + * a lesser scope intended for a target with a wider scope + * + * @version $Rev$ $Date$ + */ +public class StaticJavaComponentTargetInvoker extends AbstractJavaComponentInvoker { + + private Object instance; + + public StaticJavaComponentTargetInvoker(Method operation, Object instance) { + super(operation); + assert (instance != null) : "Instance cannot be null"; + this.instance = instance; + } + + protected Object getInstance() { + return instance; + } + + public boolean isCacheable() { + return true; + } + + public Object clone() throws CloneNotSupportedException { + StaticJavaComponentTargetInvoker invoker = (StaticJavaComponentTargetInvoker) super.clone(); + invoker.instance = null; + return invoker; + } +} diff --git a/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/loader/JavaImplementationLoader.java b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/loader/JavaImplementationLoader.java new file mode 100644 index 0000000000..c9f0a09792 --- /dev/null +++ b/branches/java-post-M1/sca/containers/container.java/src/main/java/org/apache/tuscany/container/java/loader/JavaImplementationLoader.java @@ -0,0 +1,168 @@ +/** + * + * Copyright 2005 The Apache Software Foundation + * + * 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.loader; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.tuscany.common.resource.ResourceLoader; +import org.apache.tuscany.container.java.assembly.JavaAssemblyFactory; +import org.apache.tuscany.container.java.assembly.JavaImplementation; +import org.apache.tuscany.core.config.ComponentTypeIntrospector; +import org.apache.tuscany.core.config.ConfigurationLoadException; +import org.apache.tuscany.core.config.InvalidRootElementException; +import org.apache.tuscany.core.config.JavaIntrospectionHelper; +import org.apache.tuscany.core.config.SidefileLoadException; +import org.apache.tuscany.core.config.processor.ProcessorUtils; +import org.apache.tuscany.core.loader.LoaderContext; +import org.apache.tuscany.core.loader.StAXElementLoader; +import org.apache.tuscany.core.loader.StAXLoaderRegistry; +import org.apache.tuscany.core.loader.assembly.AssemblyConstants; +import org.apache.tuscany.core.system.annotation.Autowire; +import org.apache.tuscany.model.assembly.ComponentType; +import org.osoa.sca.annotations.Destroy; +import org.osoa.sca.annotations.Init; +import org.osoa.sca.annotations.Scope; + +/** + * @version $Rev$ $Date$ + */ +@Scope("MODULE") +public class JavaImplementationLoader implements StAXElementLoader<JavaImplementation> { + public static final QName IMPLEMENTATION_JAVA = new QName("http://www.osoa.org/xmlns/sca/0.9", "implementation.java"); + public static final QName IMPLEMENTATION_JAVA_RECURSIVE = new QName("http://www.osoa.org/xmlns/sca/1.0", "implementation.java"); + + private StAXLoaderRegistry registry; + private XMLInputFactory xmlFactory; + + private JavaAssemblyFactory factory; + private ComponentTypeIntrospector introspector; + + public JavaImplementationLoader() { + // todo make this a reference to a system service + xmlFactory = XMLInputFactory.newInstance(); + } + + @Autowire + public void setRegistry(StAXLoaderRegistry registry) { + this.registry = registry; + } + + @Autowire + public void setFactory(JavaAssemblyFactory factory) { + this.factory = factory; + //FIXME JFM HACK + introspector = ProcessorUtils.createCoreIntrospector(factory); + } + + @Init(eager = true) + public void start() { + registry.registerLoader(IMPLEMENTATION_JAVA, this); + registry.registerLoader(IMPLEMENTATION_JAVA_RECURSIVE, this); + } + + @Destroy + public void stop() { + registry.unregisterLoader(IMPLEMENTATION_JAVA, this); + registry.unregisterLoader(IMPLEMENTATION_JAVA_RECURSIVE, this); + } + + public JavaImplementation load(XMLStreamReader reader, LoaderContext loaderContext) throws XMLStreamException, ConfigurationLoadException { + JavaImplementation javaImpl = factory.createJavaImplementation(); + String typeName = reader.getAttributeValue(null, "class"); + Class<?> implementationClass = getImplementationClass(loaderContext.getResourceLoader(), typeName); + javaImpl.setImplementationClass(implementationClass); + javaImpl.setComponentType(loadComponentType(loaderContext, implementationClass)); + return javaImpl; + } + + protected Class<?> getImplementationClass(ResourceLoader resourceLoader, String typeName) throws ConfigurationLoadException { + ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); + try { + // set TCCL in case the application code needs it + Thread.currentThread().setContextClassLoader(resourceLoader.getClassLoader()); + return resourceLoader.loadClass(typeName); + } catch (ClassNotFoundException e) { + throw new ConfigurationLoadException(e.getMessage(), e); + } finally { + Thread.currentThread().setContextClassLoader(oldCL); + } + } + + protected ComponentType loadComponentType(LoaderContext loaderContext, Class<?> implClass) throws ConfigurationLoadException, XMLStreamException { + String baseName = JavaIntrospectionHelper.getBaseName(implClass); + URL sidefile = implClass.getResource(baseName + ".componentType"); + if (sidefile == null) { + return loadComponentTypeByIntrospection(implClass); + } else { + return loadComponentTypeFromSidefile(sidefile, loaderContext); + } + } + + protected ComponentType loadComponentTypeByIntrospection(Class<?> implClass) throws ConfigurationLoadException { + return introspector.introspect(implClass); + } + + protected ComponentType loadComponentTypeFromSidefile(URL sidefile, LoaderContext loaderContext) throws SidefileLoadException { + try { + XMLStreamReader reader; + InputStream is; + is = sidefile.openStream(); + try { + reader = xmlFactory.createXMLStreamReader(is); + try { + reader.nextTag(); + if (!AssemblyConstants.COMPONENT_TYPE.equals(reader.getName())) { + InvalidRootElementException e = new InvalidRootElementException(AssemblyConstants.COMPONENT_TYPE, reader.getName()); + e.setResourceURI(sidefile.toString()); + throw e; + } + return (ComponentType) registry.load(reader, loaderContext); + } finally { + try { + reader.close(); + } catch (XMLStreamException e) { + // ignore + } + } + } finally { + try { + is.close(); + } catch (IOException e) { + // ignore + } + } + } catch (IOException e) { + SidefileLoadException sfe = new SidefileLoadException(e.getMessage()); + sfe.setResourceURI(sidefile.toString()); + throw sfe; + } catch (XMLStreamException e) { + SidefileLoadException sfe = new SidefileLoadException(e.getMessage()); + sfe.setResourceURI(sidefile.toString()); + throw sfe; + } catch (ConfigurationLoadException e) { + SidefileLoadException sfe = new SidefileLoadException(e.getMessage()); + sfe.setResourceURI(sidefile.toString()); + throw sfe; + } + } +} |