Package org.apache.tuscany.sca.implementation.osgi.invocation

Source Code of org.apache.tuscany.sca.implementation.osgi.invocation.OSGiImplementationProvider

/*
* 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.invocation;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;

import org.apache.tuscany.sca.assembly.ComponentProperty;
import org.apache.tuscany.sca.assembly.ComponentReference;
import org.apache.tuscany.sca.assembly.ComponentService;
import org.apache.tuscany.sca.assembly.Multiplicity;
import org.apache.tuscany.sca.assembly.Property;
import org.apache.tuscany.sca.assembly.Reference;
import org.apache.tuscany.sca.assembly.Service;
import org.apache.tuscany.sca.context.RequestContextFactory;
import org.apache.tuscany.sca.core.context.InstanceWrapper;
import org.apache.tuscany.sca.core.factory.ObjectCreationException;
import org.apache.tuscany.sca.core.factory.ObjectFactory;
import org.apache.tuscany.sca.core.invocation.JDKProxyFactory;
import org.apache.tuscany.sca.core.invocation.ProxyFactory;
import org.apache.tuscany.sca.core.scope.Scope;
import org.apache.tuscany.sca.core.scope.ScopeContainer;
import org.apache.tuscany.sca.core.scope.ScopeRegistry;
import org.apache.tuscany.sca.core.scope.ScopedImplementationProvider;
import org.apache.tuscany.sca.core.scope.ScopedRuntimeComponent;
import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint;
import org.apache.tuscany.sca.databinding.impl.SimpleTypeMapperImpl;
import org.apache.tuscany.sca.implementation.java.IntrospectionException;
import org.apache.tuscany.sca.implementation.java.injection.JavaPropertyValueObjectFactory;
import org.apache.tuscany.sca.implementation.osgi.OSGiImplementationInterface;
import org.apache.tuscany.sca.implementation.osgi.context.OSGiAnnotations;
import org.apache.tuscany.sca.implementation.osgi.xml.OSGiImplementation;
import org.apache.tuscany.sca.interfacedef.Interface;
import org.apache.tuscany.sca.interfacedef.Operation;
import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
import org.apache.tuscany.sca.invocation.Invoker;
import org.apache.tuscany.sca.osgi.runtime.OSGiRuntime;
import org.apache.tuscany.sca.runtime.EndpointReference;
import org.apache.tuscany.sca.runtime.RuntimeComponent;
import org.apache.tuscany.sca.runtime.RuntimeComponentReference;
import org.apache.tuscany.sca.runtime.RuntimeComponentService;
import org.apache.tuscany.sca.runtime.RuntimeWire;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleException;
import org.osgi.framework.BundleListener;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.FrameworkListener;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.service.packageadmin.ExportedPackage;
import org.osgi.service.packageadmin.PackageAdmin;

/**
* The runtime instantiation of OSGi component implementations
*
*/
public class OSGiImplementationProvider  implements ScopedImplementationProvider,
                                                    FrameworkListener,
                                                    BundleListener {
   
    private static final String COMPONENT_SERVICE_NAME = "component.service.name";
 
    private OSGiImplementation implementation;
    private OSGiAnnotations osgiAnnotations;
    private BundleContext bundleContext;
   
    private Hashtable<RuntimeWire, Reference> referenceWires = new Hashtable<RuntimeWire,Reference>();
    private Hashtable<RuntimeWire, ComponentReference> componentReferenceWires
                       = new Hashtable<RuntimeWire,ComponentReference>();
    private HashSet<RuntimeWire> resolvedWires = new HashSet<RuntimeWire>();  
    private boolean wiresResolved;
   
    private boolean bundleStarted;
   
    private boolean processedResolvedBundle, processingResolvedBundle;
   
    private JavaPropertyValueObjectFactory propertyValueFactory;
   

    private Hashtable<String, Object> componentProperties = new Hashtable<String, Object>();
    private RuntimeComponent runtimeComponent;
   
    private Bundle osgiBundle;
    private ArrayList<Bundle> dependentBundles = new ArrayList<Bundle>();
    private OSGiServiceListener osgiServiceListener;
    private PackageAdmin packageAdmin;
   
    private OSGiRuntime osgiRuntime;
   
    private ScopeRegistry scopeRegistry;
    private DataBindingExtensionPoint dataBindingRegistry;
   
    private boolean packagesRefreshed;
   

    public OSGiImplementationProvider(RuntimeComponent definition,
            OSGiImplementationInterface impl,
            DataBindingExtensionPoint dataBindingRegistry,
            JavaPropertyValueObjectFactory propertyValueFactory,
            ProxyFactory proxyFactory,
            ScopeRegistry scopeRegistry,
            RequestContextFactory requestContextFactory) throws BundleException {
       
       
        this.implementation = (OSGiImplementation)impl;
        this.runtimeComponent = definition;
        this.dataBindingRegistry = dataBindingRegistry;
        this.propertyValueFactory = propertyValueFactory;
        this.scopeRegistry = scopeRegistry;
       
       
        bundleContext = getBundleContext();
        osgiBundle = (Bundle)implementation.getOSGiBundle();
        bundleContext.addBundleListener(this);
        osgiServiceListener = new OSGiServiceListener(osgiBundle);       
        bundleContext.addServiceListener(osgiServiceListener);   
       
        // Install and start all dependent  bundles
        String[] imports = implementation.getImports();
        for (int i = 0; i < imports.length; i++) {
            String location = imports[i].trim();
            if (location.length() > 0) {
                Bundle bundle = bundleContext.installBundle(location);
                dependentBundles.add(bundle);
            }               
        }
       

        this.osgiAnnotations = new OSGiAnnotations(
                implementation.getModelFactories(),
                implementation.getClassList(),
                runtimeComponent,
                propertyValueFactory,
                proxyFactory,
                requestContextFactory,
                osgiBundle,
                dependentBundles);

       
        // PackageAdmin is used to resolve bundles
        org.osgi.framework.ServiceReference packageAdminReference =
            bundleContext.getServiceReference("org.osgi.service.packageadmin.PackageAdmin");
        if (packageAdminReference != null) {
            packageAdmin = (PackageAdmin) bundleContext.getService(packageAdminReference);
            bundleContext.addFrameworkListener(this);
        }
       
       
    }
   
    protected RuntimeComponent getRuntimeComponent() {
        return runtimeComponent;
    }
   
    protected OSGiImplementation getImplementation() {
        return implementation;
    }
   
    // Create a property table from the list of properties
    // The source properties are properties read from <property/> elements
    // Create property values in the table of the appropriate class based
    // on the property type specified.
    private void processProperties(List<?> props, Hashtable<String, Object> propsTable) {
       
        if (props != null) {
            for (Object p : props) {
            
                Property prop = (Property)p;
                Class javaType = SimpleTypeMapperImpl.getJavaType(prop.getXSDType());
                ObjectFactory<?> objFactory = propertyValueFactory.createValueFactory(prop, prop.getValue(), javaType);
                Object value = objFactory.getInstance();         

                propsTable.put(prop.getName(), value);
            }
        }
    }

  
    private BundleContext getBundleContext() throws BundleException {

        try {
            if (bundleContext == null) {
                osgiRuntime = OSGiRuntime.getRuntime();
                bundleContext = osgiRuntime .getBundleContext();      
            }
        } catch (BundleException e) {
           throw e;
        } catch (Exception e) {
            throw new BundleException("Could not start OSGi runtime", e);
        }
       
       
        return bundleContext;
    }
   
   
    private String getOSGiFilter(Hashtable<String, Object> props) {
       
        String filter = "";
       
        if (props != null && props.size() > 0) {
            int propCount = 0;
            for (String propName : props.keySet()) {
                if (propName.equals("service.pid"))
                    continue;
                filter = filter + "(" + propName + "=" + props.get(propName+ ")";
                propCount++;
            }
   
            if (propCount > 1) filter = "(&" + filter + ")";
        }
        else
            filter = null;
        return filter;
    }
   
    /*
     * Return a matching service registered by the specified bundle.
     * If <implementation.osgi /> has the attribute filter defined, return a service
     * reference that matches the filter. Otherwise, return a service which has a component
     * name equal to this component's name. If not found, return a service which no
     * component name set.
     *
     * Even though services registered by this bundle can be filtered using the
     * service listener, we use this method to filter all service references so that
     * the service matching functionality of OSGi can be directly used.
     */
    private org.osgi.framework.ServiceReference getOSGiServiceReference(
            String scaServiceName,
            String osgiServiceName, String filter)
        throws InvalidSyntaxException {
       
        String compServiceName = runtimeComponent.getName() + "/" + scaServiceName;
        if (filter != null && filter.length() > 0) {
           org.osgi.framework.ServiceReference[] references =
                   bundleContext.getServiceReferences(osgiServiceName, filter);
          

           org.osgi.framework.ServiceReference reference = null;
           if (references != null) {
                for (org.osgi.framework.ServiceReference ref : references) {
                    if (ref.getBundle() != osgiBundle)
                        continue;
                    Object compName = ref.getProperty(COMPONENT_SERVICE_NAME);
                    if (compName == null && reference == null)
                        reference = ref;
                    if (scaServiceName == null || compServiceName.equals(compName)) {
                        reference = ref;
                        break;
                    }
                }
           }
       
           return reference;
          
        }
       
        filter = scaServiceName == null? null :
                                         "(" + COMPONENT_SERVICE_NAME + "="+ compServiceName + ")";
       
        org.osgi.framework.ServiceReference[] references =
            bundleContext.getServiceReferences(osgiServiceName, filter);
       
        if (references != null) {           
            for (org.osgi.framework.ServiceReference ref : references) {
                if (ref.getBundle() == osgiBundle) {
                    return ref;
               }
             }
        }
       
        references = bundleContext.getServiceReferences(osgiServiceName, null);
       
        org.osgi.framework.ServiceReference reference = null;
       
        if (references != null) {
            for (org.osgi.framework.ServiceReference ref : references) {
               
                if (ref.getBundle() != osgiBundle)
                    continue;
                Object compName = ref.getProperty(COMPONENT_SERVICE_NAME);
                if (compName == null && reference == null)
                    reference = ref;
                if (compServiceName.equals(compName)) {
                    reference = ref;
                    break;
                }
            }
        }
       
        return reference;
    }
   
    protected Bundle startBundle() throws ObjectCreationException {

        try {
           
            if (!bundleStarted) {
               
                bundleStarted = true;
               
                configurePropertiesUsingConfigAdmin();
               
                resolveBundle();
               
                processAnnotations(true);
               
               
                for (Bundle bundle : dependentBundles) {
                    try {
                        if (bundle.getState() != Bundle.ACTIVE && bundle.getState() != Bundle.STARTING) {
                            bundle.start();
                        }
                    } catch (BundleException e) {
                        if (bundle.getHeaders().get("Fragment-Host") == null)
                            throw e;
                    }
                }
               
            }
   
            if (osgiBundle.getState() != Bundle.ACTIVE && osgiBundle.getState() != Bundle.STARTING) {
       

                    int retry = 0;
               
                    while (retry++ < 10) {
                        try {
                            osgiBundle.start();
                            break;
                       } catch (BundleException e) {
                            // It is possible that the thread "Refresh Packages" is in the process of
                            // changing the state of this bundle.
                            Thread.yield();
                       
                            if (retry == 10)
                            throw e;
                        }
                    }
                }    
  
        } catch (Exception e) {
            throw new ObjectCreationException(e);
        }
        return osgiBundle;
    }
   
   
    // This method is called by OSGiInstanceWrapper.getInstance to obtain the OSGI service reference
    // corresponding to the specified service. The properties used to filter the service should
    // be chosen based on whether this is a normal service or a callback.
    protected org.osgi.framework.ServiceReference getOSGiServiceReference(ComponentService service)
            throws ObjectCreationException {
        
        Hashtable<String, Object> props = new Hashtable<String, Object>();
        if (!service.isCallback())
            processProperties(implementation.getServiceProperties(service.getName()), props);
        else
            processProperties(implementation.getServiceCallbackProperties(service.getName()), props);
       
        String filter = getOSGiFilter(props);
        Interface serviceInterface = service.getInterfaceContract().getInterface();
        String scaServiceName = service.getName();
           
        return getOSGiServiceReference(serviceInterface, filter, scaServiceName);
          
    }
   
    protected org.osgi.framework.ServiceReference getOSGiServiceReference(
            EndpointReference from, Interface callbackInterface)
            throws ObjectCreationException {
       
        RuntimeWire refWire = null;
        String filter = null;
        for (RuntimeWire wire : referenceWires.keySet()) {
            if (wire.getSource() == from) {
                refWire = wire;
                break;
            }
        }
        if (refWire != null) {
            Hashtable<String, Object> props = new Hashtable<String, Object>();
            ComponentReference scaRef = componentReferenceWires.get(refWire);
            processProperties(implementation.getReferenceCallbackProperties(scaRef.getName()), props);
            filter = getOSGiFilter(props);
        }
       
        return getOSGiServiceReference(callbackInterface, filter, null);
    }
   
    private org.osgi.framework.ServiceReference getOSGiServiceReference(Interface serviceInterface,
            String filter, String scaServiceName)
            throws ObjectCreationException {
       
        try {
           
            String serviceInterfaceName = null;

            org.osgi.framework.ServiceReference osgiServiceReference = null;
           
            if (serviceInterface instanceof JavaInterface) {
                serviceInterfaceName = ((JavaInterface)serviceInterface).getJavaClass().getName();
                                 
                if ((osgiServiceReference = getOSGiServiceReference(
                        scaServiceName,
                        serviceInterfaceName, filter)) == null) {
                   
                    // The service listener for our bundle will notify us when the service is registered.
                    synchronized (implementation) {                           
                                               
                        // When declarative services are used, the component is started asynchronously
                        // So this thread has to wait for the service to be registered by the component
                        // activate method
                        // For regular bundle activators, bundle.start activates the bundle synchronously
                        // and hence the service would probably have been started by the bundle activator
                        while ((osgiServiceReference = getOSGiServiceReference(
                                scaServiceName,
                                serviceInterfaceName, filter)) == null) {
                                           
                            // Wait for the bundle to register the service
                            implementation.wait(100);
                        }
                    }  
                   
                }
            }
               
            return osgiServiceReference;
           
        } catch (Exception e) {
            throw new ObjectCreationException(e);
        }
    }
   
   
    // Felix does not support bundle fragments. This is a temporary workaround.
    protected Bundle installDummyBundleWithoutFragments(Class<?> interfaceClass)
            throws Exception {

        ByteArrayOutputStream out = new ByteArrayOutputStream();

        String EOL = System.getProperty("line.separator");

        String interfaceName = interfaceClass.getName();
        String packageName = interfaceClass.getPackage().getName();
        String bundleName = "dummy.sca." + packageName;

        String manifestStr = "Manifest-Version: 1.0" + EOL
                + "Bundle-ManifestVersion: 2" + EOL + "Bundle-Name: "
                + bundleName + EOL + "Bundle-SymbolicName: " + bundleName + EOL
                + "Bundle-Version: " + "1.0.0" + EOL
                + "Bundle-Localization: plugin" + EOL;
       
        ArrayList<String> dummyClasses = new ArrayList<String>();

        StringBuilder manifestBuf = new StringBuilder();
        manifestBuf.append(manifestStr);
        manifestBuf.append("Export-Package: " + packageName + EOL);
        String exportedInterfaces = interfaceName;
        Bundle existingBundle = getDummyHostBundle(packageName);
        String existingClasses;
        dummyClasses.add(interfaceClass.getName());
        for (Class<?> clazz :  interfaceClass.getClasses()) {
            dummyClasses.add(clazz.getName());
        }
        if (existingBundle != null &&
                (existingClasses = (String)existingBundle.getHeaders().get("SCA-Dummy-Classes")) != null) {
            exportedInterfaces = exportedInterfaces + " " +  existingClasses;
           
            StringTokenizer tokenizer = new StringTokenizer(existingClasses);
            while (tokenizer.hasMoreTokens()) {
                String className = tokenizer.nextToken();
                if (!dummyClasses.contains(className))
                    dummyClasses.add(className);
            }
        }

        manifestBuf.append("SCA-Dummy-Classes: " + exportedInterfaces + EOL);

        ByteArrayInputStream manifestStream = new ByteArrayInputStream(
                manifestBuf.toString().getBytes());
        Manifest manifest = new Manifest();
        manifest.read(manifestStream);

        JarOutputStream jarOut = new JarOutputStream(out, manifest);

        for (int i = 0; i < dummyClasses.size(); i++) {

            String className = dummyClasses.get(i);
           
            Class clazz = interfaceClass.getClassLoader().loadClass(className);
            className = clazz.getName().replaceAll("\\.", "/") + ".class";
            ZipEntry ze = new ZipEntry(className);
            jarOut.putNextEntry(ze);
            InputStream stream = clazz.getResourceAsStream(clazz.getSimpleName() + ".class");
           
            byte[] bytes = new byte[stream.available()];
            stream.read(bytes);
            jarOut.write(bytes);
            stream.close();
        }
       
       
        jarOut.close();
        out.close();
       
        if (existingBundle != null) {
            existingBundle.stop();
            existingBundle.uninstall();
        }

        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());

        Bundle bundle = bundleContext.installBundle("file://" + bundleName
                + ".jar", in);

        bundle.start();
       
        if (existingBundle != null && packageAdmin != null) {
            refreshPackages();
           
        }

        return bundle;

    }
   
    private Bundle getDummyHostBundle(String packageName) {
       
        if (packageAdmin == null)
            return null;
       
        ExportedPackage exp = packageAdmin.getExportedPackage(packageName);
        if (exp == null)
            return null;
        else
            return exp.getExportingBundle();
    }
   
   
    private Bundle installDummyBundle(Class<?> interfaceClass)
            throws Exception {
       

        if (!osgiRuntime.supportsBundleFragments()) {
            return installDummyBundleWithoutFragments(interfaceClass);
        }
       
        ByteArrayOutputStream out = new ByteArrayOutputStream();
               
        String EOL = System.getProperty("line.separator");
        ArrayList<Class<?>> dummyClasses = new ArrayList<Class<?>>();
       
        String interfaceName = interfaceClass.getName();
        String packageName = interfaceClass.getPackage().getName();
        String bundleName = "dummy.sca." + interfaceName;
       
       
        String manifestStr = "Manifest-Version: 1.0" + EOL +
                        "Bundle-ManifestVersion: 2" + EOL +
                        "Bundle-Name: " + bundleName + EOL +
                        "Bundle-SymbolicName: " + bundleName + EOL +
                        "Bundle-Version: " + "1.0.0" + EOL +
                        "Bundle-Localization: plugin" + EOL;
       
                       
        StringBuilder manifestBuf = new StringBuilder();
        manifestBuf.append(manifestStr);
        manifestBuf.append("Export-Package: " + packageName + EOL);
        Bundle dummyHost = getDummyHostBundle(packageName);
        if (dummyHost != null)
            manifestBuf.append("Fragment-Host: " + dummyHost.getSymbolicName() + EOL);
      
        ByteArrayInputStream manifestStream = new ByteArrayInputStream(manifestBuf.toString().getBytes());
        Manifest manifest = new Manifest();
        manifest.read(manifestStream);
       
        dummyClasses.add(interfaceClass);
        for (Class<?> clazz :  interfaceClass.getClasses()) {
            dummyClasses.add(clazz);
        }
       
        JarOutputStream jarOut = new JarOutputStream(out, manifest);

        for (int i = 0; i < dummyClasses.size(); i++) {
           
            Class<?> clazz = dummyClasses.get(i);
            String className = clazz.getName();
            className = clazz.getName().replaceAll("\\.", "/") + ".class";
            ZipEntry ze = new ZipEntry(className);
            jarOut.putNextEntry(ze);
            InputStream stream = clazz.getResourceAsStream(clazz.getSimpleName() + ".class");
           
            byte[] bytes = new byte[stream.available()];
            stream.read(bytes);
            jarOut.write(bytes);
            stream.close();
        }
       
        jarOut.close();
        out.close();
       
       
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
       
       
        Bundle bundle = bundleContext.installBundle(
                "file://" + bundleName + ".jar",
                in);
       
        if (dummyHost == null)
            bundle.start();
       
        return bundle;
       
    }
   
   
   
    public InstanceWrapper<?> createInstanceWrapper() throws ObjectCreationException {
       
        return new OSGiInstanceWrapper<Object>(this, osgiAnnotations, bundleContext);
    }
   
  
   
    private  void resolveWireCreateDummyBundles(Class interfaceClass) throws Exception {
       
       
        try {
                
            osgiBundle.loadClass(interfaceClass.getName());
                           
        } catch (ClassNotFoundException e) {
                       
            // The interface used by the proxy is not in the source bundle
            // A dummy bundle needs to be installed to create the proxy
                    
            Bundle dummyBundle = installDummyBundle(interfaceClass);
                               
            if (packageAdmin != null) {
                                   
                packageAdmin.resolveBundles(new Bundle[]{dummyBundle, osgiBundle});
                             
            }

        }
    }
   
    /**
     * For OSGi->Java wires, create a proxy corresponding to the Java interfaces
     * and register the proxy with the OSGi registry, so that the source OSGi bundle can
     * locate the target Java instance from the registry like a regular OSGi service.
     *
     * For OSGi->OSGi wires, start the target OSGi bundle, so that references of the
     * target are resolved before the source OSGi bundle is started. If the reference
     * has properties specified, create a Proxy and register a service with highest
     * possible ranking. The Proxy should wire to the correct OSGi instance specified
     * in the SCA composite.
     *
     * The first phase determines whether a proxy should be installed. It also registers
     * a dummy bundle if necessary to resolve the bundle. When phase1 is completed on all
     * wires of the component, the bundle should be resolved. Phase2 registers the proxy service.
     */
    private boolean resolveWireResolveReferences(Bundle bundle, Class interfaceClass, RuntimeWire wire,
            boolean isOSGiToOSGiWire) throws Exception {
       

        // FIXME: At the moment injection of values into instances require an instance to be obtained
        // throught the instance wrapper, and hence requires a proxy. When we do this processing here,
        // we dont yet know whether the target requires any property or callback injection. So it is
        // safer to create a proxy all the time.
        boolean createProxy = true;
      
        ComponentReference scaRef = componentReferenceWires.get(wire);
        Hashtable<String, Object> targetProperties = new Hashtable<String, Object>();
        processProperties(implementation.getReferenceProperties(scaRef.getName()), targetProperties);
           

        if (isOSGiToOSGiWire) {
                   
                OSGiImplementationProvider implProvider = (OSGiImplementationProvider)wire.getTarget().getComponent().getImplementationProvider();
                   
                // This is an OSGi->OSGi wire
                isOSGiToOSGiWire = true;
                   
                // If the target component is stateless, use a proxy to create a new service each time
                if (!implProvider.getScope().equals(Scope.COMPOSITE)) createProxy = true;
               
                Interface interfaze = wire.getTarget().getInterfaceContract().getInterface();
               
                // If the target interface is remotable, create a proxy to support pass-by-value semantics
                // AllowsPassByReference is not detected until the target instance is obtained.
                if (interfaze.isRemotable())
                    createProxy = true;
                   
                // If any of the operations in the target interface is non-blocking, create a proxy
                List<Operation> ops = interfaze.getOperations();
                for (Operation op : ops) {
                    if (op.isNonBlocking())
                        createProxy = true;
                }
                   
                // If properties are specified for the reference, create a proxy since rewiring may be required
                if (targetProperties.size() > 0) {
                    createProxy = true;
                }
               
                // If properties are specified for the component, create a proxy for configuring
                // the component services.
                if (componentProperties.size() > 0) {
                    createProxy = true;
                }
                   
                // Since this is an OSGi->OSGi wire, start the target bundle before starting the
                // source bundle if there is no proxy. For direct wiring without a proxy, this ordering
                // is irrelevant in terms of class resolution, but the target needs to be started at some
                // point. But there is no opportunity later on to start the target OSGi bundle without a proxy.   
                // When a Proxy is used, the target bundle needs to be resolved for the source bundle
                // to be resolved so that the interface is visible to the source. In this case the bundle
                // will be started when an instance is needed.                   
                if (!createProxy) {   
                    implProvider.startBundle();
                }
                else {
                    implProvider.resolveBundle();
                }
        }
        else {
                createProxy = true;
        }
           
        return createProxy;
    }
   
   
    // Register proxy service
    private void resolveWireRegisterProxyService(Bundle bundle, Class interfaceClass, RuntimeWire wire) throws Exception {
         
        ComponentReference scaRef = componentReferenceWires.get(wire);
        Hashtable<String, Object> targetProperties = new Hashtable<String, Object>();
        processProperties(implementation.getReferenceProperties(scaRef.getName()), targetProperties);
        targetProperties.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE);
       
        if (targetProperties.get(COMPONENT_SERVICE_NAME) == null && wire.getTarget().getComponent() != null) {
            String compServiceName = wire.getTarget().getComponent().getName() + "/" +
                                     wire.getTarget().getContract().getName();
            targetProperties.put(COMPONENT_SERVICE_NAME, compServiceName);
        }
       
          
        JDKProxyFactory proxyService = new JDKProxyFactory();
             
        Class<?> proxyInterface = bundle.loadClass(interfaceClass.getName());
               

        Object proxy = proxyService.createProxy(proxyInterface, wire);
      
           
        bundleContext.registerService(proxyInterface.getName(), proxy, targetProperties);
           
       
    }
   
    private void registerCallbackProxyService(Bundle bundle, Class interfaceClass,
            RuntimeComponentService service) throws Exception {
       
        List<RuntimeWire> wires = service.getCallbackWires();
        Hashtable<String, Object> targetProperties = new Hashtable<String, Object>();
        processProperties(implementation.getServiceCallbackProperties(service.getName()), targetProperties);
        targetProperties.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE);
         
        JDKProxyFactory proxyService = new JDKProxyFactory();
             
        Class<?> proxyInterface = bundle.loadClass(interfaceClass.getName());
               

        Object proxy = proxyService.createCallbackProxy(proxyInterface, wires);
      
           
        bundleContext.registerService(proxyInterface.getName(), proxy, targetProperties);
           
       
    }
   
    private void refreshPackages() {
   
        if (packageAdmin != null) {
            synchronized (this) {
                packagesRefreshed = false;
                packageAdmin.refreshPackages(null);
                       
                if (!packagesRefreshed) {
                  try {
                        this.wait(2000);
                  } catch (InterruptedException e) {
                    // ignore
                  }
                }
                packagesRefreshed = false;
            }                      
        }
    }
   
   
    private void resolveBundle() throws ObjectCreationException {
       
       
        try {
           
            if (!wiresResolved) {
                wiresResolved = true;
               
                if (!setReferencesAndProperties()) {
                    wiresResolved = false;
                    return;
                }
                   
                int refPlusServices = referenceWires.size() + runtimeComponent.getServices().size();
                boolean[] createProxyService = new boolean[refPlusServices];
                Class<?>[] interfaceClasses = new Class<?>[refPlusServices] ;
                boolean[] isOSGiToOSGiWire = new boolean[refPlusServices];
                boolean[] wireResolved = new boolean[refPlusServices];
                int index = 0;
                for (RuntimeWire wire : referenceWires.keySet()) {
               
                    Reference reference = referenceWires.get(wire);
                   
                    isOSGiToOSGiWire[index] = wire.getTarget().getComponent() != null &&
                            wire.getTarget().getComponent().getImplementationProvider()
                            instanceof OSGiImplementationProvider;
                           
                    Interface refInterface = reference.getInterfaceContract().getInterface();
                    if (refInterface instanceof JavaInterface) {
                        interfaceClasses[index] = ((JavaInterface)refInterface).getJavaClass();
                   
                        if (!isOSGiToOSGiWire[index])
                            resolveWireCreateDummyBundles(interfaceClasses[index]);

                    }
                   
                    if (!resolvedWires.contains(wire)) {
                        resolvedWires.add(wire);                      
                    }
                    else
                        wireResolved[index] = true;
                   
                    index++;
                }
                for (ComponentService service : runtimeComponent.getServices()) {
                    Interface callbackInterface = service.getInterfaceContract().getCallbackInterface();
                    if (callbackInterface instanceof JavaInterface) {
                        interfaceClasses[index] = ((JavaInterface)callbackInterface).getJavaClass();
                       
                        resolveWireCreateDummyBundles(interfaceClasses[index]);
                    }
                   
                    index++;
                }
               
                index = 0;
                for (RuntimeWire wire : referenceWires.keySet()) {
                   
                    if (!wireResolved[index]) {
                        createProxyService[index] = resolveWireResolveReferences(osgiBundle,
                            interfaceClasses[index],
                            wire,
                            isOSGiToOSGiWire[index]);
                    }
                    index++;
                }

                refreshPackages();
               
               
                index = 0;
                for (RuntimeWire wire : referenceWires.keySet()) {
                   
                    if (createProxyService[index] && !wireResolved[index])
                        resolveWireRegisterProxyService(osgiBundle, interfaceClasses[index], wire);
                    index++;
                }
                for (ComponentService service : runtimeComponent.getServices()) {
                    if (interfaceClasses[index] != null) {
                        registerCallbackProxyService(osgiBundle, interfaceClasses[index],
                                ((RuntimeComponentService)service));
                    }
                    index++;
                }
            }
            else if (osgiBundle.getState() == Bundle.INSTALLED && packageAdmin != null) {
                packageAdmin.resolveBundles(new Bundle[] {osgiBundle});
            }
           
        } catch (Exception e) {
            e.printStackTrace();
            throw new ObjectCreationException(e);
        }        
    }
   
  
    @SuppressWarnings("unchecked")
    private void configurePropertiesUsingConfigAdmin() {
              
        try {

            if (componentProperties.size() == 0)
                return;
           
            org.osgi.framework.ServiceReference configAdminReference =
                bundleContext.getServiceReference("org.osgi.service.cm.ConfigurationAdmin");
            if (configAdminReference != null) {
               
                Object cm = bundleContext.getService(configAdminReference);
                Class cmClass = cm.getClass().getClassLoader().loadClass("org.osgi.service.cm.ConfigurationAdmin");
                Method getConfigMethod = cmClass.getMethod("getConfiguration", String.class, String.class);
               

                Class configClass = cm.getClass().getClassLoader().loadClass("org.osgi.service.cm.Configuration");
               
                Method getMethod = configClass.getMethod("getProperties");
                Method updateMethod = configClass.getMethod("update", Dictionary.class);
               
                List<Service> services = implementation.getServices();
                HashSet<String> pidsProcessed = new HashSet<String>();
               
                for (Service service : services) {
                   
                    List<ComponentProperty> serviceProps = implementation.getServiceProperties(service.getName());
                    String pid = null;
                   
                    if (serviceProps != null) {
                        for (ComponentProperty prop : serviceProps) {
                            if (prop.getName().equals("service.pid")) {
                                ObjectFactory objFactory = propertyValueFactory.createValueFactory(prop,
                                        prop.getValue(), String.class);
                                pid = (String)objFactory.getInstance();
                            }
                        }
                    }
                    if (pid == null || pidsProcessed.contains(pid))
                        continue;
                   

                  
                   
                    Object config = getConfigMethod.invoke(cm, pid, null);
                    Dictionary props = (Dictionary) getMethod.invoke(config);
                    if (props == null)
                        props = new Hashtable<String, Object>();
                    for (String propertyName : componentProperties.keySet()) {

                        props.put(propertyName, componentProperties.get(propertyName));
                    }
                   
                    updateMethod.invoke(config, props);
                   
                   
                }               
               
            }
           
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
   
   
   
    public boolean isOptimizable() {
        return false;
    }
   
    public Scope getScope() {
        return osgiAnnotations.getScope();
    }

    public boolean isEagerInit() {
        return osgiAnnotations.isEagerInit();
    }

    public long getMaxAge() {
        return osgiAnnotations.getMaxAge();
    }

    public long getMaxIdleTime() {
        return osgiAnnotations.getMaxIdleTime();
    }
   
    protected ScopeContainer<?> getScopeContainer() {
        startBundle();
        return ((ScopedRuntimeComponent)runtimeComponent).getScopeContainer();
    }
   
    public Invoker createTargetInvoker(RuntimeComponentService service, Operation operation)  {
      
       
        Interface serviceInterface = operation.getInterface();
        boolean isRemotable = serviceInterface.isRemotable();


        Invoker invoker = new OSGiTargetInvoker(operation, this, service);
        if (isRemotable) {
            return new OSGiRemotableInvoker(osgiAnnotations, dataBindingRegistry, operation, this, service);
        } else {
            return invoker;
        }
       
    }
   
   
    public Invoker createInvoker(RuntimeComponentService service, Operation operation) {
        return createTargetInvoker(service, operation);
    }
   
    public boolean supportsOneWayInvocation() {
        return false;
    }

    private boolean setReferencesAndProperties() {
      
        for (Reference ref: implementation.getReferences()) {
            List<RuntimeWire> wireList = null;
            ComponentReference compRef = null;
            for (ComponentReference cRef : runtimeComponent.getReferences()) {
                if (cRef.getName().equals(ref.getName())) {
                   
                    wireList = ((RuntimeComponentReference)cRef).getRuntimeWires();
                   
                    compRef = cRef;
                    break;
                }
            }
               
            if (ref.getMultiplicity() == Multiplicity.ONE_N || ref.getMultiplicity() == Multiplicity.ZERO_N) {
                 for (RuntimeWire wire : wireList) {
                    referenceWires.put(wire, ref);
                    componentReferenceWires.put(wire, compRef);
                }
               
            } else {
                if (wireList == null && ref.getMultiplicity() == Multiplicity.ONE_ONE) {
                    throw new IllegalStateException("Required reference is missing: " + ref.getName());
                }
                if (wireList != null && !wireList.isEmpty()) {
                    RuntimeWire wire = wireList.get(0);
                    referenceWires.put(wire, ref);
                    componentReferenceWires.put(wire, compRef);
                }
               
            }
           
        }
       
        processProperties(runtimeComponent.getProperties(), componentProperties);
       
        return true;
       
    }
   
    public void start() {
        setReferencesAndProperties();
    }
       
    public void processAnnotations(boolean doWait) throws IntrospectionException {
       
        synchronized (this) {  
            if (processedResolvedBundle)
                return;
            else if (processingResolvedBundle) {             
                if (doWait) {
                    while (processingResolvedBundle) {
                        try {
                            wait(5000);
                        } catch (InterruptedException e) {
                        }
                    }
                }
                return;
            }
            processingResolvedBundle = true;
        }
       
        try {
            osgiAnnotations.processAnnotations();
       
            Scope scope = osgiAnnotations.getScope();
            if (scope.equals(Scope.SYSTEM) || scope.equals(Scope.COMPOSITE)) {
                // Nothing
            } else {

                if (runtimeComponent instanceof ScopedRuntimeComponent) {

                    ScopedRuntimeComponent component = (ScopedRuntimeComponent) runtimeComponent;

                    ScopeContainer oldScopeContainer = component.getScopeContainer();
                    component.setScopeContainer(null);
                    ScopeContainer scopeContainer = scopeRegistry.getScopeContainer(runtimeComponent);

                    if (oldScopeContainer != null && oldScopeContainer.getLifecycleState() == ScopeContainer.RUNNING) {
                        scopeContainer.start();
                    }
               
                    component.setScopeContainer(scopeContainer);
                }

            }
        } finally {
            synchronized (this) {               
                processingResolvedBundle = false;
                processedResolvedBundle = true;
                this.notifyAll();
            }
        } 
    }
   
    public void stop() {

        if (osgiServiceListener != null)
            bundleContext.removeServiceListener(osgiServiceListener);
    }

   
   
    public void frameworkEvent(FrameworkEvent event) {
        if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
            synchronized (this) {
                packagesRefreshed = true;
                this.notifyAll();
            }           
        }
       
    }
   
    public void bundleChanged(BundleEvent event) {
        if (event.getType() == BundleEvent.RESOLVED && event.getBundle() == osgiBundle) {
            try {
                processAnnotations(false);
            } catch (Throwable e) {
                e.printStackTrace();
            }            
        }
    }

    private class OSGiServiceListener implements ServiceListener {
       
        private Bundle bundle;
       
        OSGiServiceListener(Bundle bundle) {
            this.bundle = bundle;
        }
       
        public void serviceChanged(org.osgi.framework.ServiceEvent event) {
           

            org.osgi.framework.ServiceReference reference = event.getServiceReference();
           
            if (event.getType() == ServiceEvent.REGISTERED && reference.getBundle() == bundle) {
               
                synchronized (implementation) {
                   
                    implementation.notifyAll();
                }
            }
           
            if (event.getType() == ServiceEvent.UNREGISTERING && reference.getBundle() == bundle) {
                // TODO: Process deregistering of OSGi services.
            }
        }
    }
}
TOP

Related Classes of org.apache.tuscany.sca.implementation.osgi.invocation.OSGiImplementationProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.