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.profile;
17  
18  import org.fourthline.cling.model.meta.DeviceDetails;
19  
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.regex.Pattern;
24  
25  /**
26   * Selects device details based on a regex and the client's HTTP headers.
27   * <p>
28   * This provider will lookup and match a {@link DeviceDetails} entry in a
29   * given map that is keyed by HTTP header name and a regular expression pattern.
30   * If the control point sent an HTTP header that matches an entry's name,
31   * and the value of the control points header matches the pattern of the entry,
32   * the value of the entry is applied. This is a case-insensitive pattern match.
33   * </p>
34   *
35   * @author Mario Franco
36   * @author Christian Bauer
37   */
38  public class HeaderDeviceDetailsProvider implements DeviceDetailsProvider {
39  
40      public static class Key {
41  
42          final String headerName;
43          final String valuePattern;
44          final Pattern pattern;
45  
46          public Key(String headerName, String valuePattern) {
47              this.headerName = headerName;
48              this.valuePattern = valuePattern;
49              this.pattern = Pattern.compile(valuePattern, Pattern.CASE_INSENSITIVE);
50          }
51  
52          public String getHeaderName() {
53              return headerName;
54          }
55  
56          public String getValuePattern() {
57              return valuePattern;
58          }
59  
60          public boolean isValuePatternMatch(String value) {
61              return pattern.matcher(value).matches();
62          }
63      }
64  
65  
66      final private DeviceDetails defaultDeviceDetails;
67      final private Map<Key, DeviceDetails> headerDetails;
68  
69      public HeaderDeviceDetailsProvider(DeviceDetails defaultDeviceDetails) {
70          this(defaultDeviceDetails, null);
71      }
72  
73      public HeaderDeviceDetailsProvider(DeviceDetails defaultDeviceDetails,
74                                         Map<Key, DeviceDetails> headerDetails) {
75          this.defaultDeviceDetails = defaultDeviceDetails;
76          this.headerDetails = headerDetails != null ? headerDetails : new HashMap();
77      }
78  
79      public DeviceDetails getDefaultDeviceDetails() {
80          return defaultDeviceDetails;
81      }
82  
83      public Map<Key, DeviceDetails> getHeaderDetails() {
84          return headerDetails;
85      }
86  
87      public DeviceDetails provide(RemoteClientInfo info) {
88          if (info == null || info.getRequestHeaders().isEmpty()) return getDefaultDeviceDetails();
89  
90          for (Key key : getHeaderDetails().keySet()) {
91              List<String> headerValues;
92              if ((headerValues = info.getRequestHeaders().get(key.getHeaderName())) == null) continue;
93              for (String headerValue : headerValues) {
94                  if (key.isValuePatternMatch(headerValue))
95                      return getHeaderDetails().get(key);
96              }
97          }
98          return getDefaultDeviceDetails();
99      }
100 
101 }