Implementing sorting services

Now that we have an understanding of how to create and consume services, let's put this to practice in the address book viewer application. We'll create multiple sorting implementation modules and register these implementations as services. We'll then update the packt.addressbook module to use the ServiceLoader API to get the sorting instances, and then use one of these instances to sort the contacts list. Let's run through the five steps we've just learned in order to achieve this:

  1. Create the Java type that defines the service: We'll retain the interface SortUtil to be the common interface that various implementation types will use. The packt.sortutil module contains both the interface and implementation types now. We'll remove the implementation and leave just the interface in there. We'll also remove the default static dependency on BubbleSortUtilImpl and make this a pure and abstract interface:
        package packt.util; 
        import java.util.List; 
        public interface SortUtil { 
          public <T extends Comparable> List<T> sortList(List<T> list); 
        } 

This will be the only type in the packt.sortutil module. The module exports the packt.util package to make the interface available to both the providers and consumers. Here's module-info.java:

        module packt.sortutil { 
          exports packt.util; 
        } 
  1. Create one or more implementation modules that read the interface module and implement the interface: Let's create a couple of implementation modules--packt.sort.bubblesort, which provides the BubbleSort implementation, and packt.sort.javasort, which provides an implementation using the default sorting API of Java collections:
Make sure you don't put both the implementation classes in the two modules in the same package. For example, both the implementation classes cannot be in the same packt.util.impl package, because then you'll run into the problem of split packages, with both modules containing the same package, and the runtime will throw an error. We've covered the split packages problem in Chapter 6, Module Resolution, Accessibility, and Readability.

Both the modules requires the module packt.sortutil in order to access the packt.util.SortUtil interface. Each has an implementation of the interface.

Here's BubbleSortUtilImpl, which is a class we've already seen, so here's the truncated version:

        public class BubbleSortUtilImpl implements SortUtil { 
 
          public <T extends Comparable> List<T> sortList(
List<T> list) { ... return list; }'' }

Here's JavaSortUtilImpl, which simply uses the Collections.sort API:

        public class JavaSortUtilImpl implements SortUtil { 
          public <T extends Comparable> List<T> sortList(
List<T> list) { Collections.sort(list); return list; } }
  1. Have the implementation modules register themselves as service providers: Let's register both the implementation modules as providers using the provides keyword. The service type is the interface packt.util.SortUtil and the implementation types are the two implementation classes in the two modules, respectively.

Here's the module-info.java file for the packt.sort.bubblesort module:

        module packt.sort.bubblesort { 
          requires packt.sortutil; 
          provides packt.util.SortUtil  
           with packt.util.impl.bubblesort.BubbleSortUtilImpl; 
        } 

And here's the module-info.java file for the packt.sort.javasort module:

        module packt.sort.javasort { 
          requires packt.sortutil; 
          provides packt.util.SortUtil  
           with packt.util.impl.javasort.JavaSortUtilImpl; 
        }
  1. Have the consumer module register itself as a consumer of the service: We'll be needing instances of SortUtil in the packt.addressbook and packt.addressbook.ui. I'll showcase the steps in the packt.addressbook module alone here, because it has relatively fewer things going on. But the steps are the same and need to be applied to both modules.

Here's the module descriptor of packt.addressbook with the uses clause:

        module packt.addressbook { 
          requires java.logging; 
          requires packt.addressbook.lib; 
          uses packt.util.SortUtil; 
        } 
  1. Call the ServiceLoader API to access the provider instances in the consumer module's code: In Main.java, use the ServiceLoader API to get all provider instances of SortUtil:
        Iterable<SortUtil> sortUtils =
ServiceLoader.load(SortUtil.class);

Now, iterating through, you can access each instance. I'll loop through and sort the list using both of the sorting implementations. This is clearly unnecessary, but it's just for illustration:

        for (SortUtil sortUtil : sortUtils) { 
          System.out.println("Found an instance of SortUtil"); 
          sortUtil.sortList(contacts); 
        } 

And we are done! You've used the service mechanism to create, register, and use sorting service implementations.

Make sure you apply the same changes to the packt.addressbook.ui module as well! If not, the compilation step will fail for that module, for obvious reasons.

Compiling and running the code now should work without any errors:

$ javac --module-source-path src -d out $(find . -name '*.java') 
$ java --module-path out -m packt.addressbook/packt.addressbook.Main 
Apr 09, 2017 12:03:18 AM packt.addressbook.Main main 
INFO: Address book viewer application: Started 
Found an instance of SortUtil 
Found an instance of SortUtil 
[Charles Babbage, Tim Berners-Lee, Edsger Dijkstra, Ada Lovelace, Alan Turing] 
Apr 09, 2017 12:03:19 AM packt.addressbook.Main main 
INFO: Address book viewer application: Completed 

As you can see from the output, there have been two instances of SortUtil returned by ServiceLoader, corresponding to the two implementations we have registered.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.177.86