О программной реализации агентных приложений

УДК 004.78

А.А. СОЛДАТОВ, В.В. АНДРЕЕВ О ПРОГРАММНОЙ РЕАЛИЗАЦИИ АГЕНТНЫХ ПРИЛОЖЕНИЙ

Ключевые слова: агент, многоагентная платформа, JAVA.

Рассмотрены общие подходы программной реализации многоагентных систем.

A.A. SOLDATOV, V.V. ANDREEV ABOUT PROGRAM REALIZATION OF AGENTS APPENDICES

Key words: agent, multiagent platform, JAVA.

The general approaches of multiagents systems program realization are considered.

Многоагентный подход, появившийся сравнительно недавно, обеспечил множество программных средств новыми методами построения распределенных систем. Программные продукты, создаваемые в результате реализации данного подхода, многопрофильны и модифицируемы [1, 2].

Реализуя многоагентную платформу, необходимо учитывать большой выбор операционных систем сегодня. В связи с этим создаваемое приложение должно отвечать требованиям многоплатформенности. Поставленная задача решаема при использовании кроссплатформенных сред программирования. JAVA - наиболее удачное средство создания подобных приложений. Объектная ориентированность языка JAVA позволяет эффективно описать и скодировать приложение. Каркас программного кода представляют классы и интерфейсы.

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

Класс Agent реализует интерфейсы Runnable, Serializable, TimerListener, а также импортирует множество вспомогательных классов, наполняющих свойствами и методами агентов. Интерфейс Runnable библиотеки java.lang определяет метод run(), способный запустить новый подпроцесс из рассматриваемого класса. Интерфейс Serializable библиотеки java.io осуществляет сериализацию, при которой объект можно записать в последовательность байт и передать по сети. После процедуры передачи эту последовательность байтов можно регенерировать до восстановления оригинального объекта. Очевидно, что можно создать объект на машине с ОС Windows, сериализовать его и послать по сети на Unix машину, где он будет корректно реконструирован. Для сериализации объекта создается определенный сорт объекта OutputStream, а затем в него вкладывается объект ObjectOutputStream. После этого достаточно вызвать метод writeObject() и объект будет сериализован и послан в OutputStream. Чтобы провести обратный процесс, нужно вложить InputStream внутрь ObjectlnputStream и вызывать readObject(). Интерфейс TimerListener определяет внутреннюю систему синхронизации времени, используя для этого лишь один метод:

public interface TimerListener { void doTimeOut(Timer t);

}

Множества классов ядра платформы схожи по содержанию. Класс AgentState определяет статус жизненного состояния агента. Переменные состояния агента объявляются как «закрытые»: private String name; // имя состояния private int value; // цифровая запись состояния private Long persistentID; // цифровой ID состояния

Методы установки значений и возращения их для всех переменных аналогичны:

public void setName (String n){ name = n;

}

public String getName(){ return name;

}

Состояния двух агентов можно сравнить с помощью метода compareTo(). Метод возвращает 0, если состояния одинаковы: public int compareTo(Object o){

AgentState as = (AgentState) o;

return name .toLowerCase().toUpperCase().compareTo(as.name. toLowerCase().toUpperCase());

}

Константа STATES определяет массив возможных состояний агента: private static final AgentState[] STATES = new AgentState[] {

// агент имеет минимальный статус new AgentState("MIN state", Agent..APMIN),

// агент запущен new AgentState("Initiated", Agent. APINITIATED),

// агент активен new AgentState("Active", Agent.APACTIVE),

// агент бездействует new AgentState("Idle", AgentAPIDLE),

// агент приостановлен new AgentState("Suspended", Agent APSUSPENDED),

// агент ожидает new AgentState("Waiting", Agent. AP_WAITING),

// агент удаляется new AgentState("Deleted", AgentAP_DELETED),

// агент сохраняется new AgentState("Saving", 10),

};

Абстрактный класс LifeCycle определяет методы для работы с жизненными состояниями агентов. Экземпляр класса public abstract class LifeCycle может иметь более одного состояния. Переменные myAgent и myState объявляются с «защищенным» модификатором доступа: protected Agent myAgent; protected int myState;

Конструктор класса определяет статус агента через параметр: public LifeCycle(int s) { myState = s;

}

Далее описываются методы абстрактного класса.

// метод определяет агента void setAgent(Agent a) { myAgent = a;

}

// метод инициализирует агента public void init() {

}

// метод определяет выполнение действия агентом public void execute() throws InterruptedException,

InterruptedIOException {

}

InterruptedException способен к генерации исключений при вызове методов задержки по времени Thread.sleep() и Object.wait().

// метод, при котором тематика агента прекращается public void end() {

}

// метод определяет, является ли состояние прекращения действий агента активным

public boolean alive() { return true;

}

// метод возвращает статус агента public int getState() {

