2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
27 $Log: BrowserApp.java,v $
28 Revision 1.3 2004/05/26 01:41:58 cheshire
29 Pass proper flags to DNSSD.enumerateDomains
31 Revision 1.2 2004/04/30 21:53:34 rpantos
32 Change line endings for CVS.
34 Revision 1.1 2004/04/30 16:29:35 rpantos
37 BrowserApp demonstrates how to use DNSSD to browse for and resolve services.
40 - display resolved TXTRecord
45 import java
.awt
.event
.*;
49 import javax
.swing
.event
.*;
51 import com
.apple
.dnssd
.*;
54 class BrowserApp
implements ListSelectionListener
, ResolveListener
56 static BrowserApp app
;
58 DomainListModel domainList
;
59 BrowserListModel servicesList
, serviceList
;
60 JList domainPane
, servicesPane
, servicePane
;
61 DNSSDService servicesBrowser
, serviceBrowser
, domainBrowser
;
62 JLabel hostLabel
, portLabel
;
66 frame
= new JFrame("DNS-SD Service Browser");
67 frame
.addWindowListener(new WindowAdapter() {
68 public void windowClosing(WindowEvent e
) {System
.exit(0);}
71 domainList
= new DomainListModel();
72 servicesList
= new ServicesBrowserListModel();
73 serviceList
= new BrowserListModel();
76 domainBrowser
= DNSSD
.enumerateDomains( DNSSD
.BROWSE_DOMAINS
, 0, domainList
);
78 servicesBrowser
= DNSSD
.browse( 0, 0, "_services._mdns._udp.", "", servicesList
);
79 serviceBrowser
= null;
81 catch ( Exception ex
) { terminateWithException( ex
); }
83 this.setupSubPanes( frame
.getContentPane());
85 frame
.setVisible(true);
88 protected void setupSubPanes( Container parent
)
90 parent
.setLayout( new BoxLayout( parent
, BoxLayout
.Y_AXIS
));
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
);
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)));
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());
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)));
134 public void valueChanged( ListSelectionEvent e
)
137 if ( e
.getSource() == domainPane
&& !e
.getValueIsAdjusting())
139 int newSel
= domainPane
.getSelectedIndex();
142 if ( serviceBrowser
!= null)
143 serviceBrowser
.stop();
144 serviceList
.removeAllElements();
145 servicesBrowser
= DNSSD
.browse( 0, 0, "_services._mdns._udp.", "", servicesList
);
148 else if ( e
.getSource() == servicesPane
&& !e
.getValueIsAdjusting())
150 int newSel
= servicesPane
.getSelectedIndex();
151 if ( serviceBrowser
!= null)
152 serviceBrowser
.stop();
153 serviceList
.removeAllElements();
155 serviceBrowser
= DNSSD
.browse( 0, 0, servicesList
.getNthRegType( newSel
), "", serviceList
);
157 else if ( e
.getSource() == servicePane
&& !e
.getValueIsAdjusting())
159 int newSel
= servicePane
.getSelectedIndex();
161 hostLabel
.setText( "");
162 portLabel
.setText( "");
166 DNSSD
.resolve( 0, serviceList
.getNthInterface( newSel
),
167 serviceList
.getNthServiceName( newSel
),
168 serviceList
.getNthRegType( newSel
),
169 serviceList
.getNthDomain( newSel
),
170 new SwingResolveListener( this));
174 catch ( Exception ex
) { terminateWithException( ex
); }
177 public void serviceResolved( DNSSDService resolver
, int flags
, int ifIndex
, String fullName
,
178 String hostName
, int port
, TXTRecord txtRecord
)
180 hostLabel
.setText( hostName
);
181 portLabel
.setText( String
.valueOf( port
));
184 public void operationFailed( DNSSDService service
, int errorCode
)
186 // handle failure here
189 protected static void terminateWithException( Exception e
)
195 public static void main(String s
[])
197 app
= new BrowserApp();
202 class BrowserListModel
extends DefaultListModel
implements BrowseListener
, Runnable
204 public BrowserListModel()
206 addCache
= new Vector();
207 removeCache
= new Vector();
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
)
214 addCache
.add( new BrowserListElem( serviceName
, domain
, regType
, ifIndex
));
215 if ( ( flags
& DNSSD
.MORE_COMING
) == 0)
216 this.scheduleOnEventThread();
219 public void serviceLost( DNSSDService browser
, int flags
, int ifIndex
,
220 String serviceName
, String regType
, String domain
)
222 removeCache
.add( serviceName
);
223 if ( ( flags
& DNSSD
.MORE_COMING
) == 0)
224 this.scheduleOnEventThread();
229 while ( removeCache
.size() > 0)
231 String serviceName
= (String
) removeCache
.remove( removeCache
.size() - 1);
232 int matchInd
= this.findMatching( serviceName
); // probably doesn't handle near-duplicates well.
234 this.removeElementAt( matchInd
);
236 while ( addCache
.size() > 0)
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
);
244 public void operationFailed( DNSSDService service
, int errorCode
)
246 // handle failure here
249 /* The list contains BrowserListElem's */
250 class BrowserListElem
252 public BrowserListElem( String serviceName
, String domain
, String type
, int ifIndex
)
253 { fServiceName
= serviceName
; fDomain
= domain
; fType
= type
; fInt
= ifIndex
; }
255 public String
toString() { return fServiceName
; }
257 public String fServiceName
, fDomain
, fType
;
261 public String
getNthServiceName( int n
)
263 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
264 return sel
.fServiceName
;
267 public String
getNthRegType( int n
)
269 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
273 public String
getNthDomain( int n
)
275 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
279 public int getNthInterface( int n
)
281 BrowserListElem sel
= (BrowserListElem
) this.get( n
);
285 protected void addInSortOrder( Object obj
)
288 for ( i
= 0; i
< this.size(); i
++)
289 if ( sCollator
.compare( obj
.toString(), this.getElementAt( i
).toString()) < 0)
294 protected int findMatching( String match
)
296 for ( int i
= 0; i
< this.size(); i
++)
297 if ( match
.equals( this.getElementAt( i
).toString()))
302 protected void scheduleOnEventThread()
305 SwingUtilities
.invokeAndWait( this);
313 protected Vector removeCache
; // list of serviceNames to remove
314 protected Vector addCache
; // list of BrowserListElem's to add
316 protected static Collator sCollator
;
318 static // Initialize our static variables
320 sCollator
= Collator
.getInstance();
321 sCollator
.setStrength( Collator
.PRIMARY
);
326 class ServicesBrowserListModel
extends BrowserListModel
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.
333 regType
= serviceName
+ ( regType
.startsWith( "_udp.") ?
"._udp." : "._tcp.");
334 super.serviceFound( browser
, flags
, ifIndex
, this.mapTypeToName( serviceName
), regType
, domain
);
337 public void serviceLost( DNSSDService browser
, int flags
, int ifIndex
,
338 String serviceName
, String regType
, String domain
)
339 // Overridden to make serviceName human-readable.
341 super.serviceLost( browser
, flags
, ifIndex
, this.mapTypeToName( serviceName
), regType
, domain
);
344 protected String
mapTypeToName( String type
)
345 // Convert a registration type into a human-readable string. Returns original string on no-match.
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"
366 for ( int i
= 0; i
< namedServices
.length
; i
+=2)
367 if ( namedServices
[i
].equals( type
))
368 return namedServices
[i
+ 1];
374 class DomainListModel
extends DefaultListModel
implements DomainListener
376 /* Called when a domain is discovered. */
377 public void domainFound( DNSSDService domainEnum
, int flags
, int ifIndex
, String domain
)
379 if ( !this.contains( domain
))
380 this.addElement( domain
);
383 public void domainLost( DNSSDService domainEnum
, int flags
, int ifIndex
, String domain
)
385 if ( this.contains( domain
))
386 this.removeElement( domain
);
389 public void operationFailed( DNSSDService service
, int errorCode
)
391 // handle failure here