]> git.saurik.com Git - apple/mdnsresponder.git/blob - Clients/Java/BrowserApp.java
d3805ae7a67320e6f8b6b0c3b7af10714997bc79
[apple/mdnsresponder.git] / Clients / Java / BrowserApp.java
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 Change History (most recent first):
26
27 $Log: BrowserApp.java,v $
28 Revision 1.3 2004/05/26 01:41:58 cheshire
29 Pass proper flags to DNSSD.enumerateDomains
30
31 Revision 1.2 2004/04/30 21:53:34 rpantos
32 Change line endings for CVS.
33
34 Revision 1.1 2004/04/30 16:29:35 rpantos
35 First checked in.
36
37 BrowserApp demonstrates how to use DNSSD to browse for and resolve services.
38
39 To do:
40 - display resolved TXTRecord
41 */
42
43
44 import java.awt.*;
45 import java.awt.event.*;
46 import java.util.*;
47 import java.text.*;
48 import javax.swing.*;
49 import javax.swing.event.*;
50
51 import com.apple.dnssd.*;
52
53
54 class BrowserApp implements ListSelectionListener, ResolveListener
55 {
56 static BrowserApp app;
57 JFrame frame;
58 DomainListModel domainList;
59 BrowserListModel servicesList, serviceList;
60 JList domainPane, servicesPane, servicePane;
61 DNSSDService servicesBrowser, serviceBrowser, domainBrowser;
62 JLabel hostLabel, portLabel;
63
64 public BrowserApp()
65 {
66 frame = new JFrame("DNS-SD Service Browser");
67 frame.addWindowListener(new WindowAdapter() {
68 public void windowClosing(WindowEvent e) {System.exit(0);}
69 });
70
71 domainList = new DomainListModel();
72 servicesList = new ServicesBrowserListModel();
73 serviceList = new BrowserListModel();
74
75 try {
76 domainBrowser = DNSSD.enumerateDomains( DNSSD.BROWSE_DOMAINS, 0, domainList);
77
78 servicesBrowser = DNSSD.browse( 0, 0, "_services._mdns._udp.", "", servicesList);
79 serviceBrowser = null;
80 }
81 catch ( Exception ex) { terminateWithException( ex); }
82
83 this.setupSubPanes( frame.getContentPane());
84 frame.pack();
85 frame.setVisible(true);
86 }
87
88 protected void setupSubPanes( Container parent)
89 {
90 parent.setLayout( new BoxLayout( parent, BoxLayout.Y_AXIS));
91
92 JPanel browserRow = new JPanel();
93 browserRow.setLayout( new BoxLayout( browserRow, BoxLayout.X_AXIS));
94 domainPane = new JList( domainList);
95 domainPane.addListSelectionListener( this);
96 JScrollPane domainScroller = new JScrollPane( domainPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
97 browserRow.add( domainScroller);
98 servicesPane = new JList( servicesList);
99 servicesPane.addListSelectionListener( this);
100 JScrollPane servicesScroller = new JScrollPane( servicesPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
101 browserRow.add( servicesScroller);
102 servicePane = new JList( serviceList);
103 servicePane.addListSelectionListener( this);
104 JScrollPane serviceScroller = new JScrollPane( servicePane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
105 browserRow.add( serviceScroller);
106
107 /*
108 JPanel buttonRow = new JPanel();
109 buttonRow.setLayout( new BoxLayout( buttonRow, BoxLayout.X_AXIS));
110 buttonRow.add( Box.createHorizontalGlue());
111 JButton connectButton = new JButton( "Don't Connect");
112 buttonRow.add( connectButton);
113 buttonRow.add( Box.createRigidArea( new Dimension( 16, 0)));
114 */
115
116 JPanel labelRow = new JPanel();
117 labelRow.setLayout( new BoxLayout( labelRow, BoxLayout.X_AXIS));
118 labelRow.add( new JLabel( " Host: "));
119 hostLabel = new JLabel();
120 labelRow.add( hostLabel);
121 labelRow.add( Box.createRigidArea( new Dimension( 32, 0)));
122 labelRow.add( new JLabel( "Port: "));
123 portLabel = new JLabel();
124 labelRow.add( portLabel);
125 labelRow.add( Box.createHorizontalGlue());
126
127 parent.add( browserRow);
128 parent.add( Box.createRigidArea( new Dimension( 0, 8)));
129 parent.add( labelRow);
130 // parent.add( buttonRow);
131 parent.add( Box.createRigidArea( new Dimension( 0, 16)));
132 }
133
134 public void valueChanged( ListSelectionEvent e)
135 {
136 try {
137 if ( e.getSource() == domainPane && !e.getValueIsAdjusting())
138 {
139 int newSel = domainPane.getSelectedIndex();
140 if ( -1 != newSel)
141 {
142 if ( serviceBrowser != null)
143 serviceBrowser.stop();
144 serviceList.removeAllElements();
145 servicesBrowser = DNSSD.browse( 0, 0, "_services._mdns._udp.", "", servicesList);
146 }
147 }
148 else if ( e.getSource() == servicesPane && !e.getValueIsAdjusting())
149 {
150 int newSel = servicesPane.getSelectedIndex();
151 if ( serviceBrowser != null)
152 serviceBrowser.stop();
153 serviceList.removeAllElements();
154 if ( -1 != newSel)
155 serviceBrowser = DNSSD.browse( 0, 0, servicesList.getNthRegType( newSel), "", serviceList);
156 }
157 else if ( e.getSource() == servicePane && !e.getValueIsAdjusting())
158 {
159 int newSel = servicePane.getSelectedIndex();
160
161 hostLabel.setText( "");
162 portLabel.setText( "");
163
164 if ( -1 != newSel)
165 {
166 DNSSD.resolve( 0, serviceList.getNthInterface( newSel),
167 serviceList.getNthServiceName( newSel),
168 serviceList.getNthRegType( newSel),
169 serviceList.getNthDomain( newSel),
170 new SwingResolveListener( this));
171 }
172 }
173 }
174 catch ( Exception ex) { terminateWithException( ex); }
175 }
176
177 public void serviceResolved( DNSSDService resolver, int flags, int ifIndex, String fullName,
178 String hostName, int port, TXTRecord txtRecord)
179 {
180 hostLabel.setText( hostName);
181 portLabel.setText( String.valueOf( port));
182 }
183
184 public void operationFailed( DNSSDService service, int errorCode)
185 {
186 // handle failure here
187 }
188
189 protected static void terminateWithException( Exception e)
190 {
191 e.printStackTrace();
192 System.exit( -1);
193 }
194
195 public static void main(String s[])
196 {
197 app = new BrowserApp();
198 }
199 }
200
201
202 class BrowserListModel extends DefaultListModel implements BrowseListener, Runnable
203 {
204 public BrowserListModel()
205 {
206 addCache = new Vector();
207 removeCache = new Vector();
208 }
209
210 /* The Browser invokes this callback when a service is discovered. */
211 public void serviceFound( DNSSDService browser, int flags, int ifIndex,
212 String serviceName, String regType, String domain)
213 {
214 addCache.add( new BrowserListElem( serviceName, domain, regType, ifIndex));
215 if ( ( flags & DNSSD.MORE_COMING) == 0)
216 this.scheduleOnEventThread();
217 }
218
219 public void serviceLost( DNSSDService browser, int flags, int ifIndex,
220 String serviceName, String regType, String domain)
221 {
222 removeCache.add( serviceName);
223 if ( ( flags & DNSSD.MORE_COMING) == 0)
224 this.scheduleOnEventThread();
225 }
226
227 public void run()
228 {
229 while ( removeCache.size() > 0)
230 {
231 String serviceName = (String) removeCache.remove( removeCache.size() - 1);
232 int matchInd = this.findMatching( serviceName); // probably doesn't handle near-duplicates well.
233 if ( matchInd != -1)
234 this.removeElementAt( matchInd);
235 }
236 while ( addCache.size() > 0)
237 {
238 BrowserListElem elem = (BrowserListElem) addCache.remove( addCache.size() - 1);
239 if ( -1 == this.findMatching( elem.fServiceName)) // probably doesn't handle near-duplicates well.
240 this.addInSortOrder( elem);
241 }
242 }
243
244 public void operationFailed( DNSSDService service, int errorCode)
245 {
246 // handle failure here
247 }
248
249 /* The list contains BrowserListElem's */
250 class BrowserListElem
251 {
252 public BrowserListElem( String serviceName, String domain, String type, int ifIndex)
253 { fServiceName = serviceName; fDomain = domain; fType = type; fInt = ifIndex; }
254
255 public String toString() { return fServiceName; }
256
257 public String fServiceName, fDomain, fType;
258 public int fInt;
259 }
260
261 public String getNthServiceName( int n)
262 {
263 BrowserListElem sel = (BrowserListElem) this.get( n);
264 return sel.fServiceName;
265 }
266
267 public String getNthRegType( int n)
268 {
269 BrowserListElem sel = (BrowserListElem) this.get( n);
270 return sel.fType;
271 }
272
273 public String getNthDomain( int n)
274 {
275 BrowserListElem sel = (BrowserListElem) this.get( n);
276 return sel.fDomain;
277 }
278
279 public int getNthInterface( int n)
280 {
281 BrowserListElem sel = (BrowserListElem) this.get( n);
282 return sel.fInt;
283 }
284
285 protected void addInSortOrder( Object obj)
286 {
287 int i;
288 for ( i = 0; i < this.size(); i++)
289 if ( sCollator.compare( obj.toString(), this.getElementAt( i).toString()) < 0)
290 break;
291 this.add( i, obj);
292 }
293
294 protected int findMatching( String match)
295 {
296 for ( int i = 0; i < this.size(); i++)
297 if ( match.equals( this.getElementAt( i).toString()))
298 return i;
299 return -1;
300 }
301
302 protected void scheduleOnEventThread()
303 {
304 try {
305 SwingUtilities.invokeAndWait( this);
306 }
307 catch ( Exception e)
308 {
309 e.printStackTrace();
310 }
311 }
312
313 protected Vector removeCache; // list of serviceNames to remove
314 protected Vector addCache; // list of BrowserListElem's to add
315
316 protected static Collator sCollator;
317
318 static // Initialize our static variables
319 {
320 sCollator = Collator.getInstance();
321 sCollator.setStrength( Collator.PRIMARY);
322 }
323 }
324
325
326 class ServicesBrowserListModel extends BrowserListModel
327 {
328 /* The Browser invokes this callback when a service is discovered. */
329 public void serviceFound( DNSSDService browser, int flags, int ifIndex,
330 String serviceName, String regType, String domain)
331 // Overridden to stuff serviceName into regType and make serviceName human-readable.
332 {
333 regType = serviceName + ( regType.startsWith( "_udp.") ? "._udp." : "._tcp.");
334 super.serviceFound( browser, flags, ifIndex, this.mapTypeToName( serviceName), regType, domain);
335 }
336
337 public void serviceLost( DNSSDService browser, int flags, int ifIndex,
338 String serviceName, String regType, String domain)
339 // Overridden to make serviceName human-readable.
340 {
341 super.serviceLost( browser, flags, ifIndex, this.mapTypeToName( serviceName), regType, domain);
342 }
343
344 protected String mapTypeToName( String type)
345 // Convert a registration type into a human-readable string. Returns original string on no-match.
346 {
347 final String[] namedServices = {
348 "_afpovertcp", "Apple File Sharing",
349 "_http", "World Wide Web servers",
350 "_daap", "Digital Audio Access",
351 "_apple-sasl", "Apple Password Servers",
352 "_distcc", "Distributed Compiler nodes",
353 "_finger", "Finger servers",
354 "_ichat", "iChat clients",
355 "_presence", "iChat AV clients",
356 "_ssh", "SSH servers",
357 "_telnet", "Telnet servers",
358 "_workstation", "Macintosh Manager clients",
359 "_bootps", "BootP servers",
360 "_xserveraid", "XServe RAID devices",
361 "_eppc", "Remote AppleEvents",
362 "_ftp", "FTP services",
363 "_tftp", "TFTP services"
364 };
365
366 for ( int i = 0; i < namedServices.length; i+=2)
367 if ( namedServices[i].equals( type))
368 return namedServices[i + 1];
369 return type;
370 }
371 }
372
373
374 class DomainListModel extends DefaultListModel implements DomainListener
375 {
376 /* Called when a domain is discovered. */
377 public void domainFound( DNSSDService domainEnum, int flags, int ifIndex, String domain)
378 {
379 if ( !this.contains( domain))
380 this.addElement( domain);
381 }
382
383 public void domainLost( DNSSDService domainEnum, int flags, int ifIndex, String domain)
384 {
385 if ( this.contains( domain))
386 this.removeElement( domain);
387 }
388
389 public void operationFailed( DNSSDService service, int errorCode)
390 {
391 // handle failure here
392 }
393 }
394