2013-08-18 4 views
0

Я недавно начал работу над инфраструктурой OSGi. У меня есть один пучок по имени Bundle-A. Я хочу назвать один из методов в банке Bundle-A из моего основного приложения.Как вызвать один из методов в файле JAR-файла Bundle-A после его установки в контейнер OSGi

Я загрузил и установил 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(); 
    } 

Теперь запущен Bundle-A. Ниже приведен класс Activator для Bundle-A.

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.!"); 
    } 
} 

И ниже класс, который у меня есть в банке Bundle-A. Мне нужно вызвать метод из моего вышеуказанного основного кода приложения, как только Bundle-A был запущен.

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); 
     } 
    } 
} 

Я не уверен, что это правильный способ сделать это? Я знаю, что одним из способов является добавление зависимости этого Bundle-A в моем основном файле pom.xml приложения, поскольку я использую проект на основе maven. Но я не думаю, что это правильный способ сделать это. Потому что, в конечном счете, у меня появятся еще несколько пучков, поэтому для этого я должен быть каким-то другим способом, о котором я не знаю.

Должен ли я использовать ServiceListener или ServiceTracker здесь? Любая простая примерная основа моего кода поможет мне понять намного лучше. Благодарю.

Надеюсь, вопрос достаточно ясный. Я пытаюсь вызвать один из методов в Bundle-A после его загрузки и установки.

+0

Возможно, вам будет намного лучше начать с более удобного уровня, теперь вы пытаетесь запустить, прежде чем сможете сканировать. Самый простой способ начать работу с bndtools. Это хорошее место для начала: http://bndtools.org/tutorial.html –

ответ

2

У вас есть несколько вариантов:

Импорт пакета динамически

Вы можете использовать DynamicImport-пакет вместо Import-Package. В этом случае пучок-A не должен быть активным, когда начинается основной пучок. Хотя это работает, я не рекомендую это решение, поскольку мне не нравится DynamicImport-Package. В этом случае, конечно, расслоение А должно быть зависимостью основного расслоения.

С помощью отражения

Вы можете вызвать метод, который вы хотите с отражением, как следующий (проект примера):

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

Это немного лучше, однако это решение еще немного туманно , Я бы не сказал, что это чистый код.

Использование интерфейса и OSGi Service

Чистейший путь будет нужно немного рефакторинга. В этом случае вы должны создать интерфейс, а в Активаторе пакета A вы должны зарегистрировать услугу на основе этого интерфейса. В основном комплекте вы должны использовать трекер службы, чтобы поймать эту службу и вызвать метод на ней.

Если вы действительно хотите, чтобы ваш метод processEvent был статичным, зарегистрированный объект службы (основанный на интерфейсе) должен просто вызвать статический метод внутри.

Чтобы не было необходимости добавлять пучок А в качестве зависимости от основного пучка, интерфейс должен быть взят в третий пучок, который является зависимостью как основного, так и связного.

Хотя это решение представляется самым сложным, я бы предложил этот вариант.

Пример:

Создайте интерфейс и поместить его в новое расслоение как goldenframework-апи.

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

Goldframework-api будет зависимостью основного пучка и комплекта-A. Основной пакет будет использовать его, а bundle-A выполнит его.

Вот как расслоение его реализует:

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

Создание класса 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(); 
    } 
} 

Как вы знаете код Bundle-A, вы можете немного обмануть. Когда пакет-A находится в активном состоянии, вы можете быть уверены, что служба, в которой вы нуждаетесь, зарегистрирована. Однако в будущем вы должны думать о работе на основе событий (например, используя ServiceTracker). Я имею в виду, что это будет плохая практика :):

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

Это может решить вашу проблему сейчас, и вы можете продолжить работу. Однако, пожалуйста, подумайте о том, чтобы прочитать книгу «OSGi in Action», чтобы иметь представление о наборе OSGi и жизненных циклах службы, чтобы вы могли перепроектировать свою структуру.

+0

Спасибо, что дали мне все предложение. Возможно ли, чтобы вы предоставили мне простой пример на третьем примере? Таким образом, мне будет легче понять, а затем написать код соответственно. Я абсолютно не знаком с OSGi. Спасибо за помощь. – ferhan

+0

Отредактировал свой ответ на примере. Обратите внимание, что у меня странное чувство о вашем вопросе и ответе. Я показал некоторые трюки, однако, если вы углубитесь в мир OSGi более глубоко, вы, вероятно, разработаете код таким образом, что вам даже не нужны трюки. –

+0

Спасибо Balazs за предложение. Не могли бы вы рассказать мне, какое сомнение у вас есть в соответствии с моим вопросом? Таким образом, я могу думать о том, что я плохо делаю в своем дизайне, и что еще я могу сделать, чтобы улучшить его. – ferhan