View Javadoc
1   /*
2    * Copyright (C) 2013 4th Line GmbH, Switzerland
3    *
4    * The contents of this file are subject to the terms of either the GNU
5    * Lesser General Public License Version 2 or later ("LGPL") or the
6    * Common Development and Distribution License Version 1 or later
7    * ("CDDL") (collectively, the "License"). You may not use this file
8    * except in compliance with the License. See LICENSE.txt for more
9    * information.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14   */
15  
16  package org.fourthline.cling.support.model;
17  
18  import org.w3c.dom.Element;
19  
20  import java.net.URI;
21  import java.util.ArrayList;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Locale;
25  
26  /**
27   * @author Christian Bauer
28   * @author Mario Franco
29   */
30  public abstract class DIDLObject {
31  
32      static public abstract class Property<V> {
33  
34          public interface NAMESPACE {
35          }
36  
37          private V value;
38          final private String descriptorName;
39          final private List<Property<DIDLAttribute>> attributes = new ArrayList<>();
40  
41          protected Property() {
42              this(null, null);
43          }
44  
45          protected Property(String descriptorName) {
46              this(null, descriptorName);
47          }
48  
49          protected Property(V value, String descriptorName) {
50              this.value = value;
51              // TODO Not sure this is a good fix for https://github.com/4thline/cling/issues/62
52              this.descriptorName = descriptorName == null
53                  ? getClass().getSimpleName().toLowerCase(Locale.ROOT).replace("didlobject$property$upnp$", "")
54                  : descriptorName;
55          }
56  
57          protected Property(V value, String descriptorName, List<Property<DIDLAttribute>> attributes) {
58              this.value = value;
59              // TODO Not sure this is a good fix for https://github.com/4thline/cling/issues/62
60              this.descriptorName = descriptorName == null
61                  ? getClass().getSimpleName().toLowerCase(Locale.ROOT).replace("didlobject$property$upnp$", "")
62                  : descriptorName;
63              this.attributes.addAll(attributes);
64          }
65  
66          public V getValue() {
67              return value;
68          }
69  
70          public void setValue(V value) {
71              this.value = value;
72          }
73  
74          public String getDescriptorName() {
75              return descriptorName;
76          }
77  
78          public void setOnElement(Element element) {
79              element.setTextContent(toString());
80              for (Property<DIDLAttribute> attr : attributes) {
81                  element.setAttributeNS(
82                          attr.getValue().getNamespaceURI(),
83                          attr.getValue().getPrefix() + ':' + attr.getDescriptorName(),
84                          attr.getValue().getValue());
85              }
86          }
87  
88          public void addAttribute(Property<DIDLAttribute> attr) {
89              this.attributes.add(attr);
90          }
91  
92          public void removeAttribute(Property<DIDLAttribute> attr) {
93              this.attributes.remove(attr);
94          }
95  
96          public void removeAttribute(String descriptorName) {
97              for (Property<DIDLAttribute> attr : attributes) {
98                  if (attr.getDescriptorName().equals(descriptorName)) {
99                      this.removeAttribute(attr);
100                     break;
101                 }
102             }
103         }
104 
105         public Property<DIDLAttribute> getAttribute(String descriptorName) {
106             for (Property<DIDLAttribute> attr : attributes) {
107                 if (attr.getDescriptorName().equals(descriptorName)) {
108                     return attr;
109                 }
110             }
111             return null;
112         }
113 
114         @Override
115         public String toString() {
116             return getValue() != null ? getValue().toString() : "";
117         }
118 
119         static public class PropertyPersonWithRole extends Property<PersonWithRole> {
120 
121             public PropertyPersonWithRole() {
122             }
123 
124             public PropertyPersonWithRole(String descriptorName) {
125                 super(descriptorName);
126             }
127 
128             public PropertyPersonWithRole(PersonWithRole value, String descriptorName) {
129                 super(value, descriptorName);
130             }
131 
132             @Override
133             public void setOnElement(Element element) {
134                 if (getValue() != null)
135                     getValue().setOnElement(element);
136             }
137         }
138 
139         static public class DC {
140 
141             public interface NAMESPACE extends Property.NAMESPACE {
142                 public static final String URI = "http://purl.org/dc/elements/1.1/";
143             }
144 
145             static public class DESCRIPTION extends Property<String> implements NAMESPACE {
146                 public DESCRIPTION() {
147                 }
148 
149                 public DESCRIPTION(String value) {
150                     super(value, null);
151                 }
152             }
153 
154             static public class PUBLISHER extends Property<Person> implements NAMESPACE {
155                 public PUBLISHER() {
156                 }
157 
158                 public PUBLISHER(Person value) {
159                     super(value, null);
160                 }
161             }
162 
163             static public class CONTRIBUTOR extends Property<Person> implements NAMESPACE {
164                 public CONTRIBUTOR() {
165                 }
166 
167                 public CONTRIBUTOR(Person value) {
168                     super(value, null);
169                 }
170             }
171 
172             static public class DATE extends Property<String> implements NAMESPACE {
173                 public DATE() {
174                 }
175 
176                 public DATE(String value) {
177                     super(value, null);
178                 }
179             }
180 
181             static public class LANGUAGE extends Property<String> implements NAMESPACE {
182                 public LANGUAGE() {
183                 }
184 
185                 public LANGUAGE(String value) {
186                     super(value, null);
187                 }
188             }
189 
190             static public class RELATION extends Property<URI> implements NAMESPACE {
191                 public RELATION() {
192                 }
193 
194                 public RELATION(URI value) {
195                     super(value, null);
196                 }
197             }
198 
199             static public class RIGHTS extends Property<String> implements NAMESPACE {
200                 public RIGHTS() {
201                 }
202 
203                 public RIGHTS(String value) {
204                     super(value, null);
205                 }
206             }
207         }
208         
209         static public abstract class SEC {
210 
211             public interface NAMESPACE extends Property.NAMESPACE {
212                 public static final String URI = "http://www.sec.co.kr/";
213             }
214             
215             static public class CAPTIONINFOEX extends Property<URI> implements NAMESPACE {
216                 public CAPTIONINFOEX() {
217                     this(null);
218                 }
219                 
220                 public CAPTIONINFOEX(URI value) {
221                     super(value, "CaptionInfoEx");
222                 }
223 
224                 public CAPTIONINFOEX(URI value, List<Property<DIDLAttribute>> attributes) {
225                     super(value, "CaptionInfoEx", attributes);
226                 }
227             }
228             
229             static public class CAPTIONINFO extends Property<URI> implements NAMESPACE {
230                 public CAPTIONINFO() {
231                     this(null);
232                 }
233                 
234                 public CAPTIONINFO(URI value) {
235                     super(value, "CaptionInfo");
236                 }
237 
238                 public CAPTIONINFO(URI value, List<Property<DIDLAttribute>> attributes) {
239                     super(value, "CaptionInfo", attributes);
240                 }
241             }
242             
243             static public class TYPE extends Property<DIDLAttribute> implements NAMESPACE {
244                 public TYPE() {
245                     this(null);
246                 }
247 
248                 public TYPE(DIDLAttribute value) {
249                     super(value, "type");
250                 }
251             }
252             
253             
254         }
255 
256         static public abstract class UPNP {
257 
258             public interface NAMESPACE extends Property.NAMESPACE {
259                 public static final String URI = "urn:schemas-upnp-org:metadata-1-0/upnp/";
260             }
261 
262             static public class ARTIST extends PropertyPersonWithRole implements NAMESPACE {
263                 public ARTIST() {
264                 }
265 
266                 public ARTIST(PersonWithRole value) {
267                     super(value, null);
268                 }
269             }
270 
271             static public class ACTOR extends PropertyPersonWithRole implements NAMESPACE {
272                 public ACTOR() {
273                 }
274 
275                 public ACTOR(PersonWithRole value) {
276                     super(value, null);
277                 }
278             }
279 
280             static public class AUTHOR extends PropertyPersonWithRole implements NAMESPACE {
281                 public AUTHOR() {
282                 }
283 
284                 public AUTHOR(PersonWithRole value) {
285                     super(value, null);
286                 }
287             }
288 
289             static public class PRODUCER extends Property<Person> implements NAMESPACE {
290                 public PRODUCER() {
291                 }
292 
293                 public PRODUCER(Person value) {
294                     super(value, null);
295                 }
296             }
297 
298             static public class DIRECTOR extends Property<Person> implements NAMESPACE {
299                 public DIRECTOR() {
300                 }
301 
302                 public DIRECTOR(Person value) {
303                     super(value, null);
304                 }
305             }
306 
307             static public class GENRE extends Property<String> implements NAMESPACE {
308                 public GENRE() {
309                 }
310 
311                 public GENRE(String value) {
312                     super(value, null);
313                 }
314             }
315 
316             static public class ALBUM extends Property<String> implements NAMESPACE {
317                 public ALBUM() {
318                 }
319 
320                 public ALBUM(String value) {
321                     super(value, null);
322                 }
323             }
324 
325             static public class PLAYLIST extends Property<String> implements NAMESPACE {
326                 public PLAYLIST() {
327                 }
328 
329                 public PLAYLIST(String value) {
330                     super(value, null);
331                 }
332             }
333 
334             static public class REGION extends Property<String> implements NAMESPACE {
335                 public REGION() {
336                 }
337 
338                 public REGION(String value) {
339                     super(value, null);
340                 }
341             }
342 
343             static public class RATING extends Property<String> implements NAMESPACE {
344                 public RATING() {
345                 }
346 
347                 public RATING(String value) {
348                     super(value, null);
349                 }
350             }
351 
352             static public class TOC extends Property<String> implements NAMESPACE {
353                 public TOC() {
354                 }
355 
356                 public TOC(String value) {
357                     super(value, null);
358                 }
359             }
360 
361             static public class ALBUM_ART_URI extends Property<URI> implements NAMESPACE {
362                 public ALBUM_ART_URI() {
363                     this(null);
364                 }
365 
366                 public ALBUM_ART_URI(URI value) {
367                     super(value, "albumArtURI");
368                 }
369 
370                 public ALBUM_ART_URI(URI value, List<Property<DIDLAttribute>> attributes) {
371                     super(value, "albumArtURI", attributes);
372                 }
373             }
374 
375             static public class ARTIST_DISCO_URI extends Property<URI> implements NAMESPACE {
376                 public ARTIST_DISCO_URI() {
377                     this(null);
378                 }
379 
380                 public ARTIST_DISCO_URI(URI value) {
381                     super(value, "artistDiscographyURI");
382                 }
383             }
384 
385             static public class LYRICS_URI extends Property<URI> implements NAMESPACE {
386                 public LYRICS_URI() {
387                     this(null);
388                 }
389 
390                 public LYRICS_URI(URI value) {
391                     super(value, "lyricsURI");
392                 }
393             }
394 
395             static public class STORAGE_TOTAL extends Property<Long> implements NAMESPACE {
396                 public STORAGE_TOTAL() {
397                     this(null);
398                 }
399 
400                 public STORAGE_TOTAL(Long value) {
401                     super(value, "storageTotal");
402                 }
403             }
404 
405             static public class STORAGE_USED extends Property<Long> implements NAMESPACE {
406                 public STORAGE_USED() {
407                     this(null);
408                 }
409 
410                 public STORAGE_USED(Long value) {
411                     super(value, "storageUsed");
412                 }
413             }
414 
415             static public class STORAGE_FREE extends Property<Long> implements NAMESPACE {
416                 public STORAGE_FREE() {
417                     this(null);
418                 }
419 
420                 public STORAGE_FREE(Long value) {
421                     super(value, "storageFree");
422                 }
423             }
424 
425             static public class STORAGE_MAX_PARTITION extends Property<Long> implements NAMESPACE {
426                 public STORAGE_MAX_PARTITION() {
427                     this(null);
428                 }
429 
430                 public STORAGE_MAX_PARTITION(Long value) {
431                     super(value, "storageMaxPartition");
432                 }
433             }
434 
435             static public class STORAGE_MEDIUM extends Property<StorageMedium> implements NAMESPACE {
436                 public STORAGE_MEDIUM() {
437                     this(null);
438                 }
439 
440                 public STORAGE_MEDIUM(StorageMedium value) {
441                     super(value, "storageMedium");
442                 }
443             }
444 
445             static public class LONG_DESCRIPTION extends Property<String> implements NAMESPACE {
446                 public LONG_DESCRIPTION() {
447                     this(null);
448                 }
449 
450                 public LONG_DESCRIPTION(String value) {
451                     super(value, "longDescription");
452                 }
453             }
454 
455             static public class ICON extends Property<URI> implements NAMESPACE {
456                 public ICON() {
457                     this(null);
458                 }
459 
460                 public ICON(URI value) {
461                     super(value, "icon");
462                 }
463             }
464 
465             static public class RADIO_CALL_SIGN extends Property<String> implements NAMESPACE {
466                 public RADIO_CALL_SIGN() {
467                     this(null);
468                 }
469 
470                 public RADIO_CALL_SIGN(String value) {
471                     super(value, "radioCallSign");
472                 }
473             }
474 
475             static public class RADIO_STATION_ID extends Property<String> implements NAMESPACE {
476                 public RADIO_STATION_ID() {
477                     this(null);
478                 }
479 
480                 public RADIO_STATION_ID(String value) {
481                     super(value, "radioStationID");
482                 }
483             }
484 
485             static public class RADIO_BAND extends Property<String> implements NAMESPACE {
486                 public RADIO_BAND() {
487                     this(null);
488                 }
489 
490                 public RADIO_BAND(String value) {
491                     super(value, "radioBand");
492                 }
493             }
494 
495             static public class CHANNEL_NR extends Property<Integer> implements NAMESPACE {
496                 public CHANNEL_NR() {
497                     this(null);
498                 }
499 
500                 public CHANNEL_NR(Integer value) {
501                     super(value, "channelNr");
502                 }
503             }
504 
505             static public class CHANNEL_NAME extends Property<String> implements NAMESPACE {
506                 public CHANNEL_NAME() {
507                     this(null);
508                 }
509 
510                 public CHANNEL_NAME(String value) {
511                     super(value, "channelName");
512                 }
513             }
514 
515             static public class SCHEDULED_START_TIME extends Property<String> implements NAMESPACE {
516                 public SCHEDULED_START_TIME() {
517                     this(null);
518                 }
519 
520                 public SCHEDULED_START_TIME(String value) {
521                     super(value, "scheduledStartTime");
522                 }
523             }
524 
525             static public class SCHEDULED_END_TIME extends Property<String> implements NAMESPACE {
526                 public SCHEDULED_END_TIME() {
527                     this(null);
528                 }
529 
530                 public SCHEDULED_END_TIME(String value) {
531                     super(value, "scheduledEndTime");
532                 }
533             }
534 
535             static public class DVD_REGION_CODE extends Property<Integer> implements NAMESPACE {
536                 public DVD_REGION_CODE() {
537                     this(null);
538                 }
539 
540                 public DVD_REGION_CODE(Integer value) {
541                     super(value, "DVDRegionCode");
542                 }
543             }
544 
545             static public class ORIGINAL_TRACK_NUMBER extends Property<Integer> implements NAMESPACE {
546                 public ORIGINAL_TRACK_NUMBER() {
547                     this(null);
548                 }
549 
550                 public ORIGINAL_TRACK_NUMBER(Integer value) {
551                     super(value, "originalTrackNumber");
552                 }
553             }
554 
555 
556             static public class USER_ANNOTATION extends Property<String> implements NAMESPACE {
557                 public USER_ANNOTATION() {
558                     this(null);
559                 }
560 
561                 public USER_ANNOTATION(String value) {
562                     super(value, "userAnnotation");
563                 }
564             }
565         }
566 
567         static public abstract class DLNA {
568 
569             public interface NAMESPACE extends Property.NAMESPACE {
570                 public static final String URI = "urn:schemas-dlna-org:metadata-1-0/";
571             }
572 
573             static public class PROFILE_ID extends Property<DIDLAttribute> implements NAMESPACE {
574                 public PROFILE_ID() {
575                     this(null);
576                 }
577 
578                 public PROFILE_ID(DIDLAttribute value) {
579                     super(value, "profileID");
580                 }
581             }
582         }
583     }
584 
585     public static class Class {
586 
587         protected String value;
588         protected String friendlyName;
589         protected boolean includeDerived;
590 
591         public Class() {
592         }
593 
594         public Class(String value) {
595             this.value = value;
596         }
597 
598         public Class(String value, String friendlyName) {
599             this.value = value;
600             this.friendlyName = friendlyName;
601         }
602 
603         public Class(String value, String friendlyName, boolean includeDerived) {
604             this.value = value;
605             this.friendlyName = friendlyName;
606             this.includeDerived = includeDerived;
607         }
608 
609         public String getValue() {
610             return value;
611         }
612 
613         public void setValue(String value) {
614             this.value = value;
615         }
616 
617         public String getFriendlyName() {
618             return friendlyName;
619         }
620 
621         public void setFriendlyName(String friendlyName) {
622             this.friendlyName = friendlyName;
623         }
624 
625         public boolean isIncludeDerived() {
626             return includeDerived;
627         }
628 
629         public void setIncludeDerived(boolean includeDerived) {
630             this.includeDerived = includeDerived;
631         }
632 
633         public boolean equals(DIDLObject instance) {
634             return getValue().equals(instance.getClazz().getValue());
635 
636         }
637     }
638 
639     protected String id;
640     protected String parentID;
641 
642     protected String title; // DC
643     protected String creator; // DC
644 
645     protected boolean restricted = true; // Let's just assume read-only is default
646     protected WriteStatus writeStatus; // UPNP
647     protected Class clazz; // UPNP
648 
649     protected List<Res> resources = new ArrayList<>();
650     protected List<Property> properties = new ArrayList<>();
651 
652     protected List<DescMeta> descMetadata = new ArrayList<>();
653 
654     protected DIDLObject() {
655     }
656 
657     protected DIDLObject(DIDLObject other) {
658         this(other.getId(),
659              other.getParentID(),
660              other.getTitle(),
661              other.getCreator(),
662              other.isRestricted(),
663              other.getWriteStatus(),
664              other.getClazz(),
665              other.getResources(),
666              other.getProperties(),
667              other.getDescMetadata()
668         );
669     }
670 
671     protected DIDLObject(String id, String parentID, String title, String creator, boolean restricted, WriteStatus writeStatus, Class clazz, List<Res> resources, List<Property> properties, List<DescMeta> descMetadata) {
672         this.id = id;
673         this.parentID = parentID;
674         this.title = title;
675         this.creator = creator;
676         this.restricted = restricted;
677         this.writeStatus = writeStatus;
678         this.clazz = clazz;
679         this.resources = resources;
680         this.properties = properties;
681         this.descMetadata = descMetadata;
682     }
683 
684     public String getId() {
685         return id;
686     }
687 
688     public DIDLObject setId(String id) {
689         this.id = id;
690         return this;
691     }
692 
693     public String getParentID() {
694         return parentID;
695     }
696 
697     public DIDLObject setParentID(String parentID) {
698         this.parentID = parentID;
699         return this;
700     }
701 
702     public String getTitle() {
703         return title;
704     }
705 
706     public DIDLObject setTitle(String title) {
707         this.title = title;
708         return this;
709     }
710 
711     public String getCreator() {
712         return creator;
713     }
714 
715     public DIDLObject setCreator(String creator) {
716         this.creator = creator;
717         return this;
718     }
719 
720     public boolean isRestricted() {
721         return restricted;
722     }
723 
724     public DIDLObject setRestricted(boolean restricted) {
725         this.restricted = restricted;
726         return this;
727     }
728 
729     public WriteStatus getWriteStatus() {
730         return writeStatus;
731     }
732 
733     public DIDLObject setWriteStatus(WriteStatus writeStatus) {
734         this.writeStatus = writeStatus;
735         return this;
736     }
737 
738     public Res getFirstResource() {
739         return getResources().size() > 0 ? getResources().get(0) : null;
740     }
741 
742     public List<Res> getResources() {
743         return resources;
744     }
745 
746     public DIDLObject setResources(List<Res> resources) {
747         this.resources = resources;
748         return this;
749     }
750 
751     public DIDLObject addResource(Res resource) {
752         getResources().add(resource);
753         return this;
754     }
755 
756     public Class getClazz() {
757         return clazz;
758     }
759 
760     public DIDLObject setClazz(Class clazz) {
761         this.clazz = clazz;
762         return this;
763     }
764 
765     public List<Property> getProperties() {
766         return properties;
767     }
768 
769     public DIDLObject setProperties(List<Property> properties) {
770         this.properties = properties;
771         return this;
772     }
773 
774     public DIDLObject addProperty(Property property) {
775         if (property == null) return this;
776         getProperties().add(property);
777         return this;
778     }
779 
780     public DIDLObject replaceFirstProperty(Property property) {
781         if (property == null) return this;
782         Iterator<Property> it = getProperties().iterator();
783         while (it.hasNext()) {
784             Property p = it.next();
785             if (p.getClass().isAssignableFrom(property.getClass()))
786                 it.remove();
787         }
788         addProperty(property);
789         return this;
790     }
791 
792     public DIDLObject replaceProperties(java.lang.Class<? extends Property> propertyClass, Property[] properties) {
793         if (properties.length == 0) return this;
794         removeProperties(propertyClass);
795         return addProperties(properties);
796     }
797 
798     public DIDLObject addProperties(Property[] properties) {
799         if (properties == null) return this;
800         for (Property property : properties) {
801             addProperty(property);
802         }
803         return this;
804     }
805 
806     public DIDLObject removeProperties(java.lang.Class<? extends Property> propertyClass) {
807         Iterator<Property> it = getProperties().iterator();
808         while (it.hasNext()) {
809             Property property = it.next();
810             if (propertyClass.isInstance(property))
811                 it.remove();
812         }
813         return this;
814     }
815 
816     public boolean hasProperty(java.lang.Class<? extends Property> propertyClass) {
817         for (Property property : getProperties()) {
818             if (propertyClass.isInstance(property)) return true;
819         }
820         return false;
821     }
822 
823     public <V> Property<V> getFirstProperty(java.lang.Class<? extends Property<V>> propertyClass) {
824         for (Property property : getProperties()) {
825             if (propertyClass.isInstance(property)) return property;
826         }
827         return null;
828     }
829 
830     public <V> Property<V> getLastProperty(java.lang.Class<? extends Property<V>> propertyClass) {
831         Property found = null;
832         for (Property property : getProperties()) {
833             if (propertyClass.isInstance(property)) found = property;
834         }
835         return found;
836     }
837 
838     public <V> Property<V>[] getProperties(java.lang.Class<? extends Property<V>> propertyClass) {
839         List<Property<V>> list = new ArrayList<>();
840         for (Property property : getProperties()) {
841             if (propertyClass.isInstance(property))
842                 list.add(property);
843         }
844         return list.toArray(new Property[list.size()]);
845     }
846 
847     public <V> Property<V>[] getPropertiesByNamespace(java.lang.Class<? extends Property.NAMESPACE> namespace) {
848         List<Property<V>> list = new ArrayList<>();
849         for (Property property : getProperties()) {
850             if (namespace.isInstance(property))
851                 list.add(property);
852         }
853         return list.toArray(new Property[list.size()]);
854     }
855 
856     public <V> V getFirstPropertyValue(java.lang.Class<? extends Property<V>> propertyClass) {
857         Property<V> prop = getFirstProperty(propertyClass);
858         return prop == null ? null : prop.getValue();
859     }
860 
861     public <V> List<V> getPropertyValues(java.lang.Class<? extends Property<V>> propertyClass) {
862         List<V> list = new ArrayList<>();
863         for (Property property : getProperties(propertyClass)) {
864             list.add((V) property.getValue());
865         }
866         return list;
867     }
868 
869     public List<DescMeta> getDescMetadata() {
870         return descMetadata;
871     }
872 
873     public void setDescMetadata(List<DescMeta> descMetadata) {
874         this.descMetadata = descMetadata;
875     }
876 
877     public DIDLObject addDescMetadata(DescMeta descMetadata) {
878         getDescMetadata().add(descMetadata);
879         return this;
880     }
881 
882     @Override
883     public boolean equals(Object o) {
884         if (this == o) return true;
885         if (o == null || getClass() != o.getClass()) return false;
886 
887         DIDLObject that = (DIDLObject) o;
888 
889         if (!id.equals(that.id)) return false;
890 
891         return true;
892     }
893 
894     @Override
895     public int hashCode() {
896         return id.hashCode();
897     }
898 }