简体   繁体   English

将Bundle-A jar文件安装到OSGi容器后,如何调用其中一个方法

[英]How to call one of the methods in my Bundle-A jar file after it has been installed into OSGi container

I have recently started working on OSGi framework. 我最近开始研究OSGi框架。 I have one bundle named Bundle-A. 我有一个名为Bundle-A的包。 I want to call one of the methods in Bundle-A jar from my main application. 我想从我的主应用程序中调用Bundle-A jar中的一个方法。

I have loaded and installed Bundle-A from my main application. 我从我的主应用程序加载并安装了Bundle-A。 Below is my code for my main application where I am installing Bundle-A. 下面是我的主要应用程序的代码,我在这里安装Bundle-A。

private void initializeModelFramework() {

    try {

        FileUtils.deleteDirectory(new File("felix-cache"));
        FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next();

        Framework framework = frameworkFactory.newFramework(new HashMap<String, String>());
        framework.start();

        BundleContext bundleContext = framework.getBundleContext();

        modulesNameVersionHolder.put("Bundle-A", "1.0.0");

        List<Bundle> installedBundles = new LinkedList<Bundle>();

        String basePath = "C:\\ClientTool\\LocalStorage";

        for (Map.Entry<String, String> entry : modulesNameVersionHolder.entrySet()) {
            String version = entry.getValue();
            final String filename = name + Constants.DASH + version + Constants.DOTJAR;
            final String localFilename = GoldenModulesConstants.FILE_PROTOCOL + basePath+ File.separatorChar + filename;

            installedBundles.add(bundleContext.installBundle(localFilename));
        }   

        for (Bundle bundle : installedBundles) {
            bundle.start();// this will start bundle A
        }

        // After starting the Bundle-A, now I need to call one of the methods in Bundle-A
        for(int i=0; i<=10; i++) {
            //call processingEvents method of Bundle-A class GoldenModelFramework
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

Now the Bundle-A has been started up. 现在Bundle-A已经启动了。 Below is my Activator class for Bundle-A. 下面是我对Bundle-A的Activator类。

public class Activator implements BundleActivator {

    private static final String BUNDLE_VERSION_KEY = "Bundle-Version";
    private static Logger s_logger = Logger.getLogger(Activator.class.getName());

    @Override
    public void start(BundleContext context) throws Exception {

        final Bundle bundle = context.getBundle();
        final String bundleName = bundle.getSymbolicName();
        final String bundleVersion = (String) bundle.getHeaders().get(BUNDLE_VERSION_KEY);

        System.out.println(bundleName+" - "+bundleVersion);
    }

    @Override
    public void stop(BundleContext context) throws Exception {
            System.out.println("Bye.!");
    }
}

And below is the class I have in Bundle-A jar. 以下是我在Bundle-A jar中的课程。 I need to call processingEvents method from my above main application code as soon as Bundle-A has been started. 一旦Bundle-A启动,我需要从上面的主应用程序代码中调用processingEvents方法。

public class GoldenModelFramework {

    private static final Logger LOGGER = Logger.getLogger(GoldenModelFramework.class.getName());
    private static final long checkingAfterEveryXMinutes = 15L;


    public GoldenModelFramework() {
        // following the traditions
    }

    public static void processingEvents(final String item) {

        for (BundleRegistration.HolderEntry entry : BundleRegistration.getInstance()) {
            final String response = entry.getPlugin().process(item);
            System.out.println(response);
        }
    }
}

I am not sure what's the right way to do it? 我不确定这样做的正确方法是什么? I know one way is add the dependency of this Bundle-A in my main application pom.xml file as I am using maven based project. 我知道一种方法是在我的主应用程序pom.xml文件中添加此Bundle-A的依赖项,因为我正在使用基于maven的项目。 But I don't think so that's the right way to do it. 但我不认为这是正确的做法。 Because ultimately, I am going to have some more bundles so there should be some other way around for this which I am not aware of. 因为最终,我将有更多的捆绑,所以应该有一些其他方法,我不知道。

Should I am supposed to use ServiceListener or ServiceTracker here? 我应该在这里使用ServiceListener或ServiceTracker吗? Any simple example basis on my code will help me understand much better. 我的代码的任何简单的示例基础将帮助我更好地理解。 Thanks. 谢谢。

I hope the question is clear enough. 我希望这个问题足够清楚。 I am trying to call one of the methods in Bundle-A after it has been loaded up and installed. 我试图在Bundle-A加载并安装后调用其中一个方法。

You have several choices: 你有几个选择:

Import the package dynamically 动态导入包

You can use DynamicImport-Package instead of Import-Package. 您可以使用DynamicImport-Package而不是Import-Package。 In this case bundle-A does not have to be active when the main bundle starts. 在这种情况下,当主包启动时,bundle-A不必处于活动状态。 Although this works I do not recommend this solution as I do not like DynamicImport-Package. 虽然这有效但我不推荐这个解决方案,因为我不喜欢DynamicImport-Package。 In this case of course bundle A has to be a dependency of the main bundle. 在这种情况下,当然捆绑包A必须是主捆绑包的依赖关系。

Using reflection 用反射

You can call the method you want with reflection like the following (draft example): 您可以使用反射调用所需的方法,如下所示(草稿示例):

Class<GoldenModelFramework> clazz = bundleA.loadClass("GoldenModelFramework");
Method m = clazz.getMethod("processingEvents", String.class);
m.execute(null, myParam);

This is a bit better, however this solution is still a bit foggy, I would not say this is a clean code. 这有点好,但是这个解决方案仍然有点模糊,我不会说这是一个干净的代码。

Using interface and OSGi service 使用接口和OSGi服务

The cleanest way would need a bit of refactoring. 最干净的方式需要一些重构。 In this case you should create an interface and in the Activator of bundle A you should register a service based on that interface. 在这种情况下,您应该创建一个接口,并在bundle A的Activator中,您应该基于该接口注册服务。 In the main bundle you should use a service tracker to catch that service and call the method on it. 在主捆绑中,您应该使用服务跟踪器来捕获该服务并在其上调用该方法。

In case you really want to make your method processEvent static, the registered service object (that is based on the interface) should simply call the static method inside. 如果你真的想让你的方法processEvent静态,那么注册的服务对象(基于接口)应该只是调用内部的静态方法。

Not to have the necessity to add bundle A as a dependency to the main bundle the interface should be taken into a third bundle that is the dependency of both, the main and A bundle. 没有必要将bundle A作为依赖关系添加到主bundle中,接口应该被带入第三个bundle,它是main和A bundle的依赖关系。

Although this solution seems to be the most complex I would suggest this one. 虽然这个解决方案似乎是最复杂的,但我会建议这个。

An example: 一个例子:

Create an interface and put it to a new bundle like goldenframework-api. 创建一个界面并将其放到像goldenframework-api这样的新包中。

public interface GoldenModelFrameworkOSGi {
    void processingEvents(final String item);
}

The goldenframework-api will be a dependency of main bundle and bundle-A. goldenframework-api将是主bundle和bundle-A的依赖。 The main bundle will use it, while bundle-A will implement it. 主捆绑包将使用它,而捆绑包A将实现它。

Here is how bundle A implements it: 以下是bundle A如何实现它:

public class GoldenFrameworkOSGiImpl {
    public void processingEvents(final String item) {
        GoldenModelFramework.processEvents(item);
    }
}

Create an Activator class in bundle-A (I will leave out your code in that activator to have less typing): 在bundle-A中创建一个Activator类(我将在激活器中省略你的代码以减少输入):

public class Activator {
  private ServiceRegistration goldenFrameworkSR;

  @Override
  public void start(BundleContext context) {
    goldenFrameworkSR = context.registerService(GoldenFrameworkOSGi.class, new GoldenFrameworkOSGi(), new HashTable());
  }

  @Override
  public void stop(BundleContext context) {
    goldenFrameworkSR.unregister();
  }
}

As you know the code of Bundle-A you can cheat a bit. 如你所知,Bundle-A的代码你可以作弊。 When bundle-A is in Active state you can be sure that the service you need is registered. 当bundle-A处于Active状态时,您可以确保注册所需的服务。 However, in the future you should think in working based on events (like using a ServiceTracker). 但是,在将来,您应该考虑基于事件(例如使用ServiceTracker)进行工作。 I mean this will be a bad practice :) : 我的意思是这将是一个不好的做法:):

ServiceReference sr = context.getServiceReference(GoldenServiceOSGi.class);
GoldenServiceOSGi gs = context.getService(sr);
gs.processEvents(...);
context.ungetService(sr);

This might solve your problem for now and you can continue with your work. 这可能会解决您现在的问题,您可以继续工作。 However, please consider reading a book like "OSGi in Action" to have a feeling about OSGi bundle and service lifecycles so you may re-design your framework. 但是,请考虑阅读像“OSGi in Action”这样的书,以了解OSGi捆绑和服务生命周期,以便您可以重新设计框架。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM