/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.osgi.cdi.impl.integration;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.enterprise.inject.Instance;
import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;
import org.osgi.cdi.api.extension.annotation.Publish;
import org.osgi.cdi.impl.extension.CDIOSGiExtension;
import org.osgi.cdi.impl.extension.services.RegistrationsHolder;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceRegistration;
/**
*
* @author Mathieu ANCELIN - SERLI (mathieu.ancelin@serli.com)
*/
public class ServicePublisher {
private final Collection<String> classes;
private final Bundle bundle;
private final Instance<Object> instance;
private final Set<String> blackList;
public ServicePublisher(Collection<String> classes, Bundle bundle,
Instance<Object> instance, Set<String> blackList) {
this.classes = classes;
this.bundle = bundle;
this.instance = instance;
this.blackList = blackList;
}
public void registerAndLaunchComponents() {
System.out.println(String.format("\nRegistering/Starting OSGi Service for bundle %s\n", bundle.getSymbolicName()));
for (String className : classes) {
Class<?> clazz = null;
try {
clazz = bundle.loadClass(className);
} catch (Exception e) {
//e.printStackTrace(); // silently ignore :-)
}
if (clazz != null) {
boolean publishable = clazz.isAnnotationPresent(Publish.class);
boolean instatiation = publishable;
Annotation[] annotations = null;
Object service = null;
if (instatiation) {
List<Annotation> qualifiers = getQualifiers(clazz);
try {
annotations = qualifiers.toArray(new Annotation[qualifiers.size()]);
service = instance.select(clazz, annotations).get();
} catch (Throwable e) {
e.printStackTrace();
}
if (publishable) {
publish(clazz, service, qualifiers);
}
}
}
}
}
private void publish(Class<?> clazz, Object service, List<Annotation> qualifiers) {
// register service
Annotation[] annotations = qualifiers.toArray(new Annotation[qualifiers.size()]);
ServiceRegistration registration = null;
if (service != null) {
Publish publish = clazz.getAnnotation(Publish.class);
Class[] contracts = publish.contracts();
Properties properties = getServiceProperties(publish, qualifiers);
if (contracts.length != 0) {
for (Class contract : contracts) {
System.out.println("Registering OSGi service " + clazz.getName() + " as " + contract.getName());
registration = bundle.getBundleContext().registerService(
contract.getName(), getProxy(contract, clazz, annotations, bundle), properties);
}
} else {
// registering interfaces
if (service.getClass().getInterfaces().length > 0) {
for (Class interf : service.getClass().getInterfaces()) {
// TODO : Beurk !!!!!!!!!!!!!, there must be some kind of helper somewhere
if (!blackList.contains(interf.getName())) {
// if (!interf.getName().equals("java.io.Serializable")
// && !interf.getName().equals("org.jboss.interceptor.proxy.LifecycleMixin")
// && !interf.getName().equals("org.jboss.interceptor.util.proxy.TargetInstanceProxy")
// && !interf.getName().equals("javassist.util.proxy.ProxyObject")) {
System.out.println("Registering OSGi service " + clazz.getName() + " as " + interf.getName());
registration = bundle.getBundleContext().registerService(
interf.getName(), getProxy(interf, clazz, annotations, bundle), properties);
}
}
} else {
System.out.println("Registering OSGi service " + clazz.getName() + " as " + clazz.getName());
registration = bundle.getBundleContext().registerService(clazz.getName(), service, properties);
}
}
}
if (registration != null) {
CDIOSGiExtension.currentBundle.set(bundle.getBundleId());
instance.select(RegistrationsHolder.class).get().addRegistration(registration);
}
}
private static Properties getServiceProperties(Publish publish, List<Annotation> qualifiers) {
Properties properties = null;
if (publish.useQualifiersAsProperties()) {
if (!qualifiers.isEmpty()) {
properties = new Properties();
for (Annotation qualif : qualifiers) {
for (Method m : qualif.annotationType().getDeclaredMethods()) {
if (!m.isAnnotationPresent(Nonbinding.class)) {
try {
String key = qualif.annotationType().getName() + "." + m.getName();
Object value = m.invoke(qualif);
if (value == null) {
value = m.getDefaultValue();
}
properties.setProperty(key, value.toString());
} catch (Throwable t) {
// ignore
}
}
}
}
}
} else {
if (publish.properties().length > 0) {
properties = new Properties();
for (String property : publish.properties()) {
if (property.split("=").length == 2) {
String key = property.split("=")[0];
String value = property.split("=")[1];
properties.setProperty(key, value);
}
}
}
}
return properties;
}
private static List<Annotation> getQualifiers(Class<?> clazz) {
List<Annotation> qualifiers = new ArrayList<Annotation>();
for (Annotation a : clazz.getAnnotations()) {
if (a.annotationType().isAnnotationPresent(Qualifier.class)) {
qualifiers.add(a);
}
}
return qualifiers;
}
private <T> T getProxy(Class<T> interf, Class<? extends T> clazz, Annotation[] qualifiers, Bundle bundle) {
return interf.cast(
Proxy.newProxyInstance(
clazz.getClassLoader(),
new Class[]{interf},
new LazyService(clazz, qualifiers, bundle)));
}
private class LazyService implements InvocationHandler {
private final Class<?> contract;
private final Annotation[] qualifiers;
private final Bundle bundle;
public LazyService(Class<?> contract, Annotation[] qualifiers, Bundle bundle) {
this.contract = contract;
this.qualifiers = qualifiers;
this.bundle = bundle;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
CDIOSGiExtension.currentBundle.set(bundle.getBundleId());
return method.invoke(
instance.select(contract, qualifiers).get(),
args);
} finally {
CDIOSGiExtension.currentBundle.remove();
}
}
}
}