How can I register services into the default lookup using the system filesystem?
In short, you probably do not want to. The typical way of registering services is via META-INF/services registration: DevFaqLookupDefault. That method is easier to use and offers compatibility with non-platform applications via the Java Extension Mechanism.
But there are some special cases when registration via the system filesystem is needed. One example might be when you want to dynamically change or unregister services, since the system filesystem is writable at runtime. Again such needs are rare and you should probably avoid doing this unless there is no alternative. (Usually the service interface should be defined so that the service itself is a singleton, but it can create other objects on demand and signal certain events.) Another minor use case is to register several services with the same implementation class but different parameters; META-INF/services registrations require a zero-argument constructor, meaning you need a different implementation class for each distinct service.
As an example, assume that Module 1 defines an interface com.tomwheeler.example.intf.SampleInterface which is exported to other modules. Module 2 depends on Module 1 and provides an implementation of that interface named com.tomwheeler.example.impl.SampleImplementation. Module 1 does not need anything in its layer file (or even need a layer file at all), but Module 2 can register the service like this:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd"> <filesystem> <folder name="Services"> <folder name="wheeler-sample"> <file name="com-tomwheeler-example-this-name-is-Irrelevant.instance"> <attr name="instanceClass" stringvalue="com.tomwheeler.example.impl.SampleImplementation"/> <attr name="instanceOf" stringvalue="com.tomwheeler.example.intf.SampleInterface"/> </file> </folder> </folder> </filesystem>
The name of the file is arbitrary but must end with .instance. The value of the instanceClass attribute needs to define the implementation class being registered, while instanceOf defines the interface (or abstract class) being implemented.
If you want to create the implementation using a factory method rather than calling a zero-argument constructor, replace instanceClass with instanceCreate, e.g.:
<attr name="instanceCreate" methodvalue="com.tomwheeler.example.impl.SampleImplementations.make"/>
It is also possible to pass parameters to the factory method; see API documentation for details.
Client code is unaware of the registration mechanism, so the code used to look up a registered implementation of the interface would be the same as always; for example:
SampleInterface intf = Lookup.getDefault().lookup(SampleInterface.class); // now do something with intf...