Package jade.content.lang.sl

Source Code of jade.content.lang.sl.SLCodec

/**
* ***************************************************************
* 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.lang.sl;

import jade.content.onto.Ontology;
import jade.content.onto.OntologyException;
import jade.content.abs.*;
import jade.content.schema.ObjectSchema;
import jade.content.lang.StringCodec;
//#MIDP_EXCLUDE_BEGIN
import jade.lang.acl.ISO8601;
import jade.util.leap.Iterator;
import jade.domain.FIPANames;
import jade.core.CaseInsensitiveString;

import java.util.Date;
import java.io.StringReader;

import java.io.BufferedReader; // only for debugging purposes in the main
import java.io.InputStreamReader; // only for debugging purposes in the main
import java.io.UnsupportedEncodingException;

import org.apache.commons.codec.binary.Base64;
//#MIDP_EXCLUDE_END


/** 
* The codec class for the <b><i>FIPA-SL</i>n</b> languages. This class
* implements the <code>Codec</code> interface and allows converting
* back and forth between strings and frames, according to the SL
* grammar.
* By default the class implements full SL grammar, otherwise the proper
* value must be used in the constructor.
* @author Fabio Bellifemine - TILAB
* @author Nicolas Lhuillier - Motorola (added support for byte[] primitive)
* @version $Date: 2010-07-05 17:38:19 +0200(lun, 05 lug 2010) $ $Revision: 6354 $
*/
/*#MIDP_INCLUDE_BEGIN
public class SLCodec extends SimpleSLCodec {
#MIDP_INCLUDE_END*/
//#MIDP_EXCLUDE_BEGIN
public class SLCodec extends StringCodec {

  public static final String PRESERVE_JAVA_TYPES = "SL-preserve-java-types";
 
  private transient SLParser parser;
  private transient ExtendedSLParser extendedParser;
  private SL0Ontology slOnto; // ontology of the content language
  private Ontology domainOnto = null; // application ontology
  /** This is the StringBuffer used by the encode method **/
  private transient StringBuffer buffer = null;
  /** This variable is true, when meta symbols are allowed (metas are a semantics-specific extension to the SL Grammar) **/
  private boolean metaAllowed = true; //FIXME set/unset this variable to do
 
  private boolean preserveJavaTypes = false;

  /**
   * Construct a Codec object for the full SL-language (FIPA-SL).
   */
  public SLCodec() {
    this(3, readPreserveJavaTypesProperty());
  }

  /**
   * Create an SLCodec for the full SL-language (FIPA-SL) specifying whether or not java primitive types
   * (long, int, float, double) must be preserved.
   * This is achieved by encoding long values as <numeric-value>L and float values as <numeric-valueF.
   * It should be noticed that this encoding is NOT FIPA SL standard
   * @param preserveJavaTypes Indicates whether or not java primitive types must be preserved
   */
  public SLCodec(boolean preserveJavaTypes) {
    this(3, preserveJavaTypes);
  }

  /**
   * Construct a Codec object for the given profile of SL-language.
   * @param slType specify 0 for FIPA-SL0, 1 for FIPA-SL1, 2 for FIPA-SL2, any other value can be used for full FIPA-SL
   */
  public SLCodec(int slType) {
    this(slType, readPreserveJavaTypesProperty());
  }
 
  /**
   * Create an SLCodec for the given profile of SL-language specifying whether or not java primitive types
   * (long, int, float, double) must be preserved.
   * @param slType specify 0 for FIPA-SL0, 1 for FIPA-SL1, 2 for FIPA-SL2, any other value can be used for full FIPA-SL
   * @param preserveJavaTypes Indicates whether or not java primitive types must be preserved
   */
  public SLCodec(int slType, boolean preserveJavaTypes) {
    super((slType==0 ? FIPANames.ContentLanguage.FIPA_SL0 :
      (slType==1 ? FIPANames.ContentLanguage.FIPA_SL1 :
        (slType==2 ? FIPANames.ContentLanguage.FIPA_SL2 :
          FIPANames.ContentLanguage.FIPA_SL ))));
    if ((slType < 0) || (slType > 2)) // if outside range, set to full SL
      slType = 3;
    slOnto = (SL0Ontology) (slType == 0 ? SL0Ontology.getInstance() :
      (slType == 1 ? SL1Ontology.getInstance() :
        (slType == 2 ? SL2Ontology.getInstance() : SLOntology.getInstance())));
    this.preserveJavaTypes = preserveJavaTypes;
    initParser();
  }

