본문 바로가기

IT for developer/Java

(1~4장) JADE PROGRAMMING FOR BEGINNERS


원문 : http://jade.tilab.com/doc/tutorials/JADEProgramming-Tutorial-for-beginners.pdf

개인적으로 정리하기 위해서 번역하는 중....

이 튜토리얼은 어떻게 간단한 JADE 에이전트를 생성하고 어떻게 실행 테스크를 만들고 서로 통신하게 하는지에 대해 보여준다. JADE는 자바로 만들어졌으면 에이전트를 개발하기 위해서는 자바로 개발해야한다. 이 글을 읽는 사람들은 자바 언어에 익숙하다고 생각하고 글을 쓴다.

1 JADE OVERVIEW

JADE는 다중 에이전트 시스템 개발을 돕는 미들웨어이다.

다음을 포함하고 있다.

- 실행 환경 : 이 미들웨어 위에서 에이전트는 수행된다.
- 라이브러리: 에이전트를 개발할 때 필요한 클래스들을 제공한다.
- 그래픽 툴: 관리자가 실행중인 에이전트를 관찰할 수 있다.

1.1 컨테이너와 플랫폼.

JADE 실행환경의 각 실행 인스턴스를 컨테이너라고 부른다.  여러 에이전트를 포함할 수 있다.

진행중인 컨테이너의 집합을 플랫폼이라고 한다. 메인 컨테이너는 항상 플랫폼에서 진행 되있어야 하며
다른 컨테이너들은 시작하면서 등록된다. 이는 플랫폼에서 처음 시작하는 컨테이너는 메인 컨테이너이어야 하며, 다른 컨터이너들은 메인 컨테이너를 어디서(호스트, 포트) 찾을수 있는지 알아야한다.

다른 메인 컨테이너가 이미 네트워크 안에서 시작되었다면, 일반 컨테이너들이 등록할수 있는 다른 플랫폼을 구성한다. (: 이미 메인 컨테이너가 있는데 새로운 메인 컨테이너를 만들고자 할때는 다른 플랫폼으로 된다는 내용인듯)

그림 1은 위에서 설명한 내용의 예제 시니리오이다. 3,1 컨테이너로 구성된 두개의 JADE 플랫폼을 보여주고 있다.
JADE 에이전트는 유일한 이름에 의해 식별되며 서로의 이름을 알아서 실제적인 위치와 관계
없이 통신할 수 있다.



1,2  AMS 와 DF

다른 컨테이너들로 부터 등록을 받는 것 외에 메인컨테이너는 특별한 두개의 에이전트를 가질 수 있어서 일반 컨테이너와 다르다. 메인컨테이너가 시작할 때 자동으로 시작되는 에이전트임.

AMS(Agent Management System) : 네이밍 서비스를 제공하고 (에이전트 이름이 유일한지 여부), 플랫폼내의 승인(원격 컨테이너들에 에이전트를 생성/소멸이 가능함) 을 나타낸다. - 어떻게 동작하는지는  문서에서 설명하지 않음.

DF(Directory Facilitator) : 옐로 페이지 서비스 - 에이전트가 다른 에이전트를 찾는 데 사용. 6장에서 설명함.

2 THE “BOOK TRADING” EXAMPLE

책을 파는 에이전트와 사용자 대신 책을 사는 에이전트를 포함하고 있는 예제를 보여줌.

구매 에이전트는 명령 라인으로 사기위한 책들의 목록을 받고 알려진 모든 판매 에이전트에계 요청한다.

요청 결과를 받으면 구매 에이전트는 이것을 수용하고 주문을 요청한다. 하나이상의 판매 에이전트가 결과를 주게되면 가장 싼 가격을 채택한다.

각 판매 에이전트는 사용자가 제목( 가격, 분류 등) 을 입력할 수 있는 GUI를 가지고 있다. 판매 에이전트는 계속 해서 구매 에이전트의 요청을 기다린다. 요청받은 책이 자신의 카탈로그에 있다면 책의 가격을 응답해준다. 또는 거절한다. 주문 요청을 받은 경우 책을 제공해준다.

전자 결제와 관련된 모든 이슈는 이 튜토리얼의 범위 밖이며 고려하지 않는다.

이 예제의 완전한 소스는 JADE 예제들중 examples.bookTrading 패키지에 있다.

3 CREATING JADE AGENTS – THE AGENT CLASS

