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.registry;
17
18 import org.fourthline.cling.UpnpService;
19 import org.fourthline.cling.UpnpServiceConfiguration;
20 import org.fourthline.cling.model.DiscoveryOptions;
21 import org.fourthline.cling.model.resource.Resource;
22 import org.fourthline.cling.model.ServiceReference;
23 import org.fourthline.cling.model.meta.Device;
24 import org.fourthline.cling.model.meta.LocalDevice;
25 import org.fourthline.cling.model.meta.RemoteDevice;
26 import org.fourthline.cling.model.gena.LocalGENASubscription;
27 import org.fourthline.cling.model.gena.RemoteGENASubscription;
28 import org.fourthline.cling.model.meta.RemoteDeviceIdentity;
29 import org.fourthline.cling.model.meta.Service;
30 import org.fourthline.cling.model.types.DeviceType;
31 import org.fourthline.cling.model.types.ServiceType;
32 import org.fourthline.cling.model.types.UDN;
33 import org.fourthline.cling.protocol.ProtocolFactory;
34
35 import java.net.URI;
36 import java.util.Collection;
37
38 /**
39 * The core of the UPnP stack, keeping track of known devices and resources.
40 * <p>
41 * A running UPnP stack has one <code>Registry</code>. Any discovered device is added
42 * to this registry, as well as any exposed local device. The registry then maintains
43 * these devices continuously (see {@link RegistryMaintainer}) and when needed refreshes
44 * their announcements on the network or removes them when they have expired. The registry
45 * also keeps track of GENA event subscriptions.
46 * </p>
47 * <p>
48 * UPnP client applications typically monitor activity of the registry
49 * via {@link RegistryListener}, they are inherently asynchronous.
50 * </p>
51 * <p>
52 * The registry has to be {@link #shutdown()} properly, so it can notify all participants
53 * on the network that local devices will no longer be available and cancel all
54 * GENA subscriptions.
55 * <p>
56 * An implementation has to be thread-safe.
57 * </p>
58 *
59 * @author Christian Bauer
60 */
61 public interface Registry {
62
63 public UpnpService getUpnpService();
64 public UpnpServiceConfiguration getConfiguration();
65 public ProtocolFactory getProtocolFactory();
66
67 // #################################################################################################
68
69 /**
70 * Typically called internally when the UPnP stack is stopping.
71 * <p>
72 * Unsubscribe all local devices and GENA subscriptions.
73 * </p>
74 */
75 public void shutdown();
76
77 /**
78 * Stops background maintenance (thread) of registered items.
79 * <p>
80 * When paused, the registry will no longer remove expired remote devices if their
81 * discovery announcements stop for some reason (device was turned off). Your local
82 * control point will now see potentially unavailable remote devices. Outbound
83 * GENA subscriptions from your local control point to remote services will not
84 * be renewed automatically anymore, a remote service might drop your subscriptions
85 * if you don't resume maintenance within the subscription's expiration timeout.
86 * </p>
87 * <p>
88 * Local devices and services will not be announced periodically anymore to remote
89 * control points, only when they are manually added are removed from the registry.
90 * The registry will also no longer remove expired inbound GENA subscriptions to
91 * local service from remote control points, if that control point for some reason
92 * stops sending subscription renewal messages.
93 * </p>
94 */
95 public void pause();
96
97 /**
98 * Resumes background maintenance (thread) of registered items.
99 * <p>
100 * A local control point has to handle the following situations when resuming
101 * registry maintenance:
102 * <p>
103 * A remote device registration might have expired. This is the case when the remote
104 * device stopped sending announcements while the registry was paused (maybe because
105 * the device was switched off) and the registry was paused longer than the device
106 * advertisement's maximum age. The registry will not know if the device is still
107 * available when it resumes maintenance. However, it will simply assume that the
108 * remote device is still available and restart its expiration check cycle. That means
109 * a device will finally be removed from the registry, if no further announcements
110 * from the device are received, when the maximum age of the device has elapsed
111 * after the registry resumed operation.
112 * </p>
113 * <p>
114 * Secondly, a remote device registration might not have expired but some of your
115 * outbound GENA subscriptions to its services have not been renewed within the expected renewal
116 * period. Therefore your outbound subscriptions might be invalid, because the remote
117 * service can drop subscriptions when you don't renew them. On resume, the registry
118 * will attempt to send renewals for all outbound GENA subscriptions that require
119 * renewal, on devices that still haven't expired. If renewal fails, your subscription will
120 * end with {@link org.fourthline.cling.model.gena.CancelReason#RENEWAL_FAILED}. Although
121 * you then might conclude that the remote device is no longer available, a GENA renewal
122 * can also fail for other reasons. The remote device will be kept and maintained in the
123 * registry until it announces itself or it expires, even after a failed GENA renewal.
124 * </p>
125 * <p>
126 * If you are providing local devices and services, resuming registry maintenance has
127 * the following effects:
128 * </p>
129 * <p>
130 * Local devices and their services are announced again immediately if the registry
131 * has been paused for longer than half of the device's maximum age. Remote control
132 * points will either see this as a new device advertisement (if they have dropped
133 * your device while you paused maintenance) or as a regular update if you didn't
134 * pause longer than the device's maximum age/expiration timeout.
135 * </p>
136 * <p>
137 * Inbound GENA subscriptions to your local services are active, even in
138 * paused state - remote control points should continue renewing the subscription.
139 * If a remote control point stopped renewing a subscription without unsubscribing
140 * (hard power off), an outdated inbound subscription will be detected when you
141 * resume maintenance. This subscription will be cleaned up immediately on resume.
142 * </p>
143 */
144 public void resume();
145
146 /**
147 * @return <code>true</code> if the registry has currently no running background
148 * maintenance (thread).
149 */
150 public boolean isPaused();
151
152 // #################################################################################################
153
154 public void addListener(RegistryListener listener);
155
156 public void removeListener(RegistryListener listener);
157
158 public Collection<RegistryListener> getListeners();
159
160 /**
161 * Called internally by the UPnP stack when the discovery protocol starts.
162 * <p>
163 * The registry will notify all registered listeners of this event, unless the
164 * given device was already in the registry.
165 * </p>
166 *
167 * @param device The half-hydrated (without services) metadata of the discovered device.
168 * @return <code>false</code> if the device was already registered.
169 */
170 public boolean notifyDiscoveryStart(RemoteDevice device);
171
172 /**
173 * Called internally by the UPnP stack when the discovery protocol stopped abnormally.
174 * <p>
175 * The registry will notify all registered listeners of this event.
176 * </p>
177 *
178 * @param device The half-hydrated (without services) metadata of the discovered device.
179 * @param ex The cause for the interruption of the discovery protocol.
180 */
181 public void notifyDiscoveryFailure(RemoteDevice device, Exception ex);
182
183 // #################################################################################################
184
185 /**
186 * Call this method to add your local device metadata.
187 *
188 * @param localDevice The device to add and maintain.
189 * @throws RegistrationException If a conflict with an already registered device was detected.
190 */
191 public void addDevice(LocalDevice localDevice) throws RegistrationException;
192
193 /**
194 * Call this method to add your local device metadata.
195 *
196 * @param localDevice The device to add and maintain.
197 * @param options Immediately effective when this device is registered.
198 * @throws RegistrationException If a conflict with an already registered device was detected.
199 */
200 public void addDevice(LocalDevice localDevice, DiscoveryOptions options) throws RegistrationException;
201
202 /**
203 * Change the active {@link DiscoveryOptions} for the given (local device) UDN.
204 *
205 * @param options Set to <code>null</code> to disable any options.
206 */
207 public void setDiscoveryOptions(UDN udn, DiscoveryOptions options);
208
209 /**
210 * Get the currently active {@link DiscoveryOptions} for the given (local device) UDN.
211 *
212 * @return <code>null</code> if there are no active discovery options for the given UDN.
213 */
214 public DiscoveryOptions getDiscoveryOptions(UDN udn);
215
216 /**
217 * Called internally by the UPnP discovery protocol.
218 *
219 * @throws RegistrationException If a conflict with an already registered device was detected.
220 */
221 public void addDevice(RemoteDevice remoteDevice) throws RegistrationException;
222
223 /**
224 * Called internally by the UPnP discovery protocol.
225 */
226 public boolean update(RemoteDeviceIdentity rdIdentity);
227
228 /**
229 * Call this to remove your local device metadata.
230 *
231 * @return <code>true</code> if the device was registered and has been removed.
232 */
233 public boolean removeDevice(LocalDevice localDevice);
234
235 /**
236 * Called internally by the UPnP discovery protocol.
237 */
238 public boolean removeDevice(RemoteDevice remoteDevice);
239
240 /**
241 * Call this to remove any device metadata with the given UDN.
242 *
243 * @return <code>true</code> if the device was registered and has been removed.
244 */
245 public boolean removeDevice(UDN udn);
246
247 /**
248 * Clear the registry of all locally registered device metadata.
249 */
250 public void removeAllLocalDevices();
251
252 /**
253 * Clear the registry of all discovered remote device metadata.
254 */
255 public void removeAllRemoteDevices();
256
257 /**
258 * @param udn The device name to lookup.
259 * @param rootOnly If <code>true</code>, only matches of root devices are returned.
260 * @return The registered root or embedded device metadata, or <code>null</code>.
261 */
262 public Device getDevice(UDN udn, boolean rootOnly);
263
264 /**
265 * @param udn The device name to lookup.
266 * @param rootOnly If <code>true</code>, only matches of root devices are returned.
267 * @return The registered root or embedded device metadata, or <code>null</code>.
268 */
269 public LocalDevice getLocalDevice(UDN udn, boolean rootOnly);
270
271 /**
272 * @param udn The device name to lookup.
273 * @param rootOnly If <code>true</code>, only matches of root devices are returned.
274 * @return The registered root or embedded device metadata, or <code>null</code>.
275 */
276 public RemoteDevice getRemoteDevice(UDN udn, boolean rootOnly);
277
278 /**
279 * @return All locally registered device metadata, in no particular order, or an empty collection.
280 */
281 public Collection<LocalDevice> getLocalDevices();
282
283 /**
284 * @return All discovered remote device metadata, in no particular order, or an empty collection.
285 */
286 public Collection<RemoteDevice> getRemoteDevices();
287
288 /**
289 * @return All device metadata, in no particular order, or an empty collection.
290 */
291 public Collection<Device> getDevices();
292
293 /**
294 * @return All device metadata of devices which implement the given type, in no particular order,
295 * or an empty collection.
296 */
297 public Collection<Device> getDevices(DeviceType deviceType);
298
299 /**
300 * @return All device metadata of devices which have a service that implements the given type,
301 * in no particular order, or an empty collection.
302 */
303 public Collection<Device> getDevices(ServiceType serviceType);
304
305 /**
306 * @return Complete service metadata for a service reference or <code>null</code> if no service
307 * for the given reference has been registered.
308 */
309 public Service getService(ServiceReference serviceReference);
310
311 // #################################################################################################
312
313 /**
314 * Stores an arbitrary resource in the registry.
315 *
316 * @param resource The resource to maintain indefinitely (until it is manually removed).
317 */
318 public void addResource(Resource resource);
319
320 /**
321 * Stores an arbitrary resource in the registry.
322 * <p>
323 * Call this method repeatedly to refresh and prevent expiration of the resource.
324 * </p>
325 *
326 * @param resource The resource to maintain.
327 * @param maxAgeSeconds The time after which the registry will automatically remove the resource.
328 */
329 public void addResource(Resource resource, int maxAgeSeconds);
330
331 /**
332 * Removes a resource from the registry.
333 *
334 * @param resource The resource to remove.
335 * @return <code>true</code> if the resource was registered and has been removed.
336 */
337 public boolean removeResource(Resource resource);
338
339 /**
340 * @param pathQuery The path and optional query string of the resource's
341 * registration URI (e.g. <code>/dev/somefile.xml?param=value</code>)
342 * @return Any registered resource that matches the given URI path.
343 * @throws IllegalArgumentException If the given URI was absolute, only path and query are allowed.
344 */
345 public Resource getResource(URI pathQuery) throws IllegalArgumentException;
346
347 /**
348 * @param <T> The required subtype of the {@link org.fourthline.cling.model.resource.Resource}.
349 * @param pathQuery The path and optional query string of the resource's
350 * registration URI (e.g. <code>/dev/somefile.xml?param=value</code>)
351 * @param resourceType The required subtype of the {@link org.fourthline.cling.model.resource.Resource}.
352 * @return Any registered resource that matches the given URI path and subtype.
353 * @throws IllegalArgumentException If the given URI was absolute, only path and query are allowed.
354 */
355 public <T extends Resource> T getResource(Class<T> resourceType, URI pathQuery) throws IllegalArgumentException;
356
357 /**
358 * @return All registered resources, in no particular order, or an empty collection.
359 */
360 public Collection<Resource> getResources();
361
362 /**
363 * @param <T> The required subtype of the {@link org.fourthline.cling.model.resource.Resource}.
364 * @param resourceType The required subtype of the {@link org.fourthline.cling.model.resource.Resource}.
365 * @return Any registered resource that matches the given subtype.
366 */
367 public <T extends Resource> Collection<T> getResources(Class<T> resourceType);
368
369 // #################################################################################################
370
371 /**
372 * Called internally by the UPnP stack, during GENA protocol execution.
373 */
374 public void addLocalSubscription(LocalGENASubscription subscription);
375
376 /**
377 * Called internally by the UPnP stack, during GENA protocol execution.
378 */
379 public LocalGENASubscription getLocalSubscription(String subscriptionId);
380
381 /**
382 * Called internally by the UPnP stack, during GENA protocol execution.
383 */
384 public boolean updateLocalSubscription(LocalGENASubscription subscription);
385
386 /**
387 * Called internally by the UPnP stack, during GENA protocol execution.
388 */
389 public boolean removeLocalSubscription(LocalGENASubscription subscription);
390
391 /**
392 * Called internally by the UPnP stack, during GENA protocol execution.
393 */
394 public void addRemoteSubscription(RemoteGENASubscription subscription);
395
396 /**
397 * Called internally by the UPnP stack, during GENA protocol execution.
398 */
399 public RemoteGENASubscription getRemoteSubscription(String subscriptionId);
400
401 /**
402 * Called internally by the UPnP stack, during GENA protocol execution.
403 */
404 public void updateRemoteSubscription(RemoteGENASubscription subscription);
405
406 /**
407 * Called internally by the UPnP stack, during GENA protocol execution.
408 */
409 public void removeRemoteSubscription(RemoteGENASubscription subscription);
410
411 /**
412 * Called internally by the UPnP stack, during GENA protocol execution.
413 * <p>
414 * When subscribing with a remote host, the remote host might send the
415 * initial event message faster than the response for the subscription
416 * request. This method register that the subscription procedure is
417 * executing.
418 * </p>
419 */
420 public void registerPendingRemoteSubscription(RemoteGENASubscription subscription);
421
422 /**
423 * Called internally by the UPnP stack, during GENA protocol execution.
424 * <p>
425 * Notify that the subscription procedure has terminated.
426 * </p>
427 */
428 public void unregisterPendingRemoteSubscription(RemoteGENASubscription subscription);
429
430 /**
431 * Called internally by the UPnP stack, during GENA protocol execution.
432 * <p>
433 * Get a remote subscription from its subscriptionId. If the subscription can't be found,
434 * wait for one of the pending remote subscription procedures from the registry background
435 * maintainer to terminate, until the subscription has been found or until there are no
436 * more pending subscription procedures.
437 * </p>
438 */
439 public RemoteGENASubscription getWaitRemoteSubscription(String subscriptionId);
440
441 // #################################################################################################
442
443 /**
444 * Manually trigger advertisement messages for all local devices.
445 * <p>
446 * No messages will be send for devices with disabled advertisements, see
447 * {@link DiscoveryOptions}!
448 * </p>
449 */
450 public void advertiseLocalDevices();
451
452 }