]> git.saurik.com Git - apple/mdnsresponder.git/blob - Clients/Java/BrowserApp.java
mDNSResponder-107.3.tar.gz
[apple/mdnsresponder.git] / Clients / Java / BrowserApp.java
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
5 * ("Apple") in consideration of your agreement to the following terms, and your
6 * use, installation, modification or redistribution of this Apple software
7 * constitutes acceptance of these terms. If you do not agree with these terms,
8 * please do not use, install, modify or redistribute this Apple software.
9 *
10 * In consideration of your agreement to abide by the following terms, and subject
11 * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
12 * copyrights in this original Apple software (the "Apple Software"), to use,
13 * reproduce, modify and redistribute the Apple Software, with or without
14 * modifications, in source and/or binary forms; provided that if you redistribute
15 * the Apple Software in its entirety and without modifications, you must retain
16 * this notice and the following text and disclaimers in all such redistributions of
17 * the Apple Software. Neither the name, trademarks, service marks or logos of
18 * Apple Computer, Inc. may be used to endorse or promote products derived from the
19 * Apple Software without specific prior written permission from Apple. Except as
20 * expressly stated in this notice, no other rights or licenses, express or implied,
21 * are granted by Apple herein, including but not limited to any patent rights that
22 * may be infringed by your derivative works or by other works in which the Apple
23 * Software may be incorporated.
24 *
25 * The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
26 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
27 * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
29 * COMBINATION WITH YOUR PRODUCTS.
30 *
31 * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
33 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
35 * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
36 * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
37 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39 BrowserApp demonstrates how to use DNS-SD to browse for and resolve services.
40
41 To do:
42 - display resolved TXTRecord
43 */
44
45
46 import java.awt.*;
47 import java.awt.event.*;
48 import java.util.*;
49 import java.text.*;
50 import javax.swing.*;
51 import javax.swing.event.*;
52
53 import com.apple.dnssd.*;
54
55
56 class BrowserApp implements ListSelectionListener, ResolveListener
57 {
58 static BrowserApp app;
59 JFrame frame;
60 DomainListModel domainList;
61 BrowserListModel servicesList, serviceList;
62 JList domainPane, servicesPane, servicePane;
63 DNSSDService servicesBrowser, serviceBrowser, domainBrowser;
64 JLabel hostLabel, portLabel;
65
66 public BrowserApp()
67 {
68 frame = new JFrame("DNS-SD Service Browser");
69 frame.addWindowListener(new WindowAdapter() {
70 public void windowClosing(WindowEvent e) {System.exit(0);}
71 });
72
73 domainList = new DomainListModel();
74 servicesList = new ServicesBrowserListModel();
75 serviceList = new BrowserListModel();
76
77 try {
78 domainBrowser = DNSSD.enumerateDomains( DNSSD.BROWSE_DOMAINS, 0, domainList);
79
80 servicesBrowser = DNSSD.browse( 0, 0, "_services._dns-sd._udp.", "", servicesList);
81 serviceBrowser = null;
82 }
83 catch ( Exception ex) { terminateWithException( ex); }
84
85 this.setupSubPanes( frame.getContentPane());
86 frame.pack();
87 frame.setVisible(true);
88 }
89
90 protected void setupSubPanes( Container parent)
91 {
92 parent.setLayout( new BoxLayout( parent, BoxLayout.Y_AXIS));
93
94 JPanel browserRow = new JPanel();
95 browserRow.setLayout( new BoxLayout( browserRow, BoxLayout.X_AXIS));
96 domainPane = new JList( domainList);
97 domainPane.addListSelectionListener( this);
98 JScrollPane domainScroller = new JScrollPane( domainPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
99 browserRow.add( domainScroller);
100 servicesPane = new JList( servicesList);
101 servicesPane.addListSelectionListener( this);
102 JScrollPane servicesScroller = new JScrollPane( servicesPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
103 browserRow.add( servicesScroller);
104 servicePane = new JList( serviceList);
105 servicePane.addListSelectionListener( this);
106 JScrollPane serviceScroller = new JScrollPane( servicePane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
107 browserRow.add( serviceScroller);
108
109 /*
110 JPanel buttonRow = new JPanel();
111 buttonRow.setLayout( new BoxLayout( buttonRow, BoxLayout.X_AXIS));
112 buttonRow.add( Box.createHorizontalGlue());
113 JButton connectButton = new JButton( "Don't Connect");
114 buttonRow.add( connectButton);
115 buttonRow.add( Box.createRigidArea( new Dimension( 16, 0)));
116 */
117
118 JPanel labelRow = new JPanel();
119 labelRow.setLayout( new BoxLayout( labelRow, BoxLayout.X_AXIS));
120 labelRow.add( new JLabel( " Host: "));
121 hostLabel = new JLabel();
122 labelRow.add( hostLabel);
123 labelRow.add( Box.createRigidArea( new Dimension( 32, 0)));
124 labelRow.add( new JLabel( "Port: "));
125 portLabel = new JLabel();
126 labelRow.add( portLabel);
127 labelRow.add( Box.createHorizontalGlue());
128
129 parent.add( browserRow);
130 parent.add( Box.createRigidArea( new Dimension( 0, 8)));
131 parent.add( labelRow);
132 // parent.add( buttonRow);
133 parent.add( Box.createRigidArea( new Dimension( 0, 16)));
134 }
135
136 public void valueChanged( ListSelectionEvent e)
137 {
138 try {
139 if ( e.getSource() == domainPane && !e.getValueIsAdjusting())
140 {
141 int newSel = domainPane.getSelectedIndex();
142 if ( -1 != newSel)
143 {
144 if ( serviceBrowser != null)
145 serviceBrowser.stop();
146 serviceList.removeAllElements();
147 servicesBrowser = DNSSD.browse( 0, 0, "_services._dns-sd._udp.", "", servicesList);
148 }
149 }
150 else if ( e.getSource() == servicesPane && !e.getValueIsAdjusting())
151 {
152 int newSel = servicesPane.getSelectedIndex();
153 if ( serviceBrowser != null)
154 serviceBrowser.stop();
155 serviceList.removeAllElements();
156 if ( -1 != newSel)
157 serviceBrowser = DNSSD.browse( 0, 0, servicesList.getNthRegType( newSel), "", serviceList);
158 }
159 else if ( e.getSource() == servicePane && !e.getValueIsAdjusting())
160 {
161 int newSel = servicePane.getSelectedIndex();
162
163 hostLabel.setText( "");
164 portLabel.setText( "");
165
166 if ( -1 != newSel)
167 {
168 DNSSD.resolve( 0, serviceList.getNthInterface( newSel),
169 serviceList.getNthServiceName( newSel),
170 serviceList.getNthRegType( newSel),
171 serviceList.getNthDomain( newSel),
172 new SwingResolveListener( this));
173 }
174 }
175 }
176 catch ( Exception ex) { terminateWithException( ex); }
177 }
178
179 public void serviceResolved( DNSSDService resolver, int flags, int ifIndex, String fullName,
180 String hostName, int port, TXTRecord txtRecord)
181 {
182 hostLabel.setText( hostName);
183 portLabel.setText( String.valueOf( port));
184 }
185
186 public void operationFailed( DNSSDService service, int errorCode)
187 {
188 // handle failure here
189 }
190
191 protected static void terminateWithException( Exception e)
192 {
193 e.printStackTrace();
194 System.exit( -1);
195 }
196
197 public static void main(String s[])
198 {
199 app = new BrowserApp();
200 }
201 }
202
203
204 class BrowserListModel extends DefaultListModel implements BrowseListener, Runnable
205 {
206 public BrowserListModel()
207 {
208 addCache = new Vector();
209 removeCache = new Vector();
210 }
211
212 /* The Browser invokes this callback when a service is discovered. */
213 public void serviceFound( DNSSDService browser, int flags, int ifIndex,
214 String serviceName, String regType, String domain)
215 {
216 addCache.add( new BrowserListElem( serviceName, domain, regType, ifIndex));
217 if ( ( flags & DNSSD.MORE_COMING) == 0)
218 this.scheduleOnEventThread();
219 }
220
221 public void serviceLost( DNSSDService browser, int flags, int ifIndex,
222 String serviceName, String regType, String domain)
223 {
224 removeCache.add( serviceName);
225 if ( ( flags & DNSSD.MORE_COMING) == 0)
226 this.scheduleOnEventThread();
227 }
228
229 public void run()
230 {
231 while ( removeCache.size() > 0)
232 {
233 String serviceName = (String) removeCache.remove( removeCache.size() - 1);
234 int matchInd = this.findMatching( serviceName); // probably doesn't handle near-duplicates well.
235 if ( matchInd != -1)
236 this.removeElementAt( matchInd);
237 }
238 while ( addCache.size() > 0)
239 {
240 BrowserListElem elem = (BrowserListElem) addCache.remove( addCache.size() - 1);
241 if ( -1 == this.findMatching( elem.fServiceName)) // probably doesn't handle near-duplicates well.
242 this.addInSortOrder( elem);
243 }
244 }
245
246 public void operationFailed( DNSSDService service, int errorCode)
247 {
248 // handle failure here
249 }
250
251 /* The list contains BrowserListElem's */
252 class BrowserListElem
253 {
254 public BrowserListElem( String serviceName, String domain, String type, int ifIndex)
255 { fServiceName = serviceName; fDomain = domain; fType = type; fInt = ifIndex; }
256
257 public String toString() { return fServiceName; }
258
259 public String fServiceName, fDomain, fType;
260 public int fInt;
261 }
262
263 public String getNthServiceName( int n)
264 {
265 BrowserListElem sel = (BrowserListElem) this.get( n);
266 return sel.fServiceName;
267 }
268
269 public String getNthRegType( int n)
270 {
271 BrowserListElem sel = (BrowserListElem) this.get( n);
272 return sel.fType;
273 }
274
275 public String getNthDomain( int n)
276 {
277 BrowserListElem sel = (BrowserListElem) this.get( n);
278 return sel.fDomain;
279 }
280
281 public int getNthInterface( int n)
282 {
283 BrowserListElem sel = (BrowserListElem) this.get( n);
284 return sel.fInt;
285 }
286
287 protected void addInSortOrder( Object obj)
288 {
289 int i;
290 for ( i = 0; i < this.size(); i++)
291 if ( sCollator.compare( obj.toString(), this.getElementAt( i).toString()) < 0)
292 break;
293 this.add( i, obj);
294 }
295
296 protected int findMatching( String match)
297 {
298 for ( int i = 0; i < this.size(); i++)
299 if ( match.equals( this.getElementAt( i).toString()))
300 return i;
301 return -1;
302 }
303
304 protected void scheduleOnEventThread()
305 {
306 try {
307 SwingUtilities.invokeAndWait( this);
308 }
309 catch ( Exception e)
310 {
311 e.printStackTrace();
312 }
313 }
314
315 protected Vector removeCache; // list of serviceNames to remove
316 protected Vector addCache; // list of BrowserListElem's to add
317
318 protected static Collator sCollator;
319
320 static // Initialize our static variables
321 {
322 sCollator = Collator.getInstance();
323 sCollator.setStrength( Collator.PRIMARY);
324 }
325 }
326
327
328 class ServicesBrowserListModel extends BrowserListModel
329 {
330 /* The Browser invokes this callback when a service is discovered. */
331 public void serviceFound( DNSSDService browser, int flags, int ifIndex,
332 String serviceName, String regType, String domain)
333 // Overridden to stuff serviceName into regType and make serviceName human-readable.
334 {
335 regType = serviceName + ( regType.startsWith( "_udp.") ? "._udp." : "._tcp.");
336 super.serviceFound( browser, flags, ifIndex, this.mapTypeToName( serviceName), regType, domain);
337 }
338
339 public void serviceLost( DNSSDService browser, int flags, int ifIndex,
340 String serviceName, String regType, String domain)
341 // Overridden to make serviceName human-readable.
342 {
343 super.serviceLost( browser, flags, ifIndex, this.mapTypeToName( serviceName), regType, domain);
344 }
345
346 protected String mapTypeToName( String type)
347 // Convert a registration type into a human-readable string. Returns original string on no-match.
348 {
349 final String[] namedServices = {
350 "_afpovertcp", "Apple File Sharing",
351 "_http", "World Wide Web servers",
352 "_daap", "Digital Audio Access",
353 "_apple-sasl", "Apple Password Servers",
354 "_distcc", "Distributed Compiler nodes",
355 "_finger", "Finger servers",
356 "_ichat", "iChat clients",
357 "_presence", "iChat AV clients",
358 "_ssh", "SSH servers",
359 "_telnet", "Telnet servers",
360 "_workstation", "Macintosh Manager clients",
361 "_bootps", "BootP servers",
362 "_xserveraid", "XServe RAID devices",
363 "_eppc", "Remote AppleEvents",
364 "_ftp", "FTP services",
365 "_tftp", "TFTP services"
366 };
367
368 for ( int i = 0; i < namedServices.length; i+=2)
369 if ( namedServices[i].equals( type))
370 return namedServices[i + 1];
371 return type;
372 }
373 }
374
375
376 class DomainListModel extends DefaultListModel implements DomainListener
377 {
378 /* Called when a domain is discovered. */
379 public void domainFound( DNSSDService domainEnum, int flags, int ifIndex, String domain)
380 {
381 if ( !this.contains( domain))
382 this.addElement( domain);
383 }
384
385 public void domainLost( DNSSDService domainEnum, int flags, int ifIndex, String domain)
386 {
387 if ( this.contains( domain))
388 this.removeElement( domain);
389 }
390
391 public void operationFailed( DNSSDService service, int errorCode)
392 {
393 // handle failure here
394 }
395 }
396