JADE 에이전트는 jade.core.Agent 클래스를 상속하고 아래에서 보여지는것 과 같이 setup() 메소드를 구현하는 것으로  간단하게 생성할 수 있다.

//BookBuyerAgent.java
import jade.core.Agent;
public class BookBuyerAgent extends Agent {
 protected void setup() {
  // Printout a welcome message
  System.out.println("Hello! Buyer-agent "+getAID().getName()+" is ready.");
 }
}

 

setup()메소드는 주로 에이전트 초기화를 포함한다. 실제적인 작업은 4장에서 설명할 behaviours안에서 구현된다.


3.1 Agent identifiers

에이전트 식별은 jade.core.AID 클래스 인스턴스로 식별된다.
Agent 클래스의 getAID()메소드를 통하여 에이전트 식별자를 얻을 수 있다.
AID는 글로벌 유일 이름과 주소를 포함하고 있다. JADE의 이름 형태는 <nickname>@<platform-name>

주소는 플랫폼의 주소로 다른 플랫폼의 에이전트와 통신할 때 사용된다.

AID 인스턴스 생성 예
String nickname = "Peter";
AID id = new AID(nickname, AID.ISLOCALNAME);

ISLOCALNAME는 nickname이 글로벌 유일 네임이 아니라는 것을 표현하는 상수 이다.

3.2 Running agents

에이전트 컴파일 하기

javac -classpath <JADE-classes> BookBuyerAgent.java

실행하기.
JADE Runtime통해 실행하기

java  -classpath <JADE-classes>;.  jade.Boot  buyer:BookBuyerAgent

3.3 Agent termination

doDelete()함수를 호출하면 에이전트가 종료 된다.
에이전트가 종료 될때 자동으로 호출되는 takeDown()  메소드를 구현하여 마무리 작업을 해주자.


3.4 Passing arguments to an agent

명령어 라인 인수를 얻기 위해서 getArguments() 메소드를 호출하자.

import jade.core.Agent;
import jade.core.AID;
public class BookBuyerAgent extends Agent {
 // The title of the book to buy
 private String targetBookTitle;
 // The list of known seller agents
 private AID[] sellerAgents = {new AID("seller1", AID.ISLOCALNAME),
 new AID("seller2", AID.ISLOCALNAME)};
 // 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);
  }
  else {
   // Make the agent terminate immediately
   System.out.println("No book title specified");
   doDelete();
  }
 }
 // Put agent clean-up operations here
 protected void takeDown() {
  // Printout a dismissal message
  System.out.println("Buyer-agent "+getAID().getName()+" terminating.");
 }

}


C:\jade>java jade.Boot buyer:BookBuyerAgent (The-Lord-of-the-rings)
...
...
5-mag-2008 11.11.00 jade.core.AgentContainerImpl joinPlatform
INFO: --------------------------------------
Agent container Main-Container@NBNT2004130496 is ready.
--------------------------------------------
Hello! Buyer-agent buyer@NBNT2004130496:1099/JADE is ready.
Trying to buy The-Lord-of-the-Rings


4 AGENT TASKS – THE BEHAVIOUR CLASS

3장에서 얘기한것과 같이 에이전트의 실제적인 일은 behaviour안에서 수행된다. behaviour는 에이전트가 수행할수 있는 태스크를 나타내며 jade.core.behaviours.Behaviour클래스를 상속받는 클래스의 객체로써 구현된다. 에이전트가 behaviour 객체에 의해 구현된 태스크를 수행하게 하기 위해서 Agent 클래스의 addBehaviour() 메소드로 behaviour를 추가하기만 하면된다. behaviour는 언제든 추가될 수 있다. setup함수 또는 다른 behaviour 안에서

Behaviour를 상속한 각 클래스는 실제적으로 behaviours는 실행상태일때 수행될 연산들을 정의하는 action() 메소드와 behaviour가 끝났는지 아닌지를 나타내는 done() 메소드를 구현해야만 한다.

4.1 Behaviours scheduling and execution

에이전트는 여러 behaviour를 실행할 수 있다. 그러나 behaviour의 스케쥴링은 선점이 아니라 협력 형태이다. action()함수가 실행되면 return 될 때 까지 수행된다. 

에이전트가 behaviour 수행을 언제 다음 behaviour로 바꿀지 정의하는 것은 프로그래머이다.

귀찮지만 이것은 여러 장점을 가지고 있다.

