View Javadoc

1   /******************************************************************
2   JADE - Java Agent DEvelopment Framework is a framework to develop 
3   multi-agent systems in compliance with the FIPA specifications.
4   Copyright (C) 2000 CSELT S.p.A. 
5   
6   GNU Lesser General Public License
7   
8   This library is free software; you can redistribute it and/or
9   modify it under the terms of the GNU Lesser General Public
10  License as published by the Free Software Foundation, 
11  version 2.1 of the License. 
12  
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  Lesser General Public License for more details.
17  
18  You should have received a copy of the GNU Lesser General Public
19  License along with this library; if not, write to the
20  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  Boston, MA  02111-1307, USA.
22  *****************************************************************/
23  
24  package JADE_SL;
25  
26  import java.io.Reader;
27  import java.io.Writer;
28  import java.io.IOException;
29  import java.io.StringWriter;
30  import java.io.ByteArrayOutputStream;
31  import java.io.ByteArrayInputStream;
32  import java.io.ObjectOutputStream;
33  import java.io.ObjectInputStream;
34  import java.io.UnsupportedEncodingException;
35  import java.lang.ClassNotFoundException;
36  
37  import java.util.Date;
38  
39  import java.util.*;
40  
41  
42  import javax.agent.Envelope;
43  
44  
45  /***
46   * The class ACLMessage implements an ACL message compliant to the <b>FIPA 2000</b> "FIPA ACL Message Structure Specification" (fipa000061) specifications.
47   * All parameters are couples <em>keyword: value</em>.
48   * All keywords are <code>private final String</code>.
49   * All values can be set by using the methods <em>set</em> and can be read by using
50   * the methods <em>get</em>. <p>
51   * <p> The methods <code> setByteSequenceContent() </code> and 
52   * <code> getByteSequenceContent() </code> allow to send arbitrary
53   * sequence of bytes
54   * over the content of an ACLMessage.
55   * <p> The couple of methods 
56   * <code> setContentObject() </code> and 
57   * <code> getContentObject() </code> allow to send
58   * serialized Java objects over the content of an ACLMessage.
59   * These method are not strictly 
60   * FIPA compliant so their usage is not encouraged.
61   * @author Fabio Bellifemine - CSELT
62   * @version $Date: 2003/10/09 13:00:35 $ $Revision: 1.1.1.1 $
63   * @see <a href=http://www.fipa.org/specs/fipa00061/XC00061D.html>FIPA Spec</a>
64   */
65   
66  public class ACLMessage  {
67  	// Explicitly set for compatibility between standard and micro version
68  	private static final long serialVersionUID=3945353187608998130L;
69  
70    /*** constant identifying the FIPA performative **/
71    public static final int ACCEPT_PROPOSAL = 0;
72    /*** constant identifying the FIPA performative **/
73    public static final int AGREE = 1;
74    /*** constant identifying the FIPA performative **/
75    public static final int CANCEL = 2;
76    /*** constant identifying the FIPA performative **/
77    public static final int CFP = 3;
78    /*** constant identifying the FIPA performative **/
79    public static final int CONFIRM = 4;
80    /*** constant identifying the FIPA performative **/
81    public static final int DISCONFIRM = 5;
82    /*** constant identifying the FIPA performative **/
83    public static final int FAILURE = 6;
84    /*** constant identifying the FIPA performative **/
85    public static final int INFORM = 7;
86    /*** constant identifying the FIPA performative **/
87    public static final int INFORM_IF = 8;
88    /*** constant identifying the FIPA performative **/
89    public static final int INFORM_REF = 9;
90    /*** constant identifying the FIPA performative **/
91    public static final int NOT_UNDERSTOOD = 10;
92    /*** constant identifying the FIPA performative **/
93    public static final int PROPOSE = 11;
94    /*** constant identifying the FIPA performative **/
95    public static final int QUERY_IF = 12;
96    /*** constant identifying the FIPA performative **/
97    public static final int QUERY_REF = 13;
98    /*** constant identifying the FIPA performative **/
99    public static final int REFUSE = 14;
100   /*** constant identifying the FIPA performative **/
101   public static final int REJECT_PROPOSAL = 15;
102   /*** constant identifying the FIPA performative **/
103   public static final int REQUEST = 16;
104   /*** constant identifying the FIPA performative **/
105   public static final int REQUEST_WHEN = 17;
106   /*** constant identifying the FIPA performative **/
107   public static final int REQUEST_WHENEVER = 18;
108   /*** constant identifying the FIPA performative **/
109   public static final int SUBSCRIBE = 19;
110   /*** constant identifying the FIPA performative **/
111   public static final int PROXY = 20;
112   /*** constant identifying the FIPA performative **/
113   public static final int PROPAGATE = 21;
114   /*** constant identifying an unknown performative **/
115   public static final int UNKNOWN = -1;
116   
117 /***
118 @serial
119 */
120 private int performative; // keeps the performative type of this object
121   private static List performatives = new ArrayList(22);
122   static { // initialization of the Vector of performatives
123     performatives.add("ACCEPT-PROPOSAL");
124     performatives.add("AGREE");
125     performatives.add("CANCEL");
126     performatives.add("CFP");
127     performatives.add("CONFIRM");
128     performatives.add("DISCONFIRM");
129     performatives.add("FAILURE");
130     performatives.add("INFORM");
131     performatives.add("INFORM-IF");
132     performatives.add("INFORM-REF");
133     performatives.add("NOT-UNDERSTOOD");
134     performatives.add("PROPOSE");
135     performatives.add("QUERY-IF");
136     performatives.add("QUERY-REF");
137     performatives.add("REFUSE");
138     performatives.add("REJECT-PROPOSAL");
139     performatives.add("REQUEST");
140     performatives.add("REQUEST-WHEN");
141     performatives.add("REQUEST-WHENEVER");
142     performatives.add("SUBSCRIBE");
143     performatives.add("PROXY");
144     performatives.add("PROPAGATE");
145   }
146 
147 
148  
149   /***
150   @serial
151   */
152   private AID source = null;
153 
154   /***
155   @serial
156   */
157   private ArrayList dests = new ArrayList();
158 
159   /***
160   @serial
161   */
162   private ArrayList reply_to = new ArrayList();
163 
164   /***
165   @serial
166   */
167     // At a given time or content or byteSequenceContent are != null,
168     // it is not allowed that both are != null
169   private StringBuffer content = null;
170   private byte[] byteSequenceContent = null;
171 
172   /***
173   @serial
174   */
175   private StringBuffer reply_with = null;
176 
177   /***
178   @serial
179   */
180   private StringBuffer in_reply_to = null;
181 
182   /***
183   @serial
184   */
185   private StringBuffer encoding = null;
186 
187   /***
188   @serial
189   */
190   private StringBuffer language = null;
191 
192   /***
193   @serial
194   */
195   private StringBuffer ontology = null;
196 
197   /***
198   @serial
199   */
200   private long reply_byInMillisec = 0; 
201 
202   /***
203   @serial
204   */
205   private StringBuffer protocol = null;
206 
207   /***
208   @serial
209   */
210   private StringBuffer conversation_id = null;
211 
212   /***
213   @serial
214   */
215   private Properties userDefProps = new Properties();
216 
217   private Envelope messageEnvelope;
218 
219   //__JADE_ONLY__BEGIN
220   /***
221   Returns the list of the communicative acts.
222   @deprecated Use getAllPerformativeNames() instead
223   */
224   public static java.util.List getAllPerformatives()
225   {
226   	return (List) performatives;
227   }
228   //__JADE_ONLY__END
229   
230   /***
231   Returns the list of the communicative acts as an array of <code>String</code>.
232   */
233   public static String[] getAllPerformativeNames()
234   {
235   	// FIXME: performatives should become an array and this method should
236   	// just return it.
237   	String[] names = new String[performatives.size()];
238   	int i = 0;
239   	Iterator it = performatives.iterator();
240   	while (it.hasNext()) {
241   		names[i++] = (String) it.next();
242   	}
243   	return names;
244   }
245   
246   /***
247      @deprecated Since every ACL Message must have a message type, you
248      should use the new constructor which gets a message type as a
249      parameter.  To avoid problems, now this constructor silently sets
250      the message type to <code>not-understood</code>.
251      @see jade.lang.acl.ACLMessage#ACLMessage(int)
252   */
253   public ACLMessage() {
254     performative = NOT_UNDERSTOOD;
255   }
256 
257 
258 
259 
260   /***
261    * This constructor creates an ACL message object with the specified
262    * performative. If the passed integer does not correspond to any of
263    * the known performatives, it silently initializes the message to
264    * <code>not-understood</code>.
265    **/
266   public ACLMessage(int perf) {
267     performative = perf;
268   }
269 
270   /***
271      Writes the <code>:sender</code> slot. <em><b>Warning:</b> no
272      checks are made to validate the slot value.</em>
273      @param source The new value for the slot.
274      @see jade.lang.acl.ACLMessage#getSender()
275   */
276   public void setSender(AID s) {
277     if (s != null)
278       source = (AID)s.clone();
279     else
280       source = null;
281   }
282 
283   /***
284      Adds a value to <code>:receiver</code> slot. <em><b>Warning:</b>
285      no checks are made to validate the slot value.</em>
286      @param r The value to add to the slot value set.
287   */
288   public void addReceiver(AID r) {
289     if(r != null)
290       dests.add(r);
291   }
292 
293   /***
294      Removes a value from <code>:receiver</code>
295      slot. <em><b>Warning:</b> no checks are made to validate the slot
296      value.</em>
297      @param r The value to remove from the slot value set.
298      @return true if the AID has been found and removed, false otherwise
299   */
300   public boolean removeReceiver(AID r) {
301     if (r != null)
302       return dests.remove(r);
303     else
304       return false;
305   }
306 
307   /***
308      Removes all values from <code>:receiver</code>
309      slot. <em><b>Warning:</b> no checks are made to validate the slot
310      value.</em> 
311   */
312   public void clearAllReceiver() {
313     dests.clear();
314   }
315 
316 
317 
318   /***
319      Adds a value to <code>:reply-to</code> slot. <em><b>Warning:</b>
320      no checks are made to validate the slot value.</em>
321      @param dest The value to add to the slot value set.
322   */
323   public void addReplyTo(AID dest) {
324     if (dest != null) 
325       reply_to.add(dest);
326   }
327 
328   /***
329      Removes a value from <code>:reply_to</code>
330      slot. <em><b>Warning:</b> no checks are made to validate the slot
331      value.</em>
332      @param dest The value to remove from the slot value set.
333      @return true if the AID has been found and removed, false otherwise
334   */
335   public boolean removeReplyTo(AID dest) {
336     if (dest != null)
337       return reply_to.remove(dest);
338     else
339       return false;
340   }
341 
342   /***
343      Removes all values from <code>:reply_to</code>
344      slot. <em><b>Warning:</b> no checks are made to validate the slot
345      value.</em> 
346   */
347   public void clearAllReplyTo() {
348     reply_to.clear();
349   }
350 
351   /***
352    * set the performative of this ACL message object to the passed constant.
353    * Remind to 
354    * use the set of constants (i.e. <code> INFORM, REQUEST, ... </code>)
355    * defined in this class
356    */
357   public void setPerformative(int perf) {
358     performative = perf;
359   }
360 
361   /***
362    * Writes the <code>:content</code> slot. <em><b>Warning:</b> no
363    * checks are made to validate the slot value.</em> <p>
364    * <p>Notice that, in general, setting a String content and getting
365    * back a byte sequence content - or viceversa - does not return
366    * the same value, i.e. the following relation does not hold
367    * <code>
368    * getByteSequenceContent(setByteSequenceContent(getContent().getBytes())) 
369    * is equal to getByteSequenceContent()
370    * </code>
371    * @param content The new value for the slot.
372    * @see jade.lang.acl.ACLMessage#getContent()
373    * @see jade.lang.acl.ACLMessage#setByteSequenceContent(byte[])
374    * @see jade.lang.acl.ACLMessage#setContentObject(Serializable s)
375    */
376   public void setContent(String content) {
377       byteSequenceContent = null; //make to null the other variable
378     if (content != null)
379       this.content = new StringBuffer(content);
380     else
381       this.content = null;
382   }
383 
384   /***
385    * Writes the <code>:content</code> slot. <em><b>Warning:</b> no
386    * checks are made to validate the slot value.</em> <p>
387    * <p>Notice that, in general, setting a String content and getting
388    * back a byte sequence content - or viceversa - does not return
389    * the same value, i.e. the following relation does not hold
390    * <code>
391    * getByteSequenceContent(setByteSequenceContent(getContent().getBytes())) 
392    * is equal to getByteSequenceContent()
393    * </code>
394    * @param content The new value for the slot.
395    * @see jade.lang.acl.ACLMessage#setContent(String s)
396    * @see jade.lang.acl.ACLMessage#getByteSequenceContent()
397    * @see jade.lang.acl.ACLMessage#setContentObject(Serializable s)
398    */
399   public void setByteSequenceContent(byte[] content) {
400       this.content = null; //make to null the other variable
401       byteSequenceContent = content;
402   }
403 
404 
405 
406   /***
407   * This method sets the content of this ACLMessage to a Java object.
408   * It is not FIPA compliant so its usage is not encouraged.
409   * For example:<br>
410   * <PRE>
411   * ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
412   * Date d = new Date(); 
413   * try{
414   *  msg.setContentObject(d);
415   * }catch(IOException e){}
416   * </PRE>
417   *
418   * @param s the object that will be used to set the content of the ACLMessage. 
419   * @exception IOException if an I/O error occurs.
420   */
421   public void setContentObject(java.io.Serializable s) throws IOException
422   {
423   	ByteArrayOutputStream c = new ByteArrayOutputStream();
424   	ObjectOutputStream oos = new ObjectOutputStream(c);
425   	oos.writeObject(s);
426   	oos.flush();
427 	setByteSequenceContent(c.toByteArray());
428   }
429 
430 
431   /***
432   * This method returns the content of this ACLMessage when they have
433   * been written via the method <code>setContentObject</code>.
434   * It is not FIPA compliant so its usage is not encouraged.
435   * For example to read Java objects from the content 
436   * <PRE>
437   * ACLMessage msg = blockingReceive();
438   * try{
439   *  Date d = (Date)msg.getContentObject();
440   * }catch(UnreadableException e){}
441   * </PRE>
442   * 
443   * @return the object read from the content of this ACLMessage
444   * @exception UnreadableException when an error occurs during the deconding.
445   */
446   public java.io.Serializable getContentObject() throws UnreadableException
447   {
448   	
449     try{
450       ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(getByteSequenceContent()));
451       java.io.Serializable s = (java.io.Serializable)oin.readObject();
452       return s;
453     }
454     catch (java.lang.Error e) {
455       throw new UnreadableException(e.getMessage());
456     }
457     catch (IOException e1) {
458       throw new UnreadableException(e1.getMessage());
459     }
460     catch(ClassNotFoundException e2) {
461       throw new UnreadableException(e2.getMessage());
462     }
463 
464   }
465 
466   /***
467      Writes the <code>:reply-with</code> slot. <em><b>Warning:</b> no
468      checks are made to validate the slot value.</em>
469      @param reply The new value for the slot.
470      @see jade.lang.acl.ACLMessage#getReplyWith()
471   */
472   public void setReplyWith(String reply) {
473     if (reply != null)
474       reply_with = new StringBuffer(reply);
475     else
476       reply_with = null;
477   }
478 
479   /***
480      Writes the <code>:in-reply-to</code> slot. <em><b>Warning:</b> no
481      checks are made to validate the slot value.</em>
482      @param reply The new value for the slot.
483      @see jade.lang.acl.ACLMessage#getInReplyTo()
484   */
485   public void setInReplyTo(String reply) {
486     if (reply != null)
487       in_reply_to = new StringBuffer(reply);
488     else
489       in_reply_to = null;
490   }
491   
492   /***
493      Writes the <code>:encoding</code> slot. <em><b>Warning:</b> no
494      checks are made to validate the slot value.</em>
495      @param str The new value for the slot.
496      @see jade.lang.acl.ACLMessage#getEncoding()
497   */
498   public void setEncoding(String str) {
499     if (str != null)
500       encoding = new StringBuffer(str);
501     else
502       encoding = null;
503   }
504 
505   /***
506      Writes the <code>:language</code> slot. <em><b>Warning:</b> no
507      checks are made to validate the slot value.</em>
508      @param str The new value for the slot.
509      @see jade.lang.acl.ACLMessage#getLanguage()
510   */
511   public void setLanguage(String str) {
512     if (str != null)
513       language = new StringBuffer(str);
514     else
515       language = null;
516   }
517 
518   /***
519      Writes the <code>:ontology</code> slot. <em><b>Warning:</b> no
520      checks are made to validate the slot value.</em>
521      @param str The new value for the slot.
522      @see jade.lang.acl.ACLMessage#getOntology()
523   */
524   public void setOntology(String str) {
525     if (str != null)
526       ontology = new StringBuffer(str);
527     else
528       ontology = null;
529   }
530 
531 
532   /***
533      Writes the <code>:reply-by</code> slot. <em><b>Warning:</b> no
534      checks are made to validate the slot value.</em>
535      @param str The new value for the slot, as ISO8601 time.
536      @see jade.lang.acl.ACLMessage#getReplyBy()
537      @see jade.lang.acl.ACLMessage#setReplyByDate(Date)
538      @deprecated The value of the <code>reply-by</code> slot
539      must be a valid Date, the method <code>setReplyByDate</code> should
540      be used that guarantees avoiding problems. If the passed
541      parameter represents a wrong date, this method silently converts
542      its value to null.
543   */
544   public void setReplyBy(String str) {
545     if (str != null) {
546       try {
547 	reply_byInMillisec = ISO8601.toDate(str).getTime();
548       } catch (Exception e) {
549 	reply_byInMillisec = 0; 
550       }
551     } else {
552       reply_byInMillisec = 0; 
553     }
554   }	
555 
556   /***
557      Writes the <code>:reply-by</code> slot. <em><b>Warning:</b> no
558      checks are made to validate the slot value.</em>
559      @param date The new value for the slot.
560      @see jade.lang.acl.ACLMessage#getReplyByDate()
561   */
562   public void setReplyByDate(Date date) {
563       reply_byInMillisec = (date==null?0:date.getTime());
564   }
565 
566   /***
567      Writes the <code>:protocol</code> slot. <em><b>Warning:</b> no
568      checks are made to validate the slot value.</em>
569      @param str The new value for the slot.
570      @see jade.lang.acl.ACLMessage#getProtocol()
571   */
572   public void setProtocol( String str ) {
573     if (str != null)
574       protocol = new StringBuffer(str);
575     else
576       protocol = null;
577   }
578 
579   /***
580      Writes the <code>:conversation-id</code> slot. <em><b>Warning:</b> no
581      checks are made to validate the slot value.</em>
582      @param str The new value for the slot.
583      @see jade.lang.acl.ACLMessage#getConversationId()
584   */
585   public void setConversationId( String str ) {
586     if (str != null)
587       conversation_id = new StringBuffer(str);
588     else
589       conversation_id = null;
590   }
591 
592 
593 
594   /***
595      Reads <code>:receiver</code> slot.
596      @return An <code>Iterator</code> containing the Agent IDs of the
597      receiver agents for this message.
598   */
599   public Iterator getAllReceiver() {
600     return dests.iterator();
601   }
602 
603   /***
604      Reads <code>:reply_to</code> slot.
605      @return An <code>Iterator</code> containing the Agent IDs of the
606      reply_to agents for this message.
607   */
608   public Iterator getAllReplyTo() {
609     return reply_to.iterator();
610   }
611 
612   /***
613      Reads <code>:sender</code> slot.
614      @return The value of <code>:sender</code>slot.
615      @see jade.lang.acl.ACLMessage#setSender(AID).
616   */
617   public AID getSender() {
618     if(source != null)
619       return (AID)source.clone();
620     else
621       return null;
622   }
623 
624   /***
625     Returns the string corresponding to the integer for the performative
626     @return the string corresponding to the integer for the performative; 
627     "NOT-UNDERSTOOD" if the integer is out of range.
628   */
629   public static String getPerformative(int perf){
630     try {
631       return new String((String)performatives.get(perf));
632     } catch (Exception e) {
633       return new String((String)performatives.get(NOT_UNDERSTOOD));
634     }
635   }
636     
637   /***
638     Returns the integer corresponding to the performative
639     @returns the integer corresponding to the performative; -1 otherwise
640   */
641   public static int getInteger(String perf)
642   {
643     return performatives.indexOf(perf.toUpperCase());
644     }
645 
646   /***
647    * return the integer representing the performative of this object
648    * @return an integer representing the performative of this object
649    */
650   public int getPerformative() {
651     return performative;
652   }
653 
654     /***
655      * This method allows to check if the content of this ACLMessage
656      * is a byteSequence or a String
657      * @return true if it is a byteSequence, false if it is a String
658      **/
659     public boolean hasByteSequenceContent(){
660 	return (byteSequenceContent != null);
661     }
662 
663   /***
664    * Reads <code>:content</code> slot. <p>
665    * <p>Notice that, in general, setting a String content and getting
666    * back a byte sequence content - or viceversa - does not return
667    * the same value, i.e. the following relation does not hold
668    * <code>
669    * getByteSequenceContent(setByteSequenceContent(getContent().getBytes())) 
670    * is equal to getByteSequenceContent()
671    * </code>
672    * @return The value of <code>:content</code> slot.
673    * @see jade.lang.acl.ACLMessage#setContent(String)
674    * @see jade.lang.acl.ACLMessage#getByteSequenceContent()
675    * @see jade.lang.acl.ACLMessage#getContentObject()
676    * @see java.io.ObjectInputStream
677   */
678   public String getContent() {
679     if(content != null)
680       return new String(content);
681     else if (byteSequenceContent != null)
682 	return new String(byteSequenceContent);
683     return null;
684   }
685 
686  /***
687    * Reads <code>:content</code> slot. <p>
688    * <p>Notice that, in general, setting a String content and getting
689    * back a byte sequence content - or viceversa - does not return
690    * the same value, i.e. the following relation does not hold
691    * <code>
692    * getByteSequenceContent(setByteSequenceContent(getContent().getBytes())) 
693    * is equal to getByteSequenceContent()
694    * </code>
695    * @return The value of <code>:content</code> slot.
696    * @see jade.lang.acl.ACLMessage#setContent(String)
697    * @see jade.lang.acl.ACLMessage#getContent()
698    * @see jade.lang.acl.ACLMessage#getContentObject()
699    * @see java.io.ObjectInputStream
700   */
701   public byte[] getByteSequenceContent() {
702       if (content != null) 
703 	  return content.toString().getBytes();
704       else if (byteSequenceContent != null)
705           return byteSequenceContent;
706       return null;
707   }
708 
709   /***
710      Reads <code>:reply-with</code> slot.
711      @return The value of <code>:reply-with</code>slot.
712      @see jade.lang.acl.ACLMessage#setReplyWith(String).
713   */
714   public String getReplyWith() {
715     if(reply_with != null)
716       return new String(reply_with);
717     else return null;
718   }
719 
720   /***
721      Reads <code>:reply-to</code> slot.
722      @return The value of <code>:reply-to</code>slot.
723      @see jade.lang.acl.ACLMessage#setInReplyTo(String).
724   */
725   public String getInReplyTo() {
726     if(in_reply_to != null)
727       return new String(in_reply_to);
728     else return null;
729   }
730 
731 
732 
733   /***
734      Reads <code>:encoding</code> slot.
735      @return The value of <code>:encoding</code>slot.
736      @see jade.lang.acl.ACLMessage#setEncoding(String).
737   */
738   public String getEncoding() {
739     if(encoding != null)
740       return new String(encoding);
741     else
742       return null;
743   }
744 
745   /***
746      Reads <code>:language</code> slot.
747      @return The value of <code>:language</code>slot.
748      @see jade.lang.acl.ACLMessage#setLanguage(String).
749   */
750   public String getLanguage() {
751     if(language != null)
752       return new String(language);
753     else
754       return null;
755   }
756 
757   /***
758      Reads <code>:ontology</code> slot.
759      @return The value of <code>:ontology</code>slot.
760      @see jade.lang.acl.ACLMessage#setOntology(String).
761   */
762   public String getOntology() {
763     if(ontology != null)
764       return new String(ontology);
765     else
766       return null;
767   }
768 
769   /***
770      Reads <code>:reply-by</code> slot.
771      @return The value of <code>:reply-by</code>slot, as a string.
772      @see jade.lang.acl.ACLMessage#setReplyBy(String).
773      @see jade.lang.acl.ACLMessage#getReplyByDate().
774      @deprecated Since the value of this slot is a Date by definition, then
775      the <code>getReplyByDate</code> should be used that returns a Date
776   */
777   public String getReplyBy() {
778       if(reply_byInMillisec != 0)
779 	  return ISO8601.toString(new Date(reply_byInMillisec));
780       else
781 	  return null;
782   }
783 
784   /***
785      Reads <code>:reply-by</code> slot.
786      @return The value of <code>:reply-by</code>slot, as a
787      <code>Date</code> object.
788      @see jade.lang.acl.ACLMessage#setReplyByDate(Date).
789   */
790   public Date getReplyByDate() {
791     if(reply_byInMillisec != 0)
792       return new Date(reply_byInMillisec);
793     else
794       return null;
795   }
796 
797   /***
798      Reads <code>:protocol</code> slot.
799      @return The value of <code>:protocol</code>slot.
800      @see jade.lang.acl.ACLMessage#setProtocol(String).
801   */
802   public String getProtocol() {
803     if(protocol != null)
804       return new String(protocol);
805     else
806       return null;
807   }
808 
809   /***
810      Reads <code>:conversation-id</code> slot.
811      @return The value of <code>:conversation-id</code>slot.
812      @see jade.lang.acl.ACLMessage#setConversationId(String).
813   */
814   public String getConversationId() {
815     if(conversation_id != null)
816       return new String(conversation_id);
817     else
818       return null;
819   }
820  
821 
822 
823   /***
824    * Add a new user defined parameter to this ACLMessage.
825    * Notice that according to the FIPA specifications, the keyword of a
826    * user-defined parameter must start with the String ":X-". 
827    * If it does not, then this method adds the prefix silently!
828    * @param key the property key.
829    * @param value the property value
830   **/
831    public void addUserDefinedParameter(String key, String value) {
832        userDefProps.setProperty(key,value);
833    }
834 
835     /***
836      * Searches for the user defined parameter with the specified key. 
837      * The method returns
838      * <code>null</code> if the parameter is not found.
839      *
840      * @param   key   the parameter key.
841      * @return  the value in this ACLMessage with the specified key value.
842      */
843    public String getUserDefinedParameter(String key){
844      return userDefProps.getProperty(key);
845    }
846 
847   /***
848    * get a clone of the data structure with all the user defined parameters
849    **/
850    public Properties getAllUserDefinedParameters() {
851      return (Properties)userDefProps.clone();
852    }
853 
854   /***
855    * Removes the key and its corresponding value from the list of user
856    * defined parameters in this ACLMessage.
857    * @param key the key that needs to be removed
858      @return true if the property has been found and removed, false otherwise
859    */
860    public boolean removeUserDefinedParameter(String key) {
861      return (userDefProps.remove(key) != null);
862    }
863 
864   /***
865      Attaches an envelope to this message. The envelope is used by the
866      <b><it>ACC</it></b> for inter-platform messaging.
867      @param e The <code>Envelope</code> object to attach to this
868      message.
869      @see jade.lang.acl#getEnvelope()
870      @see jade.lang.acl#setDefaultEnvelope()
871    */
872   public void setEnvelope(Envelope e) {
873     messageEnvelope = e;
874   }
875 
876 
877   /***
878      Writes the message envelope for this message, using the
879      <code>:sender</code> and <code>:receiver</code> message slots to
880      fill in the envelope.
881      @see jade.lang.acl#setEnvelope(Envelope e)
882      @see jade.lang.acl#getEnvelope()
883    */
884 /*  public void setDefaultEnvelope() {
885     messageEnvelope = new Envelope(,source,);
886     messageEnvelope.setFrom(source);
887     Iterator it = dests.iterator();
888     while(it.hasNext())
889       messageEnvelope.addTo((AID)it.next());
890     messageEnvelope.setAclRepresentation(StringACLCodec.NAME);
891     messageEnvelope.setDate(new Date());
892   }*/
893 
894   /***
895      Reads the envelope attached to this message, if any.
896      @return The envelope for this message.
897      @see jade.lang.acl#setEnvelope(Envelope e)
898      @see jade.lang.acl#setDefaultEnvelope()
899    */
900   public Envelope getEnvelope() {
901     return messageEnvelope;
902   }
903 
904   /***
905      Writes an ACL message object on a stream as a character
906      string. This method allows to write a string representation of an
907      <code>ACLMessage</code> object onto a character stream.
908      @param w A <code>Writer</code> object to write the message onto.
909      @deprecated the <code>toString</code> method should be used instead
910      of this method.
911   */
912   public void toText(Writer w) {
913       try {
914 	  w.write(toString());
915 	  w.flush();
916       } catch(IOException ioe) {
917 	  ioe.printStackTrace();
918       }
919   }
920 
921   /***
922      Clone an <code>ACLMessage</code> object.
923      @return A copy of this <code>ACLMessage</code> object. The copy
924      must be casted back to <code>ACLMessage</code> type before being
925      used.
926   */
927   public synchronized Object clone() {
928 
929     ACLMessage result;
930 
931     try {
932       result = (ACLMessage)super.clone();
933       result.dests = (ArrayList)dests.clone();       // Deep copy
934       result.reply_to = (ArrayList)reply_to.clone(); // Deep copy
935     }
936     catch(CloneNotSupportedException cnse) {
937       throw new InternalError(); // This should never happen
938     }
939 
940     return result;
941   }
942 
943   /***
944      Convert an ACL message to its string representation. This method
945      writes a representation of this <code>ACLMessage</code> into a
946      character string.
947      If the content is a bytesequence, then it is automatically converted
948      into Base64 encoding. 
949      @return A <code>String</code> representing this message.
950   */
951   public String toString(){
952       return StringACLCodec.toString(this);
953   }
954 
955 
956  /***
957   * Resets all the message slots.
958  */
959  public void reset() {
960   source = null;
961   dests.clear();
962   reply_to.clear();
963   performative = NOT_UNDERSTOOD;
964   content = null;
965   byteSequenceContent = null;
966   reply_with = null;
967   in_reply_to = null;
968   encoding = null;
969   language = null;
970   ontology = null;
971   reply_byInMillisec = 0;
972   protocol = null;
973   conversation_id = null;
974   userDefProps.clear();
975  }
976 
977   /***
978    * create a new ACLMessage that is a reply to this message.
979    * In particular, it sets the following parameters of the new message:
980    * receiver, language, ontology, protocol, conversation-id,
981    * in-reply-to, reply-with.
982    * The programmer needs to set the communicative-act and the content.
983    * Of course, if he wishes to do that, he can reset any of the fields.
984    * @return the ACLMessage to send as a reply
985    */
986 /*  public ACLMessage createReply() {
987     ACLMessage m = (ACLMessage)clone();
988     m.clearAllReceiver();
989     Iterator it = reply_to.iterator();
990     while (it.hasNext())
991       m.addReceiver((AID)it.next());
992     if (reply_to.isEmpty())
993       m.addReceiver(getSender());
994     m.clearAllReplyTo();
995     m.setLanguage(getLanguage());
996     m.setOntology(getOntology());
997     m.setProtocol(getProtocol());
998     m.setSender(null);
999     m.setInReplyTo(getReplyWith());
1000     if (source != null)
1001       m.setReplyWith(source.getName() + java.lang.System.currentTimeMillis()); 
1002     else
1003       m.setReplyWith("X"+java.lang.System.currentTimeMillis()); 
1004     m.setConversationId(getConversationId());
1005     m.setReplyByDate(null);
1006     m.setContent(null);
1007     m.setEncoding(null);
1008     
1009     //Set the Aclrepresentation of the reply message to the aclrepresentation of the sent message 
1010     if (messageEnvelope != null)
1011     {
1012 	m.setDefaultEnvelope(); // reset the envelope after having been cloned
1013     	String aclCodec= messageEnvelope.getAclRepresentation();
1014     	if (aclCodec != null)
1015 	    m.getEnvelope().setAclRepresentation(aclCodec);
1016     }
1017     else
1018     m.setEnvelope(null);
1019 
1020     return m;
1021   }
1022 */
1023 
1024 }