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;
17  
18  import org.fourthline.cling.model.message.header.UpnpHeader;
19  
20  import java.io.ByteArrayInputStream;
21  import java.util.LinkedHashMap;
22  import java.util.LinkedList;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.logging.Level;
26  import java.util.logging.Logger;
27  import org.fourthline.cling.model.message.UpnpHeaders;
28  import org.fourthline.cling.support.model.dlna.message.header.DLNAHeader;
29  
30  /**
31   * Provides UPnP header API in addition to plain multi-map HTTP header access.
32   *
33   * @author Mario Franco
34   * @author Christian Bauer
35   */
36  public class DLNAHeaders extends UpnpHeaders {
37  
38      private static final Logger log = Logger.getLogger(DLNAHeaders.class.getName());
39  
40      protected Map<DLNAHeader.Type, List<UpnpHeader>> parsedDLNAHeaders;
41  
42      public DLNAHeaders() {
43      }
44  
45      public DLNAHeaders(Map<String, List<String>> headers) {
46          super(headers);
47      }
48  
49      public DLNAHeaders(ByteArrayInputStream inputStream) {
50          super(inputStream);
51      }
52      
53      @Override
54      protected void parseHeaders() {
55          if (parsedHeaders == null) super.parseHeaders();
56          
57          // This runs as late as possible and only when necessary (getter called and map is dirty)
58          parsedDLNAHeaders = new LinkedHashMap<>();
59          log.log(Level.FINE, "Parsing all HTTP headers for known UPnP headers: {0}", size());
60          for (Entry<String, List<String>> entry : entrySet()) {
61  
62              if (entry.getKey() == null) continue; // Oh yes, the JDK has 'null' HTTP headers
63  
64              DLNAHeader.Type type = DLNAHeader.Type.getByHttpName(entry.getKey());
65              if (type == null) {
66                  log.log(Level.FINE, "Ignoring non-UPNP HTTP header: {0}", entry.getKey());
67                  continue;
68              }
69  
70              for (String value : entry.getValue()) {
71                  UpnpHeader upnpHeader = DLNAHeader.newInstance(type, value);
72                  if (upnpHeader == null || upnpHeader.getValue() == null) {
73                      log.log(Level.FINE, "Ignoring known but non-parsable header (value violates the UDA specification?) '{0}': {1}", new Object[]{type.getHttpName(), value});
74                  } else {
75                      addParsedValue(type, upnpHeader);
76                  }
77              }
78          }
79      }
80  
81      protected void addParsedValue(DLNAHeader.Type type, UpnpHeader value) {
82          log.log(Level.FINE, "Adding parsed header: {0}", value);
83          List<UpnpHeader> list = parsedDLNAHeaders.get(type);
84          if (list == null) {
85              list = new LinkedList<>();
86              parsedDLNAHeaders.put(type, list);
87          }
88          list.add(value);
89      }
90  
91      @Override
92      public List<String> put(String key, List<String> values) {
93          parsedDLNAHeaders = null;
94          return super.put(key, values);
95      }
96  
97      @Override
98      public void add(String key, String value) {
99          parsedDLNAHeaders = null;
100         super.add(key, value);
101     }
102 
103     @Override
104     public List<String> remove(Object key) {
105         parsedDLNAHeaders = null;
106         return super.remove(key);
107     }
108 
109     @Override
110     public void clear() {
111         parsedDLNAHeaders = null;
112         super.clear();
113     }
114 
115     public boolean containsKey(DLNAHeader.Type type) {
116         if (parsedDLNAHeaders == null) parseHeaders();
117         return parsedDLNAHeaders.containsKey(type);
118     }
119 
120     public List<UpnpHeader> get(DLNAHeader.Type type) {
121         if (parsedDLNAHeaders == null) parseHeaders();
122         return parsedDLNAHeaders.get(type);
123     }
124 
125     public void add(DLNAHeader.Type type, UpnpHeader value) {
126         super.add(type.getHttpName(), value.getString());
127         if (parsedDLNAHeaders != null)
128             addParsedValue(type, value);
129     }
130 
131     public void remove(DLNAHeader.Type type) {
132         super.remove(type.getHttpName());
133         if (parsedDLNAHeaders != null)
134             parsedDLNAHeaders.remove(type);
135     }
136 
137     public UpnpHeader[] getAsArray(DLNAHeader.Type type) {
138         if (parsedDLNAHeaders == null) parseHeaders();
139         return parsedDLNAHeaders.get(type) != null
140                 ? parsedDLNAHeaders.get(type).toArray(new UpnpHeader[parsedDLNAHeaders.get(type).size()])
141                 : new UpnpHeader[0];
142     }
143 
144     public UpnpHeader getFirstHeader(DLNAHeader.Type type) {
145         return getAsArray(type).length > 0
146                 ? getAsArray(type)[0]
147                 : null;
148     }
149 
150     public <H extends UpnpHeader> H getFirstHeader(DLNAHeader.Type type, Class<H> subtype) {
151         UpnpHeader[] headers = getAsArray(type);
152         if (headers.length == 0) return null;
153 
154         for (UpnpHeader header : headers) {
155             if (subtype.isAssignableFrom(header.getClass())) {
156                 return (H) header;
157             }
158         }
159         return null;
160     }
161 
162     @Override
163     public void log() {
164         if (log.isLoggable(Level.FINE)) {
165             super.log();
166             if (parsedDLNAHeaders != null && parsedDLNAHeaders.size() > 0) {
167                 log.fine("########################## PARSED DLNA HEADERS ##########################");
168                 for (Map.Entry<DLNAHeader.Type, List<UpnpHeader>> entry : parsedDLNAHeaders.entrySet()) {
169                     log.log(Level.FINE, "=== TYPE: {0}", entry.getKey());
170                     for (UpnpHeader upnpHeader : entry.getValue()) {
171                         log.log(Level.FINE, "HEADER: {0}", upnpHeader);
172                     }
173                 }
174             }
175             log.fine("####################################################################");
176         }
177     }
178 
179 }