AbavaNet - открытые интерфейсы для компьютерной телефонии

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

Реальный пример иллюстрирует особенности реализации известного сервиса "виртуальный номер" - звонок на входящий виртуальный номер переадресуется на один из реальных номеров из некоторого списка. Смысл этой услуги состоит в том, что пользователь делает видимым (публикует) для своих партнеров (клиентов) только один реальный номер. А входящие звонки в реальности будут переадресовываться на другие номера (возможно, меняющиеся в динамике).

Почему мы остановились на этом примере, входящем в стандартную поставку Appium? На самом деле этот пример содержит практически полную реализацию достаточно популярной на российском рынке услуги "виртуальный номер" (например, продукт Logic Line компании МТУ-Информ). Обратите внимание на эту строку в коде, содержащую список обзваниваемых номеров (используются четырехзначные номера программного эмулятора):

  /** список номеров, используемых при прозвоне */
   private String[] addresses = {"1101", "1102", "1103"};

В модельном примере перебираются номера из некоторого фиксированного списка. Собственно, все, что нужно для трансформации этого примера в реальный сервис – это добавить выбор списка перебираемых номеров из базы данных. Это может быть простым программированием с использованием JDBC и в любом случае никак не связано с особенностями телефонной сети. А главное, это объем потребного кода: текст программы занимает меньше 200 строк.

Интересно узнать больше? Пишите: info@abavanet.ru

Ниже приводится текст программы:

 
package com.company.apps;

// подключение библиотек сервера
import com.appium.Basement.Def.ConfigDescriptor;
import com.appium.Statistics.Statistic;
import com.appium.TAS.SessionContainer.AbstractSessionHandler;
import com.appium.TAS.SessionContainer.StaticSessionHandler;
import com.appium.TAS.SessionContainer.TelecomApplicationMainBase;

/**
 * Базовый класс, представляющий собой Telecom Application. Именно этот файл
 * запускается в JBuilder 
 *
  */
public class TelecomApplicationMain extends TelecomApplicationMainBase {

   /**
    *  здесь и создается CallHandler (поддержка звонков)
    */
   public AbstractSessionHandler createNewSessionHandler() {
      return new CallHandler();
   }

   /**
    * Каждое приложение имеет некоторый идентификатор (их может 
    * быть более одного). Этот идентификатор представляет собой 
    * адресацию приложения внутри контейнера. 
    *
    * Приложение также создает набор буферов для связи с контейнером
    *  Код для этих функций опущен (на практике этот код создается автоматически) 
    */
   . . .
}

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

Собственно реализация:

/**
 * Copyright owned by Appium AB, 2001
 *
*/

package com.company.apps;

// подключение бибилиотек
import com.appium.Parlay.*;
import com.appium.Parlay.cc.*;
import com.appium.Parlay.cc.gccs.*;
import com.appium.Parlay.ui.*;
import com.appium.Parlay.mm.*;
import com.appium.Parlay.mm.us.*;

import com.appium.TAS.SessionContainer.SessionState;
import com.appium.TAS.SessionBase.AsynchronousCallHandlerStateMachine;

/**
 * Базовая идея – предлагаемый framework поддерживает некоторую машину 
 * состояний (или автомат). В соответствии с моделью вызова, описанной в Parlay  
 * пользовательское приложение задает конкретные реализации  (действия, 
 * которые нужно выполнить) для возникающих состояний. 
 * Базовый класс есть AsynchronousCallHandlerStateMachine
 *
 * Вызовы enterState() и setNextState() позволяют организовать переходы между 
 * состояниями. 
 *
 * В каждом состоянии приложение получает сигналы от сервера (то есть, от 
 * телефонной части нашего приложения). Здесь они называются callback, 
 * поскольку  это и есть callback в терминах Corba
 *
 * В случае машины состояний возникает важный вопрос – что есть (точнее что 
 * делать) в начальном состоянии. То есть с чего все запускается? В модели Appium 
 * TAS в начальном состоянии приложение должно реализовывать один из 
 * следующих методов (это то, что вызывается при звонке):
 *
 *     public void handleCall()
 *     public void createCall(TpAddress address)
 *     public void createCall(TpAddress from, TpAddress to)
 *     public void createCall(TpAddress[] addresses, String[] stringParameters, Any[]  
 *                                          anyParameters)
*/
public class CallHandler extends AsynchronousCallHandlerStateMachine {

   // в данном приложении – дозвонка по списку будет два состояния:
   // начальное и разговор (когда дозвонились)

   /** начальное состояние */
   private InitialState initialState = new InitialState();

   /** разговор */
   private Talking talking = new Talking();

   /** список номеров, используемых при прозвоне */
   private String[] addresses = {"1101", "1102", "1103"};

   /** индек текущего номера в списке номеров */
   private int index;

   /**
    * 
    *  Этот метод вызывается контейнером для получения начального состояния
    *  Схема следующая: для приложения (которое имеет некоторый ID) вызывается
    *  метод getInitialState() Это метод возвращает экземпляр объекта, 
    *  ответственного за начальное состояние. И у этого объекта будет вызван 
    *  метод handleCall()
    */
   public SessionState getInitialState(String applicationID, String state) 
    {
      if(state.equals("")) {
         return initialState;
      } else {
         return talking;
      }
   }

   /**
    * Начальное состояние: звоним по первому адресу из нашего списка и ждем 
    *  реакции. Это описание класса, который отвечает за поддержку начального
    *  состояния
    */
   class InitialState extends AbstractActiveState {
      
      // этот метод вызывается при входе в состояние (после метода start())
      public void handleCall() throws Exception {
         index = 0;
         callControl.routeReq(addresses[0]);
      }

      // этот метод вызывается при обработке звонка
      public void routeRes(TpCallReport eventReport, int callLegSessionID) 
throws Exception {
         if  (eventReport.CallReportType.equals(TpCallReportType.P_CALL_REPORT_ANSWER)) 
{           // если дозвонились – то переходим в другое состояние
            enterState(talking);
         }
         else {  // не дозвонились

            // меняем индекс (переходим к следующему номеру)
            index++;

            if (index < addresses.length) {  // еще есть куда звонить
               callControl.routeReq(addresses[index]);
            } else {  // все перебрали. Закрываем приложение
               shutdownCallHandler(false);
            }
         }
      }

      /**
       *  этот метод вызывается при ошибках
       */
      public void routeErr(TpCallError errorIndication, int callLegSessionID) 
               throws Exception {

         // просто переходим к следующему номеру (если он есть)
         // или завершаем приложение
         index++;
         if (index < addresses.length) {
            callControl.routeReq(addresses[index]);
         } else {
            shutdownCallHandler(false);
         }
      }
   }

   /**
    * State 2 – состояние разговора. Переходим сюда, если получен ответ на     
    * звонок. В данном примере нет никаких специальных действий.
   */
   public class Talking extends AbstractActiveState {
      /**
       *  инициализационный метод. Запоминает текущее состояние
      */
      public void start() {
         getSessionContext().setState("talking");
         saveSession();
      }

      /**
       * обработка. Ничего не делаем
       */
      public void handleCall() {
         /* то есть просто ждем окончания */
      }

      // Этот метод вызывается при ошибках
      public void routeRes(TpCallReport eventReport, int callLegSessionID)  {
         // завершаем приложение
         shutdownCallHandler(false);
      }
   }
}

Здесь routeReq() есть вызов из сервисной оболочки, который в точности
соответствует одноименному вызову из Parlay API.

Для контактов: info@abavanet.ru

© AbavaNet 2004 all rights reserved