  private static boolean readPreserveJavaTypesProperty() {
    String strPreserveJavaTypes = System.getProperty(PRESERVE_JAVA_TYPES);
    return "true".equals(strPreserveJavaTypes);
  }
 
  private void initParser() {
    int  slType  = jade.domain.FIPANames.ContentLanguage.FIPA_SL0.equals(getName()) ? 0
          : jade.domain.FIPANames.ContentLanguage.FIPA_SL2.equals(getName()) ? 1
          : jade.domain.FIPANames.ContentLanguage.FIPA_SL2.equals(getName()) ? 2 : 3;
   
    if (preserveJavaTypes) {
      extendedParser = new ExtendedSLParser(new StringReader(""));
      extendedParser.setSLType(slType);
    }
    else {
      parser = new SLParser(new StringReader(""));
      parser.setSLType(slType);
    }
  }
 
  public boolean getPreserveJavaTypes() {
    return preserveJavaTypes;
  }
 
  /**
   * Encodes a content into a String.
   * @param content the content as an abstract descriptor.
   * @return the content as a String.
   * @throws CodecException
   */
  public String encode(AbsContentElement content) throws CodecException {
    return encode(null, content);
  }

  /**
   * Encodes a content into a String.
   * @param ontology the ontology
   * @param content the content as an abstract descriptor.
   * @return the content as a String.
   * @throws CodecException
   */
  public synchronized String encode(Ontology ontology, AbsContentElement content) throws CodecException {
    try {
      domainOnto = ontology;
      buffer = new StringBuffer("(");
      if (content instanceof AbsContentElementList) {
        for (Iterator i=((AbsContentElementList)content).iterator(); i.hasNext(); ) {
          AbsObject o = (AbsObject)i.next();
          encodeAndAppend(o);
          buffer.append(' ');
        }
      } else encodeAndAppend(content);
      buffer.append(')');
      return buffer.toString();
    } finally {
      buffer = null; //frees the memory
    }
  }



  /**
   * Encode a string, taking care of quoting separated words and
   * escaping strings, if necessary.
   * And append it to the buffer.
   **/
  private void encodeAndAppend(String val) {
    // if the slotName is a String of words then quote it. If it is a meta (i.e. startsWith "??") do not quote it.
    String out = ( (SimpleSLTokenizer.isAWord(val) || (metaAllowed && val.startsWith("??")) ) ? val : SimpleSLTokenizer.quoteString(val));
    buffer.append(out);
  }


