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.meta;
17  
18  import org.fourthline.cling.model.Namespace;
19  import org.fourthline.cling.model.profile.RemoteClientInfo;
20  import org.fourthline.cling.model.profile.DeviceDetailsProvider;
21  import org.fourthline.cling.model.resource.DeviceDescriptorResource;
22  import org.fourthline.cling.model.resource.IconResource;
23  import org.fourthline.cling.model.resource.ServiceControlResource;
24  import org.fourthline.cling.model.resource.ServiceDescriptorResource;
25  import org.fourthline.cling.model.resource.ServiceEventSubscriptionResource;
26  import org.fourthline.cling.model.resource.Resource;
27  import org.fourthline.cling.model.ValidationError;
28  import org.fourthline.cling.model.ValidationException;
29  import org.fourthline.cling.model.types.DeviceType;
30  import org.fourthline.cling.model.types.ServiceId;
31  import org.fourthline.cling.model.types.ServiceType;
32  import org.fourthline.cling.model.types.UDN;
33  
34  import java.net.URI;
35  import java.util.ArrayList;
36  import java.util.Arrays;
37  import java.util.Collection;
38  import java.util.List;
39  
40  /**
41   * The metadata of a device created on this host, by application code.
42   *
43   * @author Christian Bauer
44   */
45  public class LocalDevice extends Device<DeviceIdentity, LocalDevice, LocalService> {
46  
47      final private DeviceDetailsProvider deviceDetailsProvider;
48  
49      public LocalDevice(DeviceIdentity identity) throws ValidationException {
50          super(identity);
51          this.deviceDetailsProvider = null;
52      }
53  
54      public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
55                         LocalService service) throws ValidationException {
56          super(identity, type, details, null, new LocalService[]{service});
57          this.deviceDetailsProvider = null;
58      }
59  
60      public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetailsProvider deviceDetailsProvider,
61                         LocalService service) throws ValidationException {
62          super(identity, type, null, null, new LocalService[]{service});
63          this.deviceDetailsProvider = deviceDetailsProvider;
64      }
65  
66      public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetailsProvider deviceDetailsProvider,
67                         LocalService service, LocalDevice embeddedDevice) throws ValidationException {
68          super(identity, type, null, null, new LocalService[]{service}, new LocalDevice[]{embeddedDevice});
69          this.deviceDetailsProvider = deviceDetailsProvider;
70      }
71  
72      public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
73                         LocalService service, LocalDevice embeddedDevice) throws ValidationException {
74          super(identity, type, details, null, new LocalService[]{service}, new LocalDevice[]{embeddedDevice});
75          this.deviceDetailsProvider = null;
76      }
77  
78      public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
79                         LocalService[] services) throws ValidationException {
80          super(identity, type, details, null, services);
81          this.deviceDetailsProvider = null;
82      }
83  
84      public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
85                         LocalService[] services, LocalDevice[] embeddedDevices) throws ValidationException {
86          super(identity, type, details, null, services, embeddedDevices);
87          this.deviceDetailsProvider = null;
88      }
89  
90      public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
91                         Icon icon, LocalService service) throws ValidationException {
92          super(identity, type, details, new Icon[]{icon}, new LocalService[]{service});
93          this.deviceDetailsProvider = null;
94      }
95  
96      public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
97                         Icon icon, LocalService service, LocalDevice embeddedDevice) throws ValidationException {
98          super(identity, type, details, new Icon[]{icon}, new LocalService[]{service}, new LocalDevice[]{embeddedDevice});
99          this.deviceDetailsProvider = null;
100     }
101 
102     public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
103                        Icon icon, LocalService[] services) throws ValidationException {
104         super(identity, type, details, new Icon[]{icon}, services);
105         this.deviceDetailsProvider = null;
106     }
107 
108     public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetailsProvider deviceDetailsProvider,
109                        Icon icon, LocalService[] services) throws ValidationException {
110         super(identity, type, null, new Icon[]{icon}, services);
111         this.deviceDetailsProvider = deviceDetailsProvider;
112     }
113 
114     public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
115                        Icon icon, LocalService[] services, LocalDevice[] embeddedDevices) throws ValidationException {
116         super(identity, type, details, new Icon[]{icon}, services, embeddedDevices);
117         this.deviceDetailsProvider = null;
118     }
119 
120     public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
121                        Icon[] icons, LocalService service) throws ValidationException {
122         super(identity, type, details, icons, new LocalService[]{service});
123         this.deviceDetailsProvider = null;
124     }
125 
126     public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
127                        Icon[] icons, LocalService service, LocalDevice embeddedDevice) throws ValidationException {
128         super(identity, type, details, icons, new LocalService[]{service}, new LocalDevice[]{embeddedDevice});
129         this.deviceDetailsProvider = null;
130     }
131 
132     public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetailsProvider deviceDetailsProvider,
133                        Icon[] icons, LocalService service, LocalDevice embeddedDevice) throws ValidationException {
134         super(identity, type, null, icons, new LocalService[]{service}, new LocalDevice[]{embeddedDevice});
135         this.deviceDetailsProvider = deviceDetailsProvider;
136     }
137 
138     public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
139                        Icon[] icons, LocalService[] services) throws ValidationException {
140         super(identity, type, details, icons, services);
141         this.deviceDetailsProvider = null;
142     }
143 
144     public LocalDevice(DeviceIdentity identity, DeviceType type, DeviceDetails details,
145                        Icon[] icons, LocalService[] services, LocalDevice[] embeddedDevices) throws ValidationException {
146         super(identity, type, details, icons, services, embeddedDevices);
147         this.deviceDetailsProvider = null;
148     }
149 
150     public LocalDevice(DeviceIdentity identity, UDAVersion version, DeviceType type, DeviceDetails details,
151                        Icon[] icons, LocalService[] services, LocalDevice[] embeddedDevices) throws ValidationException {
152         super(identity, version, type, details, icons, services, embeddedDevices);
153         this.deviceDetailsProvider = null;
154     }
155 
156     public LocalDevice(DeviceIdentity identity, UDAVersion version, DeviceType type, DeviceDetailsProvider deviceDetailsProvider,
157                        Icon[] icons, LocalService[] services, LocalDevice[] embeddedDevices) throws ValidationException {
158         super(identity, version, type, null, icons, services, embeddedDevices);
159         this.deviceDetailsProvider = deviceDetailsProvider;
160     }
161 
162     public DeviceDetailsProvider getDeviceDetailsProvider() {
163         return deviceDetailsProvider;
164     }
165 
166     @Override
167     public DeviceDetails getDetails(RemoteClientInfo info) {
168         if (getDeviceDetailsProvider() != null) {
169             return getDeviceDetailsProvider().provide(info);
170         }
171         return this.getDetails();
172     }
173 
174     @Override
175     public LocalService[] getServices() {
176         return this.services != null ? this.services : new LocalService[0];
177     }
178 
179     @Override
180     public LocalDevice[] getEmbeddedDevices() {
181         return this.embeddedDevices != null ? this.embeddedDevices : new LocalDevice[0];
182     }
183 
184     @Override
185     public LocalDevice newInstance(UDN udn, UDAVersion version, DeviceType type, DeviceDetails details,
186                                    Icon[] icons, LocalService[] services, List<LocalDevice> embeddedDevices)
187             throws ValidationException {
188         return new LocalDevice(
189                 new DeviceIdentity(udn, getIdentity().getMaxAgeSeconds()),
190                 version, type, details, icons,
191                 services,
192                 embeddedDevices.size() > 0 ? embeddedDevices.toArray(new LocalDevice[embeddedDevices.size()]) : null
193         );
194     }
195 
196     @Override
197     public LocalService newInstance(ServiceType serviceType, ServiceId serviceId,
198                                     URI descriptorURI, URI controlURI, URI eventSubscriptionURI,
199                                     Action<LocalService>[] actions, StateVariable<LocalService>[] stateVariables) throws ValidationException {
200         return new LocalService(
201                 serviceType, serviceId,
202                 actions, stateVariables
203         );
204     }
205 
206     @Override
207     public LocalDevice[] toDeviceArray(Collection<LocalDevice> col) {
208         return col.toArray(new LocalDevice[col.size()]);
209     }
210 
211     @Override
212     public LocalService[] newServiceArray(int size) {
213         return new LocalService[size];
214     }
215 
216     @Override
217     public LocalService[] toServiceArray(Collection<LocalService> col) {
218         return col.toArray(new LocalService[col.size()]);
219     }
220 
221     @Override
222     public List<ValidationError> validate() {
223         List<ValidationError> errors = new ArrayList<>();
224         errors.addAll(super.validate());
225 
226         // We have special rules for local icons, the URI must always be a relative path which will
227         // be added to the device base URI!
228         if (hasIcons()) {
229             for (Icon icon : getIcons()) {
230                 if (icon.getUri().isAbsolute()) {
231                     errors.add(new ValidationError(
232                             getClass(),
233                             "icons",
234                             "Local icon URI can not be absolute: " + icon.getUri()
235                     ));
236                 }
237                 if (icon.getUri().toString().contains("../")) {
238                     errors.add(new ValidationError(
239                             getClass(),
240                             "icons",
241                             "Local icon URI must not contain '../': " + icon.getUri()
242                     ));
243                 }
244                 if (icon.getUri().toString().startsWith("/")) {
245                     errors.add(new ValidationError(
246                             getClass(),
247                             "icons",
248                             "Local icon URI must not start with '/': " + icon.getUri()
249                     ));
250                 }
251             }
252         }
253 
254         return errors;
255     }
256 
257     @Override
258     public Resource[] discoverResources(Namespace namespace) {
259         List<Resource> discovered = new ArrayList<>();
260 
261         // Device
262         if (isRoot()) {
263             // This should guarantee that each logical local device tree (with all its embedded devices) has only
264             // one device descriptor resource - because only one device in the tree isRoot().
265             discovered.add(new DeviceDescriptorResource(namespace.getDescriptorPath(this), this));
266         }
267 
268         // Services
269         for (LocalService service : getServices()) {
270 
271             discovered.add(
272                     new ServiceDescriptorResource(namespace.getDescriptorPath(service), service)
273             );
274 
275             // Control
276             discovered.add(
277                     new ServiceControlResource(namespace.getControlPath(service), service)
278             );
279 
280             // Event subscription
281             discovered.add(
282                     new ServiceEventSubscriptionResource(namespace.getEventSubscriptionPath(service), service)
283             );
284 
285         }
286 
287         // Icons
288         for (Icon icon : getIcons()) {
289             discovered.add(new IconResource(namespace.prefixIfRelative(this, icon.getUri()), icon));
290         }
291 
292         // Embedded devices
293         if (hasEmbeddedDevices()) {
294             for (Device embeddedDevice : getEmbeddedDevices()) {
295                 discovered.addAll(Arrays.asList(embeddedDevice.discoverResources(namespace)));
296             }
297         }
298 
299         return discovered.toArray(new Resource[discovered.size()]);
300     }
301 
302     @Override
303     public LocalDevice getRoot() {
304         if (isRoot()) return this;
305         LocalDevice current = this;
306         while (current.getParentDevice() != null) {
307             current = current.getParentDevice();
308         }
309         return current;
310     }
311 
312     @Override
313     public LocalDevice findDevice(UDN udn) {
314         return find(udn, this);
315     }
316 
317 }