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