1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.fourthline.cling.protocol;
17
18 import org.fourthline.cling.UpnpService;
19 import org.fourthline.cling.model.Namespace;
20 import org.fourthline.cling.model.NetworkAddress;
21 import org.fourthline.cling.model.action.ActionInvocation;
22 import org.fourthline.cling.model.gena.LocalGENASubscription;
23 import org.fourthline.cling.model.gena.RemoteGENASubscription;
24 import org.fourthline.cling.model.message.IncomingDatagramMessage;
25 import org.fourthline.cling.model.message.StreamRequestMessage;
26 import org.fourthline.cling.model.message.UpnpRequest;
27 import org.fourthline.cling.model.message.UpnpResponse;
28 import org.fourthline.cling.model.message.header.UpnpHeader;
29 import org.fourthline.cling.model.meta.LocalDevice;
30 import org.fourthline.cling.model.types.InvalidValueException;
31 import org.fourthline.cling.model.types.NamedServiceType;
32 import org.fourthline.cling.model.types.NotificationSubtype;
33 import org.fourthline.cling.model.types.ServiceType;
34 import org.fourthline.cling.protocol.async.ReceivingNotification;
35 import org.fourthline.cling.protocol.async.ReceivingSearch;
36 import org.fourthline.cling.protocol.async.ReceivingSearchResponse;
37 import org.fourthline.cling.protocol.async.SendingNotificationAlive;
38 import org.fourthline.cling.protocol.async.SendingNotificationByebye;
39 import org.fourthline.cling.protocol.async.SendingSearch;
40 import org.fourthline.cling.protocol.sync.ReceivingAction;
41 import org.fourthline.cling.protocol.sync.ReceivingEvent;
42 import org.fourthline.cling.protocol.sync.ReceivingRetrieval;
43 import org.fourthline.cling.protocol.sync.ReceivingSubscribe;
44 import org.fourthline.cling.protocol.sync.ReceivingUnsubscribe;
45 import org.fourthline.cling.protocol.sync.SendingAction;
46 import org.fourthline.cling.protocol.sync.SendingEvent;
47 import org.fourthline.cling.protocol.sync.SendingRenewal;
48 import org.fourthline.cling.protocol.sync.SendingSubscribe;
49 import org.fourthline.cling.protocol.sync.SendingUnsubscribe;
50 import org.fourthline.cling.transport.RouterException;
51
52 import javax.enterprise.context.ApplicationScoped;
53 import javax.inject.Inject;
54 import java.net.URI;
55 import java.net.URL;
56 import java.util.List;
57 import java.util.logging.Level;
58 import java.util.logging.Logger;
59
60
61
62
63
64
65 @ApplicationScoped
66 public class ProtocolFactoryImpl implements ProtocolFactory {
67
68 final private static Logger log = Logger.getLogger(ProtocolFactory.class.getName());
69
70 protected final UpnpService upnpService;
71
72 protected ProtocolFactoryImpl() {
73 upnpService = null;
74 }
75
76 @Inject
77 public ProtocolFactoryImpl(UpnpService upnpService) {
78 log.fine("Creating ProtocolFactory: " + getClass().getName());
79 this.upnpService = upnpService;
80 }
81
82 public UpnpService getUpnpService() {
83 return upnpService;
84 }
85
86 public ReceivingAsync createReceivingAsync(IncomingDatagramMessage message) throws ProtocolCreationException {
87 if (log.isLoggable(Level.FINE)) {
88 log.fine("Creating protocol for incoming asynchronous: " + message);
89 }
90
91 if (message.getOperation() instanceof UpnpRequest) {
92 IncomingDatagramMessage<UpnpRequest> incomingRequest = message;
93
94 switch (incomingRequest.getOperation().getMethod()) {
95 case NOTIFY:
96 return isByeBye(incomingRequest) || isSupportedServiceAdvertisement(incomingRequest)
97 ? createReceivingNotification(incomingRequest) : null;
98 case MSEARCH:
99 return createReceivingSearch(incomingRequest);
100 }
101
102 } else if (message.getOperation() instanceof UpnpResponse) {
103 IncomingDatagramMessage<UpnpResponse> incomingResponse = message;
104
105 return isSupportedServiceAdvertisement(incomingResponse)
106 ? createReceivingSearchResponse(incomingResponse) : null;
107 }
108
109 throw new ProtocolCreationException("Protocol for incoming datagram message not found: " + message);
110 }
111
112 protected ReceivingAsync createReceivingNotification(IncomingDatagramMessage<UpnpRequest> incomingRequest) {
113 return new ReceivingNotification(getUpnpService(), incomingRequest);
114 }
115
116 protected ReceivingAsync createReceivingSearch(IncomingDatagramMessage<UpnpRequest> incomingRequest) {
117 return new ReceivingSearch(getUpnpService(), incomingRequest);
118 }
119
120 protected ReceivingAsync createReceivingSearchResponse(IncomingDatagramMessage<UpnpResponse> incomingResponse) {
121 return new ReceivingSearchResponse(getUpnpService(), incomingResponse);
122 }
123
124
125
126 protected boolean isByeBye(IncomingDatagramMessage message) {
127 String ntsHeader = message.getHeaders().getFirstHeader(UpnpHeader.Type.NTS.getHttpName());
128 return ntsHeader != null && ntsHeader.equals(NotificationSubtype.BYEBYE.getHeaderString());
129 }
130
131 protected boolean isSupportedServiceAdvertisement(IncomingDatagramMessage message) {
132 ServiceType[] exclusiveServiceTypes = getUpnpService().getConfiguration().getExclusiveServiceTypes();
133 if (exclusiveServiceTypes == null) return false;
134 if (exclusiveServiceTypes.length == 0) return true;
135
136 String usnHeader = message.getHeaders().getFirstHeader(UpnpHeader.Type.USN.getHttpName());
137 if (usnHeader == null) return false;
138
139 try {
140 NamedServiceType nst = NamedServiceType.valueOf(usnHeader);
141 for (ServiceType exclusiveServiceType : exclusiveServiceTypes) {
142 if (nst.getServiceType().implementsVersion(exclusiveServiceType))
143 return true;
144 }
145 } catch (InvalidValueException ex) {
146 log.finest("Not a named service type header value: " + usnHeader);
147 }
148 log.fine("Service advertisement not supported, dropping it: " + usnHeader);
149 return false;
150 }
151
152 public ReceivingSync createReceivingSync(StreamRequestMessage message) throws ProtocolCreationException {
153 log.fine("Creating protocol for incoming synchronous: " + message);
154
155 if (message.getOperation().getMethod().equals(UpnpRequest.Method.GET)) {
156
157 return createReceivingRetrieval(message);
158
159 } else if (getUpnpService().getConfiguration().getNamespace().isControlPath(message.getUri())) {
160
161 if (message.getOperation().getMethod().equals(UpnpRequest.Method.POST))
162 return createReceivingAction(message);
163
164 } else if (getUpnpService().getConfiguration().getNamespace().isEventSubscriptionPath(message.getUri())) {
165
166 if (message.getOperation().getMethod().equals(UpnpRequest.Method.SUBSCRIBE)) {
167 return createReceivingSubscribe(message);
168 } else if (message.getOperation().getMethod().equals(UpnpRequest.Method.UNSUBSCRIBE)) {
169 return createReceivingUnsubscribe(message);
170 }
171
172 } else if (getUpnpService().getConfiguration().getNamespace().isEventCallbackPath(message.getUri())) {
173
174 if (message.getOperation().getMethod().equals(UpnpRequest.Method.NOTIFY))
175 return createReceivingEvent(message);
176
177 } else {
178
179
180
181
182
183 if (message.getUri().getPath().contains(Namespace.EVENTS + Namespace.CALLBACK_FILE)) {
184 log.warning("Fixing trailing garbage in event message path: " + message.getUri().getPath());
185 String invalid = message.getUri().toString();
186 message.setUri(
187 URI.create(invalid.substring(
188 0, invalid.indexOf(Namespace.CALLBACK_FILE) + Namespace.CALLBACK_FILE.length()
189 ))
190 );
191 if (getUpnpService().getConfiguration().getNamespace().isEventCallbackPath(message.getUri())
192 && message.getOperation().getMethod().equals(UpnpRequest.Method.NOTIFY))
193 return createReceivingEvent(message);
194 }
195
196 }
197
198 throw new ProtocolCreationException("Protocol for message type not found: " + message);
199 }
200
201 public SendingNotificationAlive createSendingNotificationAlive(LocalDevice localDevice) {
202 return new SendingNotificationAlive(getUpnpService(), localDevice);
203 }
204
205 public SendingNotificationByebye createSendingNotificationByebye(LocalDevice localDevice) {
206 return new SendingNotificationByebye(getUpnpService(), localDevice);
207 }
208
209 public SendingSearch createSendingSearch(UpnpHeader searchTarget, int mxSeconds) {
210 return new SendingSearch(getUpnpService(), searchTarget, mxSeconds);
211 }
212
213 public SendingAction createSendingAction(ActionInvocation actionInvocation, URL controlURL) {
214 return new SendingAction(getUpnpService(), actionInvocation, controlURL);
215 }
216
217 public SendingSubscribe createSendingSubscribe(RemoteGENASubscription subscription) throws ProtocolCreationException {
218 try {
219 List<NetworkAddress> activeStreamServers =
220 getUpnpService().getRouter().getActiveStreamServers(
221 subscription.getService().getDevice().getIdentity().getDiscoveredOnLocalAddress()
222 );
223 return new SendingSubscribe(getUpnpService(), subscription, activeStreamServers);
224 } catch (RouterException ex) {
225 throw new ProtocolCreationException(
226 "Failed to obtain local stream servers (for event callback URL creation) from router",
227 ex
228 );
229 }
230 }
231
232 public SendingRenewal createSendingRenewal(RemoteGENASubscription subscription) {
233 return new SendingRenewal(getUpnpService(), subscription);
234 }
235
236 public SendingUnsubscribe createSendingUnsubscribe(RemoteGENASubscription subscription) {
237 return new SendingUnsubscribe(getUpnpService(), subscription);
238 }
239
240 public SendingEvent createSendingEvent(LocalGENASubscription subscription) {
241 return new SendingEvent(getUpnpService(), subscription);
242 }
243
244 protected ReceivingRetrieval createReceivingRetrieval(StreamRequestMessage message) {
245 return new ReceivingRetrieval(getUpnpService(), message);
246 }
247
248 protected ReceivingAction createReceivingAction(StreamRequestMessage message) {
249 return new ReceivingAction(getUpnpService(), message);
250 }
251
252 protected ReceivingSubscribe createReceivingSubscribe(StreamRequestMessage message) {
253 return new ReceivingSubscribe(getUpnpService(), message);
254 }
255
256 protected ReceivingUnsubscribe createReceivingUnsubscribe(StreamRequestMessage message) {
257 return new ReceivingUnsubscribe(getUpnpService(), message);
258 }
259
260 protected ReceivingEvent createReceivingEvent(StreamRequestMessage message) {
261 return new ReceivingEvent(getUpnpService(), message);
262 }
263 }