return myState;

}

// метод определяет переход из одного состояния агента к другому public void transitionFrom(LifeCycle from) {

}

// метод возвращает true в случае изменения статуса, если изменений не было - false

public boolean transitionTo(LifeCycle to) { return false;

}

// метод определяет, должен ли агент реагировать на входящие сообщения

public boolean isMessageAware() { return false;

}

// метод, определяющий сравнение в условии: если объект является экземпляром класса LifeCycle и статусы равны, то метод возвращает true public boolean equals(Object obj) {

if (obj instanceof LifeCycle) {

return (myState == ((LifeCycle)obj).myState);

}

return false;

}

Класс AID (Agent ID) реализует понятие идентификатора агента. Наиболее интересны методы добавления, удаления, возврата значений адреса агента на платформе и его идентификатора. Адрес агента и идентификатор объявлены как переменные контейнерного типа:

private List addresses = new ArrayList(l); private List resolvers = new ArrayList(l);

Универсальный идентификатор платформы platformID статичен для всех агентов:

private static String platformID;

Имя идентификатора также является защищенным: private String name;

Символическое имя агента несет значение локального характера, закрепляясь за определённым хостом. При этом имя представляет запись следующего вида: agent@host, где agent - имя агента, host - имя хоста.

Следующий метод определяет локальное имя агента. public void setLocalName(String n){

String pid = getPlatformID(); if (pid == null) { throw new RuntimeException("Unknown Platform name");

}

name = n.trim();

name = name.concat("@"+pid);

}

Выше использована зависимость метода getPlatformID() класса AID: static final String getPlatformID(){

return platformID;

}

Методы, обрабатывающие переменные контейнерного типа:

// метод добавляет адрес url агента public void addAddresses(String url) { if (!addresses.contains(url)) { addresses.add(url);

}

}

// метод удаляет адрес url public boolean removeAddresses(String url) { return addresses.remove(url);

}

// метод очищает все адреса агента public void clearAllAddresses() { addresses.clear();

}

// метод возвращает адреса агента через итератор

public Iterator getAllAddresses() {

return addresses.iterator();

}

// метод добавляет идентификатор агента public void addResolvers(AID aid) {

if (!resolvers.contains(aid)) { re solvers. add(aid);

}

}

// метод удаляет идентификатор public boolean removeResolvers(AID aid) { return resolvers.remove(aid);

}

// метод очищает контейнер идентификаторов public void clearAllResolvers() { resolvers.clear();

}

// метод возвращает идентификаторы агента через итератор public Iterator getAllResolvers() {

return resolvers.iterator();

}

Методы setAddressesArray(String [] adr) и setResolversArray(AID[] res), ge-tAddressesArray() и getResolversArray() схожи по содержанию, поэтому опишем по одному из каждой пары.

// метод создает массив адресов агента public void setAddressesArray(String [] adr) { addresses.clear(); for (int i=0; i<adr.length; i++) { addresses.add(adr[i]);

}

}

// метод возвращает массив идентификаторов агента public AID[] getResolversArray() {

Object[] objs = resolvers.toArray();

AID[] result = new AID[objs.length];

System.arraycopy(objs, 0, result, 0, objs.length); return result;

}

Метод equals() перегружен из класса java.lang.Object. Сравниваются имя экземпляра класса AID и переменная типа Object. public boolean equals(Object o) { if (o = = null) {

return false;

}

// если o - экземпляр класса AID if (o instanceof AID) {

return name.equalsIgnoreCase(((AID)o).name);

}

if (o instanceof String) {

return name.equalsIgnoreCase((String)o);

}

return false;

}

Метод getLocalName() возвращает локальное имя агента. public String getLocalName() {

// отлавливаем последнее появление в строке символа '@', т.е читаем строку с конца

int atPos = name.lastIndexOf('@');

// если индекс не найден, то возвращается -І if (atPos == - І) {

return name;

}

else

return name.substring(0, '@');

}

Метод getHap() возвращает название платформы. public String getHap() {

int atPos = name.lastIndexOf('@'); if (atPos = = -І) { return null;

}

else

return name.substring(atPos + І);

}

Одним из предубеждений является то, что агентная платформа должна содержать в себе область, в которой располагаются ее узлы. Данная область называется контейнером. Агент не может существовать на отдалённом хосте вне контейнера. В свою очередь, в контейнере могут размещаться агенты разной тематики. На машине с развернутой платформой обязательно существует главный контейнер с ограниченным количеством агентов поддержки системы.

Публичный класс ContainerID определяет контейнер платформы, реализуя интерфейсы Serializable и Location. Serializable - уже известный нам интерфейс библиотеки java.io. Интерфейс Location определяет четыре метода, возвращающих строковые значения идентификатора, имени, протокола, адреса контейнера платформы.

public interface Location extends Serializable {

String getID();

String getName();

String getProtocol();

String getAddress();

}

ContainerID оперирует следующими приватными переменными: private String name; private String address;

//переменная, определяющая главный контейнер: private Boolean main; private String port; private String protocol;

Методы setName и getName устанавливают и возвращают значение имени контейнера платформы соответственно. public void setName(String n) { name = n;

}

public String getName() { return name;

}

Методы setProtocol и getProtocol, setAddress и getAddress, setPort и getPort, setMain и getMain аналогичны по содержанию вышеописанным двум. Метод getID возвращает уникальный ID контейнера платформы: public String getID() {

return name + '@' + address;

}

Интерфейс Node, наследуемый интерфейс java.io.Serializable, определяет понятие узла платформы.

// метод устанавливает имя узла void setName(String name);

// метод возвращает имя узла String getName();

// метод определяет наличие менеджера платформы boolean hasPlatformManager();

// метод по команде возвращает объект Object accept(HorizontalCommand cmd);

// метод прерывает выполнение узла void interrupt();

// метод выводит узел из действия платформы void exit();

// метод прекращает действие платформы. deadPmAddress - адрес уничтожаемой платформы, notifyingPmAddress - уведомляемый адрес

void platformManagerDead(String deadPmAddress, String notifyingPmAddress). Абстрактный класс LifeCycle определяет все жизненные состояния агента.

// метод инициализирует агента public void init();

// метод определяет выполнения действия агентом public void execute();

// метод прекращения тематики агента public void end();

// метод возвращает статус агента public int getState() { return myState;

}

// метод определяет переход из одного состояния агента к другому

public void transitionFrom(LifeCycle from) { }

// метод возвращает true в случае изменения статуса public boolean transitionTo(LifeCycle to) { return false;

}

// метод определяет, должен ли агент реагировать на входящие сообщения public boolean isMessageAware() { return false;

}

Дескриптор узла - важная часть многоагентной системы. Класс, описывающий его, реализует интерфейс Serializable.

Переменные, как правило, объявлены с модификатором доступа «private».

private String myName;

private Node myNode;

private ContainerID myContainer;

private Node parentNode;

private String username;

private byte[] password;

// конструктор нового дескриптора узла public NodeDescriptor(Node node) { myName = node.getName(); myNode = node; }

// конструктор нового дескриптора узла, хостующегося на контейнере: public NodeDescriptor(ContainerID cid, Node node) { myName = cid.getName(); myNode = node; myContainer = cid;

}

// метод устанавливает имя уже определенного ранее узла либо ассоциирует имя с узлом

public void setName(String n) { myName = n;

}

public String getName() { return myName;

}

// метод устанавливает уже определенный ранее объект узла public void setNode(Node node) { myNode = node;

}

public Node getNode() {

return myNode;

}

// возвращает объект-контейнер public ContainerID getContainer() { return myContainer;

}

// определение родительского узла public void setParentNode(Node pn) { parentNode = pn;

}

public Node getParentNode() { return parentNode;

}

// метод устанавливает имя пользователя узла public void setUserName(String username) { this.username = username;

}

// метод возвращает имя пользователя узла public String getUserName() { return username;

}

// метод устанавливает пароль пользователя узла public void setPassword(byte[] password) { this.password = password;

}

public byte[] getPassword() { return password; }

Литература

1. Шогулин Э.В. Разработка многоагентной платформы для распараллеливания ресурсоёмких задач/ Э.В. Шогулин, В.В. Андреев // Вестник Чувашского университета. 2007. №2. С. 190-196.

2. Шогулин Э.В. Использование многоагентных платформ / Э.В. Шогулин, В.В. Андреев // Математические методы в технике и технологиях - ММТТ-20: сб. трудов XX Междунар. науч. конф.: в 10 т. Т. 6. Секция 12 / под общ. ред. В.С. Балакирева. Ярославль: Изд-во Яросл. гос. техн. ун-та, 2007. С. 196-198.

СОЛДАТОВ АНТОН АЛЕКСАНДРОВИЧ - аспирант кафедры телекоммуникационных систем и технологий, Чувашский государственный университет, Россия, Чебоксары (mistertv@mail.ru).

SOLDATOV ANTON ALEKSANDROVICH - post-graduate student of telecommunications systems and technologies department, Chuvash State University, Russia, Cheboksary.

АНДРЕЕВ ВСЕВОЛОД ВЛАДИМИРОВИЧ - кандидат физико-математических наук, доцент, заведующий кафедрой телекоммуникационных систем и технологий, Чувашский государственный университет, Россия, Чебоксары (andreev_vsevolod@mail.ru).

ANDrEeV VSEVOLOD VLADIMIROVICH - candidate of mathematical and physical sciences, assistant professor, head of telecommunications systems and technologies department, Chuvash State University, Russia, Cheboksary.