2014-11-23 3 views
3

Я долгое время изучал OSGi, но я все еще чувствую, что недостает важной части головоломки.Получение конкретной реализации от Felix

Это мой случай использования:

Я использую JAX-RS (гризли), чтобы создать REST API. У меня есть интерфейс, который имеет множество различных реализаций. Мое решение должно иметь возможность добавлять новые реализации в любое время.

Основываясь на какой-либо форме ввода, я должен получить один из этих конкретных экземпляров. Например, скажем, я регистрирую две реализации интерфейса с помощью Felix Interface A и Interface B. Пользователь должен уметь запросить Implementation B

С помощью командной строки, которую мы получаем от запуска felix.jar (Apache Felix Gogo) Я смог установить и запустить свои собственные пакеты. Проблема, с которой я сейчас сталкиваюсь, заключается в том, как я должен с одного из моих контроллеров извлекать любую из этих реализаций.

Вот код активатора одной из моих реализаций.

public class MyClassActivator implements BundleActivator { 

@Override 
public void start(BundleContext context) throws Exception { 
    System.out.println("Starting ImplementationA"); 
    Hashtable<String, String> props = new Hashtable<>(); 
    props.put("Identifier", "ImplementationA"); 

    context.registerService(MyInterface.class.getName(), new MyClassA(), props); 
} 

@Override 
public void stop(BundleContext context) throws Exception { 
    System.out.println("Stopping ImplementationA"); 

} 

private class ImplementationA implements MyInterface { 
    /*my implementation*/ 
} 

} 

От одного из моих классов JAX-RS, я хочу, как-то, сделайте это:

MyInterface myclassA = getBundle("ImplementationA"); 

Строка ImplementationA это та же строка, я поместил на карте реквизита.

То, что я пытался до сих пор

BundleContext bc = FrameworkUtil.getBundle(MyInterface.class).getBundleContext(); 

Это, однако, только возвращает нуль, это, кажется, не на самом деле будет «говорить» к моему примеру ФЕЛИКС.

Итак, мои вопросы: как мне получить интерфейс от Феликса? И что я хочу делать с OSGi?

ответ

4

Ваш вопрос сбивает с толку, так как вы смешиваете условия для сервисов и пакетов. Пакет - это устанавливаемый блок, содержащий код. Этот код может регистрировать и потреблять услуги. Услуги - это объекты, которые, как правило, реализуют некоторый интерфейс, который распределяется между пакетом, предоставляющим услугу, и пакетами, использующими сервисы.

Итак, первый заказ состоит в том, чтобы убедиться, что пакет интерфейса службы экспортируется каким-то пакетом и импортирован всеми пакетами, которые планируют участвовать в предоставлении и потреблении услуги. Это необходимо для обеспечения безопасности типа. То есть, пакеты-потребители могут безопасно отнести объект службы к ожидаемому типу службы.

Как только это будет сделано, как вы наблюдаете, может быть несколько поставщиков услуг. Когда поставщик регистрирует услугу, они могут указывать некоторые метаданные об услуге в виде свойств ключа/значения. Ваш пример показывает это в свойстве Identifier. Когда потребитель просматривает услугу, может быть указана строка фильтра, которая может указывать информацию, подлежащую проверке, на метаданные службы для выбора из нескольких предоставляемых услуг.

public class MyServiceConsumer implements BundleActivator { 

@Override 
public void start(BundleContext context) throws Exception { 
    System.out.println("Looking for ImplementationA"); 

    ServiceReference<MyInterface>[] refs = 
    context.getServiceReferences(MyInterface.class, "(Identifier=ImplementationA)"); 
    MyInterface service = context.getService(refs[0]); 
} 

} 

Вышеупомянутый ужасный код; фактически не используют его. Он не справляется с тем, что не работает служба, когда потребительский пакет активирован (refs == null), и он не подготовлен к тому, чтобы служба ушла. Я настоятельно рекомендую использовать декларативные службы OSGi при написании пакетов. Это делает использование сервиса и имеет дело с динамическим супер простым.

@Component 
public class MyServiceConsumer { 
MyInterface service; 

@Reference(target="(Identifier=ImplementationA)") 
private void bindService(MyInterface s) { 
    service = s; 
} 

@Activate 
private activate() { 
    // do work 
} 

@Deactivate 
private deactivate() { 
    // do work 
} 

} 

Это компонент, который будет создан только при наличии соответствующего сервиса. Он будет вызван в bindService для ввода экземпляра службы, активируется вызов, чтобы включить компонент для его работы. Если введенная служба уходит, компонент будет вызываться при деактивации и затем отбрасываться. Если позже появится другая соответствующая служба, будет активирован новый экземпляр компонента.

См. http://enroute.osgi.org/ для учебника по OSGi app dev.

Смежные вопросы