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 }