Custom discovery of remote drivers
From JPPF 5.2 Documentation
|
Main Page > Customizing JPPF > Driver discovery |
1 Rationale
The current built-in driver discovery mechanisms in the JPPF client have potential shortcomings:
- automatic discovery relies on the UDP multicast proptocol, which is not available in all environments. For instance, cloud environments do not allow it.
- the manual configuration of the connections requires that all possible drivers be known in advance, which prevents new, previously unknown drivers from being discovered
To overcome these limitations, and to allow more flexibility as to how drivers are discovered by a client, you can now implement your own custom disocovery mechanism.
2 Implementation
A driver discovery mechanism is implemented by extending the class ClientDriverDiscovery, defined as:
public abstract class ClientDriverDiscovery extends DriverDiscovery<ClientConnectionPoolInfo> { }
As we can see, this class has no method of its own, and the interesting methods are in its superclass DriverDiscovery:
public abstract class DriverDiscovery<E extends DriverConnectionInfo> { // Perform the driver discovery. This method runs in its own separate thread public abstract void discover() throws InterruptedException; // Notify that a new driver was discovered protected void newConnection(E info) // Shut this discovery down. This method is intended to be overriden // in subclasses to allow user-defined cleanup operations public void shutdown() }
By default, the shutdown() method does nothing and is intended to be overriden in subclasses if needed. It is called when closing the JPPF client and is thus part of the discovery's life cycle.
The actual discovery is performed within the discover() method. From this method, for each discovered driver you must call the newConnection() method, passing an instance of ClientConnectionPoolInfo, defined as follows:
public class ClientConnectionPoolInfo extends DriverConnectionInfo // Initialize a pool of plain connections with default name("driver"), // host ("localhost"), port (11111), priority (0) and pool sizes (1) public ClientConnectionPoolInfo() // Initialize a pool of plain connections with default priority (0) and pool sizes (1) public ClientConnectionPoolInfo(String name, String host, int port) // Initialize a pool of connections with default priority (0) and pool sizes (1) public ClientConnectionPoolInfo(String name, boolean secure, String host, int port) // Initialize a pool of connections with the specified parameters public ClientConnectionPoolInfo(String name, boolean secure, String host, int port, int priority, int poolSize, int jmxPoolSize) // Get the connection priority public int getPriority() // Get the connection pool size public int getPoolSize() // Get the associated JMX connection pool size public int getJmxPoolSize() }
The super class DriverConnectionInfo provides getters for the name, host, port and secure attributes:
public class DriverConnectionInfo // Get the name given to this connection public String getName() // Determine whether secure (with SSL/TLS) connections should be established public boolean isSecure() // Get the driver host name or IP address public String getHost() // Get the driver port to connect to public int getPort() }
Here is an example of a very simple implementation:
public class SimpleDiscovery extends ClientDriverDiscovery { @Override public void discover() throws InterruptedException { // new connection pool named "myDriver" newConnection( new ClientConnectionPoolInfo("myDriver", false, "www.myhost.org", 11111)); } }
The discover() method of a ClientDriverDiscovery is not limited to calling newConnection() only once. You can invoke this method with as many instances of ClientConnectionPoolInfo as you wish, allowing for the discovery of as many connection pools as required.
Additonally, the discover() method runs in its own separate thread and doesn't have to terminate immediately. This means that you can run a loop inside that may, for instance, perform a periodic polling of an (external) service to discover new drivers over time. Here is a more complex example illustrating this:
public class LoopingDiscovery extends ClientDriverDiscovery { // whether this discovery was shutdown private boolean shutdownFlag = false; @Override public void discover() throws InterruptedException { while (!isShutdown()) { List<ClientConnectionPoolInfo> drivers = externalLookup(); if (drivers != null) { for (ClientConnectionPoolInfo driver: drivers) newConnection(driver); } synchronized(this) { // wait 5 seconds before the next lookup wait(5000L); } } } // Query an external service for discovered drivers public List<ClientConnectionPoolInfo> externalLookup() { return ...; } public synchronized boolean isShutdown() { return shutdownFlag; } @Override public synchronized void shutdown() { shutdownFlag = true; notify(); // wake up the discover() thread } }
3 Deployment via SPI
A driver discovery mechanism can be automatically loaded and installed via the Service Provider Interface (SPI):
- in your source or resources folder, create a file META-INF/services/org.jppf.discovery.ClientDriverDiscovery
- edit this file and add a line with the fully qualified class name of your subclass of ClientDriverDiscovery, for instance org.jppf.example.SimpleDiscovery.
- make sure that this file, along with the implementation class, is in the classpath of your client application at runtime
4 Deployment via API
The class JPPFClient provides an API to add or remove ClientDriverDiscovery implementations at any time:
public class JPPFClient extends AbstractGenericClient { // Add a custom driver discovery mechanism to those already registered, if any public void addDriverDiscovery(ClientDriverDiscovery discovery) // Remove a custom driver discovery mechanism from those already registered public void removeDriverDiscovery(ClientDriverDiscovery discovery) }
Example usage:
JPPFClient client = new JPPFClient(); ClientDriverDiscovery discovery = new SimpleDiscovery(); client.addDriverDiscovery(discovery);
5 Tip
To prevent the built-in discovery mechanisms from starting, set the following client configuration property:
in the configuration file:
jppf.remote.execution.enabled = false
or via the configuration API:
JPPFConfiguration.set(JPPFProperties.REMOTE_EXECUTION_ENABLED, false);
This way, only custom driver discovery mechanisms will be used.
Main Page > Customizing JPPF > Driver discovery |