
org.jppf.client.balancer.ChannelWrapperRemote 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.io.NotSerializableException;
import java.util.*;
import java.util.concurrent.*;
import org.jppf.JPPFException;
import org.jppf.client.*;
import org.jppf.client.event.*;
import org.jppf.load.balancer.Bundler;
import org.jppf.management.*;
import org.jppf.node.protocol.*;
import org.jppf.utils.*;
import org.slf4j.*;
/**
* Context associated with a remote channel serving state and tasks submission.
* @author Martin JANDA
*/
public class ChannelWrapperRemote extends ChannelWrapper implements ClientConnectionStatusHandler {
/**
* Logger for this class.
*/
private static Logger log = LoggerFactory.getLogger(ChannelWrapperRemote.class);
/**
* Determines whether the debug level is enabled in the log configuration, without the cost of a method call.
*/
private static boolean debugEnabled = LoggingUtils.isDebugEnabled(log);
/**
* The channel to the driver to use.
*/
private final JPPFClientConnectionImpl channel;
/**
* Unique identifier of the client.
*/
protected String uuid = null;
/**
* Default initializer for remote channel wrapper.
* @param channel to the driver to use.
*/
public ChannelWrapperRemote(final JPPFClientConnection channel) {
if (channel == null) throw new IllegalArgumentException("channel is null");
this.channel = (JPPFClientConnectionImpl) channel;
JPPFConnectionPool pool = channel.getConnectionPool();
this.uuid = pool.getDriverUuid();
priority = pool.getPriority();
systemInfo = new JPPFSystemInformation(this.uuid, false, true);
managementInfo = new JPPFManagementInfo("remote", "remote", -1, getConnectionUuid(), JPPFManagementInfo.DRIVER, pool.isSslEnabled());
managementInfo.setSystemInfo(systemInfo);
executor = Executors.newSingleThreadExecutor(new JPPFThreadFactory("RemoteChannelWrapper-" + channel.getName()));
}
@Override
public void setSystemInformation(final JPPFSystemInformation systemInfo) {
if (systemInfo != null && uuid == null) {
uuid = systemInfo.getUuid().getProperty("jppf.uuid");
if (uuid != null && uuid.isEmpty()) uuid = null;
}
super.setSystemInformation(systemInfo);
}
@Override
public String getUuid() {
return uuid;
}
@Override
public String getConnectionUuid() {
return channel.getConnectionUuid();
}
@Override
public JPPFClientConnectionStatus getStatus() {
return channel.getStatus();
}
@Override
public void setStatus(final JPPFClientConnectionStatus status) {
channel.getTaskServerConnection().setStatus(status);
}
/**
* Get the wrapped channel.
* @return a AbstractJPPFClientConnection
instance.
*/
public JPPFClientConnection getChannel() {
return channel;
}
@Override
public void addClientConnectionStatusListener(final ClientConnectionStatusListener listener) {
channel.addClientConnectionStatusListener(listener);
}
@Override
public void removeClientConnectionStatusListener(final ClientConnectionStatusListener listener) {
channel.removeClientConnectionStatusListener(listener);
}
@Override
@SuppressWarnings("unchecked")
public Future> submit(final ClientTaskBundle bundle) {
setStatus(JPPFClientConnectionStatus.EXECUTING);
Runnable task = new RemoteRunnable(getBundler(), bundle, channel);
bundle.jobDispatched(this);
executor.submit(task);
return null;
}
@Override
public boolean isLocal() {
return false;
}
/**
* Called when reconnection of this channel is required.
*/
public void reconnect() {
if (channel.isClosed()) return;
TaskServerConnectionHandler handler = channel.getTaskServerConnection();
Runnable r = new Runnable() {
@Override
public void run() {
setStatus(JPPFClientConnectionStatus.DISCONNECTED);
try {
channel.getTaskServerConnection().init();
} catch (Exception e2) {
log.error(e2.getMessage(), e2);
}
}
};
new Thread(r, "connecting " + channel).start();
}
@Override
public boolean cancel(final ClientTaskBundle bundle) {
if (bundle.isCancelled()) return false;
String uuid = bundle.getClientJob().getUuid();
if (debugEnabled) log.debug("requesting cancel of jobId=" + uuid);
bundle.cancel();
return true;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append("[channel=").append(channel).append(']');
return sb.toString();
}
/**
*
*/
private class RemoteRunnable implements Runnable {
/**
* The task bundle to execute.
*/
private final ClientTaskBundle clientBundle;
/**
* Bundler used to schedule tasks for the corresponding node.
*/
private final Bundler bundler;
/**
* The connection to the driver to use.
*/
private final JPPFClientConnectionImpl connection;
/**
* Initialize this runnable for remote execution.
* @param bundler the bundler to send the resulting statistics to.
* @param clientBundle the execution to perform.
* @param connection the connection to the driver to use.
*/
public RemoteRunnable(final Bundler bundler, final ClientTaskBundle clientBundle, final JPPFClientConnectionImpl connection) {
this.bundler = bundler;
this.clientBundle = clientBundle;
this.connection = connection;
}
@Override
public void run() {
Exception exception = null;
List> tasks = this.clientBundle.getTasksL();
JPPFClient client = connection.getClient();
String uuid = clientBundle.getClientJob().getUuid();
try {
long start = System.nanoTime();
int count = 0;
boolean completed = false;
JPPFJob newJob = createNewJob(clientBundle, tasks);
if (debugEnabled) log.debug(String.format("%s executing %d tasks of job %s", ChannelWrapperRemote.this, tasks.size(), newJob));
Collection loaders = registerClassLoaders(newJob);
while (!completed) {
TaskBundle bundle = createBundle(newJob);
bundle.setUuid(uuid);
bundle.setInitialTaskCount(clientBundle.getClientJob().initialTaskCount);
ClassLoader cl = loaders.isEmpty() ? null : loaders.iterator().next();
List> notSerializableTasks = connection.sendTasks(cl, bundle, newJob);
if (!notSerializableTasks.isEmpty()) {
if (debugEnabled) log.debug(String.format("%s got %d non-serializable tasks", ChannelWrapperRemote.this, notSerializableTasks.size()));
count += notSerializableTasks.size();
clientBundle.resultsReceived(notSerializableTasks);
}
while (count < tasks.size()) {
List> results = connection.receiveResults(cl);
int n = results.size();
count += n;
if (debugEnabled) log.debug("received " + n + " tasks from server" + (n > 0 ? ", first position=" + results.get(0).getPosition() : ""));
this.clientBundle.resultsReceived(results);
}
completed = true;
}
double elapsed = System.nanoTime() - start;
bundler.feedback(tasks.size(), elapsed);
} catch (Throwable t) {
if (debugEnabled) log.debug(t.getMessage(), t);
else log.warn(ExceptionUtils.getMessage(t));
if (channel.isClosed() && !channel.getPool().getClient().isResetting()) return;
exception = (t instanceof Exception) ? (Exception) t : new JPPFException(t);
if ((t instanceof NotSerializableException) || (t instanceof InterruptedException)) {
clientBundle.resultsReceived(t);
return;
}
if (!channel.isClosed() || channel.getPool().getClient().isResetting()) {
clientBundle.resubmit();
reconnect();
}
} finally {
try {
if (!channel.isClosed() || channel.getPool().getClient().isResetting()) clientBundle.taskCompleted(exception);
clientBundle.getClientJob().removeChannel(ChannelWrapperRemote.this);
if (getStatus() == JPPFClientConnectionStatus.EXECUTING) setStatus(JPPFClientConnectionStatus.ACTIVE);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
/**
* Create a new job based on the initial one.
* @param job initial job.
* @param tasks the tasks to execute.
* @return a new {@link JPPFJob} with the same characteristics as the initial one, except for the tasks.
* @throws Exception if any error occurs.
*/
private JPPFJob createNewJob(final ClientTaskBundle job, final List> tasks) throws Exception {
JPPFJob newJob = new JPPFJob(job.getClientJob().getUuid());
newJob.setDataProvider(job.getJob().getDataProvider());
newJob.setSLA(job.getSLA());
newJob.setClientSLA(job.getJob().getClientSLA());
newJob.setMetadata(job.getMetadata());
newJob.setBlocking(job.getJob().isBlocking());
newJob.setName(job.getName());
for (Task> task : tasks) {
// needed as JPPFJob.addTask() resets the position
int pos = task.getPosition();
newJob.add(task);
task.setPosition(pos);
}
return newJob;
}
/**
* Create a task bundle for the specified job.
* @param job the job to use as a base.
* @return a JPPFTaskBundle instance.
*/
private TaskBundle createBundle(final JPPFJob job) {
TaskBundle bundle = new JPPFTaskBundle();
bundle.setUuid(job.getUuid());
return bundle;
}
/**
* Return class loader for the specified job.
* @param job the job used to determine class loader.
* @return a list of ClassLoader instances, possibly empty.
*/
private Collection registerClassLoaders(final JPPFJob job) {
if (job == null) throw new IllegalArgumentException("job is null");
Set result = new HashSet<>();
if (!job.getJobTasks().isEmpty()) {
JPPFClient client = connection.getClient();
for (Task> task: job.getJobTasks()) {
if (task != null) {
Object o = task.getTaskObject();
ClassLoader cl = (o != null) ? o.getClass().getClassLoader() : task.getClass().getClassLoader();
if ((cl != null) && !result.contains(cl)) {
client.registerClassLoader(cl, job.getUuid());
result.add(cl);
}
}
}
}
return result;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy