/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied.
*
* See the License for the specific language governing permissions
* and limitations under the License.
*/
package siebog.interaction;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.enterprise.inject.Default;
import javax.ws.rs.FormParam;
import org.hornetq.utils.json.JSONArray;
import org.hornetq.utils.json.JSONException;
import org.hornetq.utils.json.JSONObject;
import siebog.agents.AID;
/**
* Represents a FIPA ACL message. Refer to <a
* href="http://www.fipa.org/specs/fipa00061/SC00061G.pdf">FIPA ACL Message Structure
* Specification</a> for more details.
*
* @author <a href="tntvteod@neobee.net">Teodor-Najdan Trifunov</a>
* @author <a href="mitrovic.dejan@gmail.com">Dejan Mitrovic</a>
*/
@Default
public class ACLMessage implements Serializable {
private static final long serialVersionUID = 1L;
private static final String USERARG_PREFIX = "X-";
// Denotes the type of the communicative act of the ACL message.
@FormParam("performative")
public Performative performative;
/* Participants in Communication */
// Denotes the identity of the sender of the message.
@FormParam("sender")
public AID sender;
// Denotes the identity of the intended recipients of the message.
@FormParam("receivers")
public List<AID> receivers;
// This parameter indicates that subsequent messages in this conversation
// thread are to be directed to the agent named in the reply-to parameter,
// instead of to the agent named in the sender parameter.
@FormParam("replyTo")
public AID replyTo;
/* Description of Content */
// Denotes the content of the message; equivalently denotes the
// object of the action.
@FormParam("content")
public String content;
public Serializable contentObj;
public Map<String, Serializable> userArgs;
// Denotes the language in which the content parameter is expressed.
@FormParam("language")
public String language;
// Denotes the specific encoding of the content language expression.
@FormParam("encoding")
public String encoding;
// Denotes the ontology(s) used to give a meaning to the symbols in
// the content expression.
@FormParam("ontology")
public String ontology;
/* Control of Conversation */
// Denotes the interaction protocol that the sending agent is
// employing with this ACL message.
@FormParam("protocol")
public String protocol;
// Introduces an expression (a conversation identifier) which is used
// to identify the ongoing sequence of communicative acts that
// together form a conversation.
@FormParam("conversationId")
public String conversationId;
// Introduces an expression that will be used by the responding
// agent to identify this message.
@FormParam("replyWith")
public String replyWith;
// Denotes an expression that references an earlier action to which
// this message is a reply.
@FormParam("inReplyTo")
public String inReplyTo;
// Denotes a time and/or date expression which indicates the latest
// time by which the sending agent would like to receive a reply.
@FormParam("replyBy")
public long replyBy;
public ACLMessage() {
this(Performative.NOT_UNDERSTOOD);
}
public ACLMessage(Performative performative) {
this.performative = performative;
receivers = new ArrayList<>();
userArgs = new HashMap<>();
}
@SuppressWarnings("unchecked")
public ACLMessage(String jsonString) throws JSONException {
JSONObject obj = new JSONObject(jsonString);
performative = Performative.valueOf(obj.getString("performative").toUpperCase());
String str = obj.optString("sender");
if (str != null && !str.isEmpty())
sender = new AID(str);
receivers = new ArrayList<>();
JSONArray arr = obj.optJSONArray("receivers");
if (arr != null && arr.length() > 0)
for (int i = 0; i < arr.length(); i++)
receivers.add(new AID(arr.getString(i)));
str = obj.optString("replyTo");
if (str != null && !str.isEmpty())
replyTo = new AID(str);
content = obj.optString("content");
language = obj.optString("language");
encoding = obj.optString("encoding");
ontology = obj.optString("ontology");
protocol = obj.optString("protocol");
conversationId = obj.optString("conversationId");
replyWith = obj.optString("replyWith");
inReplyTo = obj.optString("inReplyTo");
replyBy = obj.optLong("replyBy");
// user args
userArgs = new HashMap<>();
Iterator<String> i = obj.keys();
while (i.hasNext()) {
String key = i.next();
if (key.startsWith(USERARG_PREFIX)) {
String subKey = key.substring(USERARG_PREFIX.length());
Serializable value = (Serializable) obj.get(key);
userArgs.put(subKey, value);
}
}
}
public boolean canReplyTo() {
return sender != null || replyTo != null;
}
public ACLMessage makeReply(Performative performative) {
if (!canReplyTo())
throw new IllegalArgumentException("There's no-one to receive the reply.");
ACLMessage reply = new ACLMessage(performative);
// receiver
reply.receivers.add(replyTo != null ? replyTo : sender);
// description of content
reply.language = language;
reply.ontology = ontology;
reply.encoding = encoding;
// control of conversation
reply.protocol = protocol;
reply.conversationId = conversationId;
reply.inReplyTo = replyWith;
return reply;
}
@Override
public String toString() {
JSONObject obj = new JSONObject();
try {
// TODO Right now, JSONObject will contain only strings, which will need to be parsed
// manually later on. Implement a better JSON builder.
obj.put("performative", performative);
obj.put("sender", sender);
JSONArray arr = new JSONArray(receivers);
obj.put("receivers", arr);
obj.put("replyTo", replyTo);
obj.put("content", content);
obj.put("language", language);
obj.put("encoding", encoding);
obj.put("ontology", ontology);
obj.put("protocol", protocol);
obj.put("conversationId", conversationId);
obj.put("replyWith", replyWith);
obj.put("inReplyTo", inReplyTo);
obj.put("replyBy", replyBy);
for (Entry<String, Serializable> e : userArgs.entrySet())
obj.put(USERARG_PREFIX + e.getKey(), e.getValue());
} catch (JSONException ex) {
}
return obj.toString();
}
}