Messages
Messages are data containers that carry information between agents. When interacting with Java/Groovy agents, messages are mapped to Java/Groovy message classes with fields with the same name as the keys in the message.
Message types are defined using the @message macro. For example:
@message "org.arl.fjage.shell.ShellExecReq" struct ShellExecReq
command::Union{String,Nothing} = nothing
ans::Bool = false
enddefines a ShellExecReq message type that maps to a Java class with the package org.arl.fjage.shell.ShellExecReq.
All messages are mutable. The @message macro also automatically adds a few fields:
performative::SymbolmessageID::StringinReplyTo::Stringsender::AgentIDrecipient::AgentIDsentAt::Int64
Messages can subtype other messages:
julia> abstract type MyAbstractMessage <: Message end
julia> @message "org.arl.fjage.demo.MyConcreteMessage" struct MyConcreteMessage <: MyAbstractMessage
a::Int
end
julia> MyConcreteMessage(a=1)
MyConcreteMessage:INFORM[a:1]
julia> MyConcreteMessage(a=1) isa MyAbstractMessage
trueIt is also possible to have a concrete message type that can also be a supertype of another message:
julia> abstract type SomeMessage <: Message end
julia> @message "org.arl.fjage.demo.SomeMessage" struct SomeMessage <: SomeMessage
a::Int
end
julia> @message "org.arl.fjage.demo.SomeExtMessage" struct SomeExtMessage <: SomeMessage
a::Int
b::Int
end
julia> SomeMessage(a=1) isa SomeMessage
true
julia> SomeExtMessage(a=1, b=2) isa SomeMessage
truePerformatives are guessed automatically based on message classname. By default, the performative is Performative.INFORM. If a message classname ends with a Req, the default performative changes to Performative.REQUEST. Performatives may be overridden at declaration or at construction (and are mutable):
julia> @message "org.arl.fjage.demo.SomeReq" struct SomeReq end;
julia> @message "org.arl.fjage.demo.SomeRsp" Performative.AGREE struct SomeRsp end;
julia> SomeReq().performative
:REQUEST
julia> SomeRsp().performative
:AGREE
julia> SomeRsp(performative=Performative.INFORM).performative
:INFORMWhen strict typing is not required, one can use the dictionary-like GenericMessage message type:
julia> msg = GenericMessage("org.arl.fjage.demo.DynamicMessage")
DynamicMessage:INFORM
julia> msg.a = 1
1
julia> msg.b = "xyz"
"xyz"
julia> msg
DynamicMessage:INFORM[a:1 b:"xyz"]
julia> classname(msg)
"org.arl.fjage.demo.DynamicMessage"
julia> msg isa GenericMessage
trueAPI
Fjage.GenericMessage — TypeGeneric message type that can carry arbitrary name-value pairs as data.
Fjage.Message — TypeBase class for messages transmitted by one agent to another.
Fjage.Message — Typemsg = Message([perf])
msg = Message(inreplyto[, perf])Create a message with just a performative (perf) and no data. If the performative is not specified, it defaults to INFORM. If the inreplyto is specified, the message inReplyTo and recipient fields are set accordingly.
Fjage.ParameterReq — TypeParameter request message.
Fjage.ParameterRsp — TypeParameter response message.
Base.get! — Methodget!(p::ParameterReq, param)Request parameter param to be fetched.
Examples
julia> p = ParameterReq(index=1)
ParameterReq[index=1]
julia> get!(p, "modulation")
ParameterReq[index=1 modulation=?]
julia> get!(p, "fec")
ParameterReq[index=1 modulation=? ...]Base.get — Methodget(p::ParameterRsp, param)Extract parameter param from a parameter response message.
Fjage.classname — Functionclassname(msg::Message)Return the fully qualified class name of a message.
Fjage.registermessages — Functionregistermessages()
registermessages(messageclasses)Register message classes with Fjage. Usually message classes are automatically registered on creation with @message. However, when developing packages, if @message is used at the module level, the types may be precompiled and the code to register the classes may not get executed at runtime. In such cases, you may need to explicitly call registermessages() in the __init()__ function for the module.
Fjage.set! — Methodset!(p::ParameterReq, param, value)Request parameter param to be set to value.
Examples
julia> p = ParameterReq(index=1)
ParameterReq[index=1]
julia> set!(p, "modulation", "ofdm")
ParameterReq[index=1 modulation=ofdm]
julia> set!(p, "fec", 1)
ParameterReq[index=1 modulation=ofdm ...]Fjage.@message — Macro@message classname [performative] struct mtype [<: supertype]
fields...
endCreate a message class from a fully qualified class name. If a performative is not specified, it is guessed based on the class name. For class names ending with "Req", the performative is assumed to be REQUEST, and for all other messages, INFORM.
Examples
julia> @message "org.arl.fjage.shell.MyShellExecReq" struct MyShellExecReq
command::String
end
julia> req = MyShellExecReq(command="ps")
MyShellExecReq:REQUEST[command:"ps"]