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.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 }