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.sync;
17  
18  import org.fourthline.cling.model.NetworkAddress;
19  import org.fourthline.cling.model.gena.RemoteGENASubscription;
20  import org.fourthline.cling.model.message.StreamResponseMessage;
21  import org.fourthline.cling.model.message.gena.IncomingSubscribeResponseMessage;
22  import org.fourthline.cling.model.message.gena.OutgoingSubscribeRequestMessage;
23  import org.fourthline.cling.UpnpService;
24  import org.fourthline.cling.protocol.SendingSync;
25  import org.fourthline.cling.transport.RouterException;
26  
27  import java.util.List;
28  import java.util.logging.Logger;
29  
30  /**
31   * Establishing a GENA event subscription with a remote host.
32   * <p>
33   * Calls the {@link org.fourthline.cling.model.gena.RemoteGENASubscription#establish()} method
34   * if the subscription request was responded to correctly.
35   * </p>
36   * <p>
37   * The {@link org.fourthline.cling.model.gena.RemoteGENASubscription#fail(org.fourthline.cling.model.message.UpnpResponse)}
38   * method will be called if the request failed. No response from the remote host is indicated with
39   * a <code>null</code> argument value. Note that this is also the response if the subscription has
40   * to be aborted early, when no local stream server for callback URL creation is available. This is
41   * the case when the local network transport layer is switched off, subscriptions will fail
42   * immediately with no response.
43   * </p>
44   *
45   * @author Christian Bauer
46   */
47  public class SendingSubscribe extends SendingSync<OutgoingSubscribeRequestMessage, IncomingSubscribeResponseMessage> {
48  
49      final private static Logger log = Logger.getLogger(SendingSubscribe.class.getName());
50  
51      final protected RemoteGENASubscription subscription;
52  
53      public SendingSubscribe(UpnpService upnpService,
54                              RemoteGENASubscription subscription,
55                              List<NetworkAddress> activeStreamServers) {
56          super(
57              upnpService,
58              new OutgoingSubscribeRequestMessage(
59                  subscription,
60                  subscription.getEventCallbackURLs(
61                      activeStreamServers,
62                      upnpService.getConfiguration().getNamespace()
63                  ),
64                  upnpService.getConfiguration().getEventSubscriptionHeaders(subscription.getService())
65              )
66          );
67  
68          this.subscription = subscription;
69      }
70  
71      protected IncomingSubscribeResponseMessage executeSync() throws RouterException {
72  
73          if (!getInputMessage().hasCallbackURLs()) {
74              log.fine("Subscription failed, no active local callback URLs available (network disabled?)");
75              getUpnpService().getConfiguration().getRegistryListenerExecutor().execute(
76                  new Runnable() {
77                      public void run() {
78                          subscription.fail(null);
79                      }
80                  }
81              );
82              return null;
83          }
84  
85          log.fine("Sending subscription request: " + getInputMessage());
86  
87          try {
88              // register this pending Subscription to bloc if the notification is received before the
89              // registration result.
90              getUpnpService().getRegistry().registerPendingRemoteSubscription(subscription);
91  
92              StreamResponseMessage response = null;
93              try {
94                  response = getUpnpService().getRouter().send(getInputMessage());
95              } catch (RouterException ex) {
96                  onSubscriptionFailure();
97                  return null;
98              }
99  
100             if (response == null) {
101                 onSubscriptionFailure();
102                 return null;
103             }
104 
105             final IncomingSubscribeResponseMessage responseMessage = new IncomingSubscribeResponseMessage(response);
106 
107             if (response.getOperation().isFailed()) {
108                 log.fine("Subscription failed, response was: " + responseMessage);
109                 getUpnpService().getConfiguration().getRegistryListenerExecutor().execute(
110                     new Runnable() {
111                         public void run() {
112                             subscription.fail(responseMessage.getOperation());
113                         }
114                     }
115                 );
116             } else if (!responseMessage.isValidHeaders()) {
117                 log.severe("Subscription failed, invalid or missing (SID, Timeout) response headers");
118                 getUpnpService().getConfiguration().getRegistryListenerExecutor().execute(
119                     new Runnable() {
120                         public void run() {
121                             subscription.fail(responseMessage.getOperation());
122                         }
123                     }
124                 );
125             } else {
126 
127                 log.fine("Subscription established, adding to registry, response was: " + response);
128                 subscription.setSubscriptionId(responseMessage.getSubscriptionId());
129                 subscription.setActualSubscriptionDurationSeconds(responseMessage.getSubscriptionDurationSeconds());
130 
131                 getUpnpService().getRegistry().addRemoteSubscription(subscription);
132 
133                 getUpnpService().getConfiguration().getRegistryListenerExecutor().execute(
134                     new Runnable() {
135                         public void run() {
136                             subscription.establish();
137                         }
138                     }
139                 );
140 
141             }
142             return responseMessage;
143         } finally {
144             getUpnpService().getRegistry().unregisterPendingRemoteSubscription(subscription);
145         }
146     }
147 
148     protected void onSubscriptionFailure() {
149         log.fine("Subscription failed");
150         getUpnpService().getConfiguration().getRegistryListenerExecutor().execute(
151             new Runnable() {
152                 public void run() {
153                     subscription.fail(null);
154                 }
155             }
156         );
157     }
158 }