/**
* ***************************************************************
* JADE - Java Agent DEvelopment Framework is a framework to develop
* multi-agent systems in compliance with the FIPA specifications.
* Copyright (C) 2000 CSELT S.p.A.
*
* GNU Lesser General Public License
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation,
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* **************************************************************
*/
package jade.content;
import jade.lang.acl.ACLMessage;
import jade.util.leap.*;
import jade.content.lang.Codec;
import jade.content.lang.StringCodec;
import jade.content.lang.ByteArrayCodec;
import jade.content.lang.Codec.CodecException;
import jade.content.abs.AbsContentElement;
import jade.content.schema.ObjectSchema;
import jade.content.onto.*;
import jade.core.CaseInsensitiveString;
/**
* This class provides all methods to manage the content languages
* and ontologies "known" by a given agent and to fill and extract the
* content of an ACL message according to a given content language and
* ontology.
* Each agent has a <code>ContentManager</code> object accessible through
* the <code>getContentManager()</code> method of the <code>Agent</code>
* class.
*
* @author Federico Bergenti
* @author Govanni Caire - TILAB
*/
public class ContentManager implements Serializable {
transient private Map languages = new HashMap();
transient private Map ontologies = new HashMap();
private boolean validationMode = true;
//#MIDP_EXCLUDE_BEGIN
private void readObject(java.io.ObjectInputStream oin) throws java.io.IOException, ClassNotFoundException {
oin.defaultReadObject();
languages = new HashMap();
ontologies = new HashMap();
}
//#MIDP_EXCLUDE_END
/**
* Registers a <code>Codec</code> for a given content language
* with its default name (i.e.
* the name returned by its <code>getName()</code> method.
* Since this operation is performed the agent that owns this
* <code>ContentManager</code> is able to "speak" the language
* corresponding to the registered <code>Codec</code>.
* @param c the <code>Codec</code> to be registered.
*/
public void registerLanguage(Codec c) {
if (c == null) {
throw new IllegalArgumentException("Null codec registered");
}
registerLanguage(c, c.getName());
}
/**
* Registers a <code>Codec</code> for a given content language
* with a given name.
* @param c the <code>Codec</code> to be registered.
* @param name the name associated to the registered codec.
*/
public void registerLanguage(Codec c, String name) {
if (c == null) {
throw new IllegalArgumentException("Null codec registered");
}
languages.put(new CaseInsensitiveString(name), c);
}
/**
* Registers an <code>Ontology</code> with its default name (i.e.
* the name returned by its <code>getName()</code> method.
* Since this operation is performed the agent that owns this
* <code>ContentManager</code> "knows" the registered
* <code>Ontology</code>.
* @param o the <code>Ontology</code> to be registered.
*/
public void registerOntology(Ontology o) {
if (o == null) {
throw new IllegalArgumentException("Null ontology registered");
}
registerOntology(o, o.getName());
}
/**
* Registers an <code>Ontology</code> with a given name.
* @param o the <code>Ontology</code> to be registered.
* @param name the name associated to the registered Ontology.
*/
public void registerOntology(Ontology o, String name) {
if (o == null) {
throw new IllegalArgumentException("Null ontology registered");
}
ontologies.put(new CaseInsensitiveString(name), o);
}
/**
* Retrieves a previously registered <code>Codec</code>
* giving its <code>name</code>.
* @param name the name associated to the <code>Codec</code>
* to be retrieved.
* @return the <code>Codec</code> associated to
* <code>name</code> or <code>null</code> if no Codec was registered
* with the given name.
*/
public Codec lookupLanguage(String name) {
return (name==null?null:(Codec) languages.get(new CaseInsensitiveString(name)));
}
/**
* Retrieves a previously registered <code>Ontology</code>
* giving its <code>name</code>.
* @param name the name associated to the <code>Ontology</code>
* to be retrieved.
* @return the <code>Ontology</code> associated to
* <code>name</code> or <code>null</code> if no Ontology was registered
* with the given name.
*/
public Ontology lookupOntology(String name) {
return (name==null?null:(Ontology) ontologies.get(new CaseInsensitiveString(name)));
}
/**
* Fills the <code>:content</code> slot of an
* <code>ACLMessage msg</code> using the content language
* and ontology indicated in the <code>:language</code> and
* <code>:ontology</code> fields of <code>msg</code>.
* @param msg the message whose content has to be filled.
* @param content the content of the message represented as an
* <code>AbsContentElement</code>.
* @throws CodecException if <code>content</code> is not compliant
* to the content language used for this operation.
* @throws OntologyException if <code>content</code> is not compliant
* to the ontology used for this operation.
*/
public void fillContent(ACLMessage msg, AbsContentElement content) throws CodecException, OntologyException {
Codec codec = lookupLanguage(msg.getLanguage());
if (codec == null) {
throw new CodecException("Unknown language "+msg.getLanguage());
}
String ontoName = msg.getOntology();
Ontology o = null;
if (ontoName != null) {
o = lookupOntology(ontoName);
if (o == null) {
throw new OntologyException("Unknown ontology "+msg.getOntology());
}
}
Ontology onto = getMergedOntology(codec, o);
validate(content, onto);
encode(msg, content, codec, onto);
}
/**
* Fills the <code>:content</code> slot of an
* <code>ACLMessage msg</code> using the content language
* and ontology indicated in the <code>:language</code> and
* <code>:ontology</code> fields of <code>msg</code>.
* @param msg the message whose content has to be filled.
* @param content the content of the message represented as a
* <code>ContentElement</code>.
* @throws CodecException if <code>content</code> is not compliant
* to the content language used for this operation.
* @throws OntologyException if <code>content</code> is not compliant
* to the ontology used for this operation.
*/
public void fillContent(ACLMessage msg, ContentElement content) throws CodecException, OntologyException {
Codec codec = lookupLanguage(msg.getLanguage());
if (codec == null) {
throw new CodecException("Unknown language "+msg.getLanguage());
}
String ontoName = msg.getOntology();
Ontology o = null;
if (ontoName != null) {
o = lookupOntology(ontoName);
if (o == null) {
throw new OntologyException("Unknown ontology "+msg.getOntology());
}
}
Ontology onto = getMergedOntology(codec, o);
AbsContentElement abs = (AbsContentElement) onto.fromObject(content);
validate(abs, onto);
encode(msg, abs, codec, onto);
}
/**
* Translates the <code>:content</code> slot of an
* <code>ACLMessage msg</code> into an <code>AbsContentElement</code>
* using the content language and ontology indicated in the
* <code>:language</code> and <code>:ontology</code> fields of <code>msg</code>.
* @param msg the message whose content has to be extracted.
* @return the content of the message represented as an
* <code>AbsContentElement</code>.
* @throws CodecException if the content of the message is not compliant
* to the content language used for this operation.
* @throws OntologyException if the content of the message is not compliant
* to the ontology used for this operation.
*/
public AbsContentElement extractAbsContent(ACLMessage msg) throws CodecException, OntologyException {
Codec codec = lookupLanguage(msg.getLanguage());
if (codec == null) {
throw new CodecException("Unknown language "+msg.getLanguage());
}
String ontoName = msg.getOntology();
Ontology o = null;
if (ontoName != null) {
o = lookupOntology(ontoName);
if (o == null) {
throw new OntologyException("Unknown ontology "+msg.getOntology());
}
}
Ontology onto = getMergedOntology(codec, o);
AbsContentElement content = decode(msg, codec, onto);
validate(content, onto);
return content;
}
/**
* Translates the <code>:content</code> slot of an
* <code>ACLMessage msg</code> into a <code>ContentElement</code>
* using the content language and ontology indicated in the
* <code>:language</code> and <code>:ontology</code> fields of <code>msg</code>.
* @param msg the message whose content has to be extracted.
* @return the content of the message represented as a
* <code>ContentElement</code>.
* @throws CodecException if the content of the message is not compliant
* to the content language used for this operation.
* @throws OntologyException if the content of the message is not compliant
* to the ontology used for this operation.
*/
public ContentElement extractContent(ACLMessage msg) throws CodecException, UngroundedException, OntologyException {
Codec codec = lookupLanguage(msg.getLanguage());
if (codec == null) {
throw new CodecException("Unknown language "+msg.getLanguage());
}
String ontoName = msg.getOntology();
Ontology o = null;
if (ontoName != null) {
o = lookupOntology(ontoName);
if (o == null) {
throw new OntologyException("Unknown ontology "+msg.getOntology());
}
}
Ontology onto = getMergedOntology(codec, o);
AbsContentElement content = decode(msg, codec, onto);
validate(content, onto);
return (ContentElement) onto.toObject(content);
}
/**
Set the validation mode i.e. whether contents that are managed
by this content manager should be validated during
message content filling/extraction.
Default value is <code>true</code>
@param mode the new validation mode
*/
public void setValidationMode(boolean mode) {
validationMode = mode;
}
/**
Return the currently set validation mode i.e. whether
contents that are managed by this content manager should
be validated during message content filling/extraction.
Default value is <code>true</code>
@return the currently set validation mode
*/
public boolean getValidationMode() {
return validationMode;
}
//#APIDOC_EXCLUDE_BEGIN
/**
*/
public Ontology getOntology(ACLMessage msg) {
return getMergedOntology(lookupLanguage(msg.getLanguage()), lookupOntology(msg.getOntology()));
}
//#APIDOC_EXCLUDE_END
/**
* Merge the reference ontology with the inner ontology of the
* content language
*/
private Ontology getMergedOntology(Codec c, Ontology o) {
Ontology ontology = null;
Ontology langOnto = c.getInnerOntology();
if (langOnto == null) {
ontology = o;
}
else if (o == null) {
ontology = langOnto;
}
else {
ontology = new Ontology(null, new Ontology[]{o, langOnto}, null);
}
return ontology;
}
private void validate(AbsContentElement content, Ontology onto) throws OntologyException {
if (validationMode) {
// Validate the content against the ontology
ObjectSchema schema = onto.getSchema(content.getTypeName());
if (schema == null) {
throw new OntologyException("No schema found for type "+content.getTypeName());
}
schema.validate(content, onto);
}
}
private void encode(ACLMessage msg, AbsContentElement content, Codec codec, Ontology onto) throws CodecException, OntologyException {
if (codec instanceof ByteArrayCodec)
msg.setByteSequenceContent(((ByteArrayCodec) codec).encode(onto, content));
else if (codec instanceof StringCodec)
msg.setContent(((StringCodec) codec).encode(onto, content));
else
throw new CodecException("UnsupportedTypeOfCodec");
}
private AbsContentElement decode(ACLMessage msg, Codec codec, Ontology onto) throws CodecException, OntologyException {
if (codec instanceof ByteArrayCodec)
return ((ByteArrayCodec) codec).decode(onto, msg.getByteSequenceContent());
else if (codec instanceof StringCodec)
return ((StringCodec) codec).decode(onto, msg.getContent());
else
throw new CodecException("UnsupportedTypeOfCodec");
}
public String toString() {
StringBuffer sb = new StringBuffer("(ContentManager:\n - registered-ontologies = ");
sb.append(ontologies);
sb.append("\n - registered-languages = ");
sb.append(languages);
sb.append(")");
return sb.toString();
}
public String[] getLanguageNames() {
String[] langs = new String[languages.size()];
int i = 0;
for (Iterator it = languages.keySet().iterator(); it.hasNext(); i++) {
langs[i] = it.next().toString();
}
return langs;
}
public String[] getOntologyNames() {
String[] onts = new String[ontologies.size()];
int i = 0;
for (Iterator it = ontologies.keySet().iterator(); it.hasNext(); i++) {
onts[i] = it.next().toString();
}
return onts;
}
}