Статьи

Учебник по JXSE и Equinox, часть 3: Введение в контейнер JP2P

 Аннотация

    После первого и второго постов этой серии прошло много времени, но за последние несколько месяцев произошло много событий , в частности тот факт, что код из eclipselabs будет перенесен в Project Chaupal, который (в конечном итоге) будет ( приезжайте) реализация OSGI спецификаций JXTA . В результате я решил переименовать пакеты и сделать архитектуру максимально чистой до изменения.

    В этом руководстве будут рассмотрены некоторые функции, которые уже доступны, и они могут немного упростить разработку приложений JXTA в Eclipse / Equinox.

ПРИМЕЧАНИЕ. В этом учебнике используется пересмотренная версия расширенных библиотек, и читатели, работавшие с предыдущими учебниками, могут обнаружить, что их код больше не будет компилироваться. Учебное пособие было обновлено, чтобы отразить изменения. Вы можете получить новые библиотеки здесь .

    Создание контейнера JP2P с нуля

Краткий обзор. В предыдущих руководствах демонстрировались способы заставить существующие приложения JXTA работать в Equinox. Несколько примеров из книги Practical JXTA II были упакованы в пакеты OSGI и могут быть запущены и просмотрены в Eclipse IDE.

Фактически, пакеты являются реализациями контейнера JP2P , что является причудливым способом сказать, что эти пакеты соответствуют определенной структуре, которую могут распознавать другие пакеты (например, JXTA Container Navigator в вашей IDE). Для конечного пользователя главная видимая особенность контейнера JP2P состоит в том, что ему требуется JP2P-INFпапка, которая служит хранилищем общего назначения ресурсов, связанных с равноправным узлом. Поскольку примеры Practical JXTA II являются автономными, предыдущие примеры не требуют таких ресурсов и поэтому могут оставаться пустыми. Результатом этого было предупреждение:

  WARNING:
  This bundle is not a valid JP2P Bundle. A JP2P-INF directory is required.

Теперь мы можем начать использовать эту особенность архитектуры Chaupal.

Для этого мы делаем пакет JP2P . Создайте новый проект плагина. В файле манифеста плагина введите имя активатора и установите флажок «активировать плагин, когда один из классов загружен». Затем создайте активатор и измените класс следующим образом:

package your.bundle.name;

import org.osgi.framework.BundleContext;
import net.osgi.jp2p.chaupal.activator.Jp2pBundleActivator;

public class Activator extends Jp2pBundleActivator {

  public static final String S_BUNDLE_ID = "your.bundle.name";

  private static Jp2pBundleActivator activator;

  public Activator() {
    super(S_BUNDLE_ID);
  }

  @Override
  public void start(BundleContext bundleContext) throws Exception {
    activator = this;
    super.start(bundleContext);
  }

  @Override
  public void stop(BundleContext bundleContext) throws Exception {
    super.stop(bundleContext);
    activator = null;
  }
	
	public static Jp2pBundleActivator getDefault(){
		return activator;
	}
}

Есть несколько изменений относительно класса Activator предыдущего урока, за исключением того, что этот активатор наследует от конкретной реализации JP2PBundleActivator, а не от своего абстрактного суперкласса. Эта реализация ищет jp2p-1.0.0.xmlфайл, хранящийся в JP2P-INFкаталоге, и анализирует этот файл, если находит его. Поэтому создайте файл с этим именем и добавьте его в папку JP2P-INF. В результате ваша структура пакета должна выглядеть примерно так (папка OSGI-INF будет включена позже):

Начнем со следующего содержания:

<?xml version='1.0' encoding='UTF-8'?>
<jp2p-container id="your.bundle.name.container" name="My Test JP2P Bundle">
  <properties>
    <bundle-id>your.bundle.name</bundle-id>
    <home-folder>${user.home}/.jp2p/${bundle-id}</home-folder>
  </properties>
</jp2p-container>

Домашняя папка — это место, где будут храниться все файлы JP2P (и JXTA). Вы можете указать предпочитаемое местоположение в этом поле, если хотите. Расположение по умолчанию — это .jp2pпапка в домашнем каталоге пользователя. Пакет используется, чтобы различать различные пакеты. Это представлено в приведенном выше примере, где для представления (в Windows) используется нотация в стиле Eclipse:

C:\Users\.jp2p\your.bundle.name\

