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 }