View Javadoc

1   /***
2    * ***************************************************************
3    * JADE - Java Agent DEvelopment Framework is a framework to develop
4    * multi-agent systems in compliance with the FIPA specifications.
5    * Copyright (C) 2000 CSELT S.p.A.
6    * 
7    * GNU Lesser General Public License
8    * 
9    * This library is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU Lesser General Public
11   * License as published by the Free Software Foundation,
12   * version 2.1 of the License.
13   * 
14   * This library is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   * Lesser General Public License for more details.
18   * 
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this library; if not, write to the
21   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22   * Boston, MA  02111-1307, USA.
23   * **************************************************************
24   */
25  package JADE_SL.lang.sl;
26  
27  import JADE_SL.onto.Ontology;
28  import JADE_SL.abs.*;
29  import JADE_SL.lang.StringCodec;
30  import sl.ISO8601;
31  import java.util.Iterator;
32  import JADE_SL.CaseInsensitiveString;
33  import JADE_SL.FIPANames;
34  
35  import java.util.Date;
36  import java.util.Vector;
37  import java.io.StringReader;
38  import java.io.BufferedReader; // only for debugging purposes in the main
39  import java.io.InputStreamReader; // only for debugging purposes in the main
40  
41  /***  
42   * The codec class for the <b><i>FIPA-SL</i>n</b> languages. This class
43   * implements the <code>Codec</code> interface and allows converting
44   * back and forth between strings and frames, according to the SL
45   * grammar.
46   * By default the class implements full SL grammar, otherwise the proper
47   * value must be used in the constructor.
48   * @author Fabio Bellifemine - TILAB 
49   * @version $Date: 2003/10/09 13:00:36 $ $Revision: 1.1.1.1 $
50   */
51  public class SLCodec extends StringCodec {
52  
53      private SLParser parser;
54  
55      /***
56       * Construct a Codec object for the full SL-language (FIPA-SL).
57       */
58      public SLCodec() {
59      	this(3);
60      }
61      
62      /***
63       * Construct a Codec object for the given profile of SL-language.
64       * @parameter slType specify 0 for FIPA-SL0, 1 for FIPA-SL1, 2 for FIPA-SL2, any other value can be used for full FIPA-SL
65       */
66      public SLCodec(int slType) {
67  	super((slType==0 ? FIPANames.ContentLanguage.FIPA_SL0 :
68  	       (slType==1 ? FIPANames.ContentLanguage.FIPA_SL1 :
69  		(slType==2 ? FIPANames.ContentLanguage.FIPA_SL2 :
70  		 FIPANames.ContentLanguage.FIPA_SL ))));
71  	if ((slType < 0) || (slType > 2)) {
72  	    slType = 3;
73  	    vectorOfPredefinedFunctionals = FullSLFunctionals;
74  	} else
75  	    vectorOfPredefinedFunctionals = SL0Functionals;
76  	parser = new SLParser(new StringReader(""));
77  	parser.setSLType(slType); 
78      }
79  
80  
81      /***
82       * Encodes a content into a String.
83       * @param content the content as an abstract descriptor.
84       * @return the content as a String.
85       * @throws CodecException
86       */
87      public String encode(AbsContentElement content) throws CodecException {
88  	return encode(null, content);
89      }
90  
91      /***
92       * Encodes a content into a String.
93       * @param ontology the ontology 
94       * @param content the content as an abstract descriptor.
95       * @return the content as a String.
96       * @throws CodecException
97       */
98      public String encode(Ontology ontology, AbsContentElement content) throws CodecException {
99  	StringBuffer str = new StringBuffer("(");
100 	if (content instanceof AbsContentElementList) {
101 	    for (Iterator i=((AbsContentElementList)content).iterator(); i.hasNext(); ) {
102 		AbsObject o = (AbsObject)i.next();
103 		str.append(toString(o));
104 		str.append(" ");
105 	    }
106 	} else str.append(toString(content));
107 	str.append(")");
108 	/*try {
109 	    return str.toString().getBytes("US-ASCII");
110 	} catch (java.io.UnsupportedEncodingException e) {
111 	    e.printStackTrace();
112 	    return str.toString().getBytes();
113 	}*/
114 	return str.toString();
115     }
116 
117   /*** 
118    * Take a java String and quote it to form a legal FIPA SL0 string.
119    * Add quotation marks to the beginning/end and escape any 
120    * quotation marks inside the string.
121    * This must be the exact inverse of the procedure in
122    * the parser (SLParser.jj) when it encounters a quoted string.
123    */
124   private String quotedString(String s)
125   {
126       // Make the stringBuffer a little larger than strictly
127       // necessary in case we need to insert any additional
128       // characters.  (If our size estimate is wrong, the
129       // StringBuffer will automatically grow as needed).
130       StringBuffer result = new StringBuffer(s.length()+20);
131       result.append("\"");
132       for( int i=0; i<s.length(); i++)
133           if( s.charAt(i) == '"' ) 
134               result.append("//\"");
135           else 
136               result.append(s.charAt(i));
137       result.append("\"");
138       return result.toString();
139   }
140 
141 
142 
143     /***
144      * Test if the given string is a legal SL0 word using the FIPA XC00008D spec.
145      * In addition to FIPA's restrictions, place the additional restriction 
146      * that a Word can not contain a '\"', that would confuse the parser at
147      * the other end.
148      */
149     private boolean isAWord( String s) {
150 	// This should permit strings of length 0 to be encoded.
151 	if( s==null || s.length()==0 )
152 	    return false; // words must have at least one character
153 
154 	String illegalFirstChar = new String("#0123456789:-?");
155      
156 	if ( illegalFirstChar.indexOf(s.charAt(0)) >= 0 )
157 	    return false;
158       
159 	for( int i=0; i< s.length(); i++)
160 	    if( s.charAt(i) == '"' || s.charAt(i) == '(' || 
161 		s.charAt(i) == ')' || s.charAt(i) <= 0x20 )
162 		return false;
163 	return true;
164     }
165 
166 
167     /***
168      * Encode a string, taking care of quoting separated words and
169      * escaping strings, if necessary
170      **/
171     private String encode(String val) {
172 	// if the slotName is a String of words then quote it
173 	if (isAWord(val)) 
174 	    return val;
175 	else
176 	    return quotedString(val);
177     }
178 
179 
180     /***
181      * this method is used by all the toString methods and it exploits
182      * the common AbsObject implementation
183      * @param encodeSlotNames if true and the name of the slot does not
184      * start with <code>Codec.UNNAMEDPREFIX</code>, then the slotName is
185      * also encoded, otherwise it is skipped.
186      **/
187     private String encode(AbsObject val, boolean encodeSlotNames) throws CodecException {
188 	StringBuffer str = new StringBuffer("(");
189 	str.append(encode(val.getTypeName()));
190 	String[] slotNames = val.getNames();
191 	// check if there is a slot name that starts With Codec.UNNAMEDPREFIX
192 	// FIXME. This can be improved because it might lower performance!
193 	if (encodeSlotNames && (slotNames != null)) {
194 	    for (int i=0; i<slotNames.length; i++)
195 		if (slotNames[i].startsWith(UNNAMEDPREFIX)) {
196 		    encodeSlotNames = false;
197 		    break;
198 		}
199 	}
200 	if (slotNames != null) 
201 	    for (int i=0; i<slotNames.length; i++) {
202 		if (encodeSlotNames) {
203 		    str.append(" :");
204 		    str.append(encode(slotNames[i]));
205 		}
206 		str.append(" ");
207 		str.append(toString(val.getAbsObject(slotNames[i])));
208 	    }
209 	str.append(")");
210 	return str.toString();
211     }
212 
213 
214     private String toString(AbsPredicate val) throws CodecException {
215 	if (val.getCount() > 0)
216 	    return encode(val, false);
217 	else
218 	    return encode(val.getTypeName()); // a proposition does not require parenthesis
219     }
220 
221     private String toString(AbsIRE val) throws CodecException {
222 	return "(" + encode(val.getTypeName()) + " " + toString(val.getVariable()) + " " + toString(val.getProposition()) + ")"; 
223     }
224 
225     private String toString(AbsVariable val) throws CodecException {
226 	String var = val.getName();
227 	if (!var.startsWith("?"))
228 	    return "?"+encode(var);
229 	else
230 	    return "?"+encode(var.substring(1));
231     }
232 
233     /*** Constant needed to create an <code>AbsIRE(SLCodec.IOTA)</code> **/
234     public final static String IOTA = "IOTA";
235     // these 2 constants, set and sequence, are also used by SLParser.jj
236     final static String SET = "set";
237     final static String SEQUENCE = "sequence";
238     /*** Vector of all the functionals which have been pre-defined by FIPA
239      * and whose slots should not be encoded */
240     private Vector vectorOfPredefinedFunctionals;
241     private static Vector SL0Functionals = new Vector(5); 
242     private static Vector FullSLFunctionals = new Vector(17); 
243     static {
244 	SL0Functionals.addElement(SET); 
245 	SL0Functionals.addElement(SEQUENCE);
246 	SL0Functionals.addElement("action");
247 	SL0Functionals.addElement("|");
248 	SL0Functionals.addElement(";");
249 	FullSLFunctionals.addElement(SL0Functionals.elementAt(0));
250 	FullSLFunctionals.addElement(SL0Functionals.elementAt(1));
251  	FullSLFunctionals.addElement(SL0Functionals.elementAt(2));
252   FullSLFunctionals.addElement(SL0Functionals.elementAt(3));
253 	FullSLFunctionals.addElement("cons");
254 	FullSLFunctionals.addElement("first");
255 	FullSLFunctionals.addElement("rest");
256 	FullSLFunctionals.addElement("nth");
257 	FullSLFunctionals.addElement("append");
258 	FullSLFunctionals.addElement("union");
259 	FullSLFunctionals.addElement("intersection");
260 	FullSLFunctionals.addElement("difference");
261 	FullSLFunctionals.addElement("+");
262 	FullSLFunctionals.addElement("-");
263 	FullSLFunctionals.addElement("/");
264 	FullSLFunctionals.addElement("%");
265     }
266 
267     /* if this is one of the FIPA-defined functionals, i.e. "+","-",...
268      * case do not add the slotName
269      */
270     private boolean requiresSlotNames(String conceptName) {
271 	return !vectorOfPredefinedFunctionals.contains(conceptName.toLowerCase());
272     }
273 
274     private String toString(AbsConcept val) throws CodecException {
275 	return encode(val, requiresSlotNames(val.getTypeName()));
276     }
277 
278 
279     private String toString(AbsAggregate val) throws CodecException {
280     	StringBuffer str = new StringBuffer("(");
281 			str.append(encode(val.getTypeName()));
282 			for (Iterator i=val.iterator(); i.hasNext(); ) {
283 				str.append(" ");
284 				str.append(toString((AbsObject)i.next()));
285 			}
286 	    str.append(")");
287 	    return str.toString();
288     }
289 
290 /*
291     private String toString(AbsAgentAction val) throws CodecException {
292     	if ( CaseInsensitiveString.equalsIgnoreCase("action",val.getTypeName()) ||
293       		 CaseInsensitiveString.equalsIgnoreCase("|",val.getTypeName()) ||
294      		 	 CaseInsensitiveString.equalsIgnoreCase(";",val.getTypeName()))
295  				return encode(val, false);
296  			else
297  				//throw new CodecException("SLEncoderRequiresTheSLActionOperator_insteadOf_"+val.getTypeName());
298     }*/
299 
300     private String toString(AbsPrimitive val) throws CodecException {
301 	Object v = val.getObject();
302 	if (v instanceof Date)
303 	    return ISO8601.toString((Date)v);
304 	else if (v instanceof Number)
305 		  return v.toString();
306   else if (v instanceof byte[])
307   	throw new CodecException("SL_does_not_allow_encoding_sequencesOfBytes");
308   else	
309 	  return encode(v.toString());
310     }
311 
312     private String toString(AbsObject val) throws CodecException {
313 	if (val instanceof AbsPrimitive) return toString( (AbsPrimitive)val);
314 	if (val instanceof AbsPredicate) return toString( (AbsPredicate)val);
315 	if (val instanceof AbsIRE) return toString( (AbsIRE)val);
316 	if (val instanceof AbsVariable) return toString( (AbsVariable)val);
317 //	if (val instanceof AbsAgentAction) return toString( (AbsAgentAction)val);
318 	if (val instanceof AbsAggregate) return toString( (AbsAggregate)val);
319 	if (val instanceof AbsConcept) return toString( (AbsConcept)val);
320 	throw new CodecException("SLCodec cannot encode this object "+val);
321     }
322 
323 
324 
325 
326     /***
327      * Decodes the content to an abstract description.
328      * @param content the content as a String.
329      * @return the content as an abstract description.
330      * @throws CodecException
331      */
332     public AbsContentElement decode(String content) throws CodecException {
333 	return decode(null, content); 
334     }
335 
336     /***
337      * Decodes the content to an abstract description.
338      * @param ontology the ontology.
339      * @param content the content as a String.
340      * @return the content as an abstract description.
341      * @throws CodecException
342      */
343     public AbsContentElement decode(Ontology ontology, String content) throws CodecException {
344 	try {
345 	    return parser.parse(ontology,content);
346 	}  catch(Throwable e) { // both ParseException and TokenMgrError
347 	    throw new CodecException("Parse exception", e);
348 	}
349     }
350 
351 
352     public static void main(String[] args) {
353 	SLCodec codec = null;
354 	try {
355 	    codec = new SLCodec(Integer.parseInt(args[0]));
356 	} catch (Exception e) {
357 	    System.out.println("usage: SLCodec SLLevel\n  where SLLevel can be 0 for SL0, 1 for SL1, 2 for SL2, 3 or more for full SL");
358 	    System.exit(0);
359 	}
360 
361 	while (true) {
362 	    try {
363 		System.out.println("insert an SL expression to parse (all the expression on a single line!): ");
364 		BufferedReader buff = new BufferedReader(new InputStreamReader(System.in));
365 		String str = buff.readLine();
366 		System.out.println("\n\n");
367 		//AbsContentElement result = codec.decode(str.getBytes("US-ASCII"));
368 		AbsContentElement result = codec.decode(str);
369 		System.out.println("DUMP OF THE DECODE OUTPUT:");
370 		result.dump();
371 		System.out.println("\n\n");
372 		System.out.println("AFTER ENCODE:");
373 		//System.out.println(new String(codec.encode(result),"US-ASCII"));
374 		System.out.println(codec.encode(result));
375 		System.out.println("\n\n");
376 	    } catch(Exception pe) {
377 		pe.printStackTrace();
378 		//System.exit(0);
379 	    }
380 	}
381     }
382 
383 
384     /***
385      * @return the ontology containing the schemas of the operator
386      * defined in this language
387      */
388     public Ontology getInnerOntology() {
389     	return SLOntology.getInstance();
390     }
391 }
392