Import jade.lang.acl.ACLMessage;
Import jade.lang.acl.MessageTemplate;
public class RequestPerformer extends Behaviour {
private AID bestSeller; //агент-продавец с лучшей(наименьшей ценой)
private int bestPrice; // лучшая цена
private int repliesCnt = 0; // счетчик ответов от продавцов
private MessageTemplate mt;
private int step = 0;
public void action() {
switch (step) {
case 0:
// отправим запрос на книгу всем продавцам
ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
for (int i = 0; i < sellerAgents.length; ++i) {
cfp.addReceiver(sellerAgents[i]);
}
cfp.setContent(targetBookTitle);
cfp.setConversationId("book-trade");
cfp.setReplyWith("cfp" + System.currentTimeMillis());
myAgent.send(cfp);
// подготовим шаблон для получения цен на книги
mt = MessageTemplate.and(MessageTemplate
.MatchConversationId("book-trade"), MessageTemplate
.MatchInReplyTo(cfp.getReplyWith()));
step = 1;
break;
case 1:
// получим ответы с ценами, либо отказами, если книги нет
ACLMessage reply = myAgent.receive(mt);
if (reply!= null) {
if (reply.getPerformative() == ACLMessage.PROPOSE) {
int price = Integer.parseInt(reply.getContent());
if (bestSeller == null || price < bestPrice) {
// это лучшее предложение
bestPrice = price;
bestSeller = reply.getSender();
}
}
repliesCnt++;
if (repliesCnt >= sellerAgents.length) {
// приняты ответы от всех продавцов
step = 2;
}
} else {
block();
}
break;
case 2:
// отправим запрос на покупку агенту, предложившему лучшую цену
ACLMessage order = new ACLMes-sage(ACLMessage.ACCEPT_PROPOSAL);
Order.addReceiver(bestSeller);
Order.setContent(targetBookTitle);
order.setConversationId("book-trade");
order.setReplyWith("order" + System.currentTimeMillis());
MyAgent.send(order);
mt = MessageTemplate.and(MessageTemplate
.MatchConversationId("book-trade"), MessageTemplate
.MatchInReplyTo(order.getReplyWith()));
step = 3;
Break;
case 3:
reply = myAgent.receive(mt);
if (reply!= null) {
// принят ответ не предложение покупки
if (reply.getPerformative() == ACLMessage.INFORM) {
// покупка совершена
System.out.println(targetBookTitle + " successfully purchased.");
System.out.println("Price = " + bestPrice);
myAgent.doDelete();
}
step = 4;
} else {
block();
}
break;
}
}
public boolean done() {
return ((step == 2 && bestSeller == null) || step == 4);
}
}
Обычно переговоры проходят по стандартной, заранее известной, схеме (протоколу). JADE предоставляет возможность реализовать переговоры по протоколу с помощью классов из пакета jade.proto. Получение сообщений в режиме блокировки. Кроме метода receive() класс Agent предоставляет еще один метод для получения входящих сообщений – метод blockingReceive(). Отличие этого метода заключается в том, что возврат из него не происходит пока не будет получено сообщение, то есть происходит блокировка агента (потока агента и, следовательно, его поведения). Аналогично, перегруженная версия метода blockingReceive, принимающая в качестве параметра шаблон, блокируется до получения сообщения, удовлетворяющего используемому шаблону.
Рис 3б.2. Диаграмма классов приложения «Торговля книгами»
3б.3. Сервис «желтых страниц»
В приведенном примере было сделано допущение, что существует некое фиксированное множество агентов-продавцов (seller1 и seller2) и каждый покупатель заранее узнает о них из строки аргументов (поле AID[] sellerAgents класса BookBuyerAgent в коде, приведенном выше (раздел 3.2 ЛР№3) Передача аргументов агенту). Далее описано, как использовать сервис «желтых страниц», предоставляемый платформой JADE, чтобы позволить агентам-покупателям динамически узнавать об агентах-продавцах, доступных в данный момент времени.
Агент DF
Агент Directory Facilitator (DF) – менеджер директорий (согласно спецификации FIPA) представляет службу желтых страниц (yellow pages), где агенты могут публиковать информацию о предоставляемых ими сервисах. С помощью DF агент может находить агентов, предоставляющих необходимые ему сервисы, и вступать с ними в переговоры. Внутри одной платформы может
существовать несколько DF, например, предоставляющих информацию о различных группах сервисов или о сервисах различных групп агентов. Пример использования DF показан на Рис 4.3.
Рис.3б.3. Сервис «желтых страниц».
Каждая платформа JADE по умолчанию поддерживает агента DF (его локальное имя «df»). Могут быть запущены и объединены несколько DF-агентов (включая те, что находятся в платформе по умолчанию), для обеспечения единого распределенного каталога «желтых страниц».
Взаимодействие с DF
Поскольку DF является агентом, имеется возможность взаимодействовать с ним стандартным образом, обмениваясь ACL-сообщениями, используя, согласно спецификациям FIPA, соответствующий язык содержания (язык SLO) и соответствующую онтологию (онтологию FIPA-agent-management). Чтобы упростить эти взаимодействия, JADE предоставляет класс jade.domain.DFService, с помощью которого можно публиковать и выполнять сервисы через вызовы методов.
Публикация сервисов
Агент, желающий опубликовать (сделать доступными) один или более сервисов, должен предоставить DF, включающий AID этого агента, список возможных языков и онтологий, которые должны быть известны другим агентам для взаимодействия с ним, и список сервисов для публикации. Для каждого публикуемого сервиса предоставляется описание, включающее тип
сервиса, его имя, языки и онтологии, необходимые для его использования, и еще некоторые свойства, специфичные для данного сервиса. Классы DFAgentDescription, ServiceDescription и Property, входящие в состав пакета jade.domain.FIPAAgentManagement, соответственно представляют собой три упомянутые абстракции.
Чтобы опубликовать сервис, агент должен создать описание, представленное экземпляром класса DFAgentDescription, и вызвать статический метод register() класса DFService. Обычно регистрация сервиса выполняется в методе setup(), как показано ниже в примере с агентом-продавцом книг.
protected void setup() {
...
// Register the book-selling service in the yellow pages
DFAgentDescription dfd = new DFAgentDescription()
dfd.setName(getAID());
ServiceDescription sd = new ServiceDescription();
sd.setType(“book-selling”);
sd.setName(“JADE-book-trading”);
dfd.addServices(sd);
try {
DFService.register(this, dfd);
}
catch (FIPAException fe) {
fe.printStackTrace();
}
...
}
Заметим, что в этом простом примере не были описаны ни языки, ни онтологии, ни свойства, специфичные для данного сервиса. Когда агент завершает работу, следует отменить регистрацию опубликованных сервисов.
protected void takeDown() {
// Deregister from the yellow pages
try {
DFService.deregister(this);
}
catch (FIPAException fe) {
fe.printStackTrace();
}
// Close the GUI
myGui.dispose();
// Printout a dismissal message
System.out.println(“Seller-agent “+getAID().getName()+” terminating.”);
}
Поиск сервисов
Агент, которому требуется найти некоторые сервисы, должен предоставить агенту DF описание необходимого шаблона. Результатом поиска является список всех описаний, которые удовлетворяют указанному шаблону.
Описание соответствует шаблону, если все поля, указанные в шаблоне, присутствуют с теми же значениями и в описании. Использование статического метод search() класса DFService можно проиллюстрировать примером, в котором агент-покупатель книг динамически
находит всех агентов, предоставляемых сервисом «book-selling» (продажа книг).
public class BookBuyerAgent extends Agent {
private String targetBookTitle; // The title of the book to buy
private AID[] sellerAgents; // The list of known seller agents
// Put agent initializations here
protected void setup() {
// Printout a welcome message
System.out.println(“Hello! Buyer-agent “+getAID().getName()+” is ready.”);
// Get the title of the book to buy as a start-up argument
Object[] args = getArguments();
if (args!= null && args.length > 0) {
targetBookTitle = (String) args[ 0];
System.out.println(“Trying to buy “+targetBookTitle);
// Add a TickerBehaviour that schedules a request to seller agents every minute
addBehaviour(new TickerBehaviour(this, 60000) {
protected void onTick() {
// Update the list of seller agents
DFAgentDescription template = new DFAgentDescription();
ServiceDescription sd = new ServiceDescription();
sd.setType(“book-selling”);
template.addServices(sd);
try {
DFAgentDescription[] result = DFService.search(myAgent, template);
sellerAgents = new AID[result.length];
for (int i = 0; i < result.length; ++i) {
sellerAgents[i] = result[i].getName();
}
catch (FIPAException fe) {
fe.printStackTrace();
}
// Perform the request
myAgent.addBehaviour(new RequestPerformer());
}
});
...
Заметим, что обновление списка известных агентов-продавцов производится каждый раз перед очередной попыткой купить указанную книгу, т.к. агенты-продавцы в системе могут динамически появляться и исчезать.
Класс DFService также предоставляет поддержку подписки на уведомления от DF о появлении агента, предоставляющего указанный сервис (методы searchUntilFound() и createSubscriptionMessage()).
ЗАДАНИЕ К ЛР№3б
1. Создайте несколько агентов-продавцов и покупателей.
2. Проследите процесс взаимодействия и результат, в том числе в сниффере.
3. Сделайте выводы.
4. Внимательно изучите код в части обмена сообщениями.
5. Приступите к выполнению индивидуального задания (Приложение А).
Примечание: отчет по ЛР 3а и 3б оформляется один общий по двум лабораторным работам.
Приложение А. Варианты заданий и план действий по реализации индивидуального проекта
1. Задания согласно варианту:
1. Разработать мультиагентное приложение «Заказы-перевозчики» в предметной области «Логистика». В фирму, выполняющую перевозки крупногабаритных грузов, поступают заказы на транспортировку разнообразных грузов на различные расстояния. Фирма располагает некоторым множеством средств перевозки (перевозчиками). Заказы характеризуются весом груза и средствами, которыми заказ располагает для оплаты перевозки. Характеристиками перевозчика являются его максимальная грузоподъемность и продолжительность перевозки. Для выполнения каждого заказа на перевозку требуется подобрать одного перевозчика, имеющего максимальную грузоподъемность и/или обеспечивающего минимальную длительность перевозки. В приложении должны функционировать 2 агента заказов и 3 агента перевозчиков со следующими значениями атрибутов.
Agent | Values |
Project Demand_1 | CargoWeight = 1000; Account = 1000 |
Project Demand_2 | CargoWeight = 2000; Account = 1500 |
Vessel Resource_1 | MaxWeight = 1000; CruiseTime = 5 |
Vessl Resource_2 | MaxWeight = 2000; CruiseTime = 6 |
Vessel Resource_3 | MaxWeight = 2500; CruiseTime = 10 |
2. Разработайте мультиагентное приложение для предметной области «Размещение заказов на оборудование». Двум фирмам требуется закупить оборудование. С помощью информации четырех заводов-изготовителей были определены показатели функционирования необходимого оборудования. Подберите для каждой фирмы завод-изготовитель.
Завод-изготовитель
(предложения)