2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
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.
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.
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.
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.
39 BrowserApp demonstrates how to use DNS-SD to browse for and resolve services.
42 - display resolved TXTRecord
47 import java
.awt
.event
.*;
51 import javax
.swing
.event
.*;
53 import com
.apple
.dnssd
.*;
56 class BrowserApp
implements ListSelectionListener
, ResolveListener
58 static BrowserApp app
;
60 DomainListModel domainList
;
61 BrowserListModel servicesList
, serviceList
;
62 JList domainPane
, servicesPane
, servicePane
;
63 DNSSDService servicesBrowser
, serviceBrowser
, domainBrowser
;
64 JLabel hostLabel
, portLabel
;
68 frame
= new JFrame("DNS-SD Service Browser");
69 frame
.addWindowListener(new WindowAdapter() {
70 public void windowClosing(WindowEvent e
) {System
.exit(0);}
73 domainList
= new DomainListModel();
74 servicesList
= new ServicesBrowserListModel();
75 serviceList
= new BrowserListModel();
78 domainBrowser
= DNSSD
.enumerateDomains( DNSSD
.BROWSE_DOMAINS
, 0, domainList
);
80 servicesBrowser
= DNSSD
.browse( 0, 0, "_services._dns-sd._udp.", "", servicesList
);
81 serviceBrowser
= null;
83 catch ( Exception ex
) { terminateWithException( ex
); }
85 this.setupSubPanes( frame
.getContentPane());
87 frame
.setVisible(true);
90 protected void setupSubPanes( Container parent
)
92 parent
.setLayout( new BoxLayout( parent
, BoxLayout
.Y_AXIS
));
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
);
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)));
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());
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)));
136 public void valueChanged( ListSelectionEvent e
)
139 if ( e
.getSource() == domainPane
&& !e
.getValueIsAdjusting())
141 int newSel
= domainPane
.getSelectedIndex();
144 if ( serviceBrowser
!= null)
145 serviceBrowser
.stop();
146 serviceList
.removeAllElements();
147 servicesBrowser
= DNSSD
.browse( 0, 0, "_services._dns-sd._udp.", "", servicesList
);
150 else if ( e
.getSource() == servicesPane
&& !e
.getValueIsAdjusting())
152 int newSel
= servicesPane
.getSelectedIndex();
153 if ( serviceBrowser
!= null)
154 serviceBrowser
.stop();
155 serviceList
.removeAllElements();
157 serviceBrowser
= DNSSD
.browse( 0, 0, servicesList
.getNthRegType( newSel
), "", serviceList
);
159 else if ( e
.getSource() == servicePane
&& !e
.getValueIsAdjusting())
161 int newSel
= servicePane
.getSelectedIndex();
163 hostLabel
.setText( "");
164 portLabel
.setText( "");
168 DNSSD
.resolve( 0, serviceList
.getNthInterface( newSel
),
169 serviceList
.getNthServiceName( newSel
),
170 serviceList
.getNthRegType( newSel
),
171 serviceList
.getNthDomain( newSel
),
172 new SwingResolveListener( this));
176 catch ( Exception ex
) { terminateWithException( ex
); }
179 public void serviceResolved( DNSSDService resolver
, int flags
, int ifIndex
, String fullName
,
180 String hostName
, int port
, TXTRecord txtRecord
)
182 hostLabel
.setText( hostName
);
183 portLabel
.setText( String
.valueOf( port
));
186 public void operationFailed( DNSSDService service
, int errorCode
)
188 // handle failure here
191 protected static void terminateWithException( Exception e
)
197 public static void main(String s
[])
199 app
= new BrowserApp();
204 class BrowserListModel
extends DefaultListModel
implements BrowseListener
, Runnable
206 public BrowserListModel()
208 addCache
= new Vector();
209 removeCache
= new Vector();
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
)
216 addCache
.add( new BrowserListElem( serviceName
, domain
, regType
, ifIndex
));
217 if ( ( flags
& DNSSD
.MORE_COMING
) == 0)
218 this.scheduleOnEventThread();
221 public void serviceLost( DNSSDService browser
, int flags
, int ifIndex
,
222 String serviceName
, String regType
, String domain
)
224 removeCache
.add( serviceName
);
225 if ( ( flags
& DNSSD
.MORE_COMING
) == 0)
226 this.scheduleOnEventThread();
231 while ( removeCache
.size() > 0)
233 String serviceName
= (String
) removeCache
.remove( removeCache
.size() - 1);
234 int matchInd
= this.findMatching( serviceName
); // probably doesn't handle near-duplicates well.
236 this.removeElementAt( matchInd
);
238 while ( addCache
.size() > 0)
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
);
246 public void operationFailed( DNSSDService service
, int errorCode
)
248 // handle failure here
251 /* The list contains BrowserListElem's */
252 class BrowserListElem
254 public BrowserListElem( String serviceName
, String domain
, String type
, int ifIndex
)
255 { fServiceName
= serviceName
; fDomain
= domain
; fType
= type
; fInt
= ifIndex
; }
257 public String
toString() { return fServiceName
; }
259 public String fServiceName
, fDomain
, fType
;
263 public String
getNthServiceName( int n
)
265 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
266 return sel
.fServiceName
;
269 public String
getNthRegType( int n
)
271 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
275 public String
getNthDomain( int n
)
277 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
281 public int getNthInterface( int n
)
283 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
287 protected void addInSortOrder( Object obj
)
290 for ( i
= 0; i
< this.size(); i
++)
291 if ( sCollator
.compare( obj
.toString(), this.getElementAt( i
).toString()) < 0)
296 protected int findMatching( String match
)
298 for ( int i
= 0; i
< this.size(); i
++)
299 if ( match
.equals( this.getElementAt( i
).toString()))
304 protected void scheduleOnEventThread()
307 SwingUtilities
.invokeAndWait( this);
315 protected Vector removeCache
; // list of serviceNames to remove
316 protected Vector addCache
; // list of BrowserListElem's to add
318 protected static Collator sCollator
;
320 static // Initialize our static variables
322 sCollator
= Collator
.getInstance();
323 sCollator
.setStrength( Collator
.PRIMARY
);
328 class ServicesBrowserListModel
extends BrowserListModel
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.
335 regType
= serviceName
+ ( regType
.startsWith( "_udp.") ?
"._udp." : "._tcp.");
336 super.serviceFound( browser
, flags
, ifIndex
, this.mapTypeToName( serviceName
), regType
, domain
);
339 public void serviceLost( DNSSDService browser
, int flags
, int ifIndex
,
340 String serviceName
, String regType
, String domain
)
341 // Overridden to make serviceName human-readable.
343 super.serviceLost( browser
, flags
, ifIndex
, this.mapTypeToName( serviceName
), regType
, domain
);
346 protected String
mapTypeToName( String type
)
347 // Convert a registration type into a human-readable string. Returns original string on no-match.
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"
368 for ( int i
= 0; i
< namedServices
.length
; i
+=2)
369 if ( namedServices
[i
].equals( type
))
370 return namedServices
[i
+ 1];
376 class DomainListModel
extends DefaultListModel
implements DomainListener
378 /* Called when a domain is discovered. */
379 public void domainFound( DNSSDService domainEnum
, int flags
, int ifIndex
, String domain
)
381 if ( !this.contains( domain
))
382 this.addElement( domain
);
385 public void domainLost( DNSSDService domainEnum
, int flags
, int ifIndex
, String domain
)
387 if ( this.contains( domain
))
388 this.removeElement( domain
);
391 public void operationFailed( DNSSDService service
, int errorCode
)
393 // handle failure here