-  에이전트당 하나의 자바스레드를 허락한다ㅣ(제한된 리소스 환경에서 무지 중요)
- behaviour의 스위치가 자바스레드 스위치보다 빠르므로 좋은 성능을 가져온다.
- 동시에 수행되는 behaviour사이에 동기화 이슈를 제거한다. (성능향상)
- 스위치시 에이전트의 상태중 stack정보는 포함하지 않는다. (persistencfy, mobility를 가능케 한다.)
그림 2는 에이전트 쓰레드의 실행 순서도 이다.





다음과 같이 action() 메소드를 구현하면 다른 behaviour가 실행될 수 없다.-- 이렇게 구현하면 안된다.

public class OverbearingBehaviour extends Behaviour {
public void action() {
while (true) {
// do something
}
}
public boolean done() {
return true;
}
}


더이상 수행할 behaviour가 없는 에이전트는 sleep상태가 된다. (CPU를 낭비하지 않기 위해서)

4.2 One-shot behaviours, cyclic behaviours and generic behaviours

behaviour타입을  다음과 같이 구분할 수있다.

1) One-shot: action() 메소드가 한번 수행된다. jade.core.behaviours.OneShotBehaviour는 이미 done()메소드가 true를 리턴하도록 구현되어 있다.
public class MyOneShotBehaviour extends OneShotBehaviour {
public void action() {
// perform operation X
}
}

operation X는 단 한번 수행.

2) Cyclic :jade.core.behaviours.CyclicBehaviour는 이미 done()메소드가 false를 리턴하도록 구현되어 있다.

public class MyCyclicBehaviour extends CyclicBehaviour {
public void action() {
// perform operation Y
}
}

operation Y는 반복적으로 수행된다. (에이전트가 해당 behaviour를 중지하기전까지)

3) Generic : 상태값을 가지고 있어서 상태에 따라 다르게 수행한다.


public class MyThreeStepBehaviour extends Behaviour {
private int step = 0;
public void action() {
switch (step) {
case 0:
// perform operation X
step++;
break;
case 1:
// perform operation Y
step++;
break;
case 2:
// perform operation Z
step++;
break;
}
}
public boolean done() {
return step == 3;
}
}


operation X, Y, Z는 차례로 수행된후 완료 된다.

그밖의 것들 SequentialBehaviour, ParallelBehaviour,  FSMBehaviour (이 튜토리얼 범위밖)


4.4 Behaviours required in the book trading example

4.4.1 Book-buyer agent behaviours

2장에서 구매 에이전트는 주기적으로 판매 에이전트에게 살 책들을 요청한다.


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() {
myAgent.addBehaviour(new RequestPerformer());
}
} );
}
else {
// Make the agent terminate
System.out.println("No target book title specified");
doDelete();
}
}


RequestPerformer는 실제 요청을 수행하는 behaviour로 5장에서 설명할 것이다.

4.4.2 Book-seller agent behaviours

2장에서 설명한것과 같이 판매 에이전트는 구매 에이전트의 요청을 기다린다.

요청은 조건에 맞는 책 요청, 구매 요청이다.

책 요청, 구매 요청을 처리하기 위한 각각의 behaviour를 디자인한다. 실제적으로 요청을 어떻게 받는지에 대한 부분은 5장에서 설명한다.

더불어 사용자가 GUI를 통해 새로운 책을 추가할 때 마다 책 카탈로그에 추가하는 behaviour를 수행해야한다. 그부분에대한 구현은 아래와 같다.

import jade.core.Agent;
import jade.core.behaviours.*;
import java.util.*;
public class BookSellerAgent extends Agent {
// The catalogue of books for sale (maps the title of a book to its price)
private Hashtable catalogue;
// The GUI by means of which the user can add books in the catalogue
private BookSellerGui myGui;
// Put agent initializations here
protected void setup() {
// Create the catalogue
catalogue = new Hashtable();
// Create and show the GUI
myGui = new BookSellerGui(this);
myGui.show();
// Add the behaviour serving requests for offer from buyer agents
addBehaviour(new OfferRequestsServer());
// Add the behaviour serving purchase orders from buyer agents
addBehaviour(new PurchaseOrdersServer());
}
// Put agent clean-up operations here
protected void takeDown() {
// Close the GUI
myGui.dispose();
// Printout a dismissal message
System.out.println("Seller-agent "+getAID().getName()+" terminating.");
}
/**
This is invoked by the GUI when the user adds a new book for sale
*/
public void updateCatalogue(final String title, final int price) {
addBehaviour(new OneShotBehaviour() {
public void action() {
catalogue.put(title, new Integer(price));
}
} );
}
}