View Javadoc

1   /*
2    * jSDP: A Java implementation of SDP protocol Copyright (C) 2007 Claudio Di
3    * Vita
4    */
5   package net.sourceforge.jsdp;
6   
7   import java.util.ArrayList;
8   import java.util.Collection;
9   import java.util.HashMap;
10  import java.util.Iterator;
11  import java.util.LinkedList;
12  import java.util.List;
13  
14  /**
15   * A <tt>SessionDescription</tt> represents the data defined by the Session
16   * Description Protocol.
17   * <p>
18   * The session description holds information about the originator of a session,
19   * the media types that a client can support and the host and port on which the
20   * client will listen for that media. It also holds timing information for the
21   * session (e.g. start, end, repeat, time zone) and bandwidth supported for the
22   * session.
23   * </p>
24   * 
25   * <p>
26   * For further information please refer to <a
27   * href="http://www.ietf.org/rfc/rfc4566.txt">RFC 4566</a>.
28   * </p>
29   * 
30   * @see TimeDescription
31   * @see MediaDescription
32   * 
33   * @since 0.1.0
34   * 
35   * @version 1.1
36   * 
37   * @author <a href="mailto:cdivita@users.sourceforge.net">Claudio Di Vita</a>
38   */
39  public class SessionDescription implements Description {
40  
41      /** The class Stream Unique Identifier, SUID */
42      private static final long serialVersionUID = -2804972731894656668L;
43  
44      /** The version field */
45      protected Version v;
46  
47      /** The origin field */
48      protected Origin o;
49  
50      /** The session name field */
51      protected SessionName s;
52  
53      /** The information field */
54      protected Information i;
55  
56      /** The uri field */
57      protected Uri u;
58  
59      /** The email fields */
60      protected ArrayList emails;
61  
62      /** The phone fields */
63      protected ArrayList phones;
64  
65      /** The connection field */
66      protected Connection c;
67  
68      /** The bandwith fields */
69      protected HashMap bandwiths;
70  
71      /** The time descriptions */
72      protected ArrayList timeDescriptions;
73  
74      /** The time zone field */
75      protected TimeZone z;
76  
77      /** The key field */
78      protected Key k;
79  
80      /** The attribute fields */
81      protected HashMap attributes;
82  
83      /** The media descriptions */
84      protected ArrayList mediaDescriptions;
85  
86      /**
87       * Creates a <tt>SessionDescription</tt>.
88       */
89      protected SessionDescription() {
90  
91          super();
92  
93          this.emails = new ArrayList();
94          this.phones = new ArrayList();
95          this.bandwiths = new HashMap();
96          this.timeDescriptions = new ArrayList();
97          this.attributes = new HashMap();
98          this.mediaDescriptions = new ArrayList();
99      }
100 
101     /**
102      * Creates a <tt>SessionDescription</tt>. This constructor is used to
103      * implement the @link #clone()} method.
104      * 
105      * @param sd the <tt>SessionDescription</tt> to clone
106      */
107     protected SessionDescription(final SessionDescription sd) {
108 
109         super();
110 
111         this.v = (Version) sd.v.clone();
112         this.o = (Origin) sd.o.clone();
113         this.s = (SessionName) sd.s.clone();
114         this.i = (Information) sd.i.clone();
115         this.u = (Uri) sd.u.clone();
116         this.emails = (ArrayList) sd.emails.clone();
117         this.phones = (ArrayList) sd.phones.clone();
118         this.c = (Connection) sd.c.clone();
119         this.bandwiths = (HashMap) sd.bandwiths.clone();
120         this.timeDescriptions = (ArrayList) sd.timeDescriptions.clone();
121         this.z = (TimeZone) sd.z.clone();
122         this.attributes = (HashMap) sd.attributes.clone();
123         this.mediaDescriptions = (ArrayList) sd.mediaDescriptions.clone();
124     }
125 
126     /**
127      * Creates a <tt>SessionDescription</tt>.
128      * 
129      * @param v the version field
130      * 
131      * @param o the origin field
132      * 
133      * @param s the session name field
134      * 
135      * @param td the time description
136      * 
137      * @throws IllegalArgumentException if one or more parameters are
138      *         <tt>null</tt>
139      */
140     public SessionDescription(final Version v, final Origin o, final SessionName s, final TimeDescription td) throws IllegalArgumentException {
141 
142         this();
143 
144         setVersion(v);
145         setOrigin(o);
146         setSessionName(s);
147 
148         addTimeDescription(td);
149     }
150 
151     /**
152      * Adds an attribute field. If an <tt>Attribute</tt> with the same name is
153      * already present it will be added.
154      * 
155      * @param field the attribute field to set
156      * 
157      * @throws IllegalArgumentException if the field is <tt>null</tt>
158      */
159     public void addAttribute(final Attribute field) throws IllegalArgumentException {
160 
161         if (field == null) {
162             throw new IllegalArgumentException("An attribute field cannot be null");
163         }
164 
165         /* Get attribute name */
166         String name = field.getName();
167 
168         /* An object with the same name is already present */
169         if (attributes.containsKey(name)) {
170 
171             List values = null;
172             Object maybe = attributes.get(name);
173 
174             /* There are many attributes with that name */
175             if (maybe instanceof List) {
176 
177                 values = (List) maybe;
178             }
179             /* There is only an attribute with that name */
180             else {
181 
182                 /* Get previous attribute */
183                 Attribute previous = (Attribute) maybe;
184 
185                 /*
186                  * Create a list that contains all the attributes with the given
187                  * name
188                  */
189                 values = new LinkedList();
190 
191                 /* Add the previous attribute to list */
192                 values.add(previous);
193 
194                 attributes.put(field.getName(), values);
195             }
196 
197             values.add(field);
198 
199         }
200         /* An attribute with given name is not present */
201         else {
202 
203             attributes.put(field.getName(), field);
204         }
205     }
206 
207     /**
208      * Adds a bandwith field. If a <tt>Bandwith</tt> with the same modifier is
209      * already present it will be replaced.
210      * 
211      * @param bandwith the bandwith field to set
212      * 
213      * @throws IllegalArgumentException if the bandwith field is <tt>null</tt>
214      */
215     public void addBandwith(final Bandwith bandwith) throws IllegalArgumentException {
216 
217         if (bandwith == null) {
218             throw new IllegalArgumentException("A bandwith field cannot be null");
219         }
220 
221         bandwiths.put(bandwith.getModifier(), bandwith);
222     }
223 
224     /**
225      * Adds an email field.
226      * 
227      * @param field the email field to add
228      * 
229      * @throws IllegalArgumentException if the field is <tt>null</tt>
230      */
231     public void addEmail(final Email field) throws IllegalArgumentException {
232 
233         if (field == null) {
234             throw new IllegalArgumentException("An email field cannot be null");
235         }
236 
237         emails.add(field);
238     }
239 
240     /**
241      * Adds a media description.
242      * 
243      * @param md the media description to add
244      * 
245      * @throws IllegalArgumentException if the media description is
246      *         <tt>null</tt>
247      * 
248      * @throws SDPException if both session and media description doesn't have a
249      *         connection field
250      */
251     public void addMediaDescription(final MediaDescription md) throws IllegalArgumentException, SDPException {
252 
253         if (md == null) {
254             throw new IllegalArgumentException("A media description cannot be null");
255         }
256 
257         if (!hasConnection() && !md.hasConnection()) {
258             throw new SDPException("This media description must have a connection field");
259         }
260 
261         /* Add the media description */
262         mediaDescriptions.add(md);
263     }
264 
265     /**
266      * Adds a phone field.
267      * 
268      * @param field the phone field to add
269      * 
270      * @throws IllegalArgumentException tf the field is <tt>null</tt>
271      */
272     public void addPhone(final Phone field) throws IllegalArgumentException {
273 
274         if (field == null) {
275             throw new IllegalArgumentException("A phone field cannot be null");
276         }
277 
278         /* Add the phone field */
279         phones.add(field);
280     }
281 
282     /**
283      * Adds a time description.
284      * 
285      * @param td the time description to set
286      * 
287      * @throws IllegalArgumentException if the description is <tt>null</tt>
288      */
289     public void addTimeDescription(final TimeDescription td) throws IllegalArgumentException {
290 
291         if (td == null) {
292             throw new IllegalArgumentException("A time description cannot be null");
293         }
294 
295         timeDescriptions.add(td);
296     }
297 
298     /**
299      * Remove all attribute fields contained in the description.
300      */
301     public void clearAttributes() {
302     
303         attributes.clear();
304     }
305 
306     /**
307      * Remove all bandwith fields contained in the session description.
308      */
309     public void clearBandwiths() {
310 
311         this.bandwiths.clear();
312     }
313 
314     /**
315      * Remove all email fields contained in the session description.
316      */
317     public void clearEmails() {
318 
319         this.emails.clear();
320     }
321 
322     /**
323      * Remove all media descriptions contained in the session description.
324      */
325     public void clearMediaDescriptions() {
326 
327         this.mediaDescriptions.clear();
328     }
329 
330     /**
331      * Remove all phone fields contained in the session description.
332      */
333     public void clearPhones() {
334 
335         this.phones.clear();
336     }
337 
338     /**
339      * Returns a clone of this description.
340      * 
341      * @return a clone of this description
342      */
343     public Object clone() {
344 
345         return new SessionDescription(this);
346     }
347 
348     /**
349      * Returns all attribute fields.
350      * 
351      * @return an array that contains the attribute fields contained in the
352      *         description
353      */
354     public Attribute[] getAttributes() {
355 
356         Object maybe = null;
357         List values = null;
358 
359         Collection result = new LinkedList();
360 
361         for (Iterator i = attributes.values().iterator(); i.hasNext();) {
362 
363             maybe = i.next();
364 
365             if (maybe instanceof Attribute) {
366 
367                 result.add(maybe);
368             }
369             else {
370 
371                 values = (List) maybe;
372 
373                 for (Iterator j = values.iterator(); j.hasNext();) {
374 
375                     result.add(j.next());
376                 }
377             }
378         }
379 
380         return (Attribute[]) result.toArray(new Attribute[result.size()]);
381     }
382 
383     /**
384      * Returns the attribute with the specified name. If there are multiple
385      * occurencies of attributes with that name, the first one is returned
386      * 
387      * @param name the name of the attribute
388      * 
389      * @return an attribute field
390      */
391     public Attribute getAttribute(final String name) {
392 
393         Attribute result = null;
394         Object maybe = attributes.get(name);
395 
396         if (maybe != null) {
397 
398             if (maybe instanceof List) {
399 
400                 List values = (List) maybe;
401 
402                 result = (Attribute) values.get(0);
403             }
404             else {
405 
406                 result = (Attribute) maybe;
407             }
408         }
409 
410         return result;
411     }
412 
413     /**
414      * Returns a specified occurence of an attribute with the specified name.
415      * 
416      * @param name the name of the attribute
417      * @param index the occurence index
418      * 
419      * @return an attribute field
420      */
421     public Attribute getAttribute(final String name, final int index) {
422 
423         Attribute result = null;
424         Object maybe = attributes.get(name);
425 
426         if ((maybe != null) && (maybe instanceof List)) {
427 
428             List values = (List) maybe;
429 
430             result = (Attribute) values.get(index);
431         }
432 
433         return result;
434     }
435 
436     /**
437      * Returns the attributes with the specified name.
438      * 
439      * <p>
440      * If there is only an occurence of that attribute the length of returned
441      * array is <tt>1</tt>, instead if there aren't attributes with the given
442      * name the length of returned array is <tt>0</tt>
443      * </p>
444      * 
445      * @param name the name of the attribute
446      * 
447      * @return an array of attributes
448      */
449     public Attribute[] getAttributes(final String name) {
450 
451         Attribute[] result;
452         Object maybe = attributes.get(name);
453 
454         if (maybe != null) {
455 
456             if (maybe instanceof List) {
457 
458                 List values = (List) maybe;
459 
460                 result = (Attribute[]) values.toArray(new Attribute[values.size()]);
461             }
462             else {
463 
464                 result = new Attribute[1];
465                 result[0] = (Attribute) maybe;
466             }
467         }
468         else {
469             result = new Attribute[0];
470         }
471 
472         return result;
473     }
474 
475     /**
476      * Returns the number of attributes with a specified name
477      * 
478      * @param name the name of the attribute
479      * 
480      * @return an integer
481      */
482     public int getAttributesCount(final String name) {
483 
484         int result = 0;
485         Object maybe = attributes.get(name);
486 
487         if (maybe != null) {
488 
489             if (maybe instanceof List) {
490 
491                 List values = (List) maybe;
492 
493                 result = values.size();
494             }
495             else {
496 
497                 result = 1;
498             }
499         }
500 
501         return result;
502     }
503 
504     /**
505      * Returns the bandwith field with a specified modifier.
506      * 
507      * @param modifier the bandwith modifier
508      * 
509      * @return the bandwith field specified by modifier if present,
510      *         <tt>null</tt> otherwise
511      */
512     public Bandwith getBandwith(final String modifier) {
513 
514         return (Bandwith) bandwiths.get(modifier);
515     }
516 
517     /**
518      * Returns the bandwith fields.
519      * 
520      * @return an array that contains the bandwith fields contained in the
521      *         session description
522      */
523     public Bandwith[] getBandwiths() {
524 
525         Bandwith[] values = new Bandwith[bandwiths.size()];
526         Iterator iterator = bandwiths.values().iterator();
527 
528         for (int j = 0; j < values.length; j++) {
529             values[j] = (Bandwith) iterator.next();
530         }
531 
532         return values;
533     }
534 
535     /**
536      * Returns the connection field.
537      * 
538      * @return the connection field if present, <tt>null</tt> otherwise
539      */
540     public Connection getConnection() {
541 
542         return c;
543     }
544 
545     /**
546      * Returns the email fields.
547      * 
548      * @return an array that contains the email fields contained in the session
549      *         description
550      */
551     public Email[] getEmails() {
552 
553         return (Email[]) emails.toArray(new Email[emails.size()]);
554     }
555 
556     /**
557      * Returns the information field.
558      * 
559      * @return the information field if present, <tt>null</tt> otherwise
560      */
561     public Information getInformation() {
562 
563         return i;
564     }
565 
566     /**
567      * Returns the key field.
568      * 
569      * @return the key field if present, <tt>null</tt> otherwise
570      */
571     public Key getKey() {
572 
573         return k;
574     }
575 
576     /**
577      * Returns the media descriptions.
578      * 
579      * @return an array that contains the media descriptions contained in the
580      *         session description
581      */
582     public MediaDescription[] getMediaDescriptions() {
583 
584         return (MediaDescription[]) mediaDescriptions.toArray(new MediaDescription[mediaDescriptions.size()]);
585     }
586 
587     /**
588      * Returns the number of media descriptions.
589      *
590      * @return an integer
591      */
592     public int getMediaDescriptionsCount() {
593 
594         return mediaDescriptions.size();
595     }
596 
597     /**
598      * Returns the origin field.
599      * 
600      * @return the origin field
601      */
602     public Origin getOrigin() {
603 
604         return o;
605     }
606 
607     /**
608      * Returns the phone fields.
609      * 
610      * @return an array that contains the phone fields contained in the session
611      *         description
612      */
613     public Phone[] getPhones() {
614 
615         return (Phone[]) phones.toArray(new Phone[phones.size()]);
616     }
617 
618     /**
619      * Returns the session name field.
620      * 
621      * @return the session name field
622      */
623     public SessionName getSessionName() {
624 
625         return s;
626     }
627 
628     /**
629      * Returns the time descriptions.
630      * 
631      * @return an array that contains the time descriptions contained in the
632      *         session description
633      */
634     public TimeDescription[] getTimeDescriptions() {
635 
636         return (TimeDescription[]) timeDescriptions.toArray(new TimeDescription[timeDescriptions.size()]);
637     }
638 
639     /**
640      * Returns the time zone field.
641      * 
642      * @return the time zone field if present, <tt>null</tt> otherwise
643      */
644     public TimeZone getTimeZone() {
645 
646         return z;
647     }
648 
649     /**
650      * Returns the uri field.
651      * 
652      * @return the uri field if present, <tt>null</tt> otherwise
653      */
654     public Uri getUri() {
655 
656         return u;
657     }
658 
659     /**
660      * Returns the version field.
661      * 
662      * @return the version field
663      */
664     public Version getVersion() {
665 
666         return v;
667     }
668 
669     /**
670      * Indicates if an attribute with a specified name is present.
671      * 
672      * @param name the name of the attribute
673      * 
674      * @return <tt>true</tt> if the attribute is present,
675      *         <tt>false</tt> otherwise
676      */
677     public boolean hasAttribute(String name) {
678 
679         boolean result = false;
680 
681         if (name != null) {
682             result = attributes.containsKey(name);
683         }
684 
685         return result;
686     }
687 
688     /**
689      * Indicates if the connection field is present.
690      * 
691      * @return <tt>true</tt> if the connection field is present,
692      *         <tt>false</tt> otherwise
693      */
694     public boolean hasConnection() {
695 
696         return c != null;
697     }
698 
699     /**
700      * Indicates if one or more email fields are present.
701      * 
702      * @return <tt>true</tt> if one or more email fields are present,
703      *         <tt>false</tt> otherwise
704      */
705     public boolean hasEmails() {
706 
707         return (emails.size() > 0);
708     }
709 
710     /**
711      * Indicates if the information field is present.
712      * 
713      * @return <tt>true</tt> if the information field is present,
714      *         <tt>false</tt> otherwise
715      */
716     public boolean hasInformation() {
717 
718         return i != null;
719     }
720 
721     /**
722      * Indicates if the encryption key field is present.
723      * 
724      * @return <tt>true</tt> if the encryption key field is present,
725      *         <tt>false</tt> otherwise
726      */
727     public boolean hasKey() {
728 
729         return k != null;
730     }
731 
732     /**
733      * Indicates if one or more phone fields are present.
734      * 
735      * @return <tt>true</tt> if one or more phone fields are present,
736      *         <tt>false</tt> otherwise
737      */
738     public boolean hasPhones() {
739 
740         return (phones.size() > 0);
741     }
742 
743     /**
744      * Indicates if the timezone field is present.
745      * 
746      * @return <tt>true</tt> if the timezone field is present, <tt>false</tt>
747      *         otherwise
748      */
749     public boolean hasTimeZone() {
750 
751         return z != null;
752     }
753 
754     /**
755      * Indicates if the uri field is present
756      * 
757      * @return <tt>true</tt> if the uri field is present, <tt>false</tt>
758      *         otherwise
759      */
760     public boolean hasUri() {
761 
762         return u != null;
763     }
764 
765     /**
766      * Removes the attribute field with an associated name. If there are multiple
767      * occurencies of attributes with that name, the first one is removed
768      * 
769      * @param name the name of the attribute field to remove
770      * 
771      * @return the removed attribute if present, <tt>null</tt>
772      *         otherwise
773      */
774     public Attribute removeAttribute(final String name) {
775 
776         Attribute a = null;
777         Object maybe = attributes.get(name);
778 
779         if (maybe != null) {
780 
781             if (maybe instanceof List) {
782 
783                 List values = (List) maybe;
784 
785                 /* Remove the first occurence of the attribute */
786                 a = (Attribute) values.remove(0);
787 
788                 /* Remove multiple attributes values, if empty */
789                 if (values.isEmpty()) {
790                     attributes.remove(name);
791                 }
792             }
793             else {
794                 a = (Attribute) attributes.remove(name);
795             }
796         }
797 
798         return a;
799     }
800 
801     /**
802      * Removes a specified occurence of an attribute with the specified name.
803      * 
804      * @param name the name of the attribute
805      * @param index the occurence index
806      * 
807      * @return the removed attribute
808      */
809     public Attribute removeAttribute(final String name, final int index) {
810 
811         Attribute a = null;
812         Object maybe = attributes.get(name);
813 
814         if ((maybe != null) && (maybe instanceof List)) {
815 
816             List values = (List) maybe;
817 
818             a = (Attribute) values.remove(index);
819         }
820 
821         return a;
822     }
823 
824     /**
825      * Remove all occurencies of attributes with the specified name.
826      * 
827      * @param name the name of the attribute
828      */
829     public Attribute[] removeAttributes(final String name) {
830 
831         /* Get attributes with given name */
832         Attribute[] result = getAttributes(name);
833 
834         /* Remove attributes */
835         attributes.remove(name);
836 
837         return result;
838     }
839 
840     /**
841      * Remove the bandwith field with an associated modifier
842      * 
843      * @param modifier the modifier associated to the bandwith field to remove
844      * 
845      * @return the removed bandwith if present, <tt>null</tt>
846      *         otherwise
847      */
848     public Bandwith removeBandwith(final String modifier) {
849 
850         return (Bandwith) bandwiths.remove(modifier);
851     }
852 
853     /**
854      * Set attribute fields. Please note that previous attributes will be
855      * replaced
856      * 
857      * @param fields the fields to set
858      * 
859      * @throws IllegalArgumentException if one or more field are <tt>null</tt>
860      */
861     public void setAttributes(Attribute[] fields) {
862 
863         if (fields == null) {
864             throw new IllegalArgumentException("Attribute fields cannot be null");
865         }
866 
867         int length = fields.length;
868         HashMap backup = (HashMap) attributes.clone();
869 
870         try {
871 
872             /* Remove current attributes */
873             attributes.clear();
874 
875             /* Add attributes */
876             for (int i = 0; i < length; i++) {
877                 addAttribute(fields[i]);
878             }
879         }
880         catch (IllegalArgumentException exception) {
881 
882             /* An error is occured, so we "rollback" */
883             attributes = backup;
884 
885             /* Rethrow the exception */
886             throw exception;
887         }
888     }
889 
890     /**
891      * Set bandwith fields. Please note that previous bandwiths will be
892      * replaced
893      * 
894      * @param fields the fields to set
895      * 
896      * @throws IllegalArgumentException if one or more field are <tt>null</tt>
897      */
898     public void setBandwiths(Bandwith[] fields) {
899 
900         if (fields == null) {
901             throw new IllegalArgumentException("Bandwith fields cannot be null");
902         }
903 
904         int length = fields.length;
905         HashMap backup = (HashMap) bandwiths.clone();
906 
907         try {
908 
909             /* Remove current bandwiths */
910             bandwiths.clear();
911 
912             /* Add bandwiths */
913             for (int i = 0; i < length; i++) {
914                 addBandwith(fields[i]);
915             }
916         }
917         catch (IllegalArgumentException exception) {
918 
919             /* An error is occured, so we "rollback" */
920             bandwiths = backup;
921 
922             /* Rethrow the exception */
923             throw exception;
924         }
925     }
926 
927     /**
928      * Sets the connection field.
929      * 
930      * @param c the connection field to set
931      */
932     public void setConnection(final Connection c) {
933 
934         //FIXME Prevent the field removal while it isn't specified in the media descriptions
935         this.c = c;
936     }
937 
938     /**
939      * Sets email fields.
940      * 
941      * @param fields the email fields to set
942      * 
943      * @throws IllegalArgumentException if one or more field are <tt>null</tt>
944      */
945     public void setEmails(final Email[] fields) throws IllegalArgumentException {
946 
947         if (fields == null) {
948             throw new IllegalArgumentException("Email fields cannot be null");
949         }
950 
951         int length = fields.length;
952         ArrayList backup = (ArrayList) emails.clone();
953 
954         try {
955 
956             /* Clear current email fields */
957             emails.clear();
958         
959             /* Add email fields */
960             for (int i = 0; i < length; i++) {
961 
962                 addEmail(fields[i]);
963             }
964         }
965         catch (IllegalArgumentException exception) {
966 
967             /* Rollback */
968             emails = backup;
969 
970             /* Rethrow the exception */
971             throw exception;
972         }
973     }
974 
975     /**
976      * Sets the information field.
977      * 
978      * @param i the information field to set
979      */
980     public void setInformation(final Information i) {
981 
982         this.i = i;
983     }
984 
985     /**
986      * Sets the encryption key field.
987      * 
988      * @param k the encryption key field to set
989      */
990     public void setKey(final Key k) {
991 
992         this.k = k;
993     }
994 
995     /**
996      * Sets media descriptions.
997      * 
998      * @param descriptions the media descriptions to set
999      * 
1000      * @throws IllegalArgumentException if one or more descriptions are
1001      *         <tt>null</tt>
1002      */
1003     public void setMediaDescriptions(final MediaDescription[] descriptions) throws IllegalArgumentException, SDPException {
1004 
1005         if (descriptions == null) {
1006             throw new IllegalArgumentException("Media descriptions cannot be null");
1007         }
1008 
1009         int length = descriptions.length;
1010         ArrayList backup = (ArrayList) mediaDescriptions.clone();
1011 
1012         try {
1013 
1014             /* Clear current media descriptions */
1015             mediaDescriptions.clear();
1016         
1017             /* Add media descriptions */
1018             for (int i = 0; i < length; i++) {
1019 
1020                 addMediaDescription(descriptions[i]);
1021             }
1022         }
1023         catch (IllegalArgumentException exception) {
1024 
1025             /* Rollback */
1026             mediaDescriptions = backup;
1027 
1028             /* Rethrow the exception */
1029             throw exception;
1030         }
1031         catch (SDPException sdpException) {
1032 
1033             /* Rollback */
1034             mediaDescriptions = backup;
1035 
1036             /* Rethrow the exception */
1037             throw sdpException;
1038         }
1039     }
1040 
1041     /**
1042      * Sets the origin field.
1043      * 
1044      * @param o the origin field to set
1045      * 
1046      * @throws IllegalArgumentException if the field is <tt>null</tt>
1047      */
1048     public void setOrigin(final Origin o) throws IllegalArgumentException {
1049 
1050         if (o == null) {
1051             throw new IllegalArgumentException("Origin field cannot be null");
1052         }
1053 
1054         this.o = o;
1055     }
1056 
1057     /**
1058      * Sets phone fields.
1059      * 
1060      * @param fields the phone fields to set
1061      * 
1062      * @throws IllegalArgumentException if one or more phone fields are
1063      *         <tt>null</tt>
1064      */
1065     public void setPhones(final Phone[] fields) throws IllegalArgumentException {
1066 
1067         if (fields == null) {
1068             throw new IllegalArgumentException("Phone fields cannot be null");
1069         }
1070 
1071         int length = fields.length;
1072         ArrayList backup = (ArrayList) phones.clone();
1073 
1074         try {
1075 
1076             /* Clear current phone fields */
1077             phones.clear();
1078         
1079             /* Add phone fields */
1080             for (int i = 0; i < length; i++) {
1081 
1082                 addPhone(fields[i]);
1083             }
1084         }
1085         catch (IllegalArgumentException exception) {
1086 
1087             /* Rollback */
1088             phones = backup;
1089 
1090             /* Rethrow the exception */
1091             throw exception;
1092         }
1093     }
1094 
1095     /**
1096      * Sets session name field.
1097      * 
1098      * @param s the session name field to set
1099      * 
1100      * @throws IllegalArgumentException if the field is <tt>null</tt>
1101      */
1102     public void setSessionName(final SessionName s) throws IllegalArgumentException {
1103 
1104         if (s == null) {
1105             throw new IllegalArgumentException("Session name field cannot be null");
1106         }
1107 
1108         this.s = s;
1109     }
1110 
1111     /**
1112      * Sets time descriptions.
1113      * 
1114      * @param descriptions the time descriptions to set
1115      * 
1116      * @throws IllegalArgumentException if one or more description are
1117      *         <tt>null</tt>
1118      */
1119     public void setTimeDescriptions(final TimeDescription[] descriptions) throws IllegalArgumentException {
1120 
1121         if (descriptions == null) {
1122             throw new IllegalArgumentException("Time descriptions cannot be null");
1123         }
1124 
1125         int length = descriptions.length;
1126         ArrayList backup = (ArrayList) timeDescriptions.clone();
1127 
1128         try {
1129 
1130             /* Clear current time descriptions */
1131             timeDescriptions.clear();
1132         
1133             /* Add time descriptions */
1134             for (int i = 0; i < length; i++) {
1135 
1136                 addTimeDescription(descriptions[i]);
1137             }
1138         }
1139         catch (IllegalArgumentException exception) {
1140 
1141             /* Rollback */
1142             timeDescriptions = backup;
1143 
1144             /* Rethrow the exception */
1145             throw exception;
1146         }
1147     }
1148 
1149     /**
1150      * Sets the timezone field.
1151      * 
1152      * @param z the timezone field to set
1153      */
1154     public void setTimeZone(final TimeZone z) {
1155 
1156         this.z = z;
1157     }
1158 
1159     /**
1160      * Sets the uri field.
1161      * 
1162      * @param u the uri field to set
1163      */
1164     public void setUri(final Uri u) {
1165 
1166         this.u = u;
1167     }
1168 
1169     /**
1170      * Sets the version field.
1171      * 
1172      * @param v the version field to set
1173      * 
1174      * @throws IllegalArgumentException if the field is <tt>null</tt>
1175      */
1176     public void setVersion(final Version v) throws IllegalArgumentException {
1177 
1178         if (v == null) {
1179             throw new IllegalArgumentException("Version field cannot be null");
1180         }
1181 
1182         this.v = v;
1183     }
1184 
1185     /**
1186      * Returns a string representation of this description.
1187      * 
1188      * @return A string representation of the description
1189      */
1190     public String toString() {
1191 
1192         /* Add the version field */
1193         StringBuffer result = new StringBuffer(v.toString());
1194         result.append(Field.END_OF_FIELD);
1195 
1196         /* Add the origin field */
1197         result.append(o.toString());
1198         result.append(Field.END_OF_FIELD);
1199 
1200         /* Add the session name field */
1201         result.append(s.toString());
1202         result.append(Field.END_OF_FIELD);
1203 
1204         /* Add the information field, if present */
1205         if (i != null) {
1206             result.append(i.toString());
1207             result.append(Field.END_OF_FIELD);
1208         }
1209 
1210         /* Add the uri field, if present */
1211         if (u != null) {
1212             result.append(u.toString());
1213             result.append(Field.END_OF_FIELD);
1214         }
1215 
1216         /* Add the email fields, if present */
1217         for (Iterator iterator = emails.iterator(); iterator.hasNext();) {
1218             result.append(iterator.next());
1219             result.append(Field.END_OF_FIELD);
1220         }
1221 
1222         /* Add the phone fields, if present */
1223         for (Iterator iterator = phones.iterator(); iterator.hasNext();) {
1224             result.append(iterator.next());
1225             result.append(Field.END_OF_FIELD);
1226         }
1227 
1228         /* Add the connection field, if present */
1229         if (c != null) {
1230             result.append(c.toString());
1231             result.append(Field.END_OF_FIELD);
1232         }
1233 
1234         int size = 0;
1235         
1236         Bandwith[] myBandwiths = getBandwiths();
1237         size = myBandwiths.length;
1238 
1239         /* Add the bandwith fields */
1240         for (int i = 0; i < size; i++) {
1241             result.append(myBandwiths[i]);
1242             result.append(Field.END_OF_FIELD);
1243         }
1244 
1245         /* Add the time descriptions */
1246         for (Iterator i = timeDescriptions.iterator(); i.hasNext();) {
1247             result.append(i.next());
1248             /*
1249              * Don't append END_OF_FIELD because this element is a time
1250              * description
1251              */
1252         }
1253 
1254         /* Add the timezone field, if present */
1255         if (z != null) {
1256             result.append(z.toString());
1257             result.append(Field.END_OF_FIELD);
1258         }
1259 
1260         /* Add the key field, if present */
1261         if (k != null) {
1262             result.append(k.toString());
1263             result.append(Field.END_OF_FIELD);
1264         }
1265 
1266         Attribute[] myAttributes = getAttributes();
1267         size = myAttributes.length;
1268 
1269         /* Add the attribute fields */
1270         for (int i = 0; i < size; i++) {
1271             result.append(myAttributes[i]);
1272             result.append(Field.END_OF_FIELD);
1273         }
1274 
1275         /* Add the media descriptions */
1276         for (Iterator i = mediaDescriptions.iterator(); i.hasNext();) {
1277             result.append(i.next());
1278             /*
1279              * Don't append END_OF_FIELD because this element is a media
1280              * description
1281              */
1282         }
1283 
1284         return result.toString();
1285     }
1286 }