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 package example.controlpoint;
16
17 import org.fourthline.cling.mock.MockUpnpService;
18 import org.fourthline.cling.model.message.UpnpMessage;
19 import org.fourthline.cling.model.message.header.DeviceTypeHeader;
20 import org.fourthline.cling.model.message.header.HostHeader;
21 import org.fourthline.cling.model.message.header.MANHeader;
22 import org.fourthline.cling.model.message.header.MXHeader;
23 import org.fourthline.cling.model.message.header.RootDeviceHeader;
24 import org.fourthline.cling.model.message.header.STAllHeader;
25 import org.fourthline.cling.model.message.header.ServiceTypeHeader;
26 import org.fourthline.cling.model.message.header.UDADeviceTypeHeader;
27 import org.fourthline.cling.model.message.header.UDAServiceTypeHeader;
28 import org.fourthline.cling.model.message.header.UDNHeader;
29 import org.fourthline.cling.model.message.header.UpnpHeader;
30 import org.fourthline.cling.model.types.DeviceType;
31 import org.fourthline.cling.model.types.NotificationSubtype;
32 import org.fourthline.cling.model.types.ServiceType;
33 import org.fourthline.cling.model.types.UDADeviceType;
34 import org.fourthline.cling.model.types.UDAServiceType;
35 import org.fourthline.cling.model.types.UDN;
36 import org.fourthline.cling.protocol.async.SendingSearch;
37 import org.testng.annotations.Test;
38
39 import java.util.UUID;
40
41 import static org.testng.Assert.*;
42
43 /**
44 * Searching the network
45 * <p>
46 * When your control point joins the network it probably won't know any UPnP devices and services that
47 * might be available. To learn about the present devices it can broadcast - actually with UDP multicast
48 * datagrams - a search message which will be received by every device. Each receiver then inspects the
49 * search message and decides if it should reply directly (with notification UDP datagrams) to the
50 * sending control point.
51 * </p>
52 * <p>
53 * Search messages carry a <em>search type</em> header and receivers consider this header when they
54 * evaluate a potential response. The Cling <code>ControlPoint</code> API accepts a
55 * <code>UpnpHeader</code> argument when creating outgoing search messages.
56 * </p>
57 * <a class="citation" href="javadoc://this#searchAll" style="read-title: false;"/>
58 * <a class="citation" href="javadoc://this#searchUDN" style="read-title: false;"/>
59 * <a class="citation" href="javadoc://this#searchDeviceType" style="read-title: false;"/>
60 * <a class="citation" href="javadoc://this#searchServiceType" style="read-title: false;"/>
61 */
62 public class SearchExecuteTest {
63
64 /**
65 * <p>
66 * Most of the time you'd like all devices to respond to your search, this is what the
67 * dedicated <code>STAllHeader</code> is used for:
68 * </p>
69 * <a class="citation" href="javacode://this" style="include: SEARCH"/>
70 * <p>
71 * Notification messages will be received by your control point and you can listen to
72 * the <code>Registry</code> and inspect the found devices and their services. (By the
73 * way, if you call <code>search()</code> without any argument, that's the same.)
74 * </p>
75 */
76 @Test
77 public void searchAll() throws Exception {
78 MockUpnpService upnpService = new MockUpnpService();
79
80 upnpService.getControlPoint().search( // DOC: SEARCH
81 new STAllHeader()
82 ); // DOC: SEARCH
83
84 assertMessages(upnpService, new STAllHeader());
85 }
86
87 /**
88 * <p>
89 * On the other hand, when you already know the unique device name (UDN) of the device you
90 * are searching for - maybe because your control point remembered it while it was turned off - you
91 * can send a message which will trigger a response from only a particular device:
92 * </p>
93 * <a class="citation" href="javacode://this" style="include: SEARCH"/>
94 * <p>
95 * This is mostly useful to avoid network congestion when dozens of devices might <em>all</em>
96 * respond to a search request. Your <code>Registry</code> listener code however still has to
97 * inspect each newly found device, as registrations might occur independently from searches.
98 * </p>
99 */
100 @Test
101 public void searchUDN() throws Exception {
102 MockUpnpService upnpService = new MockUpnpService();
103
104 UDN udn = new UDN(UUID.randomUUID());
105 upnpService.getControlPoint().search( // DOC: SEARCH
106 new UDNHeader(udn)
107 ); // DOC: SEARCH
108
109 assertMessages(upnpService, new UDNHeader(udn));
110 }
111
112 /**
113 * <p>
114 * You can also search by device or service type. This search request will trigger responses
115 * from all devices of type "<code>urn:schemas-upnp-org:device:BinaryLight:1</code>":
116 * </p>
117 * <a class="citation" href="javacode://this" style="include: SEARCH_UDA"/>
118 * <p>
119 * If the desired device type is of a custom namespace, use this variation:
120 * </p>
121 * <a class="citation" id="javacode_dt_search_custom" href="javacode://this" style="include: SEARCH_CUSTOM"/>
122 */
123 @Test
124 public void searchDeviceType() throws Exception {
125 MockUpnpService upnpService = new MockUpnpService();
126
127 UDADeviceType udaType = new UDADeviceType("BinaryLight"); // DOC: SEARCH_UDA
128 upnpService.getControlPoint().search(
129 new UDADeviceTypeHeader(udaType)
130 ); // DOC: SEARCH_UDA
131
132 assertMessages(upnpService, new UDADeviceTypeHeader(udaType));
133
134 upnpService.getRouter().getOutgoingDatagramMessages().clear();
135
136 DeviceType type = new DeviceType("org-mydomain", "MyDeviceType", 1); // DOC: SEARCH_CUSTOM
137 upnpService.getControlPoint().search(
138 new DeviceTypeHeader(type)
139 ); // DOC: SEARCH_CUSTOM
140
141 assertMessages(upnpService, new DeviceTypeHeader(type));
142 }
143
144 /**
145 * <p>
146 * Or, you can search for all devices which implement a particular service type:
147 * </p>
148 * <a class="citation" href="javacode://this" style="include: SEARCH_UDA"/>
149 * <a class="citation" id="javacode_st_search_custom" href="javacode://this" style="include: SEARCH_CUSTOM"/>
150 */
151 @Test
152 public void searchServiceType() throws Exception {
153 MockUpnpService upnpService = new MockUpnpService();
154
155 UDAServiceType udaType = new UDAServiceType("SwitchPower"); // DOC: SEARCH_UDA
156 upnpService.getControlPoint().search(
157 new UDAServiceTypeHeader(udaType)
158 ); // DOC: SEARCH_UDA
159
160 assertMessages(upnpService, new UDAServiceTypeHeader(udaType));
161
162 upnpService.getRouter().getOutgoingDatagramMessages().clear();
163
164 ServiceType type = new ServiceType("org-mydomain", "MyServiceType", 1); // DOC: SEARCH_CUSTOM
165 upnpService.getControlPoint().search(
166 new ServiceTypeHeader(type)
167 ); // DOC: SEARCH_CUSTOM
168
169 assertMessages(upnpService, new ServiceTypeHeader(type));
170 }
171
172
173 @Test
174 public void searchRoot() throws Exception {
175 MockUpnpService upnpService = new MockUpnpService();
176 upnpService.getControlPoint().search(new RootDeviceHeader());
177 assertMessages(upnpService, new RootDeviceHeader());
178 }
179
180
181 @Test
182 public void searchDefaults() {
183 SendingSearch search = new SendingSearch(new MockUpnpService());
184 assertEquals(search.getSearchTarget().getString(), new STAllHeader().getString());
185 }
186
187 @Test(expectedExceptions = java.lang.IllegalArgumentException.class)
188 public void searchInvalidST() {
189 SendingSearch search = new SendingSearch(new MockUpnpService(), new MXHeader());
190 }
191
192 protected void assertMessages(MockUpnpService upnpService, UpnpHeader header) throws Exception {
193 assertEquals(upnpService.getRouter().getOutgoingDatagramMessages().size(), 5);
194 for (UpnpMessage msg : upnpService.getRouter().getOutgoingDatagramMessages()) {
195 assertSearchMessage(msg, header);
196 }
197 }
198
199 protected void assertSearchMessage(UpnpMessage msg, UpnpHeader searchTarget) {
200 assertEquals(msg.getHeaders().getFirstHeader(UpnpHeader.Type.MAN).getString(), new MANHeader(NotificationSubtype.DISCOVER.getHeaderString()).getString());
201 assertEquals(msg.getHeaders().getFirstHeader(UpnpHeader.Type.MX).getString(), new MXHeader().getString());
202 assertEquals(msg.getHeaders().getFirstHeader(UpnpHeader.Type.ST).getString(), searchTarget.getString());
203 assertEquals(msg.getHeaders().getFirstHeader(UpnpHeader.Type.HOST).getString(), new HostHeader().getString());
204 }
205 }