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.dlna.message.header;
17  
18  import org.seamless.util.Exceptions;
19  
20  import java.util.HashMap;
21  import java.util.Map;
22  import java.util.logging.Level;
23  import java.util.logging.Logger;
24  import org.fourthline.cling.model.message.header.InvalidHeaderException;
25  import org.fourthline.cling.model.message.header.UpnpHeader;
26  
27  /**
28   * Transforms known and standardized DLNA/HTTP headers from/to string representation.
29   * <p>
30   * The {@link #newInstance(org.fourthline.cling.support.model.dlna.message.header.DLNAHeader.Type, String)} method
31   * attempts to instantiate the best header subtype for a given header (name) and string value.
32   * </p>
33   *
34   * @author Mario Franco
35   * @author Christian Bauer
36   */
37  public abstract class DLNAHeader<T> extends UpnpHeader<T> {
38  
39      final private static Logger log = Logger.getLogger(DLNAHeader.class.getName());
40  
41      /**
42       * Maps a standardized DLNA header to potential header subtypes.
43       */
44      public static enum Type {
45  
46          TimeSeekRange("TimeSeekRange.dlna.org", TimeSeekRangeHeader.class),
47          XSeekRange("X-Seek-Range", TimeSeekRangeHeader.class),
48          PlaySpeed("PlaySpeed.dlna.org", PlaySpeedHeader.class),
49          AvailableSeekRange("availableSeekRange.dlna.org", AvailableSeekRangeHeader.class),
50          GetAvailableSeekRange("getAvailableSeekRange.dlna.org", GetAvailableSeekRangeHeader.class),
51          GetContentFeatures("getcontentFeatures.dlna.org", GetContentFeaturesHeader.class),
52          ContentFeatures("contentFeatures.dlna.org", ContentFeaturesHeader.class),
53          TransferMode("transferMode.dlna.org", TransferModeHeader.class),
54          FriendlyName("friendlyName.dlna.org", FriendlyNameHeader.class),
55          PeerManager("peerManager.dlna.org", PeerManagerHeader.class),
56          AvailableRange("Available-Range.dlna.org", AvailableRangeHeader.class),
57          SCID("scid.dlna.org", SCIDHeader.class),
58          RealTimeInfo("realTimeInfo.dlna.org", RealTimeInfoHeader.class),
59          ScmsFlag("scmsFlag.dlna.org", ScmsFlagHeader.class),
60          WCT("WCT.dlna.org", WCTHeader.class),
61          MaxPrate("Max-Prate.dlna.org", MaxPrateHeader.class),
62          EventType("Event-Type.dlna.org", EventTypeHeader.class),
63          Supported("Supported", SupportedHeader.class),
64          BufferInfo("Buffer-Info.dlna.org", BufferInfoHeader.class),
65          RTPH264DeInterleaving("rtp-h264-deint-buf-cap.dlna.org", BufferBytesHeader.class),
66          RTPAACDeInterleaving("rtp-aac-deint-buf-cap.dlna.org", BufferBytesHeader.class),
67          RTPAMRDeInterleaving("rtp-amr-deint-buf-cap.dlna.org", BufferBytesHeader.class),
68          RTPAMRWBPlusDeInterleaving("rtp-amrwbplus-deint-buf-cap.dlna.org", BufferBytesHeader.class),
69          PRAGMA("PRAGMA", PragmaHeader.class);
70              
71          private static Map<String, Type> byName = new HashMap<String, Type>() {{
72              for (Type t : Type.values()) {
73                  put(t.getHttpName(), t);
74              }
75          }};
76  
77          private String httpName;
78          private Class<? extends DLNAHeader>[] headerTypes;
79  
80          @SafeVarargs
81          private Type(String httpName, Class<? extends DLNAHeader>... headerClass) {
82              this.httpName = httpName;
83              this.headerTypes = headerClass;
84          }
85  
86          public String getHttpName() {
87              return httpName;
88          }
89  
90          public Class<? extends DLNAHeader>[] getHeaderTypes() {
91              return headerTypes;
92          }
93  
94          public boolean isValidHeaderType(Class<? extends DLNAHeader> clazz) {
95              for (Class<? extends DLNAHeader> permissibleType : getHeaderTypes()) {
96                  if (permissibleType.isAssignableFrom(clazz)) {
97                      return true;
98                  }
99              }
100             return false;
101         }
102 
103         /**
104          * @param httpName A case-insensitive HTTP header name.
105          */
106         public static Type getByHttpName(String httpName) {
107             if (httpName == null) return null;
108         	return byName.get(httpName);
109         }
110     }
111 
112 
113 
114     /**
115      * Create a new instance of a {@link DLNAHeader} subtype that matches the given type and value.
116      * <p>
117      * This method iterates through all potential header subtype classes as declared in {@link Type}.
118      * It creates a new instance of the subtype class and calls its {@link #setString(String)} method.
119      * If no {@link org.fourthline.cling.model.message.header.InvalidHeaderException} is thrown, the subtype
120      * instance is returned.
121      * </p>
122      *
123      * @param type The type (or name) of the header.
124      * @param headerValue The value of the header.
125      * @return The best matching header subtype instance, or <code>null</code> if no subtype can be found.
126      */
127     public static DLNAHeader newInstance(DLNAHeader.Type type, String headerValue) {
128 
129         // Try all the UPnP headers and see if one matches our value parsers
130         DLNAHeader upnpHeader = null;
131         for (int i = 0; i < type.getHeaderTypes().length && upnpHeader == null; i++) {
132             Class<? extends DLNAHeader> headerClass = type.getHeaderTypes()[i];
133             try {
134                 log.finest("Trying to parse '" + type + "' with class: " + headerClass.getSimpleName());
135                 upnpHeader = headerClass.newInstance();
136                 if (headerValue != null) {
137                     upnpHeader.setString(headerValue);
138                 }
139             } catch (InvalidHeaderException ex) {
140                 log.finest("Invalid header value for tested type: " + headerClass.getSimpleName() + " - " + ex.getMessage());
141                 upnpHeader = null;
142             } catch (Exception ex) {
143                 log.severe("Error instantiating header of type '" + type + "' with value: " + headerValue);
144                 log.log(Level.SEVERE, "Exception root cause: ", Exceptions.unwrap(ex));
145             }
146 
147         }
148         return upnpHeader;
149     }
150 }