August 29, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Dynamic Service Discovery with Java

  • February 19, 2008
  • By Rob Lybarger
  • Send Email »
  • More Articles »

Now, you have the code modifications for the client.

public class TestClient implements ServiceBrowserListener {

  public static final String SERVICE_NAME = "timeDemo";

  public static void main(String[] args) {
    new TestClient();
  }

  ServiceBrowser browser;
  Vector<ServiceDescription> descriptors;
  
  TestClient() {
    descriptors = new Vector<ServiceDescription>();

    /* first browse for any 'timeDemo' instance */
    browser = new ServiceBrowser();
    browser.addServiceBrowserListener(this);
    browser.setServiceName(SERVICE_NAME);
    browser.startListener();
    browser.startLookup();
    System.out.println(
        "Browser started. Will search for 2 secs.");
    try {
      Thread.sleep(2000);
    }
    catch (InterruptedException ie) {
      // ignore
    }
    browser.stopLookup();
    browser.stopListener();
    
    /* now if the browser found any matches, we'll
     * print out the complete list, but only connect
     * to the first one.
     */
    if (descriptors.size()>0) {

      System.out.println("\n---TIME SERVERS---");
      for (ServiceDescription descriptor : descriptors) {
        System.out.println(descriptor.toString());
      }

      System.out.println("\n---FIRST SERVER'S TIME IS---");
      ServiceDescription descriptor = descriptors.get(0);
      try {
        Socket socket = new Socket(descriptor.getAddress(),
                                   descriptor.getPort());
        InputStreamReader reader =
           new InputStreamReader(socket.getInputStream());
        BufferedReader bufferedReader =
           new BufferedReader(reader);
        String line = bufferedReader.readLine();
        System.out.println(line);
        socket.close();
      }
      catch (IOException ie) {
        System.err.println("Exception: "+ie);
        System.exit(1);
      }
    }
    else {
      System.out.println("\n---NO TIME SERVERS FOUND---");
    }
    
    System.out.println("\nThat's all folks.");
    System.exit(0);
  }

  /* This is an event call-back method the browser uses
   * when it receives a response. This will only be
   * called during the two-second execution window.
   */
  public void serviceReply(ServiceDescription descriptor) {
    int pos = descriptors.indexOf(descriptor);
    if (pos>-1) {
      descriptors.removeElementAt(pos);
    }
    descriptors.add(descriptor);
  }

}

The structure is a little bit different this time just to satisfy needing an instance method to implement the ServiceBrowserListener interface. (However, you could write an inner/anonymous implementation and keep everything entirely in the static 'main' method, if you want.) Before connecting, the client first needs to run the discovery browser to poll the network for available services. After letting the browser run for a little while, the browser is stopped, and the vector of responses is displayed. (The vector stores the same descriptor objects that the server-side code uses.) The first response in the vector is used to make a direct connection, just as before.

And, there you have it. You can run as many Time Server instances on the network as you want (just use different instance names for each). You can run them on any port you want, and you can bring the servers up and down as desired. Whenever this client runs, it will look for any instance that responds to the browse query.

Conclusion

Adding dynamic service discovery to an application actually can be a fairly simple matter. The browser/responder code only needs to be written once, and then it can be packaged along with your client and server application components time after time. (And I've already given you a good, basic starting point for this code.)

Other Directions

If you skipped the Concept section, you should note there are a few extra things that the browser/responder can incorporate to add a little more robustness and efficiency. One of these is "known answer suppression." This requires a little variation in the packets the browser sends out to include a list of those instances it already knows about, because the browse period is likely (and, for practical purposes, should be) long enough to send out a few browse requests. It also requires a corresponding variation in the responder code to look for you "known answer" tokens in the browse requests so it can ignore them. Another nice touch is to have the server send out an "available/not-available" announcement when it starts up or when it shuts down. (Catching a control-C signal can be arranged using the Runtime.addShutdownHook method.) Clients that watch for these extra announcements can maintain an even more up-to-date list of available servers. (In a chat application, you would see someone immediately join or leave, for example.) Finally, if you start making a lot of use of discovery code, and you have a lot of server and client nodes, you might consider a known-answer caching mechanism (with some extra intelligence to allow these caches to gradually expire, and the like). You even can have client browsers running in a passive mode to cache responses that were triggered by other browse requests in more active clients. I'll leave implementation of these ideas to the reader.

Download the Code

You can download the code that accompanies this article here.

About the Author

Rob Lybarger is a software guy (and a degreed aerospace engineer) in the Houston, TX area who has been using Java for nearly ten years. He has used various versions of Windows, various distributions of Linux, but loves Mac OS X. He likes exploring new techniques and new approaches to organizing and wiring applications, and loves to let the computer do as much work for him as possible.





Page 4 of 4



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel