LiteCoding

Заметки о программировании

Пишем плагин для Vuze. Часть 2. Обработчики событий

3 комментария

Обработчики событий — это фундамент, на котором выстроена вся система плагинов в Vuze. А это означает, что при разработке своего плагина вы обязательно столкнетесь с ними. Несмотря на весьма скудное описание в официальной документации (я имею в виду javadoc), назначение отдельных обработчиков становится ясным из их названия.

Обработчики событий делятся на две группы: глобальные и локальные. Это моя собственная классификация, так что тут могут быть некоторые расхождения с мнением других разработчиков плагинов. Глобальные обработчики событий привязываются к объектам, существующим в единственном экземпляре во время работы Vuze. Как правило, в качестве таких объектов выступают менеджеры (экземпляр класса, содержащего в своем названии слово Manager, например, TorrentManager). Локальные обработчики событий привязываются к объектам, создаваемым в процессе работы Vuze. В качестве таких объектов могут выступать торренты, пиры и т.д. Сам факт создания (и не только создания) объекта, к которому можно привязать локальный обработчик, является событием глобального обработчика.

Начинать работу следует с установки обработчика событий. Обработчик каждого типа событий реализует свой интерфейс, поэтому ошибиться при его установке практически невозможно. Для установки используются методы вида add<Xxx>Listener. Например, вот так:

DownloadManager downloadMgr = pluginInterface.getDownloadManager();				
Download[] downloads = downloadMgr.getDownloads();
for(Download download: downloads)
{
    download.addPeerListener(new CustomDownloadPeerListener());
}

Приведенный выше фрагмент кода не очень хорош по двум причинам. Первое, из способа получения объекта менеджера закачек следует, что код выполняется во время инициализации плагина. А это значит, что все остальные составляющие части Vuze будут ожидать окончания инициализации, в том числе и графическая подсистема. Второй минус — мы не сможем самостоятельно удалить обработчик, т.к. методы remove<Xxx>Listener требуют ссылку на удаляемый обработчик событий.

При реализации интерфейса не забывайте, что ресурсоемкие операции можно и нужно выносить за пределы обработчика событий. Отложенные задания (java.utils.TimerTask, org.gudy.azureus2.plugins.utils.UTTimerEventPerformer) или отдельный поток-worker отлично подходят под такие задачи.

Давайте посмотрим на исходный код одного из распространенных плагинов Vuze, чтобы изучить особенности обработчиков событий в «естественной среде обитания».

Плагин Rating (версия на момент написания статьи: 1.3.1), написанный Olivier Chalouhi и TuxPaper, предназначен для комментирования и выставления оценок раздачам. Для хранения метаинформации к торрентам он использует Distributed Database (DDB).

Первый вызов установки обработчика событий находится в методе RatingPlugin.initialize:

...
    pluginInterface.getUIManager().addUIListener(
			new UIManagerListener()
			{
				public void
				UIAttached(
					UIInstance		instance )
				{
					if ( instance instanceof UISWTInstance ){
						
						UISWTInstance	swt = (UISWTInstance)instance;
						
						initialise( swt );
					}
				}
				
				public void
				UIDetached(
					UIInstance		instance )
				{
					
				}
			});
...

Как вы видите, автор использовал здесь анонимный класс, реализующий интерфейс UIManagerListener, в качестве обработчика событий. Этот фрагмент любопытен еще тем, что с его помощью реализуется двухфазная инициализация плагина (вызов второй фазы находится в строчке 13).

Второй достойный упоминания фрагмент кода находится в классе RatingsUpdater:

...
      database.read(new DistributedDatabaseListener() {
       
        List results = new ArrayList();
       
        public void event(DistributedDatabaseEvent event) {
          
          if(event.getType() == DistributedDatabaseEvent.ET_VALUE_READ) {
            results.add(event.getValue());
          }
         
          if(event.getType() == DistributedDatabaseEvent.ET_OPERATION_COMPLETE 
               || event.getType() == DistributedDatabaseEvent.ET_OPERATION_TIMEOUT) {
            plugin.logInfo(torrentName + " : Rating received");
            RatingResults ratings = new RatingResults();
            
            for(int i = 0 ; i < results.size() ; i++) {
              
              DistributedDatabaseValue value = (DistributedDatabaseValue) results.get(i);
              
              try {
                
                byte[] bValue = (byte[]) value.getValue(byte[].class);
                
                RatingData data = new RatingData(bValue);
                
                plugin.logInfo("        " + data.getScore() + ", " + value.getContact().getName() + ", " +  data.getNick() + " : " + data.getComment());
                
                ratings.addRating(data);
                
              } catch(Exception e) {
                
                e.printStackTrace();
                
              }                            
            }
            
            synchronized (torrentRatings) {
              torrentRatings.put(download,ratings);
              download.setAttribute(attributeGlobalRating,"" + ratings.getRealAverageScore());
            }
            
            updateRatings(downloads);
          }
        }
      },ddKey,READ_TIMEOUT);    
...

В этом фрагменте кода обработчик устанавливается на операцию чтения из DDB по заранее сгенерированному ключу. В строках 8, 12 и 13 раскрывается назначение событий типа ET_VALUE_READ, ET_OPERATION_COMPLETE, ET_OPERATION_TIMEOUT.

События первого типа возникают, когда приходят данные. При использовании DDB мы не знаем, какие ноды хранят интересующую нас информацию. Данные могут приходить с разных нод, а также с одной ноды, если несколько пиров хранят данные, связанные с одним ключом. На каждое полученное значение генерируется событие ET_VALUE_READ.

Если последний ожидаемый ответ приходит раньше, чем истечет отпущенное на запрос время, то генерируется событие типа ET_OPERATION_COMPLETE. В противном случае - ET_OPERATION_TIMEOUT.

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

Предыдущая статья: Пишем плагин для Vuze. Часть 1. Что могут плагины?
Следующая статья: Пишем плагин для Vuze. Часть 3. Инициализация и конфигурация

Share and Enjoy:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • LinkedIn
  • Tumblr

Written by Дмитрий Воробьев

Четверг, Апрель 8th, 2010 at 09:20

3 комментария to 'Пишем плагин для Vuze. Часть 2. Обработчики событий'

Subscribe to comments with RSS or TrackBack to 'Пишем плагин для Vuze. Часть 2. Обработчики событий'.

  1. […] статья: Пишем плагин для Vuze. Часть 2. Обработчики событий Category: Статьи  | Tags: Java, p2p, Vuze, плагин You can follow any […]

  2. Добрый день. есть у меня специфическая задача. через вузе я раздаю около 200 раздач. плюс имеется фильтр по айпиадресам. но очень часто бывает так, что много раздач раздается где вообще нет пиров-личеров. а где очень много-личеров, те раздачи в очереди. как написать плугин простой. чтобы раз в 10 минут опрашивал трекер(или получал список пиров), и в очередь отправлял те раздачи которые без личеров, а на раздачу ставил именно те где много личеров.

    буду ждать от вас ответа. можно на мыло.

    Nurm

    23 Апр 10 at 04:04

  3. 2 Nurm:
    А действительно ли для решения данной задачи нужен плагин? Большую часть проблемы можно решить настройками самого Vuze (например, там можно снять лимит на количество одновременно активных раздач: Tools->Options, раздел Queue).

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

    Dmitry S. Vorobiev

    23 Апр 10 at 09:10

Leave a Reply

You must be logged in to post a comment.