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.protocol.async;
17  
18  import org.fourthline.cling.UpnpService;
19  import org.fourthline.cling.model.Location;
20  import org.fourthline.cling.model.NetworkAddress;
21  import org.fourthline.cling.model.message.discovery.OutgoingNotificationRequest;
22  import org.fourthline.cling.model.message.discovery.OutgoingNotificationRequestDeviceType;
23  import org.fourthline.cling.model.message.discovery.OutgoingNotificationRequestRootDevice;
24  import org.fourthline.cling.model.message.discovery.OutgoingNotificationRequestServiceType;
25  import org.fourthline.cling.model.message.discovery.OutgoingNotificationRequestUDN;
26  import org.fourthline.cling.model.meta.LocalDevice;
27  import org.fourthline.cling.model.types.NotificationSubtype;
28  import org.fourthline.cling.model.types.ServiceType;
29  import org.fourthline.cling.protocol.SendingAsync;
30  import org.fourthline.cling.transport.RouterException;
31  
32  import java.util.ArrayList;
33  import java.util.List;
34  import java.util.logging.Logger;
35  
36  /**
37   * Sending notification messages for a registered local device.
38   * <p>
39   * Sends all required (dozens) of messages three times, waits between 0 and 150
40   * milliseconds between each bulk sending procedure.
41   * </p>
42   *
43   * @author Christian Bauer
44   */
45  public abstract class SendingNotification extends SendingAsync {
46  
47      final private static Logger log = Logger.getLogger(SendingNotification.class.getName());
48  
49      private LocalDevice device;
50  
51      public SendingNotification(UpnpService upnpService, LocalDevice device) {
52          super(upnpService);
53          this.device = device;
54      }
55  
56      public LocalDevice getDevice() {
57          return device;
58      }
59  
60      protected void execute() throws RouterException {
61  
62          List<NetworkAddress> activeStreamServers =
63              getUpnpService().getRouter().getActiveStreamServers(null);
64          if (activeStreamServers.size() == 0) {
65              log.fine("Aborting notifications, no active stream servers found (network disabled?)");
66              return;
67          }
68  
69          // Prepare it once, it's the same for each repetition
70          List<Location> descriptorLocations = new ArrayList<>();
71          for (NetworkAddress activeStreamServer : activeStreamServers) {
72              descriptorLocations.add(
73                      new Location(
74                              activeStreamServer,
75                              getUpnpService().getConfiguration().getNamespace().getDescriptorPathString(getDevice())
76                      )
77              );
78          }
79  
80          for (int i = 0; i < getBulkRepeat(); i++) {
81              try {
82  
83                  for (Location descriptorLocation : descriptorLocations) {
84                      sendMessages(descriptorLocation);
85                  }
86  
87                  // UDA 1.0 is silent about this but UDA 1.1 recomments "a few hundred milliseconds"
88                  log.finer("Sleeping " + getBulkIntervalMilliseconds() + " milliseconds");
89                  Thread.sleep(getBulkIntervalMilliseconds());
90  
91              } catch (InterruptedException ex) {
92                  log.warning("Advertisement thread was interrupted: " + ex);
93              }
94          }
95      }
96  
97      protected int getBulkRepeat() {
98          return 3; // UDA 1.0 says maximum 3 times for alive messages, let's just do it for all
99      }
100 
101     protected int getBulkIntervalMilliseconds() {
102         return 150;
103     }
104 
105     public void sendMessages(Location descriptorLocation) throws RouterException {
106         log.finer("Sending root device messages: " + getDevice());
107         List<OutgoingNotificationRequest> rootDeviceMsgs =
108                 createDeviceMessages(getDevice(), descriptorLocation);
109         for (OutgoingNotificationRequest upnpMessage : rootDeviceMsgs) {
110             getUpnpService().getRouter().send(upnpMessage);
111         }
112 
113         if (getDevice().hasEmbeddedDevices()) {
114             for (LocalDevice embeddedDevice : getDevice().findEmbeddedDevices()) {
115                 log.finer("Sending embedded device messages: " + embeddedDevice);
116                 List<OutgoingNotificationRequest> embeddedDeviceMsgs =
117                         createDeviceMessages(embeddedDevice, descriptorLocation);
118                 for (OutgoingNotificationRequest upnpMessage : embeddedDeviceMsgs) {
119                     getUpnpService().getRouter().send(upnpMessage);
120                 }
121             }
122         }
123 
124         List<OutgoingNotificationRequest> serviceTypeMsgs =
125                 createServiceTypeMessages(getDevice(), descriptorLocation);
126         if (serviceTypeMsgs.size() > 0) {
127             log.finer("Sending service type messages");
128             for (OutgoingNotificationRequest upnpMessage : serviceTypeMsgs) {
129                 getUpnpService().getRouter().send(upnpMessage);
130             }
131         }
132     }
133 
134     protected List<OutgoingNotificationRequest> createDeviceMessages(LocalDevice device,
135                                                                      Location descriptorLocation) {
136         List<OutgoingNotificationRequest> msgs = new ArrayList<>();
137 
138         // See the tables in UDA 1.0 section 1.1.2
139 
140         if (device.isRoot()) {
141             msgs.add(
142                     new OutgoingNotificationRequestRootDevice(
143                             descriptorLocation,
144                             device,
145                             getNotificationSubtype()
146                     )
147             );
148         }
149 
150         msgs.add(
151                 new OutgoingNotificationRequestUDN(
152                         descriptorLocation, device, getNotificationSubtype()
153                 )
154         );
155         msgs.add(
156                 new OutgoingNotificationRequestDeviceType(
157                         descriptorLocation, device, getNotificationSubtype()
158                 )
159         );
160 
161         return msgs;
162     }
163 
164     protected List<OutgoingNotificationRequest> createServiceTypeMessages(LocalDevice device,
165                                                                           Location descriptorLocation) {
166         List<OutgoingNotificationRequest> msgs = new ArrayList<>();
167 
168         for (ServiceType serviceType : device.findServiceTypes()) {
169             msgs.add(
170                     new OutgoingNotificationRequestServiceType(
171                             descriptorLocation, device,
172                             getNotificationSubtype(), serviceType
173                     )
174             );
175         }
176 
177         return msgs;
178     }
179 
180     protected abstract NotificationSubtype getNotificationSubtype();
181 
182 }