One prominent application for agents is wrapping legacy systems and "agentifying" them.
Hence, it is an important point how separate processes can interact with Jadex agents as
these applications often use other means of communications such as sockets or RMI. A Jadex
agent executes behavior sequentially and does not allow any parallel access to its internal
structures due to integrity constraints. For this reason it is disallowed and discouraged to
block the active plan thread e.g. by opening sockets and waiting for connections or simply by
calling Thread.sleep()
. This can cause the whole agent to hang
because the agent waits for the completion of the current plan step. It will possibly
abort the plan when the maximum plan step execution time has been exceeded (if the maximum
execution is restricted within the agent runtime.properties). When external processes need
to interact directly with the agent, they have to use methods from the so called
jadex.runtime.IExternalAccess
interface, which offers the most common agent methods.
Create a new file for the ServerPlanG1.
Declare the ServerSocket as attribute within the plan
protected ServerSocket server;
Create a constructor which takes the server port as argument and creates a the server within it:
try { this.server = new ServerSocket(port); } catch(IOException e) { throw new RuntimeException(e.getMessage()); } getLogger().info("Created: "+server);
Additionally create a close method that can be used for shutting down the server socket:
public void close() { try { getExternalAccess().getLogger().info("Closing: "+server); server.close(); } catch(IOException e) { e.printStackTrace(); } }
In the body simply start a new thread that will handle client request in the run method. Additionally add an agent listener that gets invoked when the agent will be terminating. In this case the server is shut down:
new Thread(this).start(); getScope().addAgentListener(new IAgentListener() { public void agentTerminating(AgentEvent ae) { close(); } }, false);
In the threads run method create and dispatch goals for every incoming request:
while(true) { Socket client = server.accept(); IGoal goal = getExternalAccess().getGoalbase().createGoal("translate"); goal.getParameter("client").setValue(client); getExternalAccess().getGoalbase().dispatchTopLevelGoal(goal); }
Modify the EnglishGermanTranslationPlanG1 to handle translation goals.
Extract the socket from the goal and read the English word:
Socket client = (Socket)getParameter("client").getValue(); BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); String request = in.readLine(); // Read the word to translate from the input string
Translate the word as usual by using the query
Send back answer to the client:
PrintStream out = new PrintStream(client.getOutputStream()); out.print("HTTP/1.0 200 OK\r\n"); out.print("Content-type: text/html\r\n"); out.println("\r\n"); out.println("<html><head><title>TranslationG1 - "+eword +"</title></head><body>"); out.println("<p>Translated from english to german: "+eword+" = "+gword+"."); out.println("</p></body></html>"); client.close();
Create a file TranslationG1.agent.xml by copying TranslationC2.agent.xml.
The addword plan and event declarations are not used and can be removed for clarity.
Introduce the translation goal type:
<achievegoal name="translate"> <parameter name="client" class="java.net.Socket"/> </achievegoal>
Introduce the new plan for setting up the server and start the plan initially:
<plan name="server"> <body>new ServerPlanG1(9099)</body> </plan> ... <configurations> <configuration name="default"> <plans> <initialplan ref="server"/> </plans> </configuration> </configurations>
Modify the trigger of the translation plan to react on translation goals and add a parameter for the client:
<plan name="egtrans"> <parameter name="client" class="Socket"> <goalmapping ref="translate.client"/> </parameter> <body>new EnglishGermanTranslationPlanG1()</body> <trigger> <goal ref="translate"/> </trigger> </plan>
Start and test the agent.
Start the agent and open a browser to issue translation request. This can be done by entering the server url and appending the word to translate, e.g. http://localhost:9099/dog. The result should be printed out in the returned web page.