  /** Encode the passed Abstract Predicate and append its encoding to buffer **/
  private void encodeAndAppend(AbsPredicate val) throws CodecException {
    String propositionSymbol = val.getTypeName();
    if (val.getCount() > 0) { // predicate with arguments
      String[] slotNames = getSlotNames(val);
      buffer.append('(');
      if (slOnto.isUnaryLogicalOp(propositionSymbol)) {
        // Unary logical operator of the SL language (NOT)
        buffer.append(propositionSymbol);
        buffer.append(' ');
        try {
          encodeAndAppend((AbsPredicate)val.getAbsObject(slotNames[0]));
        } catch (RuntimeException e) {
          throw new CodecException("A UnaryLogicalOp requires a formula argument",e);
        }
      } else if (slOnto.isBinaryLogicalOp(propositionSymbol)) {
        // Bynary logical operator of the SL language (AND, OR)
        buffer.append(propositionSymbol);
        buffer.append(' ');
        try {
          encodeAndAppend((AbsPredicate)val.getAbsObject(slotNames[0]));
          buffer.append(' ');
          encodeAndAppend((AbsPredicate)val.getAbsObject(slotNames[1]));
        } catch (RuntimeException e) {
          throw new CodecException("A BinaryLogicalOp requires 2 formula arguments",e);
        }
      } else if (slOnto.isQuantifier(propositionSymbol)) {
        // Quantifier operator of the SL language (EXISTS, FORALL)
        buffer.append(propositionSymbol);
        buffer.append(' ');
        try {
          encodeAndAppend((AbsVariable)val.getAbsObject(slotNames[0])); //FIXME. The hypothesis is that the first slot is the variable
          buffer.append(' ');
          encodeAndAppend((AbsPredicate)val.getAbsObject(slotNames[1]));
        } catch (RuntimeException e) {
          throw new CodecException("A Quantifier requires a variable and a formula arguments",e);
        }
      } else if (slOnto.isModalOp(propositionSymbol)) {
        // Modal operator of the SL language (B, I, U, PG)
        buffer.append(propositionSymbol);
        buffer.append(' ');
        try {
          encodeAndAppend((AbsTerm)val.getAbsObject(slotNames[0]));
          buffer.append(' ');
          encodeAndAppend((AbsPredicate)val.getAbsObject(slotNames[1]));
        } catch (RuntimeException e) {
          throw new CodecException("A ModalOp requires a term and a formula arguments",e);
        }
      } else if (slOnto.isActionOp(propositionSymbol)) {
        // Action operator of the SL language (DONE, FEASIBLE)
        buffer.append(propositionSymbol);
        buffer.append(' ');
        try {
          encodeAndAppend((AbsTerm)val.getAbsObject(slotNames[0])); //FIXME check it is an action expression
          AbsPredicate ap = (AbsPredicate)val.getAbsObject(slotNames[1]);
          if (ap != null) { // Second argument is optional
            buffer.append(' ');
            encodeAndAppend(ap);
          }
        } catch (RuntimeException e) {
          throw new CodecException("An ActionOp requires an actionexpression and (optionally) a formula arguments",e);
        }
      } else if (slOnto.isBinaryTermOp(propositionSymbol)) {
        // Binary term operator of the SL language (RESULT, =)
        buffer.append(propositionSymbol);
        buffer.append(' ');
        try {
          encodeAndAppend((AbsTerm)val.getAbsObject(slotNames[0]));
          buffer.append(' ');
          encodeAndAppend((AbsTerm)val.getAbsObject(slotNames[1]));
        } catch (RuntimeException e) {
          throw new CodecException("A BinaryTermOp requires 2 term arguments",e);
        }
      } else {
        encodeAndAppend(propositionSymbol);
        // Predicate in the ontology
        try {
          encodeSlotsByOrder(val, slotNames);
        } catch (RuntimeException e) {
          throw new CodecException("SL allows predicates with term arguments only",e);
        }
      }
      buffer.append(')');
    } else
      // Proposition
      encodeAndAppend(propositionSymbol)
  }

  private void encodeAndAppend(AbsIRE val) throws CodecException {
    buffer.append('(');
    encodeAndAppend(val.getTypeName());
    buffer.append(' ');
    encodeAndAppend(val.getTerm());
    buffer.append(' ');
    encodeAndAppend(val.getProposition());
    buffer.append(')');
  }

  private void encodeAndAppend(AbsVariable val) throws CodecException {
    String var = val.getName();
    if (var.charAt(0) == '?') {
      encodeAndAppend(var);
    } else {
      buffer.append('?');
      encodeAndAppend(var);
    }
  }

