1 /* -*- Mode: Java; tab-width: 4 -*-
3 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
5 * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
6 * ("Apple") in consideration of your agreement to the following terms, and your
7 * use, installation, modification or redistribution of this Apple software
8 * constitutes acceptance of these terms. If you do not agree with these terms,
9 * please do not use, install, modify or redistribute this Apple software.
11 * In consideration of your agreement to abide by the following terms, and subject
12 * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
13 * copyrights in this original Apple software (the "Apple Software"), to use,
14 * reproduce, modify and redistribute the Apple Software, with or without
15 * modifications, in source and/or binary forms; provided that if you redistribute
16 * the Apple Software in its entirety and without modifications, you must retain
17 * this notice and the following text and disclaimers in all such redistributions of
18 * the Apple Software. Neither the name, trademarks, service marks or logos of
19 * Apple Computer, Inc. may be used to endorse or promote products derived from the
20 * Apple Software without specific prior written permission from Apple. Except as
21 * expressly stated in this notice, no other rights or licenses, express or implied,
22 * are granted by Apple herein, including but not limited to any patent rights that
23 * may be infringed by your derivative works or by other works in which the Apple
24 * Software may be incorporated.
26 * The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
27 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
28 * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
30 * COMBINATION WITH YOUR PRODUCTS.
32 * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
34 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
36 * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
37 * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
38 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 BrowserApp demonstrates how to use DNS-SD to browse for and resolve services.
43 - display resolved TXTRecord
48 import java
.awt
.event
.*;
52 import javax
.swing
.event
.*;
54 import com
.apple
.dnssd
.*;
57 class BrowserApp
implements ListSelectionListener
, ResolveListener
59 static BrowserApp app
;
61 DomainListModel domainList
;
62 BrowserListModel servicesList
, serviceList
;
63 JList domainPane
, servicesPane
, servicePane
;
64 DNSSDService servicesBrowser
, serviceBrowser
, domainBrowser
;
65 JLabel hostLabel
, portLabel
;
69 frame
= new JFrame("DNS-SD Service Browser");
70 frame
.addWindowListener(new WindowAdapter() {
71 public void windowClosing(WindowEvent e
) {System
.exit(0);}
74 domainList
= new DomainListModel();
75 servicesList
= new ServicesBrowserListModel();
76 serviceList
= new BrowserListModel();
79 domainBrowser
= DNSSD
.enumerateDomains( DNSSD
.BROWSE_DOMAINS
, 0, domainList
);
81 servicesBrowser
= DNSSD
.browse( 0, 0, "_services._dns-sd._udp.", "", servicesList
);
82 serviceBrowser
= null;
84 catch ( Exception ex
) { terminateWithException( ex
); }
86 this.setupSubPanes( frame
.getContentPane());
88 frame
.setVisible(true);
91 protected void setupSubPanes( Container parent
)
93 parent
.setLayout( new BoxLayout( parent
, BoxLayout
.Y_AXIS
));
95 JPanel browserRow
= new JPanel();
96 browserRow
.setLayout( new BoxLayout( browserRow
, BoxLayout
.X_AXIS
));
97 domainPane
= new JList( domainList
);
98 domainPane
.addListSelectionListener( this);
99 JScrollPane domainScroller
= new JScrollPane( domainPane
, JScrollPane
.VERTICAL_SCROLLBAR_ALWAYS
, JScrollPane
.HORIZONTAL_SCROLLBAR_ALWAYS
);
100 browserRow
.add( domainScroller
);
101 servicesPane
= new JList( servicesList
);
102 servicesPane
.addListSelectionListener( this);
103 JScrollPane servicesScroller
= new JScrollPane( servicesPane
, JScrollPane
.VERTICAL_SCROLLBAR_ALWAYS
, JScrollPane
.HORIZONTAL_SCROLLBAR_ALWAYS
);
104 browserRow
.add( servicesScroller
);
105 servicePane
= new JList( serviceList
);
106 servicePane
.addListSelectionListener( this);
107 JScrollPane serviceScroller
= new JScrollPane( servicePane
, JScrollPane
.VERTICAL_SCROLLBAR_ALWAYS
, JScrollPane
.HORIZONTAL_SCROLLBAR_ALWAYS
);
108 browserRow
.add( serviceScroller
);
111 JPanel buttonRow = new JPanel();
112 buttonRow.setLayout( new BoxLayout( buttonRow, BoxLayout.X_AXIS));
113 buttonRow.add( Box.createHorizontalGlue());
114 JButton connectButton = new JButton( "Don't Connect");
115 buttonRow.add( connectButton);
116 buttonRow.add( Box.createRigidArea( new Dimension( 16, 0)));
119 JPanel labelRow
= new JPanel();
120 labelRow
.setLayout( new BoxLayout( labelRow
, BoxLayout
.X_AXIS
));
121 labelRow
.add( new JLabel( " Host: "));
122 hostLabel
= new JLabel();
123 labelRow
.add( hostLabel
);
124 labelRow
.add( Box
.createRigidArea( new Dimension( 32, 0)));
125 labelRow
.add( new JLabel( "Port: "));
126 portLabel
= new JLabel();
127 labelRow
.add( portLabel
);
128 labelRow
.add( Box
.createHorizontalGlue());
130 parent
.add( browserRow
);
131 parent
.add( Box
.createRigidArea( new Dimension( 0, 8)));
132 parent
.add( labelRow
);
133 // parent.add( buttonRow);
134 parent
.add( Box
.createRigidArea( new Dimension( 0, 16)));
137 public void valueChanged( ListSelectionEvent e
)
140 if ( e
.getSource() == domainPane
&& !e
.getValueIsAdjusting())
142 int newSel
= domainPane
.getSelectedIndex();
145 if ( serviceBrowser
!= null)
146 serviceBrowser
.stop();
147 serviceList
.removeAllElements();
148 servicesBrowser
= DNSSD
.browse( 0, 0, "_services._dns-sd._udp.", "", servicesList
);
151 else if ( e
.getSource() == servicesPane
&& !e
.getValueIsAdjusting())
153 int newSel
= servicesPane
.getSelectedIndex();
154 if ( serviceBrowser
!= null)
155 serviceBrowser
.stop();
156 serviceList
.removeAllElements();
158 serviceBrowser
= DNSSD
.browse( 0, 0, servicesList
.getNthRegType( newSel
), "", serviceList
);
160 else if ( e
.getSource() == servicePane
&& !e
.getValueIsAdjusting())
162 int newSel
= servicePane
.getSelectedIndex();
164 hostLabel
.setText( "");
165 portLabel
.setText( "");
169 DNSSD
.resolve( 0, serviceList
.getNthInterface( newSel
),
170 serviceList
.getNthServiceName( newSel
),
171 serviceList
.getNthRegType( newSel
),
172 serviceList
.getNthDomain( newSel
),
173 new SwingResolveListener( this));
177 catch ( Exception ex
) { terminateWithException( ex
); }
180 public void serviceResolved( DNSSDService resolver
, int flags
, int ifIndex
, String fullName
,
181 String hostName
, int port
, TXTRecord txtRecord
)
183 hostLabel
.setText( hostName
);
184 portLabel
.setText( String
.valueOf( port
));
187 public void operationFailed( DNSSDService service
, int errorCode
)
189 // handle failure here
192 protected static void terminateWithException( Exception e
)
198 public static void main(String s
[])
200 app
= new BrowserApp();
205 class BrowserListModel
extends DefaultListModel
implements BrowseListener
, Runnable
207 public BrowserListModel()
209 addCache
= new Vector();
210 removeCache
= new Vector();
213 /* The Browser invokes this callback when a service is discovered. */
214 public void serviceFound( DNSSDService browser
, int flags
, int ifIndex
,
215 String serviceName
, String regType
, String domain
)
217 addCache
.add( new BrowserListElem( serviceName
, domain
, regType
, ifIndex
));
218 if ( ( flags
& DNSSD
.MORE_COMING
) == 0)
219 this.scheduleOnEventThread();
222 public void serviceLost( DNSSDService browser
, int flags
, int ifIndex
,
223 String serviceName
, String regType
, String domain
)
225 removeCache
.add( serviceName
);
226 if ( ( flags
& DNSSD
.MORE_COMING
) == 0)
227 this.scheduleOnEventThread();
232 while ( removeCache
.size() > 0)
234 String serviceName
= (String
) removeCache
.remove( removeCache
.size() - 1);
235 int matchInd
= this.findMatching( serviceName
); // probably doesn't handle near-duplicates well.
237 this.removeElementAt( matchInd
);
239 while ( addCache
.size() > 0)
241 BrowserListElem elem
= (BrowserListElem
) addCache
.remove( addCache
.size() - 1);
242 if ( -1 == this.findMatching( elem
.fServiceName
)) // probably doesn't handle near-duplicates well.
243 this.addInSortOrder( elem
);
247 public void operationFailed( DNSSDService service
, int errorCode
)
249 // handle failure here
252 /* The list contains BrowserListElem's */
253 class BrowserListElem
255 public BrowserListElem( String serviceName
, String domain
, String type
, int ifIndex
)
256 { fServiceName
= serviceName
; fDomain
= domain
; fType
= type
; fInt
= ifIndex
; }
258 public String
toString() { return fServiceName
; }
260 public String fServiceName
, fDomain
, fType
;
264 public String
getNthServiceName( int n
)
266 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
267 return sel
.fServiceName
;
270 public String
getNthRegType( int n
)
272 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
276 public String
getNthDomain( int n
)
278 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
282 public int getNthInterface( int n
)
284 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
288 protected void addInSortOrder( Object obj
)
291 for ( i
= 0; i
< this.size(); i
++)
292 if ( sCollator
.compare( obj
.toString(), this.getElementAt( i
).toString()) < 0)
297 protected int findMatching( String match
)
299 for ( int i
= 0; i
< this.size(); i
++)
300 if ( match
.equals( this.getElementAt( i
).toString()))
305 protected void scheduleOnEventThread()
308 SwingUtilities
.invokeAndWait( this);
316 protected Vector removeCache
; // list of serviceNames to remove
317 protected Vector addCache
; // list of BrowserListElem's to add
319 protected static Collator sCollator
;
321 static // Initialize our static variables
323 sCollator
= Collator
.getInstance();
324 sCollator
.setStrength( Collator
.PRIMARY
);
329 class ServicesBrowserListModel
extends BrowserListModel
331 /* The Browser invokes this callback when a service is discovered. */
332 public void serviceFound( DNSSDService browser
, int flags
, int ifIndex
,
333 String serviceName
, String regType
, String domain
)
334 // Overridden to stuff serviceName into regType and make serviceName human-readable.
336 regType
= serviceName
+ ( regType
.startsWith( "_udp.") ?
"._udp." : "._tcp.");
337 super.serviceFound( browser
, flags
, ifIndex
, this.mapTypeToName( serviceName
), regType
, domain
);
340 public void serviceLost( DNSSDService browser
, int flags
, int ifIndex
,
341 String serviceName
, String regType
, String domain
)
342 // Overridden to make serviceName human-readable.
344 super.serviceLost( browser
, flags
, ifIndex
, this.mapTypeToName( serviceName
), regType
, domain
);
347 protected String
mapTypeToName( String type
)
348 // Convert a registration type into a human-readable string. Returns original string on no-match.
350 final String
[] namedServices
= {
351 "_afpovertcp", "Apple File Sharing",
352 "_http", "World Wide Web servers",
353 "_daap", "Digital Audio Access",
354 "_apple-sasl", "Apple Password Servers",
355 "_distcc", "Distributed Compiler nodes",
356 "_finger", "Finger servers",
357 "_ichat", "iChat clients",
358 "_presence", "iChat AV clients",
359 "_ssh", "SSH servers",
360 "_telnet", "Telnet servers",
361 "_workstation", "Macintosh Manager clients",
362 "_bootps", "BootP servers",
363 "_xserveraid", "XServe RAID devices",
364 "_eppc", "Remote AppleEvents",
365 "_ftp", "FTP services",
366 "_tftp", "TFTP services"
369 for ( int i
= 0; i
< namedServices
.length
; i
+=2)
370 if ( namedServices
[i
].equals( type
))
371 return namedServices
[i
+ 1];
377 class DomainListModel
extends DefaultListModel
implements DomainListener
379 /* Called when a domain is discovered. */
380 public void domainFound( DNSSDService domainEnum
, int flags
, int ifIndex
, String domain
)
382 if ( !this.contains( domain
))
383 this.addElement( domain
);
386 public void domainLost( DNSSDService domainEnum
, int flags
, int ifIndex
, String domain
)
388 if ( this.contains( domain
))
389 this.removeElement( domain
);
392 public void operationFailed( DNSSDService service
, int errorCode
)
394 // handle failure here