Spis treści:
Przykłady adaptacji komponentów zewnętrznych.
Zamieszczone tutaj dwa przykłady (propertiesxml i propertiesxml2) prezentują w jaki sposób można wykorzystać adaptowanie zewnętrznych komponentów na obecnym etapie. Przykłady dostępne są w pod adresem https://herman.iisg.agh.edu.pl/svn/jage/trunk/examples/.Uruchamia się je analogicznie do aplikacji Hello World wykorzystując pliki uruchomieniowe Eclipse'a propertiesxml.launch i propertiesxml2.launch dostępne w projekcie applications w katalogu src/main/config.
Niestety nie jest możliwe stworzenie pseudo-agenta niezalężnego od jAgE'a, którego można by zaadoptować.
Dlatego w przygotowanych przykładach stworzeni zostali agenci, którzy spełniają warunki narzucone przez platformę, ale korzystają z adaptowanych zewnętrznych komponentów.
Przykład 1
W tym przykładzie tworzone jest środowisko obliczeniowe z trzema agentami Scully, Mulder i Skinner.
Wszyscy są zagregowani w TheXFiles.
Do każdego z agentów przypisany jest obiekt komponentu SimpleFunctionCounter potrafiący obliczać sumę kwadratów dwóch liczb.
Obiekty te są przy starcie inicjalizowane wartościami (x i y) podanymi w pliku konfiguracyjnym środowiska obliczeniowego.
Przy każdym wywołaniem metody liczącej obie zmienne są inkrementowane.
W każdej turze agent przy pomocy swojego obiektu komponentu oblicza wartość funkcji, a wynik obliczeń jest logowany.
Dodatkowo co 3 tury agent "rozgląda" się w swoim środowisku i informuje jakich agentów "widzi".
Wynik działania
W wyniku uruchomienia przykładu na konsoli powinno się pojawić coś podobnego do:
[main ][INFO ][PropertiesSimpleAgent ] Constructing [main ][INFO ][PropertiesSimpleAgent ] Constructing [main ][INFO ][PropertiesSimpleAgent ] Constructing [main ][INFO ][SimpleAggregate ] Agent Scully@ added to the aggregate TheXFiles@ [main ][INFO ][SimpleAggregate ] Agent Mulder@ added to the aggregate TheXFiles@ [main ][INFO ][SimpleAggregate ] Agent Skinner@ added to the aggregate TheXFiles@ [main ][INFO ][SimpleAggregate ] Agents added. [main ][INFO ][PropertiesSimpleAgent ] Initializing agent: Skinner@ [main ][INFO ][PropertiesSimpleAgent ] Initializing agent: Mulder@ [main ][INFO ][PropertiesSimpleAgent ] Initializing agent: Scully@ [main ][INFO ][PicoWorkplaceManager ] Workplace TheXFiles@ initialized [main ][INFO ][SimpleWorkplace ] TheXFiles@ is starting... [main ][INFO ][PicoWorkplaceManager ] Workplace TheXFiles@ started [TheXFiles@ ][INFO ][IsolatedSimpleWorkplace ] TheXFiles@ has been started. Step to go: 10 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent Skinner@: step 1 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent: Skinner@ counted function. The result for 100^2 + 200^2 is: 50000 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent Mulder@: step 1 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent: Mulder@ counted function. The result for 10^2 + 20^2 is: 500 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent: Mulder@ can see in its environment: TheXFiles@ following agents: [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] agent: Skinner@ with properties: [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] address: Skinner@ [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] functionCounter: 101^2 + 201^2 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] actor: Mitch Pileggi [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] agent: Scully@ with properties: [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] address: Scully@ [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] functionCounter: 1^2 + 2^2 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] actor: Gillian Anderson [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent Scully@: step 1 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent: Scully@ counted function. The result for 1^2 + 2^2 is: 5 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent: Scully@ can see in its environment: TheXFiles@ following agents: [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] agent: Skinner@ with properties: [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] address: Skinner@ [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] functionCounter: 101^2 + 201^2 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] actor: Mitch Pileggi [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] agent: Mulder@ with properties: [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] address: Mulder@ [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] functionCounter: 11^2 + 21^2 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] actor: David Duchovny [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent Skinner@: step 2 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent: Skinner@ counted function. The result for 101^2 + 201^2 is: 50602 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent Mulder@: step 2 [TheXFiles@ ][INFO ][PropertiesSimpleAgent ] Agent: Mulder@ counted function. The result for 11^2 + 21^2 is: 562
Konfiguracja środowiska
Konfiguracja aplikacji znajduje się w projekcie applications-examples w pliku: src/main/resources/examples/properties/xml/workplace.xml. Plik ten definiuje strukturę lokalnego środowiska obliczeniowego. Poniżej przedstawiono jego zawartość:
<configuration>
<object name="workplace" class="org.jage.workplace.IsolatedSimpleWorkplace">
<property name="address">
<value class="AgentAddress" value="TheXFiles" />
</property>
<property name="endConditionStepsCnt">
<value class="Integer" value="10" />
</property>
<object name="functionCounter1" class="org.jage.examples.properties.xml.SimpleFunctionCounter">
<property name="xParameter">
<value class="Integer" value="1" />
</property>
<property name="yParameter">
<value class="Integer" value="2" />
</property>
</object>
<object name="functionCounter2" class="org.jage.examples.properties.xml.SimpleFunctionCounter">
<property name="xParameter">
<value class="Integer" value="10" />
</property>
<property name="yParameter">
<value class="Integer" value="20" />
</property>
</object>
<object name="functionCounter3" class="org.jage.examples.properties.xml.SimpleFunctionCounter">
<property name="xParameter">
<value class="Integer" value="100" />
</property>
<property name="yParameter">
<value class="Integer" value="200" />
</property>
</object>
<list name="agents">
<object name="scully" class="org.jage.examples.properties.xml.PropertiesSimpleAgent">
<property name="address">
<value class="AgentAddress" value="Scully" />
</property>
<property name="actor">
<value class="String" value="Gillian Anderson" />
</property>
<property name="functionCounter">
<reference target="functionCounter1" />
</property>
</object>
<reference target="scully" />
<object name="mulder" class="org.jage.examples.properties.xml.PropertiesSimpleAgent">
<property name="address">
<value class="AgentAddress" value="Mulder" />
</property>
<property name="actor">
<value class="String" value="David Duchovny" />
</property>
<property name="functionCounter">
<reference target="functionCounter2" />
</property>
</object>
<reference target="mulder" />
<object name="skinner" class="org.jage.examples.properties.xml.PropertiesSimpleAgent">
<property name="address">
<value class="AgentAddress" value="Skinner" />
</property>
<property name="actor">
<value class="String" value="Mitch Pileggi" />
</property>
<property name="functionCounter">
<reference target="functionCounter3" />
</property>
</object>
<reference target="skinner" />
</list>
<property name="agents">
<reference target="agents" />
</property>
</object>
</configuration>
Należy zwrócić uwagę, że w konfiguracji zawarta jest również konfiguracja komponentów obliczających funkcję.
Implementacja agenta
Implementacja agenta jest właściwie standardową implementacją, dlatego część kodu została pominięta poniżej.
Ważne są elementy związane z SimpleFunctionCounter. Plik źródłowy znajduje się w projekcie solutions-example w katalogu src/main/java/org/jage/examples/properties/xml.
public class PropertiesSimpleAgent extends SimpleAgent {
public PropertiesSimpleAgent() {}
public PropertiesSimpleAgent(IAgentAddress address) {}
public void init() {}
@PropertyField(propertyName = "actor")
private String actor = null;
private transient int counter = 0;
private SimpleFunctionCounter functionCounter;
public void step() {
counter++;
_log.info("Agent " + getAddress() + ": step " + counter);
_log.info("Agent: " + getAddress() + " counted function. The result for " + functionCounter.toString()
+ " is: " + functionCounter.countSquareSum());
if ((counter + this.hashCode()) % 3 == 0) {
watch();
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
_log.error("Interrupted", e);
}
}
private void watch() {
final IQueryResult answer;
try {
answer = this.queryEnvironment(Query.EMPTY);
_log.info("Agent: " + getAddress() + " can see in its environment: " + getParentAddress()
+ " following agents:");
for (IQueryResult.Entry entry : answer.entries()) {
IAgentAddress address = entry.getAddress();
if (address != getAddress()) {
_log.info(" agent: " + address + " with properties:");
IPropertiesSet properties = entry.getProperties();
for (Property property : properties) {
_log.info(" " + property.getMetaProperty().getName() + ": " + property.getValue());
}
}
}
} catch (AgentException ae) {
_log.error("Can't query environment.", ae);
}
}
public void finish() {}
@PropertyGetter(propertyName = "functionCounter", isMonitorable = true)
public SimpleFunctionCounter getFunctionCounter() {
return functionCounter;
}
@PropertySetter(propertyName = "functionCounter", type = SimpleFunctionCounter.class)
public void setFunctionCounter(SimpleFunctionCounter functionCounter) throws Exception {
this.functionCounter = functionCounter;
}
}
Implementacja SimpleFunctionCounter
Poniżej prezentowana jest implementacja komponentu zewnętrznego obliczającego wartość funkcji oraz XMLowy plik kontraktu dla tegoż komponentu.
Należy pamiętać, że plik kontraktu musi znajdować się w tym samym pakiecie co komponent.
W tym przykładzie plik źródłowy SimpleFunctionCounter.java znajduje się w projekcie solutions-example w katalogu src/main/java/org/jage/examples/properties/xml.
Plik kontraktu SimpleFunctionCounter.contract.xml znajduje się w projekcie solutions-example w katalogu src/main/resources/org/jage/examples/properties/xml.
SimpleFunctionCounter.java
public class SimpleFunctionCounter {
private final String version = "1.0.0";
private int x;
private int y;
public SimpleFunctionCounter() {
this.x = 0;
this.y = 0;
}
public SimpleFunctionCounter(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int countSquareSum() {
int result = x * x + y * y;
x++;
y++;
return result;
}
public int getY() {
return y;
}
public String toString() {
return x + "^2 + " + y + "^2";
}
}
SimpleFunctionCounter.contract.xml
<?xml version="1.0" encoding="UTF-8"?>
<component
class="org.jage.examples.properties.xml.SimpleFunctionCounter"
version="" xmlns="org.jage"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="org.jage ageDependency.xsd">
<declaration>
<attribute access="setter" modifier="2" name="xParameter" required="true" setter="setX" getter="getX">
<type>
<primitive name="int"/>
</type>
</attribute>
<attribute access="direct" modifier="2" name="yParameter" required="true" fieldName="y">
<type>
<primitive name="int"/>
</type>
</attribute>
</declaration>
</component>
Należy zwrócić uwagę na zdefiniowane propery i sposób ich obsługi.
W tym przykładzie mamy dwa property:
- xParameter - zdefiniowany w pierwszym attribute poprzez parametr
name. Wartość parametruaccessustawiono nasetter, a więc zapis i odczyt wartości będzie obsługiwany przez setter (setX) i getter (getX). - yParameter - zdefiniowany w drugim attribute poprzez parametr
name. Wartość parametruaccessustawiono nadirect, a więc zapis i odczyt wartości będzie obsługiwany przez refleksję na atrybuciey(jak zdefinowano za pomocąfieldName).
Przykład 2
W tym przykładzie tworzone jest środowisko obliczeniowe z dwoma agentami Scully i Mulder.
Oboje są zagregowani w TheXFiles.
Do każdego z agentów przypisany jest obiekt komponentu ExampleComponent, w którym są przechowywane informacje o danym agencie.
Obiekty te są przy starcie inicjalizowane wartościami podanymi w pliku konfiguracyjnym środowiska obliczeniowego.
W każdej turze agent przedstawia się przy pomocy swojego obiektu komponentu.
Wynik działania
W wyniku uruchomienia przykładu na konsoli powinno się pojawić coś podobnego do:
[main ][INFO ][SimpleAggregate ] Agent Scully@ added to the aggregate TheXFiles@ [main ][INFO ][SimpleAggregate ] Agent Mulder@ added to the aggregate TheXFiles@ [main ][INFO ][SimpleAggregate ] Agents added. [main ][INFO ][XMLContractHelloWorldSimpleAgent ] Initializing Hello World Simple Agent with XMLContracts. [main ][INFO ][XMLContractHelloWorldSimpleAgent ] Initializing Hello World Simple Agent with XMLContracts. [main ][INFO ][PicoWorkplaceManager ] Workplace TheXFiles@ initialized [main ][INFO ][SimpleWorkplace ] TheXFiles@ is starting... [main ][INFO ][PicoWorkplaceManager ] Workplace TheXFiles@ started [TheXFiles@ ][INFO ][IsolatedSimpleWorkplace ] TheXFiles@ has been started. Step to go: 10 [TheXFiles@ ][INFO ][XMLContractHelloWorldSimpleAgent ] Hello world! An example not-ClassPropertyContainer object will introduce himself: My name is Mulder's component My version is 777 I'm holding reference to java.lang.Object@bb7465 [TheXFiles@ ][INFO ][XMLContractHelloWorldSimpleAgent ] Hello world! An example not-ClassPropertyContainer object will introduce himself: My name is Scully's component My version is 1 I'm holding reference to java.lang.Object@d6c16c [TheXFiles@ ][INFO ][XMLContractHelloWorldSimpleAgent ] Hello world! An example not-ClassPropertyContainer object will introduce himself: My name is Mulder's component My version is 777 I'm holding reference to java.lang.Object@bb7465 [TheXFiles@ ][INFO ][XMLContractHelloWorldSimpleAgent ] Hello world! An example not-ClassPropertyContainer object will introduce himself: My name is Scully's component My version is 1 I'm holding reference to java.lang.Object@d6c16c
Konfiguracja środowiska
Konfiguracja aplikacji znajduje się w projekcie applications-examples w pliku: src/main/resources/examples/properties/xml/workplace2.xml. Plik ten definiuje strukturę lokalnego środowiska obliczeniowego. Poniżej przedstawiono jego zawartość:
<configuration> <object name="workplace" class="org.jage.workplace.IsolatedSimpleWorkplace"> <property name="address"> <value class="AgentAddress" value="TheXFiles" /> </property> <property name="endConditionStepsCnt"> <value class="Integer" value="10" /> </property> <list name="agents"> <object name="exampleComponentForScully" class="org.jage.examples.properties.xml.ExampleComponent"> <property name="name"> <value value="Scully's component" class="String"/> </property> <property name="version"> <value value="1" class="Integer"/> </property> <object name="sampleObject" class="java.lang.Object"/> <property name="holder"> <reference target="sampleObject"/> </property> </object> <object name="exampleComponentForMulder" class="org.jage.examples.properties.xml.ExampleComponent"> <property name="name"> <value value="Mulder's component" class="String"/> </property> <property name="version"> <value value="777" class="Integer"/> </property> <object name="sampleObject" class="java.lang.Object"/> <property name="holder"> <reference target="sampleObject"/> </property> </object> <object name="scully" class="org.jage.examples.properties.xml.XMLContractHelloWorldSimpleAgent"> <property name="address"> <value value="Scully" class="AgentAddress" /> </property> <property name="exampleComponent"> <reference target="exampleComponentForScully"></reference> </property> </object> <reference target="scully"/> <object name="mulder" class="org.jage.examples.properties.xml.XMLContractHelloWorldSimpleAgent"> <property name="address"> <value value="Mulder" class="AgentAddress" /> </property> <property name="exampleComponent"> <reference target="exampleComponentForMulder"></reference> </property> </object> <reference target="mulder"/> </list> <property name="agents"> <reference target="agents"/> </property> </object> </configuration>
Należy zwrócić uwagę, że w konfiguracji zawarta jest również konfiguracja komponentów zewnętrznych.
Implementacja agenta
Implementacja agenta jest właściwie standardową implementacją, dlatego część kodu została pominięta poniżej.
Ważne są elementy związane z ExampleComponent. Plik źródłowy znajduje się w projekcie solutions-example w katalogu src/main/java/org/jage/examples/properties/xml.
public class XMLContractHelloWorldSimpleAgent extends SimpleAgent {
@PropertyField(propertyName = "exampleComponent", type = ExampleComponent.class)
private ExampleComponent _component;
public void step() {
_log.info("Hello world! An example not-ClassPropertyContainer object will introduce himself: ");
_component.printComponentInfo();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
_log.error("Interrupted", ex);
}
}
}
Implementacja ExampleComponent
Poniżej prezentowana jest implementacja komponentu zewnętrznego przechowującego dane o agencie oraz XMLowy plik kontraktu dla tegoż komponentu.
Należy pamiętać, że plik kontraktu musi znajdować się w tym samym pakiecie co komponent.
W tym przykładzie plik źródłowy ExampleComponent.java znajduje się w projekcie solutions-example w katalogu src/main/java/org/jage/examples/properties/xml.
Plik kontraktu ExampleComponent.contract.xml znajduje się w projekcie solutions-example w katalogu src/main/resources/org/jage/examples/properties/xml.
ExampleComponent.java
public class ExampleComponent {
@SuppressWarnings("unused")
private static final String version = "1.0.0";
private String _name = "";
private int _versionNo = 0;
private Object _holder = null;
public void setName(String name) {
this._name = name;
}
public String getName() {
return _name;
}
public int getVersionNo() {
return _versionNo;
}
public Object getHoldedObject() {
return _holder;
}
public void printComponentInfo() {
System.out.println("My name is " + _name);
System.out.println("My version is " + _versionNo);
System.out.println("I'm holding reference to " + _holder);
}
ExampleComponent.contract.xml
<?xml version="1.0" encoding="UTF-8"?>
<component class="org.jage.examples.properties.xml.ExampleComponent"
version="1.0.0" xmlns="org.jage"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="org.jage ageDependency.xsd">
<declaration>
<attribute access="setter" name="name" required="true" setter="setName" getter="getName">
<type>
<simpleClass class="java.lang.String" interface="false"/>
</type>
</attribute>
<attribute access="direct" name="version"
required="true" fieldName="_versionNo">
<type>
<primitive name="int" />
</type>
</attribute>
<attribute access="direct" name="holder"
required="true" fieldName="_holder">
<type>
<simpleClass class="java.lang.Object" interface="false" />
</type>
</attribute>
</declaration>
</component>
Należy zwrócić uwagę na zdefiniowane propery i sposób ich obsługi.
W tym przykładzie mamy trzy property:
- name - zdefiniowany w pierwszym attribute poprzez parametr
name. Wartość parametruaccessustawiono nasetter, a więc zapis i odczyt wartości będzie obsługiwany przez setter (setName) i getter (getName). - version - zdefiniowany w drugim attribute poprzez parametr
name. Wartość parametruaccessustawiono nadirect, a więc zapis i odczyt wartości będzie obsługiwany przez refleksję na atrybucie_versionNo(jak zdefinowano za pomocąfieldName). - holder - zdefiniowany w drugim attribute poprzez parametr
name. Wartość parametruaccessustawiono nadirect, a więc zapis i odczyt wartości będzie obsługiwany przez refleksję na atrybucie_holder(jak zdefinowano za pomocąfieldName).