  private void encodeAndAppend(AbsConcept val) throws CodecException {
    String functionSymbol = val.getTypeName();
    buffer.append('(');
    String[] slotNames = getSlotNames(val);
    if (slOnto.isSLFunctionWithoutSlotNames(functionSymbol)) {
      // A Functional operator of the SL language (ACTION, + ...)
      // The form is: functionSymbol Term*
      buffer.append(functionSymbol);
      try {
        encodeSlotsByOrder(val, slotNames);
      } catch (RuntimeException e) {
        throw new CodecException("A FunctionalOperator requires 1 or 2 Term arguments",e);
      }
    } else {
      // A generic term in the ontology. The form can be both
      // functionSymbol Parameter* or functionSymbol Term*. Get the
      // preferred way from the ontology.
      encodeAndAppend(functionSymbol);
      try {
        // FIXME: To improve performances the two operations that imply
        // retrieving a schema from the ontology (getting slot names and
        // getting the preferred encoding type) should be carried out at
        // the same time.
        if (getEncodingByOrder(val)) {
          encodeSlotsByOrder(val, slotNames);
        }
        else {
          encodeSlotsByName(val, slotNames);
        }
      } catch (RuntimeException e) {
        throw new CodecException("A FunctionalTerm requires Terms arguments",e);
      }
    }

    buffer.append(')');
  }


  private void encodeAndAppend(AbsAggregate val) throws CodecException {
    buffer.append('(');
    encodeAndAppend(val.getTypeName());
    for (Iterator i=val.iterator(); i.hasNext(); ) {
      buffer.append(' ');
      encodeAndAppend((AbsObject)i.next());
    }
    buffer.append(')');
  }


  private void encodeAndAppend(AbsPrimitive val) throws CodecException {
    Object v = val.getObject();
    if (v instanceof Date)
      buffer.append(ISO8601.toString((Date)v));
    else if (v instanceof Number) {
      buffer.append(v.toString());
      if (preserveJavaTypes) {
        if (v instanceof Long) {
          buffer.append('L');
        }
        else if (v instanceof Float) {
          buffer.append('F');
        }
      }
    }
    else if (v instanceof byte[]) {
      // Note: Use US-ASCII charSet and Base64 encoding
      byte[] b = (byte[]) v;
      b = Base64.encodeBase64(b);
     
      buffer.append('#');
      buffer.append(b.length);
      buffer.append('"');
      try {
        buffer.append(new String(b, "US-ASCII"));
      } catch (UnsupportedEncodingException uee) {
        throw new CodecException("Error encoding byte-array to Base64 US-ASCII", uee);
      }
    }
    else if (v instanceof Boolean)
      buffer.append(v.toString());
    else {
      String vs = v.toString();
      if ( (CaseInsensitiveString.equalsIgnoreCase("true",vs)) ||
          (CaseInsensitiveString.equalsIgnoreCase("false",vs)) ) {
        // quote true and false to avoid confusion with booleans
        buffer.append('"');
        buffer.append(vs);
        buffer.append('"');
      } else
        encodeAndAppend(vs);
    }
  }

