blob: 1d5d99cd34df7e43a0141788cd6c142253b884b2 [file] [log] [blame]
/*
* 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?
}
}
}