View Javadoc

1   /*
2    * jSDP: A Java implementation of SDP protocol Copyright (C) 2007 Claudio Di
3    * Vita
4    */
5   
6   package net.sourceforge.jsdp;
7   
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>MediaDescription</tt> identifies the set of medias that may be
16   * received. It includes:
17   * <ul>
18   * <li>A media type (e.g., audio, video, etc.)</li>
19   * <li>A port number (or set of ports)</li>
20   * <li>A protocol to be used (e.g., RTP/AVP)</li>
21   * <li>Set of media formats which correspond to attributes</li>
22   * </ul>
23   * 
24   * @see Attribute
25   * 
26   * @since 0.1.0
27   * 
28   * @version 1.1
29   * 
30   * @author <a href="mailto:cdivita@users.sourceforge.net">Claudio Di Vita</a>
31   */
32  public class MediaDescription implements Description {
33  
34      /** The class Stream Unique Identifier, SUID */
35      private static final long serialVersionUID = 2260842521161330113L;
36  
37      /** The media field */
38      protected Media m;
39  
40      /** The information field */
41      protected Information i;
42  
43      /** The connection field */
44      protected Connection c;
45  
46      /** The bandwith fields */
47      protected HashMap bandwiths;
48  
49      /** The key field */
50      protected Key k;
51  
52      /** The attribute fields */
53      protected HashMap attributes;
54  
55      /**
56       * 
57       */
58      private MediaDescription() {
59  
60          super();
61      }
62  
63      /**
64       * Creates a new <tt>MediaDescription</tt>.
65       * 
66       * @param media the media field
67       * 
68       * @throws IllegalArgumentException if the media field is <tt>null</tt>
69       */
70      public MediaDescription(final Media media) throws IllegalArgumentException {
71  
72          super();
73  
74          setMedia(media);
75  
76          bandwiths = new HashMap();
77          attributes = new HashMap();
78      }
79  
80      /**
81       * Adds an attribute field. If an <tt>Attribute</tt> with the same name is
82       * already present it will be added.
83       * 
84       * @param field the attribute field to set
85       * 
86       * @throws IllegalArgumentException if the field is <tt>null</tt>
87       */
88      public void addAttribute(final Attribute field) throws IllegalArgumentException {
89  
90          if (field == null) {
91              throw new IllegalArgumentException("An attribute field cannot be null");
92          }
93  
94          /* Get attribute name */
95          String name = field.getName();
96  
97          /* An object with the same name is already present */
98          if (attributes.containsKey(name)) {
99  
100             List values = null;
101             Object maybe = attributes.get(name);
102 
103             /* There are many attributes with that name */
104             if (maybe instanceof List) {
105 
106                 values = (List) maybe;
107             }
108             /* There is only an attribute with that name */
109             else {
110 
111                 /* Get previous attribute */
112                 Attribute previous = (Attribute) maybe;
113 
114                 /*
115                  * Create a list that contains all the attributes with the given
116                  * name
117                  */
118                 values = new LinkedList();
119 
120                 /* Add the previous attribute to list */
121                 values.add(previous);
122 
123                 attributes.put(field.getName(), values);
124             }
125 
126             values.add(field);
127 
128         }
129         /* An attribute with given name is not present */
130         else {
131 
132             attributes.put(field.getName(), field);
133         }
134     }
135 
136     /**
137      * Adds a bandwith field. If a <tt>Bandwith</tt> with the same modifier is
138      * already present it will be replaced.
139      * 
140      * @param field the bandwith field to set
141      * 
142      * @throws IllegalArgumentException if the bandwith field is <tt>null</tt>
143      */
144     public void addBandwith(final Bandwith field) throws IllegalArgumentException {
145 
146         if (field == null) {
147             throw new IllegalArgumentException("A bandwith field cannot be null");
148         }
149 
150         bandwiths.put(field.getModifier(), field);
151     }
152 
153     /**
154      * Remove all attribute fields contained in the description.
155      */
156     public void clearAttributes() {
157 
158         attributes.clear();
159     }
160 
161     /**
162      * Remove all bandwith fields contained in the description.
163      */
164     public void clearBandwiths() {
165 
166         bandwiths.clear();
167     }
168 
169     /*
170      * (non-Javadoc)
171      * 
172      * @see java.lang.Object#clone()
173      */
174     public Object clone() {
175 
176         MediaDescription clone = new MediaDescription();
177 
178         clone.m = (Media) this.m.clone();
179         clone.i = (Information) this.i.clone();
180         clone.c = (Connection) this.c.clone();
181         clone.bandwiths = (HashMap) this.bandwiths.clone();
182         clone.k = (Key) this.k.clone();
183         clone.attributes = (HashMap) this.attributes.clone();
184 
185         return clone;
186     }
187 
188     /**
189      * Returns the attribute with the specified name. If there are multiple
190      * occurencies of attributes with that name, the first one is returned
191      * 
192      * @param name the name of the attribute
193      * 
194      * @return an attribute field
195      */
196     public Attribute getAttribute(final String name) {
197 
198         Attribute result = null;
199         Object maybe = attributes.get(name);
200 
201         if (maybe != null) {
202 
203             if (maybe instanceof List) {
204 
205                 List values = (List) maybe;
206 
207                 result = (Attribute) values.get(0);
208             }
209             else {
210 
211                 result = (Attribute) maybe;
212             }
213         }
214 
215         return result;
216     }
217 
218     /**
219      * Returns a specified occurence of an attribute with the specified name.
220      * 
221      * @param name the name of the attribute
222      * @param index the occurence index
223      * 
224      * @return an attribute field
225      */
226     public Attribute getAttribute(final String name, final int index) {
227 
228         Attribute result = null;
229         Object maybe = attributes.get(name);
230 
231         if ((maybe != null) && (maybe instanceof List)) {
232 
233             List values = (List) maybe;
234 
235             result = (Attribute) values.get(index);
236         }
237 
238         return result;
239     }
240 
241     /**
242      * Returns all attribute fields.
243      * 
244      * @return an array that contains the attribute fields contained in the
245      *         description
246      */
247     public Attribute[] getAttributes() {
248 
249         Object maybe = null;
250         List values = null;
251 
252         Collection result = new LinkedList();
253 
254         for (Iterator i = attributes.values().iterator(); i.hasNext();) {
255 
256             maybe = i.next();
257 
258             if (maybe instanceof Attribute) {
259 
260                 result.add(maybe);
261             }
262             else {
263 
264                 values = (List) maybe;
265 
266                 for (Iterator j = values.iterator(); j.hasNext();) {
267 
268                     result.add(j.next());
269                 }
270             }
271         }
272 
273         return (Attribute[]) result.toArray(new Attribute[result.size()]);
274     }
275 
276     /**
277      * Returns the attribute fields with the specified name.
278      * 
279      * <p>
280      * If there is only an occurence of that attribute the length of returned
281      * array is <tt>1</tt>, instead if there aren't attributes with the given
282      * name the length of returned array is <tt>0</tt>
283      * </p>
284      * 
285      * @param name the name of the attribute
286      * 
287      * @return an array of attribute fields
288      */
289     public Attribute[] getAttributes(final String name) {
290 
291         Attribute[] result;
292         Object maybe = attributes.get(name);
293 
294         if (maybe != null) {
295 
296             if (maybe instanceof List) {
297 
298                 List values = (List) maybe;
299 
300                 result = (Attribute[]) values.toArray(new Attribute[values.size()]);
301             }
302             else {
303 
304                 result = new Attribute[1];
305                 result[0] = (Attribute) maybe;
306             }
307         }
308         else {
309             result = new Attribute[0];
310         }
311 
312         return result;
313     }
314 
315     /**
316      * Returns the number of attribute fields with the specified name.
317      
318      * @param name the name of the attribute
319      
320      * @return an integer
321      */
322     public int getAttributesCount(final String name) {
323 
324         int result = 0;
325         Object maybe = attributes.get(name);
326 
327         if (maybe != null) {
328 
329             if (maybe instanceof List) {
330 
331                 List values = (List) maybe;
332 
333                 result = values.size();
334             }
335             else {
336 
337                 result = 1;
338             }
339         }
340 
341         return result;
342     }
343 
344     /**
345      * Returns the bandwith field with a specified modifier.
346      * 
347      * @param modifier the bandwith modifier
348      * 
349      * @return the bandwith field specified by modifier if present,
350      *         <tt>null</tt> otherwise
351      */
352     public Bandwith getBandwith(final String modifier) {
353 
354         return (Bandwith) this.bandwiths.get(modifier);
355     }
356 
357     /**
358      * Returns the bandwith fields.
359      * 
360      * @return an array that contains the bandwith fields contained in the
361      *         description
362      */
363     public Bandwith[] getBandwiths() {
364 
365         Bandwith[] values = new Bandwith[bandwiths.size()];
366         Iterator iterator = bandwiths.values().iterator();
367 
368         for (int j = 0; j < values.length; j++) {
369             values[j] = (Bandwith) iterator.next();
370         }
371 
372         return values;
373     }
374 
375     /**
376      * Returns the connection field.
377      * 
378      * @return the connection field is present, <tt>null</tt> otherwise
379      */
380     public Connection getConnection() {
381 
382         return c;
383     }
384 
385     /**
386      * Returns the information field.
387      * 
388      * @return the information field if is present, <tt>null</tt> otherwise
389      */
390     public Information getInformation() {
391 
392         return i;
393     }
394 
395     /**
396      * Returns the encryption key field.
397      * 
398      * @return the encryption key field if present, <tt>null</tt> otherwise
399      */
400     public Key getKey() {
401 
402         return k;
403     }
404 
405     /**
406      * Returns the media field.
407      * 
408      * @return the media field
409      */
410     public Media getMedia() {
411 
412         return m;
413     }
414 
415     /**
416      * Indicates if an attribute with a specified name is present.
417      * 
418      * @param name the name of the attribute
419      * 
420      * @return <tt>true</tt> if the attribute is present,
421      *         <tt>false</tt> otherwise
422      */
423     public boolean hasAttribute(String name) {
424 
425         boolean result = false;
426 
427         if (name != null) {
428             result = attributes.containsKey(name);
429         }
430 
431         return result;
432     }
433 
434     /**
435      * Indicates if the connection field is present.
436      * 
437      * @return <tt>true</tt> if the connection field is present,
438      *         <tt>false</tt> otherwise
439      */
440     public boolean hasConnection() {
441 
442         return c != null;
443     }
444 
445     /**
446      * Indicates if the information field is present.
447      * 
448      * @return <tt>true</tt> if the information field is present,
449      *         <tt>false</tt> otherwise
450      */
451     public boolean hasInformation() {
452 
453         return i != null;
454     }
455 
456     /**
457      * Indicates if the encryption key field is present.
458      * 
459      * @return <tt>true</tt> if the encryption key field is present,
460      *         <tt>false</tt> otherwise
461      */
462     public boolean hasKey() {
463 
464         return k != null;
465     }
466 
467     /**
468      * Removes the attribute field with an associated name. If there are multiple
469      * occurencies of attributes with that name, the first one is removed
470      * 
471      * @param name the name of the attribute field to remove
472      * 
473      * @return the removed <tt>Attribute</tt> if present, <tt>null</tt>
474      *         otherwise
475      */
476     public Attribute removeAttribute(final String name) {
477 
478         Attribute a = null;
479         Object maybe = attributes.get(name);
480 
481         if (maybe != null) {
482 
483             if (maybe instanceof List) {
484 
485                 List values = (List) maybe;
486 
487                 /* Remove the first occurence of the attribute */
488                 a = (Attribute) values.remove(0);
489 
490                 /* Remove multiple attributes values, if empty */
491                 if (values.isEmpty()) {
492                     attributes.remove(name);
493                 }
494             }
495             else {
496                 a = (Attribute) attributes.remove(name);
497             }
498         }
499 
500         return a;
501     }
502 
503     /**
504      * Removes a specified occurence of an attribute field with the specified
505      * name.
506      * 
507      * @param name the name of the attribute
508      * @param index the occurence index
509      * 
510      * @return the removed field
511      */
512     public Attribute removeAttribute(final String name, final int index) {
513 
514         Attribute a = null;
515         Object maybe = attributes.get(name);
516 
517         if ((maybe != null) && (maybe instanceof List)) {
518 
519             List values = (List) maybe;
520 
521             a = (Attribute) values.remove(index);
522         }
523 
524         return a;
525     }
526 
527     /**
528      * Remove all occurencies of attributes with the specified name.
529      * 
530      * @param name the name of the attribute
531      */
532     public Attribute[] removeAttributes(final String name) {
533 
534         /* Get attributes with given name */
535         Attribute[] result = getAttributes(name);
536 
537         /* Remove attributes */
538         attributes.remove(name);
539 
540         return result;
541     }
542 
543     /**
544      * Remove the bandwith field with an associated modifier
545      * 
546      * @param modifier the modifier associated to the bandwith field to remove
547      * 
548      * @return the removed <tt>Bandwith</tt> if present, <tt>null</tt>
549      *         otherwise
550      */
551     public Bandwith removeBandwith(final String modifier) {
552         return (Bandwith) bandwiths.remove(modifier);
553     }
554 
555     /**
556      * Set attribute fields. Please note that previous attributes will be
557      * replaced
558      * 
559      * @param fields the fields to set
560      * 
561      * @throws IllegalArgumentException if one or more field are <tt>null</tt>
562      */
563     public void setAttributes(Attribute[] fields) {
564 
565         if (fields == null) {
566             throw new IllegalArgumentException("Attribute fields cannot be null");
567         }
568 
569         int length = fields.length;
570         HashMap backup = (HashMap) attributes.clone();
571 
572         try {
573 
574             /* Remove current attributes */
575             attributes.clear();
576 
577             /* Add attributes */
578             for (int i = 0; i < length; i++) {
579                 addAttribute(fields[i]);
580             }
581         }
582         catch (IllegalArgumentException exception) {
583 
584             /* An error is occured, so we "rollback" */
585             attributes = backup;
586 
587             /* Rethrow the exception */
588             throw exception;
589         }
590     }
591 
592     /**
593      * Set bandwith fields. Please note that previous bandwiths will be
594      * replaced
595      * 
596      * @param fields the fields to set
597      * 
598      * @throws IllegalArgumentException if one or more field are <tt>null</tt>
599      */
600     public void setBandwiths(Bandwith[] fields) {
601 
602         if (fields == null) {
603             throw new IllegalArgumentException("Bandwith fields cannot be null");
604         }
605 
606         int length = fields.length;
607         HashMap backup = (HashMap) bandwiths.clone();
608 
609         try {
610 
611             /* Remove current bandwiths */
612             bandwiths.clear();
613 
614             /* Add bandwiths */
615             for (int i = 0; i < length; i++) {
616                 addBandwith(fields[i]);
617             }
618         }
619         catch (IllegalArgumentException exception) {
620 
621             /* An error is occured, so we "rollback" */
622             bandwiths = backup;
623 
624             /* Rethrow the exception */
625             throw exception;
626         }
627     }
628 
629     /**
630      * Sets the connection field.
631      * 
632      * @param c the field to set. It can be <tt>null</tt>
633      */
634     public void setConnection(final Connection c) {
635 
636         this.c = c;
637     }
638 
639     /**
640      * Sets the information field.
641      * 
642      * @param i the field to set. It can be <tt>null</tt>
643      */
644     public void setInformation(final Information i) {
645 
646         this.i = i;
647     }
648 
649     /**
650      * Sets the encryption key field.
651      * 
652      * @param k the field to set. It can be <tt>null</tt>
653      */
654     public void setKey(final Key k) {
655 
656         this.k = k;
657     }
658 
659     /**
660      * Sets the media field.
661      * 
662      * @param m the field to set
663      * 
664      * @throws IllegalArgumentException if the field is <tt>null</tt>
665      */
666     public void setMedia(final Media m) throws IllegalArgumentException {
667 
668         if (m == null) {
669             throw new IllegalArgumentException("The media field cannot be null");
670         }
671 
672         this.m = m;
673     }
674 
675     /**
676      * Returns a string representation of the description.
677      * 
678      * @return a string representation of the description
679      */
680     public String toString() {
681 
682         /* Add the media field */
683         StringBuffer result = new StringBuffer(m.toString());
684         result.append(Field.END_OF_FIELD);
685 
686         /* Add the information field, if present */
687         if (i != null) {
688             result.append(i.toString());
689             result.append(Field.END_OF_FIELD);
690         }
691 
692         /* Add the connection field, if present */
693         if (c != null) {
694             result.append(c.toString());
695             result.append(Field.END_OF_FIELD);
696         }
697 
698         int size = 0;
699         
700         Bandwith[] myBandwiths = getBandwiths();
701         size = myBandwiths.length;
702 
703         /* Add the bandwith fields */
704         for (int i = 0; i < size; i++) {
705             result.append(myBandwiths[i]);
706             result.append(Field.END_OF_FIELD);
707         }
708 
709         /* Add the key field, if present */
710         if (k != null) {
711             result.append(k.toString());
712             result.append(Field.END_OF_FIELD);
713 
714         }
715 
716         Attribute[] myAttributes = getAttributes();
717         size = myAttributes.length;
718 
719         /* Add the attribute fields */
720         for (int i = 0; i < size; i++) {
721             result.append(myAttributes[i]);
722             result.append(Field.END_OF_FIELD);
723         }
724 
725         return result.toString();
726     }
727 }