  private void encodeAndAppend(AbsObject val) throws CodecException {
    if (val instanceof AbsPrimitive)      encodeAndAppend( (AbsPrimitive)val);
    else if (val instanceof AbsPredicate) encodeAndAppend( (AbsPredicate)val);
    else if (val instanceof AbsIRE)       encodeAndAppend( (AbsIRE)val);
    else if (val instanceof AbsVariableencodeAndAppend( (AbsVariable)val);
    //  if (val instanceof AbsAgentAction) return toString( (AbsAgentAction)val);
    else if (val instanceof AbsAggregate) encodeAndAppend( (AbsAggregate)val);
    else if (val instanceof AbsConcept)   encodeAndAppend( (AbsConcept)val);
    else throw new CodecException("SLCodec cannot encode this object "+val);
  }


  /**
   * Decodes the content to an abstract description.
   * @param content the content as a String.
   * @return the content as an abstract description.
   * @throws CodecException
   */
  public AbsContentElement decode(String content) throws CodecException {
    return decode(null, content);
  }

  /**
   * Decodes the content to an abstract description.
   * @param ontology the ontology.
   * @param content the content as a String.
   * @return the content as an abstract description.
   * @throws CodecException
   */
  public synchronized AbsContentElement decode(Ontology ontology, String content) throws CodecException {
    try {
      AbsContentElementList tuple = null;
      if (preserveJavaTypes) {
        extendedParser.reinit(ontology, content);
        tuple = extendedParser.Content();
      }
      else {
        parser.reinit(ontology, content);
        tuple = parser.Content();
      }
      if (tuple.size() > 1)
        return tuple;
      else  // if there is a single ContentExpression than return just it, not the tuple
        return tuple.get(0);
    catch(Throwable e) { // both ParseException and TokenMgrError
      throw new CodecException("Parse exception", e);
    }
  }



  /**
   * Decodes the content to an abstract description, where the content is known to be a Term.
   * @param ontology the ontology.
   * @param cterm the term as a String.
   * @return the content as an abstract description.
   * @throws CodecException
   * @since JADE 3.4
   */
  public synchronized AbsTerm decodeTerm(Ontology ontology, String term) throws CodecException {
    try {
      if (preserveJavaTypes) {
        extendedParser.reinit(ontology, term);
        return extendedParser.Term();
      }
      else {
        parser.reinit(ontology, term);
        return parser.Term();
      }
    }  catch(Throwable e) { // both ParseException and TokenMgrError
      throw new CodecException("Parse exception", e);
    }
  }


  /**
   * Encodes the content into a String, where the content is known to be a Term.
   * @param ontology the ontology.
   * @param term the termt as an abstract descriptor
   * @return the content as a String
   * @throws CodecException
   * @since JADE 3.4
   */
  public synchronized String encodeTerm(Ontology ontology, AbsTerm term) throws CodecException {
    try {
      domainOnto = ontology;
      buffer = new StringBuffer();
      encodeAndAppend(term);
      return buffer.toString();
    } finally {
      buffer = null; //frees the memory
    }
  }


  /**
   * Decodes the content to an abstract description, where the content is known to be a Well-formed Formula
   * @param ontology the ontology.
   * @param formula the content as a String.
   * @return the content as an abstract description.
   * @throws CodecException
   * @since JADE 3.4
   */
  public synchronized AbsPredicate decodeFormula(Ontology ontology, String formula) throws CodecException {
    try {
      if (preserveJavaTypes) {
        extendedParser.reinit(ontology, formula);
        return extendedParser.Wff();
      }
      else {
        parser.reinit(ontology, formula);
        return parser.Wff();
      }
    }  catch(Throwable e) { // both ParseException and TokenMgrError
      throw new CodecException("Parse exception", e);
    }
  }


  /**
   * Encodes the content into a String, where the content is known to be a Well-formed Formula
   * @param ontology the ontology.
   * @param formula the formula as an abstract descriptor
   * @return the content as a String
   * @throws CodecException
   * @since JADE 3.4
   */
  public synchronized String encodeFormula(Ontology ontology, AbsPredicate formula) throws CodecException {
    try {
      domainOnto = ontology;
      buffer = new StringBuffer();
      encodeAndAppend(formula);
      return buffer.toString();
    } finally {
      buffer = null; //frees the memory
    }
  }


  public static void main(String[] args) {
    SLCodec codec = null;
    char contentType = 'C';
    try {
      codec = new SLCodec(Integer.parseInt(args[0]));
      contentType = (args.length > 1 ? args[1].charAt(0) : 'C');
    } catch (Exception e) {
      System.out.println("usage: SLCodec SLLevel [ContentType]\n where SLLevel can be 0 for SL0, 1 for SL1, 2 for SL2, 3 or more for full SL \n and where ContentType is a char representing the type of content to be parsed: C for a contentexpression (default), T for a term, F for a formula");
      System.exit(0);
    }

    while (true) {
      try {
        System.out.println("insert an SL " + (contentType == 'F' ? "Well-Formed Formula" : (contentType == 'T' ? "Term" : "Content Expression")) + " to parse (all the expression on a single line!): ");
        BufferedReader buff = new BufferedReader(new InputStreamReader(System.in));
        String str = buff.readLine();
        System.out.println("\n\n");
        if (contentType == 'F') {
          AbsPredicate result = codec.decodeFormula(null, str);
          System.out.println("DUMP OF THE DECODE OUTPUT (just for debugging):");
          System.out.println(result);
          System.out.println("\n\n");
          System.out.println("AFTER ENCODE:");
          System.out.println(codec.encodeFormula(null, result));
          System.out.println("\n\n");
        } else if (contentType == 'T') {
          AbsTerm result = codec.decodeTerm(null, str);
          System.out.println("DUMP OF THE DECODE OUTPUT (just for debugging):");
          System.out.println(result);
          System.out.println("\n\n");
          System.out.println("AFTER ENCODE:");
          System.out.println(codec.encodeTerm(null, result));
          System.out.println("\n\n");
        } else {
          AbsContentElement result = codec.decode(str);
          System.out.println("DUMP OF THE DECODE OUTPUT (just for debugging):");
          System.out.println(result);
          System.out.println("\n\n");
          System.out.println("AFTER ENCODE:");
          System.out.println(codec.encode(result));
          System.out.println("\n\n");
        }
      } catch(Exception pe) {
        pe.printStackTrace();
        //System.exit(0);
      }
    }
  }

  /**
   * @return the ontology containing the schemas of the operator
   * defined in this language
   */
  public Ontology getInnerOntology() {
    return slOnto;
  }

  private String[] getSlotNames(AbsObject abs) throws CodecException {
    String[] slotNames = null;
    String type = abs.getTypeName();
    if (domainOnto != null) {
      // If an ontology is specified, get the slot names from it
      // (and not directly from the abstract descriptor val) to preserve
      // the order
      try {
        ObjectSchema s = domainOnto.getSchema(type);
        if (s == null) {
          throw new CodecException("No schema found for symbol "+type);
        }
        slotNames = s.getNames();
      }
      catch (OntologyException oe) {
        throw new CodecException("Error getting schema for symbol "+type, oe);
      }
    }
    else {
      slotNames = abs.getNames();
    }
    return slotNames;
  }

  private boolean getEncodingByOrder(AbsObject abs) throws CodecException {
    if (domainOnto != null) {
      String type = abs.getTypeName();
      try {
        ObjectSchema s = domainOnto.getSchema(type);
        return s.getEncodingByOrder();
      }
      catch (Exception e) {
        // Just ignore it
      }
    }
    return false;
  }

  /**
   * Encode the slots of an abstract descriptor by order, i.e.
   * without writing the slot names. Also take into account that, in
   * order to ensure a correct parsing, empty slots can only occur at
   * the end.
   * Append this encoded string to buffer.
   */
  private void encodeSlotsByOrder(AbsObject val, String[] slotNames) throws CodecException {
    boolean lastSlotEmpty = false;
    for (int i=0; i<slotNames.length; i++) {
      AbsTerm t = (AbsTerm)val.getAbsObject(slotNames[i]);
      if (t != null) {
        if (lastSlotEmpty) {
          throw new CodecException("Non-empty slot "+slotNames[i]+" follows empty slot "+slotNames[i-1]);
        }
        buffer.append(' ');
        encodeAndAppend(t);
      }
      else {
        lastSlotEmpty = true;
      }
    }
  }

  /**
   * Encode the slots of an abstract descriptor by name, i.e.
   * writing for each non-empty slot the slot name followed by the
   * slot value.
   * Append this encoded string to buffer.
   */
  private void encodeSlotsByName(AbsObject val, String[] slotNames) throws CodecException {
    for (int i=0; i<slotNames.length; i++) {
      AbsTerm t = (AbsTerm)val.getAbsObject(slotNames[i]);
      if (t != null) {
        // if this isn't un unnamed slot, then encode it otherwise just encode its value
        if (!slotNames[i].startsWith(this.UNNAMEDPREFIX)) {
          buffer.append(" :");
          encodeAndAppend(slotNames[i]);
        }
        buffer.append(' ');
        encodeAndAppend(t);
      }
    }
  }

  /**
   * Restore parser after deserialization. <br>
   * The readResolve method is called when ObjectInputStream has read an object from the stream
   * and is preparing to return it to the caller. <br>
   * The readResolve method is not invoked on the object until the object is fully constructed.
   */
  protected Object readResolve() throws java.io.ObjectStreamException {
    initParser();
    return this;
  }

//#MIDP_EXCLUDE_END
}

TOP

Related Classes of jade.content.lang.sl.SLCodec

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.