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ść parametruaccess
ustawiono 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ść parametruaccess
ustawiono 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ść parametruaccess
ustawiono 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ść parametruaccess
ustawiono 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ść parametruaccess
ustawiono nadirect
, a więc zapis i odczyt wartości będzie obsługiwany przez refleksję na atrybucie_holder
(jak zdefinowano za pomocąfieldName
).