
org.jppf.server.JPPFDriver Maven / Gradle / Ivy
Show all versions of jppf-server Show documentation
/*
* JPPF.
* Copyright (C) 2005-2015 JPPF Team.
* http://www.jppf.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jppf.server;
import static org.jppf.utils.stats.JPPFStatisticsHelper.createServerStatistics;
import java.util.*;
import org.jppf.*;
import org.jppf.classloader.*;
import org.jppf.comm.discovery.JPPFConnectionInformation;
import org.jppf.comm.recovery.*;
import org.jppf.job.*;
import org.jppf.logging.jmx.JmxMessageNotifier;
import org.jppf.management.JPPFSystemInformation;
import org.jppf.nio.NioServer;
import org.jppf.node.initialization.OutputRedirectHook;
import org.jppf.process.LauncherListener;
import org.jppf.queue.JPPFQueue;
import org.jppf.server.job.JPPFJobManager;
import org.jppf.server.nio.acceptor.AcceptorNioServer;
import org.jppf.server.nio.classloader.LocalClassContext;
import org.jppf.server.nio.classloader.client.ClientClassNioServer;
import org.jppf.server.nio.classloader.node.NodeClassNioServer;
import org.jppf.server.nio.client.ClientNioServer;
import org.jppf.server.nio.nodeserver.*;
import org.jppf.server.node.JPPFNode;
import org.jppf.server.node.local.*;
import org.jppf.server.protocol.*;
import org.jppf.server.queue.JPPFPriorityQueue;
import org.jppf.startup.JPPFDriverStartupSPI;
import org.jppf.utils.*;
import org.jppf.utils.hooks.HookFactory;
import org.jppf.utils.stats.JPPFStatistics;
import org.slf4j.*;
/**
* This class serves as an initializer for the entire JPPF server. It follows the singleton pattern and provides access,
* across the JVM, to the tasks execution queue.
* It also holds a server for incoming client connections, a server for incoming node connections, along with a class server
* to handle requests to and from remote class loaders.
* @author Laurent Cohen
* @author Lane Schwartz (dynamically allocated server port)
*/
public class JPPFDriver {
// this static block must be the first thing executed when this class is loaded
static {
JPPFInitializer.init();
}
/**
* Logger for this class.
*/
static Logger log = LoggerFactory.getLogger(JPPFDriver.class);
/**
* Determines whether debug-level logging is enabled.
*/
private static boolean debugEnabled = LoggingUtils.isDebugEnabled(log);
/**
* Flag indicating whether collection of debug information is available via JMX.
*/
public static final boolean JPPF_DEBUG = JPPFConfiguration.getProperties().getBoolean("jppf.debug.enabled", false);
/**
* Singleton instance of the JPPFDriver.
*/
private static JPPFDriver instance = null;
/**
* Reference to the local node if it is enabled.
*/
private JPPFNode localNode = null;
/**
* The queue that handles the tasks to execute. Objects are added to, and removed from, this queue, asynchronously and by multiple threads.
*/
private final JPPFPriorityQueue taskQueue;
/**
* Serves the execution requests coming from client applications.
*/
private ClientNioServer clientNioServer = null;
/**
* Serves the JPPF nodes.
*/
private NodeNioServer nodeNioServer = null;
/**
* Serves class loading requests from the JPPF nodes.
*/
private ClientClassNioServer clientClassServer = null;
/**
* Serves class loading requests from the JPPF nodes.
*/
private NodeClassNioServer nodeClassServer = null;
/**
* Handles the initial handshake and peer channel identification.
*/
private AcceptorNioServer acceptorServer = null;
/**
* Determines whether this server has initiated a shutdown, in which case it does not accept connections anymore.
*/
private boolean shuttingDown = false;
/**
* Holds the statistics monitors.
*/
private final JPPFStatistics statistics = createServerStatistics();
/**
* Manages and monitors the jobs throughout their processing within this driver.
*/
private JPPFJobManager jobManager = null;
/**
* Uuid for this driver.
*/
private final String uuid;
/**
* Performs initialization of the driver's components.
*/
private DriverInitializer initializer = null;
/**
* Configuration for this driver.
*/
private final TypedProperties config;
/**
* System ibnformation for this driver.
*/
private JPPFSystemInformation systemInformation = null;
/**
* Initialize this JPPFDriver.
* @exclude
*/
protected JPPFDriver() {
instance = this;
config = JPPFConfiguration.getProperties();
String s;
this.uuid = (s = config.getString("jppf.driver.uuid", null)) == null ? JPPFUuid.normalUUID() : s;
new JmxMessageNotifier(); // initialize the jmx logger
Thread.setDefaultUncaughtExceptionHandler(new JPPFDefaultUncaughtExceptionHandler());
new OutputRedirectHook().initializing(new UnmodifiableTypedProperties(config));
VersionUtils.logVersionInformation("driver", uuid);
SystemUtils.printPidAndUuid("driver", uuid);
systemInformation = new JPPFSystemInformation(uuid, false, true);
jobManager = new JPPFJobManager();
taskQueue = new JPPFPriorityQueue(this, jobManager);
initializer = new DriverInitializer(this, config);
}
/**
* Initialize and start this driver.
* @throws Exception if the initialization fails.
* @exclude
*/
@SuppressWarnings("unchecked")
public void run() throws Exception {
JPPFConnectionInformation info = initializer.getConnectionInformation();
initializer.registerDebugMBean();
initializer.initRecoveryServer();
initializer.initJmxServer();
RecoveryServer recoveryServer = initializer.getRecoveryServer();
int[] sslPorts = extractValidPorts(info.sslServerPorts);
boolean useSSL = (sslPorts != null) && (sslPorts.length > 0);
clientClassServer = startServer(recoveryServer, new ClientClassNioServer(this, useSSL));
nodeClassServer = startServer(recoveryServer, new NodeClassNioServer(this, useSSL));
clientNioServer = startServer(recoveryServer, new ClientNioServer(this, useSSL));
nodeNioServer = startServer(recoveryServer, new NodeNioServer(this, taskQueue, useSSL));
jobManager.loadTaskReturnListeners();
if (isManagementEnabled(config)) initializer.registerProviderMBeans();
HookFactory.registerSPIMultipleHook(JPPFDriverStartupSPI.class, null, null).invoke("run");
initializer.getNodeConnectionEventHandler().loadListeners();
acceptorServer = startServer(recoveryServer, new AcceptorNioServer(extractValidPorts(info.serverPorts), sslPorts));
if (config.getBoolean("jppf.local.node.enabled", false)) {
LocalClassLoaderChannel localClassChannel = new LocalClassLoaderChannel(new LocalClassContext());
localClassChannel.getContext().setChannel(localClassChannel);
LocalNodeChannel localNodeChannel = new LocalNodeChannel(new LocalNodeContext(nodeNioServer.getTransitionManager()));
localNodeChannel.getContext().setChannel(localNodeChannel);
final boolean offline = JPPFConfiguration.getProperties().getBoolean("jppf.node.offline", false);
localNode = new JPPFLocalNode(new LocalNodeConnection(localNodeChannel), offline ? null : new LocalClassLoaderConnection(localClassChannel));
nodeClassServer.initLocalChannel(localClassChannel);
nodeNioServer.initLocalChannel(localNodeChannel);
new Thread(localNode, "Local node").start();
}
initializer.initBroadcaster();
initializer.initPeers(clientClassServer);
System.out.println("JPPF Driver initialization complete");
}
/**
* Get the singleton instance of the JPPFDriver.
* @return a JPPFDriver
instance.
*/
public static JPPFDriver getInstance() {
return instance;
}
/**
* Get the queue that handles the tasks to execute.
* @return a JPPFQueue instance.
* @exclude
*/
public static JPPFQueue getQueue() {
return getInstance().taskQueue;
}
/**
* Get the JPPF client server.
* @return a ClientNioServer
instance.
* @exclude
*/
public ClientNioServer getClientNioServer() {
return clientNioServer;
}
/**
* Get the JPPF class server.
* @return a ClassNioServer
instance.
* @exclude
*/
public ClientClassNioServer getClientClassServer() {
return clientClassServer;
}
/**
* Get the JPPF class server.
* @return a ClassNioServer
instance.
* @exclude
*/
public NodeClassNioServer getNodeClassServer() {
return nodeClassServer;
}
/**
* Get the JPPF nodes server.
* @return a NodeNioServer
instance.
* @exclude
*/
public NodeNioServer getNodeNioServer() {
return nodeNioServer;
}
/**
* Get the server which handles the initial handshake and peer channel identification.
* @return a {@link AcceptorNioServer} instance.
* @exclude
*/
public AcceptorNioServer getAcceptorServer() {
return acceptorServer;
}
/**
* Determines whether this server has initiated a shutdown, in which case it does not accept connections anymore.
* @return true if a shutdown is initiated, false otherwise.
* @exclude
*/
public boolean isShuttingDown() {
return shuttingDown;
}
/**
* Get this driver's unique identifier.
* @return the uuid as a string.
*/
public String getUuid() {
return uuid;
}
/**
* Initialize this task with the specified parameters.
* The shutdown is initiated after the specified shutdown delay has expired.
* If the restart parameter is set to false then the JVM exits after the shutdown is complete.
* @param shutdownDelay delay, in milliseconds, after which the server shutdown is initiated. A value of 0 or less
* means an immediate shutdown.
* @param restart determines whether the server should restart after shutdown is complete.
* If set to false, then the JVM will exit.
* @param restartDelay delay, starting from shutdown completion, after which the server is restarted.
* A value of 0 or less means the server is restarted immediately after the shutdown is complete.
* @exclude
*/
public void initiateShutdownRestart(final long shutdownDelay, final boolean restart, final long restartDelay) {
log.info("Scheduling server shutdown in " + shutdownDelay + " ms");
shuttingDown = true;
if (acceptorServer != null) acceptorServer.shutdown();
if (clientClassServer != null) clientClassServer.shutdown();
if (nodeClassServer != null) nodeClassServer.shutdown();
if (nodeNioServer != null) nodeNioServer.shutdown();
if (clientNioServer != null) clientNioServer.shutdown();
Timer timer = new Timer();
ShutdownRestartTask task = new ShutdownRestartTask(timer, restart, restartDelay, this);
timer.schedule(task, (shutdownDelay <= 0L) ? 0L : shutdownDelay);
}
/**
* Shutdown this server and all its components.
* @exclude
*/
public void shutdown() {
log.info("Shutting down");
initializer.stopBroadcaster();
initializer.stopPeerDiscoveryThread();
initializer.stopJmxServer();
jobManager.close();
initializer.stopRecoveryServer();
}
/**
* Get the object that manages and monitors the jobs throughout their processing within this driver.
* @return an instance of JPPFJobManager
.
* @exclude
*/
public JPPFJobManager getJobManager() {
return jobManager;
}
/**
* Get the object which manages the registration and unregistration of job
* dispatch listeners and notifies these listeners of job dispatch events.
* @return an instance of {@link TaskReturnManager}.
* @deprecated use {@link #getJobTasksListenerManager()} instead.
*/
public TaskReturnManager getTaskReturnManager() {
return jobManager;
}
/**
* Get the object which manages the registration and unregistration of job
* dispatch listeners and notifies these listeners of job dispatch events.
* @return an instance of {@link JobTasksListenerManager}.
*/
public JobTasksListenerManager getJobTasksListenerManager() {
return jobManager;
}
/**
* Get this driver's initializer.
* @return a DriverInitializer
instance.
* @exclude
*/
public DriverInitializer getInitializer() {
return initializer;
}
/**
* Start the JPPF server.
* @param args not used.
*/
public static void main(final String...args) {
try {
if (debugEnabled) log.debug("starting the JPPF driver");
if ((args == null) || (args.length <= 0))
throw new JPPFException("The driver should be run with an argument representing a valid TCP port or 'noLauncher'");
if (!"noLauncher".equals(args[0])) {
int port = Integer.parseInt(args[0]);
new LauncherListener(port).start();
}
new JPPFDriver().run();
} catch(Exception e) {
e.printStackTrace();
log.error(e.getMessage(), e);
System.exit(1);
}
}
/**
* Start server, register it to recovery server if requested and print initialization message.
* @param recoveryServer Recovery server for nioServers that implements ReaperListener
* @param nioServer starting nio server
* @param the type of the server to start
* @return started nioServer
*/
private static T startServer(final RecoveryServer recoveryServer, final T nioServer) {
if(nioServer == null) throw new IllegalArgumentException("nioServer is null");
if(recoveryServer != null && nioServer instanceof ReaperListener) {
Reaper reaper = recoveryServer.getReaper();
reaper.addReaperListener((ReaperListener) nioServer);
}
nioServer.start();
printInitializedMessage(nioServer.getPorts(), nioServer.getSSLPorts(), nioServer.getName());
return nioServer;
}
/**
* Print a message to the console to signify that the initialization of a server was successful.
* @param ports the ports on which the server is listening.
* @param sslPorts SSL ports for initialization message.
* @param name the name to use for the server.
*/
private static void printInitializedMessage(final int[] ports, final int[] sslPorts, final String name) {
StringBuilder sb = new StringBuilder();
if (name != null) {
sb.append(name);
sb.append(" initialized");
}
if ((ports != null) && (ports.length > 0)) {
sb.append("\n- accepting plain connections on port");
if (ports.length > 1) sb.append('s');
for (int n: ports) sb.append(' ').append(n);
}
if ((sslPorts != null) && (sslPorts.length > 0)) {
sb.append("\n- accepting secure connections on port");
if (sslPorts.length > 1) sb.append('s');
for (int n: sslPorts) sb.append(' ').append(n);
}
System.out.println(sb.toString());
}
/**
* Determine whether management is enabled and if there is an active remote connector server.
* @return true
if management is enabled, false
otherwise.
* @param config the configuration to test whether management is enabled.
*/
private static boolean isManagementEnabled(final TypedProperties config) {
return config.getBoolean("jppf.management.enabled", true) || config.getBoolean("jppf.management.ssl.enabled", false);
}
/**
* Get the system ibnformation for this driver.
* @return a {@link JPPFSystemInformation} instance.
*/
public JPPFSystemInformation getSystemInformation() {
return systemInformation;
}
/**
* Extract only th valid ports from the input array.
* @param ports the array of port numbers to check.
* @return an array, possibly of length 0, containing all the valid port numbers in the input array.
*/
private int[] extractValidPorts(final int[] ports) {
if ((ports == null) || (ports.length == 0)) return ports;
List list = new ArrayList<>();
for (int port: ports) {
if (port >= 0) list.add(port);
}
int[] result = new int[list.size()];
for (int i=0; i