Пакет создается более одного раза с использованием DS

Я создаю приложение, у которого есть бедра связок. Некоторые из них являются интерфейсами, а некоторые являются реализацией этих интерфейсов. Я использую декларативные сервисы (DS) для предоставления и использования сервисов, что означает, что в каждом пакете есть файл component.xml, описывающий сервис (ы), которые я предоставляю / на которые ссылаюсь.

В настоящее время у меня есть класс под названием ClockWidget который реализует 3 интерфейса (как вы можете видеть на прилагаемой диаграмме). Для каждого реализованного сервиса у меня есть определенный класс, который ссылается на этот сервис. Например, Timeout класс имеет методы привязки, которые получает любой, кто реализует TimeoutListener оказание услуг.

Проблема в том, что конструктор ClockWidget класс вызывается три раза. Очевидно, я связал это с количеством сервисов, которые используются другими пакетами.

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

ClockWidget.class:

public class ClockWidget implements Widget, TimeoutListener, DummyInterface {

    public ClockWidget() {
        System.out.println("ClockWidget constructor.");
    }

    @Override
    public String getWidgetName() {
        return "Clock widget";
    }

    @Override
    public void onTimeout() {
        System.out.println("Timeout!");
    }

    @Override
    public void dummyMethod() {
        // Does nothing.
    }
}

Определение его компонента ClockWidget.xml

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="test.e4.ClockWidget">
   <implementation class="test.e4.history.ClockWidget"/>
   <service>
      <provide interface="test.e4.widget.Widget"/>
      <provide interface="test.e4.timeoutlistener.TimeoutListener"/>
      <provide interface="test.e4.dummyinterface.DummyInterface"/>
   </service>
</scr:component>

Класс, который использует сервис, предоставляемый ClockWidget, В этом случае Timeout учебный класс:

public class Timeout {

    private ArrayList<TimeoutListener> listeners;

    public Timeout() {
        listeners = new ArrayList<>();
        startTimeoutTimer();
    }

    public void startTimeoutTimer() {
        long timeoutInMs = 60 * 1000;
        Timer timeoutTimer = new Timer();
        timeoutTimer.schedule(new TimerTask() {

            @Override
            public void run() {
                timeout();
            }
        }, timeoutInMs);
    }

    // Bind method from DS
    public void addListener(TimeoutListener listener) {
        listeners.add(listener);
    }

    // Unbind method from DS
    public void removeListener(TimeoutListener listener) {
        listeners.remove(listener);
    }

    public void timeout() {
        for (TimeoutListener listener : listeners) {
            listener.onTimeout();
        }
    }
}

Описание компонента тайм-аута:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="test.e4.Timeout">
   <implementation class="test.e4.Timeout"/>
   <reference bind="addListener" cardinality="0..n" interface="test.e4.timeoutlistener.TimeoutListener" name="TimeoutListener" policy="dynamic" unbind="removeListener"/>
</scr:component>

Любое предложение?

2 ответа

Решение

Извините, ребята, я не был полностью честен с вами. Конечно, моя система намного сложнее. Это как мой ClockWidget У класса есть другой метод, который вызывается в конструкторе. Я не знал, что это может вызвать проблему. Вот как полный ClockWidget.class будет выглядеть так:

public class ClockWidget extends Widget implements TimeoutListener, DummyInterface {

    private ArrayList<ActivityListeners> activityListeners;

    public ClockWidget() {
        super();
        System.out.println("ClockWidget constructor.");
        lookupActivityListeners();
    }

    @Override
    public String getWidgetName() {
        return "Clock widget";
    }

    @Override
    public void onTimeout() {
        System.out.println("Timeout!");
    }

    @Override
    public void dummyMethod() {
        // Does nothing.
    }

    private void lookupActivityListeners() {

        activityListeners = new ArrayList<>();

        try {
            BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); 
            Collection<ServiceReference<ActivityListener>> serviceReferences = context.getServiceReferences(ActivityListener.class, null);

            for (ServiceReference<ActivityListener> serviceReference : serviceReferences) {
                ActivityListener activityListener = (ActivityListener) context.getService(serviceReference);
                if (activityListener != null) {
                    activityListeners.add(activityListener);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Как видите, метод lookupActivityListeners ищет всех ActivityListeners устанавливается в OSGi и добавляет их в список массивов. Я прокомментировал строку ActivityListener activityListener = (ActivityListener) context.getService(serviceReference); и конструктор был вызван один раз.

Поэтому я должен был изменить lookupActivityListeners(); звонить в другое место вместо конструктора. Сейчас все в порядке. Тем не менее, я до сих пор не знаю, почему это будет источником проблемы.

В любом случае, спасибо за ответы.

ClockWidget один компонент DS зарегистрирован под 3 именами служб? Или 3 компонента DS, каждый из которых зарегистрирован под одним именем службы. Если последнее, то да, ClockWidget будет создан один раз для каждой службы, поскольку это все, что DS знает. Если первое, то ClockWidget должен создаваться только один раз, поскольку это единственный сервис, доступный под 3 именами сервисов.

Другие вопросы по тегам