You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@felix.apache.org by "Pierre De Rop (JIRA)" <ji...@apache.org> on 2014/08/27 14:38:57 UTC

[jira] [Commented] (FELIX-4614) Factory create() method should have access to the component definition

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

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

In order to make sure I understand, can we discuss about the following example: for instance, assume that you want to create an aspect service as a java DynamicProxy.

To do so, you can use a Factory object instance with a create method, and that Factory has to hold the necessary informations in order to create the dynamic proxy (at least we need the aspect interface class, but the Factory could hold more data, if necessary, like a label in the following example):

{code}
public class Activator extends DependencyActivatorBase {  
    public static interface ServiceInterface {
        public void invoke();
    }
    
    public static class ServiceProvider implements ServiceInterface {
        public void invoke() {
            System.out.println("ServiceProvider.invoke");
        }
    }
    
    public static class ServiceConsumer  {
        volatile ServiceInterface m_service;
        public void start() {
            System.out.println("ServiceConsumer.start");
            m_service.invoke();
        }
    }

    static class AspectProxy implements InvocationHandler {
        private volatile ServiceInterface m_service;
        private final String m_label;
        
        public AspectProxy(String label) {
            m_label = label;
        }
        
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("AspectProxy.invoke (label=" + m_label + ")");
            Method m = m_service.getClass().getMethod(method.getName(), method.getParameterTypes());
            return m.invoke(m_service, args);
        }
    }
        
    public static class AspectProxyFactory {
        private Class m_class;
        private final String m_label;

        public AspectProxyFactory(Class clazz, String label) {
            m_class = clazz;
            m_label = label;
        }
        
        public Object create() {
            return Proxy.newProxyInstance(m_class.getClassLoader(), new Class[] { m_class }, new AspectProxy(m_label));
        }
    }
    
    @Override
    public void init(BundleContext context, DependencyManager mgr) throws Exception {
        mgr.add(createComponent()
            .setInterface(ServiceInterface.class.getName(), null)
            .setImplementation(ServiceProvider.class));

        mgr.add(createAspectService(ServiceInterface.class, null, 10, "m_service")
           .setFactory(new AspectProxyFactory(ServiceInterface.class, "label"), "create"));

        mgr.add(createComponent()
            .setImplementation(ServiceConsumer.class)
            .add(createServiceDependency().setService(ServiceInterface.class).setRequired(true)));        
    }
}
{code}

so, in the above example, the AspectProxyFactory class holds the ServiceInterface class in its "m_class" attribute (needed to create the DynamicProxy), as well as a "m_label" field, which will be passed to the DynamicProxy constructor.

So, can you please modify the example above in order to let me understand what kind of improvement you would like to have ? 

Do you mean that the org.apache.felix.dm.Component object (for the aspect) should be passed to the create method and then the Factory could do a class.forName on the aspect interface (that can be accessed from Component.getComponentDeclaration().getServices() method in dependency manager 4.0.0, from the sanbdox) in order to be able to create the java DynamicProxy ?

But yet, we still have to hold the "label" context in the Factory object, in order to pass it to the AspectProxy constructor ...
So, it is not exaclty what may be you would like to have, but I wonder about the following improvement: instead of having a setFactory(Object factoryInstance method, String create method), we could then introduce a simple interface in DM API that would only have a create method, and notice that having one single method would allow to use a nice lambda in java8, since it would be compatible with a functional interface:

Something like

{code}
package org.apache.felix.dm;

// @FunctionalInterface
public interface Factory {
    Object create();
}
{code}

then we could introduce a new setFactory(Factory factory) method in the Component interface:

{code}
interface Component {
    ...
    void setFactory(Factory factory);
}
{code}

and given the initial example, we could then do something like this (in java8 style):

{code}
        mgr.add(createAspectService(ServiceInterface.class, null, 10, "m_service")
           .setFactory(() -> 
               new Proxy.newProxyInstance(ServiceInterface.class.getClassLoader(), 
                                                                new Class[] {ServiceInterface.class }, new AspectProxy("label"));
           );
{code}

and in java7:

{code}
        mgr.add(createAspectService(ServiceInterface.class, null, 10, "m_service")
           .setFactory(new Factory() {
               public Object create() {
                     return new Proxy.newProxyInstance(ServiceInterface.class.getClassLoader(), 
                                                                                new Class[] {ServiceInterface.class }, new AspectProxy("label"));
              }
           }));
{code}

(not sure if this is making sense or if this is really what you would like to have, please let me know what you think ...)

/pierre



> Factory create() method should have access to the component definition
> ----------------------------------------------------------------------
>
>                 Key: FELIX-4614
>                 URL: https://issues.apache.org/jira/browse/FELIX-4614
>             Project: Felix
>          Issue Type: Improvement
>          Components: Dependency Manager
>            Reporter: Paul Bakker
>
> Currently the factory mechanism uses a _create()_ method without arguments. Because of this there is not enough context to create instances. For example creating a Proxy is not possible because we don't know which interface to use for the Proxy. 
> The _create()_ method should support an argument to get access to the component definition. 



--
This message was sent by Atlassian JIRA
(v6.2#6252)