/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.sca.implementation.osgi.context; import java.lang.annotation.ElementType; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import org.apache.tuscany.sca.assembly.ComponentProperty; import org.apache.tuscany.sca.assembly.ComponentService; import org.apache.tuscany.sca.context.RequestContextFactory; import org.apache.tuscany.sca.core.context.RequestContextImpl; import org.apache.tuscany.sca.core.factory.ObjectCreationException; import org.apache.tuscany.sca.core.factory.ObjectFactory; import org.apache.tuscany.sca.core.invocation.CallbackWireObjectFactory; import org.apache.tuscany.sca.core.invocation.ProxyFactory; import org.apache.tuscany.sca.implementation.java.IntrospectionException; import org.apache.tuscany.sca.implementation.java.JavaImplementation; import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl; import org.apache.tuscany.sca.implementation.java.impl.JavaResourceImpl; import org.apache.tuscany.sca.implementation.java.injection.ArrayMultiplicityObjectFactory; import org.apache.tuscany.sca.implementation.java.injection.ConversationIDObjectFactory; import org.apache.tuscany.sca.implementation.java.injection.FieldInjector; import org.apache.tuscany.sca.implementation.java.injection.Injector; import org.apache.tuscany.sca.implementation.java.injection.InvalidAccessorException; import org.apache.tuscany.sca.implementation.java.injection.JavaPropertyValueObjectFactory; import org.apache.tuscany.sca.implementation.java.injection.ListMultiplicityObjectFactory; import org.apache.tuscany.sca.implementation.java.injection.MethodInjector; import org.apache.tuscany.sca.implementation.java.injection.ResourceObjectFactory; import org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper; import org.apache.tuscany.sca.runtime.RuntimeComponent; import org.apache.tuscany.sca.runtime.RuntimeComponentReference; import org.apache.tuscany.sca.runtime.RuntimeWire; import org.osoa.sca.ComponentContext; import org.osoa.sca.RequestContext; import org.osoa.sca.annotations.ConversationID; /** * OSGi property injection support * * @version $Rev$ $Date$ */ public class OSGiPropertyInjector { private ArrayList injectionSites = new ArrayList(); private Hashtable factories = new Hashtable(); private Injector[] injectors; public OSGiPropertyInjector( JavaImplementation javaImpl, RuntimeComponent component, JavaPropertyValueObjectFactory propertyValueFactory, ProxyFactory proxyFactory, RequestContextFactory requestContextFactory) throws IntrospectionException { createInjectionSites(javaImpl, component, propertyValueFactory, proxyFactory, requestContextFactory); injectors = createInjectors(); } @SuppressWarnings("unchecked") public void injectProperties(Object instance) { for (Injector injector : injectors) { injector.inject(instance); } } @SuppressWarnings("unchecked") private void createInjectionSites( JavaImplementation javaImpl, RuntimeComponent component, JavaPropertyValueObjectFactory propertyValueFactory, ProxyFactory proxyFactory, RequestContextFactory requestContextFactory) { List componentProperties = component.getProperties(); Map propertyMembers = javaImpl.getPropertyMembers(); for (ComponentProperty prop : componentProperties) { JavaElementImpl element = propertyMembers.get(prop.getName()); if (element != null && !(element.getAnchor() instanceof Constructor) && prop.getValue() != null) { Class propertyJavaType = JavaIntrospectionHelper.getBaseType(element.getType(), element.getGenericType()); ObjectFactory objFactory = propertyValueFactory.createValueFactory(prop, prop.getValue(), propertyJavaType); factories.put(element, objFactory); injectionSites.add(element); } } for (Member member : javaImpl.getConversationIDMembers()) { ObjectFactory factory = new ConversationIDObjectFactory(); if (member instanceof Field) { JavaElementImpl element = new JavaElementImpl((Field) member); element.setClassifer(ConversationID.class); injectionSites.add(element); factories.put(element, factory); } else if (member instanceof Method) { JavaElementImpl element = new JavaElementImpl((Method) member, 0); element.setName(JavaIntrospectionHelper.toPropertyName(member.getName())); element.setClassifer(ConversationID.class); injectionSites.add(element); factories.put(element, factory); } else { throw new InvalidAccessorException( "Member must be a field or method: " + member.getName()); } } if (!javaImpl.getCallbackMembers().isEmpty()) { Map> callbackWires = new HashMap>(); for (ComponentService service : component.getServices()) { RuntimeComponentReference callbackReference = (RuntimeComponentReference)service.getCallbackReference(); if (callbackReference != null) { List wires = callbackReference.getRuntimeWires(); if (!wires.isEmpty()) { callbackWires.put(wires.get(0).getSource().getInterfaceContract().getInterface().toString(), wires); } } } for (Map.Entry> entry : javaImpl.getCallbackMembers() .entrySet()) { List wires = callbackWires.get(entry.getKey()); if (wires == null) { // this can happen when there are no client wires to a // component that has a callback continue; } for(JavaElementImpl element : entry.getValue()) { ObjectFactory factory = new CallbackWireObjectFactory(element.getType(), proxyFactory, wires); if (!(element.getAnchor() instanceof Constructor)) { injectionSites.add(element); } factories.put(element, factory); } } } for (JavaResourceImpl resource : javaImpl.getResources().values()) { ObjectFactory objectFactory; Class type = resource.getElement().getType(); if (ComponentContext.class.equals(type)) { objectFactory = new ComponentContextFactory(component); } else if (RequestContext.class.equals(type)) { objectFactory = new RequestContextObjectFactory(requestContextFactory, proxyFactory); } else { boolean optional = resource.isOptional(); String mappedName = resource.getMappedName(); objectFactory = new ResourceObjectFactory(type, mappedName, optional, null); } factories.put(resource.getElement(), objectFactory); if (!(resource.getElement().getAnchor() instanceof Constructor)) { injectionSites.add(resource.getElement()); } } } @SuppressWarnings("unchecked") private Injector[] createInjectors() { Injector[] injectors = (Injector[])new Injector[injectionSites.size()]; int i = 0; for (JavaElementImpl element : injectionSites) { Object obj = factories.get(element); if (obj != null) { if (obj instanceof ObjectFactory) { ObjectFactory factory = (ObjectFactory)obj; Member member = (Member)element.getAnchor(); if (element.getElementType() == ElementType.FIELD) { injectors[i++] = new FieldInjector((Field)member, factory); } else if (element.getElementType() == ElementType.PARAMETER && member instanceof Method) { injectors[i++] = new MethodInjector((Method)member, factory); } else if (member instanceof Constructor) { // Ignore } else { throw new AssertionError(String.valueOf(element)); } } else { injectors[i++] = createMultiplicityInjector(element, (List>)obj); } } } return injectors; } @SuppressWarnings("unchecked") protected Injector createMultiplicityInjector(JavaElementImpl element, List> factories) { Class interfaceType = JavaIntrospectionHelper.getBaseType(element.getType(), element.getGenericType()); if (element.getAnchor() instanceof Field) { Field field = (Field)element.getAnchor(); if (field.getType().isArray()) { return new FieldInjector(field, new ArrayMultiplicityObjectFactory(interfaceType, factories)); } else { return new FieldInjector(field, new ListMultiplicityObjectFactory(factories)); } } else if (element.getAnchor() instanceof Method) { Method method = (Method)element.getAnchor(); if (method.getParameterTypes()[0].isArray()) { return new MethodInjector(method, new ArrayMultiplicityObjectFactory(interfaceType, factories)); } else { return new MethodInjector(method, new ListMultiplicityObjectFactory(factories)); } } else { throw new InvalidAccessorException("Member must be a field or method: " + element.getName()); } } private static class ComponentContextFactory implements ObjectFactory { RuntimeComponent component; private ComponentContextFactory(RuntimeComponent component) { this.component = component; } public Object getInstance() throws ObjectCreationException { return component.getComponentContext(); } } private static class RequestContextObjectFactory implements ObjectFactory { private RequestContextFactory factory; private ProxyFactory proxyFactory; public RequestContextObjectFactory(RequestContextFactory factory) { this(factory, null); } public RequestContextObjectFactory(RequestContextFactory factory, ProxyFactory proxyFactory) { this.factory = factory; this.proxyFactory = proxyFactory; } public RequestContext getInstance() throws ObjectCreationException { if (factory != null) { return factory.createRequestContext(); } else { return new RequestContextImpl(proxyFactory); } } } }