spring-projects / spring-plugin

Apache License 2.0
441 stars 117 forks source link

PluginRegistry and OrderAwarePluginRegistry #1

Closed nocquidant closed 11 years ago

nocquidant commented 11 years ago

"Using the Spring Plugin namespace you will get a PluginRegistry instance that is capable of preserving the order defined by the mentioned means."

I effectively get a OrderAwarePluginRegistry but plugins are not ordered...

When I change for:

    @Override
    public OrderAwarePluginRegistry<T, S> getObject() {
       // return OrderAwarePluginRegistry.create(getBeans());  // TODO yay!
       return OrderAwarePluginRegistry.create(new ArrayList<T>(getBeans()));
}

in PluginRegistryFactoryBean, it is then OK. It looks like there is an issue with the JdkDynamicaopProxy list.

Thanks, Nicolas

odrotbohm commented 11 years ago

Are you using @Order or the Ordered interface? For plugin implementations being proxied you essentially have to use the interface approach as the comparator only inspects the outer type for @Order.

nocquidant commented 11 years ago

I just tried using the Ordered interface, but still without success...

odrotbohm commented 11 years ago

I've just pushed a test case using Ordered with a proxy and it appears to be working. Is there more code you can show to dig into what's going on in your case?

nocquidant commented 11 years ago

The problem seems to be relative to:

BeansOfTypeTargetSource targetSource = new     BeansOfTypeTargetSource(ApplicationContextProvider.getApplicationContext(), TestPlugin.class, false);

ProxyFactory factory = new ProxyFactory(List.class, targetSource);
List<TestPlugin> beans = (List<TestPlugin>) factory.getProxy();
OrderAwarePluginRegistry<TestPlugin, String> registry = OrderAwarePluginRegistry.create(beans); 

My very ugly test is:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:application-context.xml")
public class OrderAwarePluginRegistryBisUnitTest {

  TestPlugin firstPlugin;
  TestPlugin secondPlugin;

  @Before
  public void setUp() {
    firstPlugin = new FirstImplementation();
    secondPlugin = new SecondImplementation();
  }

  @Test
  public void considersJdkProxiedOrderedImplementation() {
    BeansOfTypeTargetSource targetSource = new BeansOfTypeTargetSource(
        ApplicationContextProvider.getApplicationContext(), TestPlugin.class, false);

    ProxyFactory factory = new ProxyFactory(List.class, targetSource);
    List<TestPlugin> beans = (List<TestPlugin>) factory.getProxy();
    OrderAwarePluginRegistry<TestPlugin, String> registry = OrderAwarePluginRegistry.create(beans);

    List<TestPlugin> plugins = registry.getPlugins();
    Assert.assertTrue(plugins.get(0) == secondPlugin);
  }

  private static interface TestPlugin extends Plugin<String> {

  }

  @Order(5)
  private static class FirstImplementation implements TestPlugin {

    @Override
    public boolean supports(String delimiter) {

      return true;
    }
  }

  @Order(1)
  private static class SecondImplementation implements TestPlugin {

    @Override
    public boolean supports(String delimiter) {

      return true;
    }
  }

  private static class ThirdImplementation implements TestPlugin, Ordered {

    @Override
    public int getOrder() {
      return 3;
    }

    @Override
    public boolean supports(String delimiter) {
      return true;
    }
  }
}

With:

  <bean id="applicationContextProvider" class="org.springframework.plugin.core.ApplicationContextProvider">  </bean>
  <bean class="org.springframework.plugin.core.OrderAwarePluginRegistryBisUnitTest$FirstImplementation" />
  <bean class="org.springframework.plugin.core.OrderAwarePluginRegistryBisUnitTest$SecondImplementation" />
  <bean class="org.springframework.plugin.core.OrderAwarePluginRegistryBisUnitTest$ThirdImplementation" />

And:

public class ApplicationContextProvider implements ApplicationContextAware {
  private static ApplicationContext ctx = null;

  public static ApplicationContext getApplicationContext() {
    return ctx;
  }

  public void setApplicationContext(ApplicationContext ctx) throws BeansException {
    this.ctx = ctx;
  }
}

You'll also have to turn the static class BeansOfTypeTargetSource public...

Thanks, Nicolas

odrotbohm commented 11 years ago

There's a very obvious reason this test case fails, you're comparing an instance you created yourself (in setUp()) with a one created by the Spring container without having the equals(…) method implemented correctly. You can also just inject the ApplicationContext you created using:

@Autowired
ApplicationContext context;

Feel free to open an according pull request with the core you have (widening the scope of the BeansOfTypeTargetSource to the package scope if necessary). That will make it easier for me to pick it up if necessary.

nocquidant commented 11 years ago

Here is my very small project I use to test: https://github.com/nocquidant/my-tests

Thanks, Nicolas