Далее нам нужно добавить декларативный сервис, чтобы пакет был зарегистрирован в IDE. Эта процедура точно такая же, как и в предыдущем уроке, поэтому здесь я приведу лишь краткий обзор:

  1. Создайте папку OSGI-INF в вашем комплекте и добавьте ее в файл build.properties

  2. создайте файл jp2p.xml со следующим содержимым:

    <?xml version="1.0"encoding="UTF-8"?>
        <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="<your.bundle.name>.jp2p">
        <implementation class="<your.bundle.name>.OsgiComponent"/>
        <reference bind="setAttendeeService"cardinality="1..1"interface="org.eclipselabs.osgi.ds.broker.IAttendeeService"name="IAttendeeService"policy="static"unbind="unsetAttendeeService"/>
    </scr:component>
  3. Зарегистрируйте сервис в Manifest.MFфайле, включив следующую строку:

  4. Service-Component: OSGI-INF/jp2p.xml

  5. Реализуйте класс реализации OsgiComponent:

    package <your.bundle.name>;
    
    import net.jp2p.container.startup.Jp2pStartupService;
    
      import net.osgi.jp2p.chaupal.core.Jp2pDSComponent;
      import <your.bundle.name>.Activator;
    
      public class OsgiComponent extends JxseDSComponent<Jp2pStartupService> {
       
       public OsgiComponent() {
         super( Activator.getDefault());
       }
    }

    Есть еще одно небольшое изменение в отношении компонента OSGI из предыдущего урока, и это то, что a Jp2pStartupServiceзаменил NetworkManager. Благодаря этому вы сможете запустить пакет в IDE, который вы создали ранее.

    Откройте конфигурацию запуска, убедитесь, что все необходимые пакеты добавлены (УДАЛИТЕ пакет net.osgi.jxse.compatibility!), И запустите модуль запуска. Если все прошло хорошо, вы должны увидеть следующее:

    Рисунок 1: Простой пакет JP2P

    На данный момент у вас есть пустой контейнер JP2P. JP2P Контейнер Навигатор состоит только из одного узла, сам контейнер. На странице свойств отображается (преобразованная) информация, которая приводится в файле jp2p-1.0.0.xml. Кроме того, это не так много, так что давайте пнуть его к жизни! Измените файл jp2p-1.0.0.xml следующим образом:

<?xmlversion='1.0'encoding='UTF-8'?>
  <jp2p-container id="your.bundle.name.container" name="My Test JP2P Bundle">
    <properties>
      <bundle-id>your.bundle.name</bundle-id>
      <home-folder>${user.home}/.jp2p/${bundle-id}</home-folder>
    </properties>
    <startup-service auto-start="true"/>
    <logger-service auto-start="true"/>
    <persistence-service context="chaupal"/>
    <network-manager clear-config="true" auto-start="true">
      <properties>
        <config-mode>RENDEZVOUS</config-mode>
        <peer-id create="true" persist="true"/>
      </properties>
      <network-configurator>
        <properties>
          <tcp>
            <enabled>true</enabled>
            <incoming-status>true</incoming-status>
            <outgoing-status>true</outgoing-status>
            <port>9715</port>
          </tcp>
          <multicast>
            <enabled>false</enabled>
          </multicast>
        </properties>
     </network-configurator>
   </network-manager>
</jp2p-container>

Перезапустите и взгляните на Контейнерный навигатор JP2P. Как вы можете видеть, контейнер теперь показывает дерево, которое представляет пакет JP2P. Фактически, приведенный выше XML описывает пример практического JXTA II «Jack the Rendezvous»! Вот так выглядит Анна Пограничная.

<?xmlversion='1.0'encoding='UTF-8'?>
  <jp2p-container id="anna.the.edge.peer.bundle.container" name="Anna the Edge Peer">
    <properties>
      <bundle-id>anna.the.edge.peer.bundle</bundle-id>
      <home-folder>${user.home}/.jp2p/${bundle-id}</home-folder>
    </properties>
    <startup-service auto-start="true"/>
    <persistence-service context="chaupal"/>
    <logger-service auto-start="true"/>
    <network-manager clear-config="true">
      <properties>
        <config-mode>EDGE</config-mode>
        <peer-id create="true" persist="true"/>
      </properties>
        <network-configurator>
          <properties>
            <tcp>
              <enabled>true</enabled>
              <port>9711</port>
              <incoming-status>true</incoming-status>
              <outgoing-status>true</outgoing-status>
            </tcp>
            <multicast>
            <enabled>false</enabled>
          </multicast>
          <use-only_relay_seeds>false</use-only_relay_seeds>
          <use-only_rendezvous_seeds>false</use-only_rendezvous_seeds>
          <seed-list>
            <my-seed1>RDV, tcp://localhost:9715</my-seed1>
          </seed-list>
        </properties>
      </network-configurator>
    </network-manager>
</jp2p-container>

Как вы можете видеть, JP2P — это попытка развязать программирование приложений JXTA и превратить его в вопрос конфигурации. Кроме того, часто пугающие зависимости между службами JXTA скрыты от пользователя в максимально возможной степени. Приложение JXTA представляет собой последовательность действий, которые сильно зависят друг от друга: сначала вы должны сконфигурировать менеджер сети, затем конфигуратор, запустить менеджер сети, получить сетевую группу, запустить обнаружение, создать рекламу …

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

