| /* |
| * 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.runtime; |
| |
| import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.REMOTE_CONFIG_SCA; |
| import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SCA_REFERENCE; |
| import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_IMPORTED; |
| import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_IMPORTED_CONFIGS; |
| import static org.osgi.framework.Constants.SERVICE_RANKING; |
| |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Proxy; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| import java.util.List; |
| |
| import org.apache.tuscany.sca.assembly.ComponentReference; |
| import org.apache.tuscany.sca.assembly.ComponentService; |
| import org.apache.tuscany.sca.assembly.EndpointReference; |
| import org.apache.tuscany.sca.assembly.Extensible; |
| import org.apache.tuscany.sca.core.invocation.ProxyFactory; |
| import org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint; |
| import org.apache.tuscany.sca.implementation.osgi.OSGiImplementation; |
| import org.apache.tuscany.sca.implementation.osgi.OSGiImplementationFactory; |
| import org.apache.tuscany.sca.implementation.osgi.OSGiProperty; |
| import org.apache.tuscany.sca.interfacedef.InterfaceContract; |
| 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.provider.ImplementationProvider; |
| 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.RuntimeEndpointReference; |
| import org.oasisopen.sca.ServiceRuntimeException; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.BundleException; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceException; |
| import org.osgi.framework.ServiceFactory; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.framework.ServiceRegistration; |
| |
| /** |
| * |
| */ |
| public class OSGiImplementationProvider implements ImplementationProvider { |
| private RuntimeComponent component; |
| private ProxyFactoryExtensionPoint proxyFactoryExtensionPoint; |
| private Bundle osgiBundle; |
| private boolean startedByMe; |
| private OSGiImplementation implementation; |
| private List<ServiceRegistration> registrations = new ArrayList<ServiceRegistration>(); |
| private OSGiImplementationFactory implementationFactory; |
| |
| public OSGiImplementationProvider(RuntimeComponent component, |
| OSGiImplementation impl, |
| ProxyFactoryExtensionPoint proxyFactoryExtensionPoint, |
| OSGiImplementationFactory implementationFactory) throws BundleException { |
| this.component = component; |
| this.proxyFactoryExtensionPoint = proxyFactoryExtensionPoint; |
| this.implementationFactory = implementationFactory; |
| this.implementation = impl; |
| this.osgiBundle = impl.getBundle(); |
| } |
| |
| public Invoker createInvoker(RuntimeComponentService service, Operation operation) { |
| return new OSGiTargetInvoker(operation, this, service); |
| } |
| |
| public void start() { |
| // First try to start the osgi bundle |
| try { |
| int state = osgiBundle.getState(); |
| if ((state & Bundle.STARTING) == 0 && (state & Bundle.ACTIVE) == 0) { |
| osgiBundle.start(); |
| startedByMe = true; |
| } |
| } catch (BundleException e) { |
| throw new ServiceRuntimeException(e); |
| } |
| |
| for (ComponentReference ref : component.getReferences()) { |
| RuntimeComponentReference reference = (RuntimeComponentReference)ref; |
| InterfaceContract interfaceContract = reference.getInterfaceContract(); |
| final JavaInterface javaInterface = (JavaInterface)interfaceContract.getInterface(); |
| // final Class<?> interfaceClass = javaInterface.getJavaClass(); |
| |
| // final Hashtable<String, Object> props = new Hashtable<String, Object>(); |
| // props.put(FILTER_MATCH_CRITERIA, ""); |
| // Collection<String> interfaceNames = new ArrayList<String>(); |
| // props.put(INTERFACE_MATCH_CRITERIA, interfaceNames); |
| // interfaceNames.add(interfaceClass.getName()); |
| |
| final Hashtable<String, Object> osgiProps = getOSGiProperties(reference); |
| osgiProps.put(SERVICE_RANKING, Integer.MAX_VALUE); |
| osgiProps.put(SCA_REFERENCE, component.getURI() + "#reference(" + ref.getName() + ")"); |
| osgiProps.put(SERVICE_IMPORTED, "true"); |
| osgiProps.put(SERVICE_IMPORTED_CONFIGS, new String[] {REMOTE_CONFIG_SCA}); |
| |
| for (EndpointReference epr : reference.getEndpointReferences()) { |
| final OSGiServiceFactory serviceFactory = new OSGiServiceFactory(javaInterface.getName(), epr); |
| ServiceRegistration registration = |
| AccessController.doPrivileged(new PrivilegedAction<ServiceRegistration>() { |
| public ServiceRegistration run() { |
| // Register the proxy as OSGi service |
| BundleContext context = osgiBundle.getBundleContext(); |
| ServiceRegistration registration = |
| context.registerService(javaInterface.getName(), serviceFactory, osgiProps); |
| return registration; |
| } |
| }); |
| registrations.add(registration); |
| } |
| } |
| |
| // Set the OSGi service reference properties into the SCA service |
| for (ComponentService service : component.getServices()) { |
| // The properties might have been set by the export service |
| boolean found = false; |
| for (Object ext : service.getExtensions()) { |
| if (ext instanceof OSGiProperty) { |
| found = true; |
| break; |
| } |
| } |
| if (found) { |
| continue; |
| } |
| ServiceReference serviceReference = getServiceReference(osgiBundle.getBundleContext(), service); |
| if (serviceReference != null) { |
| service.getExtensions().addAll(implementationFactory.createOSGiProperties(serviceReference)); |
| } |
| } |
| } |
| |
| public void stop() { |
| for (ServiceRegistration registration : registrations) { |
| try { |
| registration.unregister(); |
| } catch (IllegalStateException e) { |
| // The service has been unregistered, ignore it |
| } |
| } |
| registrations.clear(); |
| // [REVIEW] Shoud it take care of stopping the bundle? |
| if (startedByMe) { |
| try { |
| int state = osgiBundle.getState(); |
| if ((state & Bundle.STOPPING) == 0 && (state & Bundle.ACTIVE) != 0) { |
| osgiBundle.stop(); |
| } |
| } catch (BundleException e) { |
| throw new ServiceRuntimeException(e); |
| } finally { |
| startedByMe = false; |
| } |
| } |
| } |
| |
| public boolean supportsOneWayInvocation() { |
| return false; |
| } |
| |
| /** |
| * Get all the OSGi properties from the extension list |
| * @param extensible |
| * @return |
| */ |
| protected Hashtable<String, Object> getOSGiProperties(Extensible extensible) { |
| Hashtable<String, Object> props = new Hashtable<String, Object>(); |
| for (Object ext : extensible.getExtensions()) { |
| if (ext instanceof OSGiProperty) { |
| OSGiProperty p = (OSGiProperty)ext; |
| props.put(p.getName(), p.getValue()); |
| } |
| } |
| return props; |
| } |
| |
| protected Object getOSGiService(ComponentService service) { |
| BundleContext bundleContext = osgiBundle.getBundleContext(); |
| ServiceReference ref = getServiceReference(bundleContext, service); |
| if (ref != null) { |
| Object instance = bundleContext.getService(ref); |
| return instance; |
| } else { |
| return null; |
| } |
| } |
| |
| private ServiceReference getServiceReference(BundleContext bundleContext, ComponentService service) { |
| JavaInterface javaInterface = (JavaInterface)service.getInterfaceContract().getInterface(); |
| // String filter = getOSGiFilter(provider.getOSGiProperties(service)); |
| // FIXME: What is the filter? |
| String filter = "(!(" + SERVICE_IMPORTED + "=*))"; |
| // "(sca.service=" + component.getURI() + "#service-name\\(" + service.getName() + "\\))"; |
| ServiceReference ref; |
| try { |
| ref = bundleContext.getServiceReferences(javaInterface.getName(), filter)[0]; |
| } catch (InvalidSyntaxException e) { |
| throw new ServiceRuntimeException(e); |
| } |
| return ref; |
| } |
| |
| RuntimeComponent getComponent() { |
| return component; |
| } |
| |
| OSGiImplementation getImplementation() { |
| return implementation; |
| } |
| |
| /** |
| * A proxy invocation handler that wrap exceptions into OSGi ServiceException |
| */ |
| private static class InvocationHandlerDelegate implements InvocationHandler { |
| private final Object instance; |
| |
| public InvocationHandlerDelegate(Object instance) { |
| super(); |
| this.instance = instance; |
| } |
| |
| public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
| if (!Proxy.isProxyClass(instance.getClass())) { |
| Method m = instance.getClass().getMethod(method.getName(), method.getParameterTypes()); |
| try { |
| return m.invoke(instance, args); |
| } catch (InvocationTargetException e) { |
| wrapException(method, e.getCause()); |
| return null; |
| } |
| } else { |
| InvocationHandler handler = Proxy.getInvocationHandler(instance); |
| try { |
| return handler.invoke(instance, method, args); |
| } catch (Throwable e) { |
| wrapException(method, e); |
| return null; |
| } |
| } |
| } |
| |
| private void wrapException(Method method, Throwable e) throws Throwable { |
| for (Class<?> exType : method.getExceptionTypes()) { |
| if (exType.isInstance(e)) { |
| throw e; |
| } |
| } |
| throw new ServiceException(e.getMessage(), ServiceException.REMOTE, e); |
| } |
| |
| /** |
| * A utility to cast the object to the given interface. If the class for the object |
| * is loaded by a different classloader, a proxy will be created. |
| * |
| * @param <T> |
| * @param obj |
| * @param cls |
| * @return |
| */ |
| static <T> T cast(Object obj, Class<T> cls) { |
| if (obj == null) { |
| return null; |
| } else { |
| return cls.cast(Proxy.newProxyInstance(cls.getClassLoader(), |
| new Class<?>[] {cls}, |
| new InvocationHandlerDelegate(obj))); |
| } |
| } |
| } |
| |
| public class OSGiServiceFactory implements ServiceFactory { |
| private RuntimeEndpointReference epr; |
| private String interfaceName; |
| |
| /** |
| * @param interfaceName |
| * @param epr |
| */ |
| public OSGiServiceFactory(String interfaceName, EndpointReference epr) { |
| super(); |
| this.interfaceName = interfaceName; |
| this.epr = (RuntimeEndpointReference)epr; |
| } |
| |
| public Object getService(Bundle bundle, ServiceRegistration registration) { |
| try { |
| Class<?> interfaceClass = null; |
| try { |
| interfaceClass = bundle.loadClass(interfaceName); |
| } catch (ClassNotFoundException e) { |
| return null; |
| } |
| ProxyFactory proxyService = proxyFactoryExtensionPoint.getInterfaceProxyFactory(); |
| if (!interfaceClass.isInterface()) { |
| proxyService = proxyFactoryExtensionPoint.getClassProxyFactory(); |
| } |
| Object proxy = proxyService.createProxy(interfaceClass, epr); |
| return InvocationHandlerDelegate.cast(proxy, interfaceClass); |
| } catch (Throwable e) { |
| throw new ServiceException(e.getMessage(), ServiceException.FACTORY_EXCEPTION, e); |
| } |
| } |
| |
| public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { |
| // Do we need to release the proxy? |
| } |
| |
| } |
| |
| } |