In order to implement artifacts that provides I/O functionalities for interacting with the external world (e.g. network communication, user I/O, GUI, etc.), a further kind of await
primitive is provided, accepting an object of type IBlockingCommand
representing a command to be executed. The primitive suspends the execution of the operation until the specified command - which typically contains some kind of I/O and a blocking behaviour - has been executed. In the following example, two agents communicate by means of two artifacts that function as network port, providing I/O network communication based on UDP sockets.
MAS example07_extcommand { environment: c4jason.CartagoEnvironment agents: sender agentArchClass c4jason.CAgentArch #1; receiver agentArchClass c4jason.CAgentArch #1; classpath: "../../../lib/cartago.jar";"../../../lib/c4jason.jar"; }
The agent sender
creates and uses its port to send two messages:
!send_info. +!send_info : true <- makeArtifact("senderPort","c4jexamples.Port",[23000]); sendMsg("hello1","localhost:25000"); sendMsg("hello2","localhost:25000").
The agent receiver
creates and uses its own port to get the messages, using two different receiving styles:
!receive_msgs. +!receive_msgs : true <- makeArtifact("receiverPort","c4jexamples.Port",[25000],Id); receiveMsg(Msg,Sender); println("received ",Msg," from ",Sender); focus(Id); startReceiving. +new_msg(Msg,Sender) <- println("received ",Msg," from ",Sender).
The first message is received by means of a receiveMsg
action, while the second as a signal new_msg
generated by the artifact.The Port
artifact exploits the await with a blocking command to implement its functionalities:
public class Port extends Artifact { DatagramSocket socket; ReadCmd cmd; boolean receiving; @OPERATION void init(int port) throws Exception { socket = new DatagramSocket(port); cmd = new ReadCmd(); receiving = false; } @OPERATION void sendMsg(String msg, String fullAddress) { try { int index = fullAddress.indexOf(':'); InetAddress address = InetAddress.getByName(fullAddress.substring( 0, index)); int port = Integer.parseInt(fullAddress.substring(index + 1)); socket.send(new DatagramPacket(msg.getBytes(), msg.getBytes().length, address, port)); } catch (Exception ex) { this.failed(ex.toString()); } } @OPERATION void receiveMsg(OpFeedbackParam msg, OpFeedbackParam sender) { await(cmd); msg.set(cmd.getMsg()); sender.set(cmd.getSender()); } @OPERATION void startReceiving() { receiving = true; execInternalOp("receiving"); } @INTERNAL_OPERATION void receiving() { while (true) { await(cmd); signal("new_msg", cmd.getMsg(), cmd.getSender()); } } @OPERATION void stopReceiving() { receiving = false; } class ReadCmd implements IBlockingCmd { private String msg; private String sender; private DatagramPacket packet; public ReadCmd() { packet = new DatagramPacket(new byte[1024], 1024); } public void exec() { try { socket.receive(packet); byte[] info = packet.getData(); msg = new String(info); sender = packet.getAddress().toString(); } catch (Exception ex) { } } public String getMsg() { return msg; } public String getSender() { return sender; } } }
The ReadCmd
implements a blocking command - implementing the IBlockingCmd
interface - containing in the exec
method the command code, in this case receiving an UDP packet from a socket.
Highlights:
await
unblocked.