
org.jppf.client.balancer.JobManagerClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jppf-client Show documentation
Show all versions of jppf-client Show documentation
JPPF, the open source grid computing solution
/*
* 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.client.balancer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jppf.client.*;
import org.jppf.client.balancer.queue.*;
import org.jppf.client.event.*;
import org.jppf.load.balancer.Bundler;
import org.jppf.load.balancer.spi.JPPFBundlerFactory;
import org.jppf.management.*;
import org.jppf.node.protocol.Task;
import org.jppf.queue.*;
import org.jppf.utils.*;
import org.slf4j.*;
/**
* This task provides asynchronous management of tasks submitted through the resource adapter.
* It relies on a queue where job are first added, then submitted when a connection becomes available.
* It also provides methods to check the status of a job and retrieve the results.
* @author Laurent Cohen
* @author Martin JANDA
* @exclude
*/
public class JobManagerClient extends ThreadSynchronization implements JobManager {
/**
* Logger for this class.
*/
private static final Logger log = LoggerFactory.getLogger(JobManagerClient.class);
/**
* Determines whether debug-level logging is enabled.
*/
private static boolean debugEnabled = LoggingUtils.isDebugEnabled(log);
/**
* A reference to the tasks queue.
*/
private final JPPFPriorityQueue queue;
/**
* The bundler factory.
*/
private final JPPFBundlerFactory bundlerFactory = new JPPFBundlerFactory(JPPFBundlerFactory.Defaults.CLIENT);
/**
* Task that dispatches queued jobs to available nodes.
*/
private final TaskQueueChecker taskQueueChecker;
/**
* Mapping client connections to channel wrapper.
*/
private final Map wrapperMap = new HashMap<>();
/**
* A list of all the connections.
*/
private final List allConnections = new ArrayList<>();
/**
* Listener used for monitoring state changes.
*/
private final ClientConnectionStatusListener statusListener = new ClientConnectionStatusListener() {
@Override
public void statusChanged(final ClientConnectionStatusEvent event) {
if (event.getSource() instanceof JPPFClientConnection) {
updateConnectionStatus(((JPPFClientConnection) event.getSource()), event.getOldStatus());
} else if (event.getSource() instanceof ChannelWrapper) {
updateConnectionStatus((ChannelWrapper) event.getSource(), event.getOldStatus());
}
}
};
/**
* Determines whether local execution is enabled on this client.
*/
private boolean localEnabled;
/**
* Wrapper for local execution node.
*/
private ChannelWrapperLocal wrapperLocal = null;
/**
* Holds the current connections with ACTIVE or EXECUTING status.
*/
private final ConcurrentHashMap workingConnections = new ConcurrentHashMap<>();
/**
* Determines whether this job manager has been closed.
*/
private final AtomicBoolean closed = new AtomicBoolean(false);
/**
* Instantiates client job manager.
* @param client JPPF client that manages connections to the JPPF drivers.
* @throws Exception if any error occurs.
*/
public JobManagerClient(final JPPFClient client) throws Exception {
if (client == null) throw new IllegalArgumentException("client is null");
this.localEnabled = client.getConfig().getBoolean("jppf.local.execution.enabled", false);
Bundler bundler = bundlerFactory.createBundlerFromJPPFConfiguration();
this.queue = new JPPFPriorityQueue(this);
taskQueueChecker = new TaskQueueChecker(queue);
taskQueueChecker.setBundler(bundler);
this.queue.addQueueListener(new QueueListenerAdapter() {
@Override
public void bundleAdded(final QueueEvent event) {
taskQueueChecker.wakeUp();
}
});
new Thread(taskQueueChecker, "TaskQueueChecker").start();
this.queue.addQueueListener(client);
client.addConnectionPoolListener(new ConnectionPoolListenerAdapter() {
@Override
public void connectionAdded(final ConnectionPoolEvent event) {
addConnection(event.getConnection());
}
@Override
public void connectionRemoved(final ConnectionPoolEvent event) {
removeConnection(event.getConnection());
}
});
updateLocalExecution(this.localEnabled);
}
/**
* Add the specified connection wrapper to the list of connections handled by this manager.
* @param wrapper the connection wrapper to add.
*/
protected void addConnection(final ChannelWrapper wrapper) {
if (wrapper == null) throw new IllegalArgumentException("wrapper is null");
if (closed.get()) throw new IllegalStateException("this job manager was closed");
if (log.isDebugEnabled()) log.debug("adding connection " + wrapper);
synchronized(allConnections) {
allConnections.add(wrapper);
}
updateConnectionStatus(wrapper, JPPFClientConnectionStatus.NEW, wrapper.getStatus());
}
/**
* Remove the specified connection wrapper from the list of connections handled by this manager.
* @param wrapper the connection wrapper to remove.
*/
protected void removeConnection(final ChannelWrapper wrapper) {
if (wrapper == null) throw new IllegalArgumentException("wrapper is null");
try {
updateConnectionStatus(wrapper, wrapper.getStatus(), JPPFClientConnectionStatus.DISCONNECTED);
} finally {
synchronized(allConnections) {
allConnections.remove(wrapper);
}
}
}
/**
* Add the specified client connection to the list of connections handled by this manager.
* @param cnn the client connection to add.
* @return wrapper for the added client connection.
*/
protected ChannelWrapper addConnection(final JPPFClientConnection cnn) {
if (log.isDebugEnabled()) log.debug("adding connection " + cnn);
if (closed.get()) throw new IllegalStateException("this job manager was closed");
ChannelWrapper wrapper = null;
synchronized(wrapperMap) {
wrapper = wrapperMap.get(cnn);
}
if (wrapper == null) {
try {
wrapper = new ChannelWrapperRemote(cnn);
JPPFConnectionPool pool = cnn.getConnectionPool();
JPPFSystemInformation systemInfo = cnn.getSystemInfo();
if (systemInfo != null) wrapper.setSystemInformation(systemInfo);
JPPFManagementInfo info = new JPPFManagementInfo(cnn.getHost(), pool.getJmxPort(), cnn.getDriverUuid(), JPPFManagementInfo.DRIVER, cnn.isSSLEnabled());
if (systemInfo != null) info.setSystemInfo(systemInfo);
wrapper.setManagementInfo(info);
} catch (Throwable e) {
log.error("Error while adding connection " + cnn, e);
} finally {
synchronized(wrapperMap) {
wrapperMap.put(cnn, wrapper);
}
addConnection(wrapper);
}
}
if (log.isDebugEnabled()) log.debug("end of adding connection " + cnn);
return wrapper;
}
/**
* Remove the specified client connection from the list of connections handled by this manager.
* @param connection the client connection to remove.
* @return wrapper for the removed client connection or null.
*/
protected ChannelWrapper removeConnection(final JPPFClientConnection connection) {
ChannelWrapper wrapper = null;
synchronized(wrapperMap) {
wrapper = wrapperMap.remove(connection);
}
if (wrapper != null) removeConnection(wrapper);
return wrapper;
}
/**
* Get all the client connections handled by this manager.
* @return a list of ChannelWrapper
instances.
*/
public List getAllConnections() {
synchronized(allConnections) {
return new ArrayList<>(allConnections);
}
}
/**
* Get all the client connections with a working status.
* @return a list of {@link ChannelWrapper} instances.
*/
public List getWorkingConnections() {
return new ArrayList<>(workingConnections.values());
}
/**
* Get all the client connections with a working status, excluding the local executor if it is enabled.
* @return a list of {@link ChannelWrapper} instances.
*/
public List getWorkingRemoteConnections() {
List result = getWorkingConnections();
if (isLocalExecutionEnabled()) {
Iterator it = result.iterator();
while (it.hasNext()) {
ChannelWrapper channel = it.next();
if (channel.isLocal()) {
it.remove();
break;
}
}
}
return result;
}
/**
* Determine whether there is at least one working connection, idle or not.
* @return {@code true} if there is at least one connection, {@code false} otherwise.
*/
public boolean hasWorkingConnection() {
return !workingConnections.isEmpty();
}
/**
* @param connection the client connection.
* @param oldStatus the connection status before the change.
*/
private void updateConnectionStatus(final JPPFClientConnection connection, final JPPFClientConnectionStatus oldStatus) {
ChannelWrapper wrapper = null;
synchronized(wrapperMap) {
wrapper = wrapperMap.get(connection);
}
if (wrapper != null) {
if (oldStatus == JPPFClientConnectionStatus.CONNECTING && wrapper.getStatus() == JPPFClientConnectionStatus.ACTIVE) {
JPPFSystemInformation systemInfo = connection.getSystemInfo();
JMXDriverConnectionWrapper jmx = connection.getConnectionPool().getJmxConnection();
wrapper.setSystemInformation(systemInfo);
if (!wrapper.isLocal()) {
String driverUuid = connection.getDriverUuid();
JPPFManagementInfo info = null;
if (jmx != null) info = new JPPFManagementInfo(connection.getHost(), jmx.getPort(), jmx.getId(), JPPFManagementInfo.DRIVER, connection.isSSLEnabled());
else info = new JPPFManagementInfo(connection.getHost(), -1, driverUuid != null ? driverUuid : "?", JPPFManagementInfo.DRIVER, connection.isSSLEnabled());
info.setSystemInfo(systemInfo);
wrapper.setManagementInfo(info);
}
}
updateConnectionStatus(wrapper, oldStatus);
}
}
/**
* @param wrapper the connection wrapper.
* @param oldStatus the connection status before the change.
*/
private void updateConnectionStatus(final ChannelWrapper wrapper, final JPPFClientConnectionStatus oldStatus) {
if (wrapper == null) return;
updateConnectionStatus(wrapper, oldStatus, wrapper.getStatus());
}
/**
* @param wrapper the connection wrapper.
* @param oldStatus the connection status before the change.
* @param newStatus the connection status after the change.
*/
private void updateConnectionStatus(final ChannelWrapper wrapper, final JPPFClientConnectionStatus oldStatus, final JPPFClientConnectionStatus newStatus) {
if (oldStatus == null) throw new IllegalArgumentException("oldStatus is null");
if (newStatus == null) throw new IllegalArgumentException("newStatus is null");
if (wrapper == null || oldStatus == newStatus) return;
if (newStatus == JPPFClientConnectionStatus.ACTIVE) taskQueueChecker.addIdleChannel(wrapper);
else {
taskQueueChecker.removeIdleChannel(wrapper);
if(newStatus.isTerminatedStatus() || newStatus == JPPFClientConnectionStatus.DISCONNECTED) queue.cancelBroadcastJobs(wrapper.getUuid());
}
boolean bNew = newStatus.isWorkingStatus();
boolean bOld = oldStatus.isWorkingStatus();
if (bNew && !bOld) workingConnections.put(wrapper.getConnectionUuid(), wrapper);
else if (!bNew && bOld) workingConnections.remove(wrapper.getConnectionUuid());
}
@Override
public String submitJob(final JPPFJob job) {
return submitJob(job, null);
}
@Override
@SuppressWarnings("deprecation")
public String submitJob(final JPPFJob job, final JobStatusListener listener) {
if (closed.get()) throw new IllegalStateException("this jobmanager was closed");
List> pendingTasks = new ArrayList<>();
if (listener != null) job.getResultCollector().addJobStatusListener(listener);
List> tasks = job.getJobTasks();
for (Task> task: tasks) if (!job.getResults().hasResult(task.getPosition())) pendingTasks.add(task);
queue.addBundle(new ClientJob(job, pendingTasks));
return job.getUuid();
}
@Override
public String resubmitJob(final JPPFJob job) {
return submitJob(job);
}
@Override
public boolean cancelJob(final String jobId) throws Exception {
if (debugEnabled) log.debug("requesting cancel of jobId=" + jobId);
queue.cancelJob(jobId);
return true;
}
@Override
public synchronized boolean hasAvailableConnection() {
return taskQueueChecker.hasIdleChannel() || ((wrapperLocal != null) && (wrapperLocal.getStatus() == JPPFClientConnectionStatus.ACTIVE));
}
@Override
public synchronized boolean isLocalExecutionEnabled() {
return localEnabled;
}
@Override
public synchronized void setLocalExecutionEnabled(final boolean localExecutionEnabled) {
if (this.localEnabled == localExecutionEnabled) return;
this.localEnabled = localExecutionEnabled;
updateLocalExecution(this.localEnabled);
}
/**
* Starts or stops local execution node according to specified parameter.
* @param localExecutionEnabled true
to enable local execution, false
otherwise
*/
private void updateLocalExecution(final boolean localExecutionEnabled) {
if (closed.get()) throw new IllegalStateException("this job manager was closed");
if (localExecutionEnabled) {
wrapperLocal = new ChannelWrapperLocal();
wrapperLocal.addClientConnectionStatusListener(statusListener);
addConnection(wrapperLocal);
} else if (wrapperLocal != null) {
try {
wrapperLocal.close();
} finally {
removeConnection(wrapperLocal);
wrapperLocal = null;
}
}
}
@Override
public Vector getAvailableConnections() {
List idleChannels = taskQueueChecker.getIdleChannels();
Vector availableConnections = new Vector<>(idleChannels.size());
for (ChannelWrapper idleChannel : idleChannels) {
if (idleChannel instanceof ChannelWrapperRemote) {
ChannelWrapperRemote wrapperRemote = (ChannelWrapperRemote) idleChannel;
availableConnections.add(wrapperRemote.getChannel());
}
}
return availableConnections;
}
@Override
public ClientConnectionStatusListener getClientConnectionStatusListener() {
return this.statusListener;
}
@Override
public void reset() {
synchronized(allConnections) {
for (ChannelWrapper channel: allConnections) channel.close();
allConnections.clear();
if (taskQueueChecker != null) taskQueueChecker.clearChannels();
}
}
@Override
public void close() {
if (debugEnabled) log.debug("closing {}", this);
closed.set(true);
setStopped(true);
wakeUp();
if (taskQueueChecker != null) {
taskQueueChecker.setStopped(true);
taskQueueChecker.wakeUp();
}
queue.close();
synchronized(allConnections) {
for (ChannelWrapper channel: allConnections) channel.close();
allConnections.clear();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy