ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button O'Reilly Book Excerpts: Zero Configuration Networking: The Definitive Guide

Zero Configuration Networking: Using the Java APIs, Part 1

by Daniel H. Steinberg, Stuart Cheshire

Editor's Note: Zeroconf, also known by Apple's trade name of Bonjour, and previously as Rendezvous, offers interesting solutions to the problems of self-networking, in the potential absence of host naming and address assignment. Zeroconf applications can advertise themselves on the network and discover available services. Zero Configuration Networking: The Definitive Guide, by Stuart Cheshire and Daniel H. Steinberg, introduces the concepts and the many implementations of Zeroconf, including its Java API. In this first of a two-part introduction, the authors look at registering a service with Java.

Related Reading

Zero Configuration Networking: The Definitive Guide
By Daniel H. Steinberg, Stuart Cheshire

Starting in Mac OS X 10.3.9, new APIs enable Java software to advertise and discover services on the network using Zeroconf's DNS Service Discovery. The same Java DNS-SD APIs are also available in Bonjour for Windows, Bonjour for Linux, Solaris, *BSD, etc., enabling Java software to make use of Zeroconf's DNS Service Discovery across a wide range of platforms, not just on Mac OS X. In this chapter, you will take a quick look through the APIs, see short examples of how to register, browse for, add TXT records to, and resolve services, and finally see a complete example of using Java DNS-SD in a tic-tac-toe game.

Understanding the APIs

The com.apple.dnssd package exposes an abstract factory class, DNSSD, used to create the various types of DNSSDService objects, two classes used to manipulate DNS records, a collection of interfaces that are implemented as appropriate by client code to receive callback messages, and an exception:

  • Factory Class:

    • DNSSD

  • References to ongoing asynchronous operations:

    • DNSSDService

    • DNSSDRegistration

  • DNS Record Classes:

    • DNSRecord

    • TXTRecord

  • Callback Interface Classes, implemented by client:

    • BaseListener

    • RegisterListener

    • BrowseListener

    • ResolveListener

    • DomainListener

    • QueryListener

  • DNSSD Error Exception:

    • DNSSDException

The pattern for using the APIs will most often consist of calling a static method from the DNSSD factory class, passing in an instance of a class that implements the appropriate interface to receive callback messages. For example, when calling DNSSD.browse( ) to initiate a browsing operation, the client must supply an object that implements the BrowseListener interface.

As with all the different flavors of DNS-SD API, the Java APIs are asynchronous—you start an operation and get callback messages when interesting events happen—and to make effective use of the API, it is helpful to understand the mechanism by which those callback messages are delivered. Recall that in the C API, since there is no single event-handling model universally adopted by all C programs, the API returns a socket file descriptor to the client, so that the client can integrate it into the client's chosen event-handling model, such as a select( ) loop or similar. In contrast, when using the Mac OS X Cocoa APIs, it is assumed that the client will be using a Cocoa RunLoop, so ongoing asynchronous operations are automatically added to the current RunLoop, and events are automatically delivered sequentially to the client, as with other RunLoop events.

Unlike C (and its standard libraries), Java was designed from the start with full support for multithreaded code, so just as it is reasonable to assume that Cocoa programs use a RunLoop, it is reasonable to assume that Java programs can take advantage of threads. For this reason, Java clients get a benefit not present in the C API: Java clients don't need to take any special scheduling action to receive the events generated by the DNS-SD APIs. As soon as an asynchronous operation is initiated, the listener object will immediately begin receiving events, delivered "by magic," as it were, on a different thread automatically created for this purpose. Of course, all magic comes at some cost, and the cost is that the client code needs to be thread-safe. The moment a client thread calls DNSSD.browse( ), the listener object may start receiving events, running on another thread, even before the DNSSD.browse( ) call has returned to the caller. For this reason, even though the DNSSDService object is returned as the result of the DNSSD.browse( ) call, it is also passed as the first parameter in listener object methods, so that those methods can get reliable access to that value if they need it (for example, to stop the operation once they've received the result they need). Don't make the mistake of writing client code that calls DNSSD.browse( ) and places the result into some global or class variable, and then writing listener object methods that make use of the value in that variable. Frequently, the listener object methods will be invoked so quickly that they will be running before the main thread has done its assignment, resulting in the listener object methods accessing the value of the variable before it has been set.

Another issue to be aware of is that some other Java APIs have multithreading restrictions. For example, if you're writing Swing/AWT GUI code, it's important to remember that Swing components can be accessed by only one thread at a time. Generally, this thread is the event-dispatching thread. If you don't heed this warning, and you make Swing calls from other threads, then your program will be unreliable and is likely to fail randomly in mysterious ways. Since the typical purpose of a BrowseListener object is to update the user interface in response to services coming and going on the network, and since BrowseListener events are delivered asynchronously as they happen, on their own thread, this presents a small dilemma. How can a BrowseListener method legally perform Swing/AWT user interface operations? The solution is that the BrowseListener should use SwingUtilities.invokeAndWait to cause the event to be handled synchronously on the AWT event dispatching thread, where it can safely make user interface calls. The tic-tac-toe programming example at the end of this chapter demonstrates how to do this. There is also some sample code in the Clients/Java folder of Apple's Darwin mDNSResponder project. That code defines helper classes with names like SwingBrowseListener, which act as intermediaries between the raw DNS-SD events, delivered on their own background threads, and your own listener routines, which need to run on the AWT event-dispatching thread if they're going to make user interface calls. These helper objects receive the raw DNS-SD events on your behalf and then schedule your listener method to be executed on the AWT event-dispatching thread. Similar techniques can be used to accommodate other packages that have their own multithreading restrictions.

In this section, you will survey the com.apple.dnssd package.

Pages: 1, 2, 3, 4, 5

Next Pagearrow