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
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;
121 private static List performatives = new ArrayList(22);
122 static {
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
168
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
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
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
236
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;
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;
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
885
886
887
888
889
890
891
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();
934 result.reply_to = (ArrayList)reply_to.clone();
935 }
936 catch(CloneNotSupportedException cnse) {
937 throw new InternalError();
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
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024 }