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;
39 import java.io.InputStreamReader;
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
109
110
111
112
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
127
128
129
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
151 if( s==null || s.length()==0 )
152 return false;
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
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
192
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());
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
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
268
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
292
293
294
295
296
297
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
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) {
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
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
374 System.out.println(codec.encode(result));
375 System.out.println("\n\n");
376 } catch(Exception pe) {
377 pe.printStackTrace();
378
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