felix-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Pierre De Rop (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (FELIX-4853) Create a new ServiceDependency that sets the TCCL to the incoming servicereference bundle's classloader before invoking callbaks
Date Fri, 17 Apr 2015 23:06:58 GMT

    [ https://issues.apache.org/jira/browse/FELIX-4853?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14500871#comment-14500871
] 

Pierre De Rop commented on FELIX-4853:
--------------------------------------

Regarding the java8 example, we can even push the limit of java8 using type inference:

In the TCCLCallback, we can introduce a static method that can be used to create a TCCLCallback
instance with generic types inferred from the Consumer parameter:

{code}
/**
 * Tool that allows to delegate a dependency callback with TCCL set to the injected service
dependency.
 *
 * @param <T> The type of the class where the service dependency has to be injected
to, but with TCCL set to the injected service class loader.
 * @param <U> The type of the injected service.
 */
public class TCCLCallback<T, U> {
    
    private final BiConsumer<T, U> consumer;

    /**
     * Creates a TCCLCallback instance with generic types automatically infered from the consumer
parameter.
     */
    static <U,V> TCCLCallback<U,V> tccl(BiConsumer<U,V> consumer) {
        return new TCCLCallback<U,V>(consumer);
    }    
    
    public TCCLCallback(BiConsumer<T, U> consumer) {
        this.consumer = consumer;
    }
            
    void bind(Component component, ServiceReference ref, U service) {
        Thread t = Thread.currentThread();
        ClassLoader current = t.getContextClassLoader();
        Bundle bundle = ref.getBundle();
        BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
        ClassLoader cl = bundleWiring.getClassLoader();
        try {
            t.setContextClassLoader(cl);
            T instance = component.getInstance();
            consumer.accept(instance, service);
        } finally {
            t.setContextClassLoader(current);
        }
    }
    
}
{code}

And using the static tccl factory method above, we can now reduce again the "code ceremony"
in the Activator:

{code}
import static tcclcallback.TCCLCallback.tccl;
...
public class Activator extends DependencyActivatorBase {

    @Override
    public void init(BundleContext bc, DependencyManager dm) throws Exception {
        dm.add(createComponent()
            .setImplementation(ServiceImpl.class)
            .setInterface(Service.class.getName(), null));
                    
        dm.add(createComponent()
            .setImplementation(Pojo.class)
            .add(createServiceDependency()
                 .setService(Service.class).setCallbacks(tccl(Pojo::bind), "bind", null)));
    }
    
}

{code}

> Create a new ServiceDependency that sets the TCCL to the incoming servicereference bundle's
classloader before invoking callbaks
> --------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: FELIX-4853
>                 URL: https://issues.apache.org/jira/browse/FELIX-4853
>             Project: Felix
>          Issue Type: New Feature
>          Components: Dependency Manager
>    Affects Versions: dependencymanager-3.2.0
>            Reporter: Carlos Sierra
>         Attachments: examples.tgz
>
>
> The invoke method would go like this:
> {code:title=TCCLServiceDependencyImpl.java|borderStyle=solid}
>         @Override
> 	@SuppressWarnings("rawtypes")
> 	public void invoke(
> 		Object[] callbackInstances, DependencyService dependencyService,
>                 ServiceReference reference, Object service, String name) {
> 		Bundle bundle = reference.getBundle();
> 		BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
> 		ClassLoader bundleClassLoader = bundleWiring.getClassLoader();
> 		Thread currentThread = Thread.currentThread();
> 		ClassLoader contextClassLoader = currentThread.getContextClassLoader();
> 		currentThread.setContextClassLoader(bundleClassLoader);
> 		try {
> 			super.invoke(
> 				callbackInstances, dependencyService, reference, service, name);
> 		}
> 		finally {
> 			currentThread.setContextClassLoader(contextClassLoader);
> 		}
> 	}
> {code}
> If you think this is useful I can provide a patch. Which version and which repo should
I use for it?



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Mime
View raw message