В качестве демонстрации этой другой перспективы взгляните на дерево навигатора JP2P выше. Сетевая peergroup стала отдельной службой в корне контейнера. Несмотря на то, что эта группа peer тесно связана с сетевым менеджером в JXTA (посредством startNetwork()метода это не отображается в контейнере JP2P. Этот вариант реализации скрыт в конфигурации.

В то время как мы находимся на этом, возможно, стоит рассмотреть файл конфигурации XML более подробно. Раздел свойств контейнера говорит сам за себя. Затем определяются три службы:

  1. Стартап-служба заботится о активации контейнера. Директива автозапуска указует приложение , чтобы начать как можно скорее. Конкретно, это означает, что служба диспетчера сети будет выполнять «startNetwork» после ее настройки.

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

  3. Регистратор-служба добавляется , чтобы показать некоторые сообщения о создании и активации JP2P услуг. В настоящее время он просто отображает несколько системных сообщений о прогрессе, и вы можете видеть их в виде сообщений черного журнала в консоли. Это будет рассмотрено более подробно в следующей серии уроков

Обратите внимание, что все эти сервисы не зависят от JXTA. Служба JP2P никоим образом не связана с библиотеками JXTA. Фактически, основная функциональность обеспечивается пакетом net.jp2p.container, который имеет зависимости только от классов JAVA. Функциональность JXTA обеспечивается пакетом net.jp2p.jxta, который представляет собой так называемый фрагмент с библиотеками, необходимыми для включения служб JXTA в контейнер JP2P. Если этот фрагмент не включен, то синтаксический анализатор не будет распознавать службу сетевого менеджера и сетевой конфигуратор.

Эти сервисы достаточно понятны для тех, кто работал с JXTA раньше или кто читает книгу Practical JXTA II. Раздел начального списка службы конфигурации сети, тем не менее, заслуживает некоторого внимания. Этот сервис содержит список пар ключ-значение, первая из которых — выбор между рандеву (RDV) или ретрансляцией (RELAY), а вторая — URL. В приведенном выше примере предоставляется только один из них, и он указывает на порт Джека Рандеву! Если Jack the Rendezvous является единственным активным пакетом, то ваша консоль в конечном итоге вызовет одно повторяющееся сообщение:

New Seeding...
Jan 29, 2014 11:59:20 PM net.jxta.logging.Logging logCheckedInfo
INFO: Line 995 net.jxta.impl.rendezvous.rpv.PeerView.seed()

Если оба пакета активированы, вы должны увидеть немного больше активности:

INFO: Line 127 net.jxta.impl.pipe.NonBlockingWireOutputPipe.<init>()
Constructing for urn:jxta:cbid-59616261646162614E50472050325033F078673BFEEC42949856BDD37C5DDA1804
Jan 30, 2014 12:01:22 AM net.jxta.logging.Logging logCheckedInfo
INFO: Line 1635 net.jxta.impl.rendezvous.rpv.PeerView.openWirePipes()
Propagate Pipes opened.

Если вы видите что-то подобное, значит, вы успешно установили контакт между двумя сверстниками!

Единственная проблема заключается в том, что у вас нет никакой ловушки для функциональности, которую вы хотите добавить самостоятельно. Этот хук можно получить, добавив наблюдателя в контейнер. Создайте класс с именем ContainerObserver в ваших пакетах:

package <your.bundle.name>;

import net.jp2p.container.component.ComponentChangedEvent;
import net.jp2p.container.component.IComponentChangedListener;

public class ContainerObserver implements IComponentChangedListener {

  public ContainerObserver() {
    System.out.println( this.getClass().getName() + ": " +
      "Starting to Observe.");
  }

  @Override
  public void notifyServiceChanged(ComponentChangedEvent event) {
    System.out.println( "OBSERVING: " + this.getClass().getName() + ": " +
      event.toString() );
  }
}

Наблюдатель может быть включен в метод запуска вашего активатора:

@Override
public void start(BundleContext bundleContext) throws Exception {
   super.setObserver( new ContainerObserver() );
   super.start(bundleContext);
   activator = this;
}

Если вы перезапустите приложение, наблюдатель начнет порождать сообщения, когда службы JP2P добавляются (или удаляются) из контейнера.

Вывод

Этот учебник представил контейнер JP2P как средство перехода от программирования приложений JXTA к их настройке . Многие детали реализации скрыты для разработчика JXTA-приложения, которому нужно только понимать службы и свойства, которые могут быть включены. В настоящее время многие функциональные возможности еще должны быть реализованы, но контейнер уже можно использовать, поскольку разработчики могут подключиться к коду в любой заданной точке и расширить или изменить предоставленную функциональность.

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