Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Extensionpoint in plugin and access that in a different one #97

Closed
lyze237 opened this issue Mar 21, 2016 · 11 comments
Closed

Create Extensionpoint in plugin and access that in a different one #97

lyze237 opened this issue Mar 21, 2016 · 11 comments

Comments

@lyze237
Copy link

lyze237 commented Mar 21, 2016

Dear Developer,

I'm currently struggling with the following thing:

I have a plugin which creates some extension points for other plugins.
Now I want those other plugins to use those extension points and use those plugins then inside my project.

E.g.:

Plugin CommandProvider: Has a interface: public interface CommandExtension extends ExtensionPoint

Plugin TestPlugin: Has a plugin public class TestPlugin extends Plugin which has a class inside @Extension public static class TestExtension implements CommandExtension


Now I want to access every CommandExtension from my CommandProvider:

for (CommandExtension commandExtension : comandPluginWrapper.getPluginManager().getExtensions(CommandExtension.class)) {
                if (commandExtension.canCall(pluginId, event)) {
                    commandExtension.call(pluginId, event);
                }
            }

This however returns always 0 Command Extension Points.

The following test however says that the plugin has the proper extension point:

   public void processEvent(String pluginId, Event event) {
        PluginWrapper plugin = wrapper.getPluginManager().getPlugin("Test Service");

        for (String extension : plugin.getPluginManager().getExtensionClassNames(plugin.getPluginId())) {
            logger.debug("Found Extension " + extension);
            try {
                for (Class<?> clazz : plugin.getPluginClassLoader().loadClass(extension).getInterfaces()) {
                    logger.warn(clazz.getName());
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        logger.warn("Found Command Extension " + plugin.getPluginManager().getExtensions(CommandExtension.class).size() + " times");
        if (event instanceof GenericMessageChatToBotEvent || event instanceof GenericMessageBotToChatEvent) {
            for (CommandExtension commandExtension : plugin.getPluginManager().getExtensions(CommandExtension.class)) {
                if (commandExtension.canCall(pluginId, event)) {
                    commandExtension.call(pluginId, event);
                }
            }
        }
    }
}

This produces the following output:

GlobalCommandPlugin - Found Command Extension 0 times
GlobalCommandPlugin - Found Extension at.lyze.plugin.testPlugin.TestPlugin$TestExtension:
GlobalCommandPlugin - at.lyze.pluginApi.extensions.services.ServiceExtension
GlobalCommandPlugin - at.lyze.plugin.globalCommandPlugin.CommandExtension

Do I do something wrong here?

@decebals
Copy link
Member

Check to see that extensions.idx file is generated for TestPlugin. If you can, please supply the log file (with level on debug).

@lyze237
Copy link
Author

lyze237 commented Mar 21, 2016

Testplugin idx file:

# Generated by PF4J
at.lyze.plugin.testPlugin.TestPlugin$TestExtension
at.lyze.plugin.testPlugin.TestPlugin$TestExtension

Command Plugin idx file:

# Generated by PF4J
at.lyze.plugin.globalCommandPlugin.GlobalCommandPlugin$EventProcessor

Log File: Search for "WARN" to find the outputs: http://pastebin.com/Q3cH5uL3

Currently the plugin zips look like this:

  • TestPlugin
    • lib
      • CommandPlugin.jar (That's the unmodified jar, so class files are direct in the root directory)
    • classes
      • normal classfiles
      • meta-inf directory with extensions.idx and manifest.mf
  • CommandPlugin
    • classes
      • normal classfiles
      • meta-inf directory with extensions.idx and manifest.mf

@decebals
Copy link
Member

# Generated by PF4J
at.lyze.plugin.testPlugin.TestPlugin$TestExtension
at.lyze.plugin.testPlugin.TestPlugin$TestExtension

I don't like that you have duplicate lines in extensions.idx

I will investigate the log file and I will come with conclusions.

@lyze237
Copy link
Author

lyze237 commented Mar 21, 2016

@decebals
Copy link
Member

If I search after Finding extensions for extension point 'at.lyze.plugin.globalCommandPlugin.CommandExtension' I retrieved (line 310):

2016-03-21 16:21:04,652 DEBUG ro.fortsoft.pf4j.AbstractExtensionFinder - Loading class 'at.lyze.plugin.testPlugin.TestPlugin$TestExtension' using class loader 'ro.fortsoft.pf4j.PluginClassLoader@621be5d1'
2016-03-21 16:21:04,652 DEBUG ro.fortsoft.pf4j.AbstractExtensionFinder - Checking extension type 'at.lyze.plugin.testPlugin.TestPlugin$TestExtension'
2016-03-21 16:21:04,652 DEBUG ro.fortsoft.pf4j.AbstractExtensionFinder - 'at.lyze.plugin.testPlugin.TestPlugin$TestExtension' is not an extension for extension point 'at.lyze.plugin.globalCommandPlugin.CommandExtension'

If you found PluginClassLoader@621be5d1 you can see that:

2016-03-21 16:20:59,792 DEBUG ro.fortsoft.pf4j.DefaultPluginManager - Loading plugin '/testPlugin-16-03-21_16_20'
2016-03-21 16:20:59,792 DEBUG ro.fortsoft.pf4j.DefaultPluginManager - Created class loader 'ro.fortsoft.pf4j.PluginClassLoader@621be5d1'

so it's OK

The problem is why 'at.lyze.plugin.testPlugin.TestPlugin$TestExtension' is not an extension for extension point 'at.lyze.plugin.globalCommandPlugin.CommandExtension'?
The above line is generated by AbstractExtensionFinder.find(Class<T> type) if type.isAssignableFrom(extensionClass) return false.
Here are two possible causes:

  • something is wrong related to how you mark the extension point or extension
  • CommandExtension and TestExtension is loaded by two different class loaders

@lyze237
Copy link
Author

lyze237 commented Mar 21, 2016

CommandExtension is used by both plugins so it needs to be loaded by their two classloaders? (Or am I wrong here?)

For clarification, those are the two files:

CommandPlugin.CommandExtension

public interface CommandExtension extends ExtensionPoint {
    boolean canCall(String pluginId, Event event);
    void call(String pluginId, Event event);
}

TestPlugin.TestPlugin

public class TestPlugin extends Plugin {
    @Extension
    public static class TestExtension implements ServiceExtension, CommandExtension {
        @Override
        public boolean canCall(String pluginId, Event event) {
            return true;
        }

        @Override
        public void call(String pluginId, Event event) {
            logger.warn("Command got called! " + event);
        }
    }
}

@decebals
Copy link
Member

The idea is : if Plugin_1 declares the extension point ExtensionPoint_1 than if in Plugin_2 you want to provide an extension for ExtensionPoint_1 you must specify that Plugin_1 is a dependency for Plugin_2 (in plugin manifest file).

I don't know if I can create a defense (a warning in log) to highlight this type of problems.

Please make the modifications and tell me if the problem disappears.

@lyze237
Copy link
Author

lyze237 commented Mar 21, 2016

Ah oh god I forgot that exists.
I'm sorry, that worked!

@decebals
Copy link
Member

Good. Please close the issue if the problem is resolved.

@lyze237
Copy link
Author

lyze237 commented Mar 21, 2016

Thanks again for the quick help!
And I#m sorry that I forgot about that X)

@lyze237 lyze237 closed this as completed Mar 21, 2016
@decebals
Copy link
Member

No problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants