УДК 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.