com.dell.cpsd.service.common.client.manager.AbstractServiceCallbackManager Maven / Gradle / Ivy
/**
* Copyright © 2017 Dell Inc. or its subsidiaries. All Rights Reserved.
* Dell EMC Confidential/Proprietary Information
*/
package com.dell.cpsd.service.common.client.manager;
import com.dell.cpsd.common.logging.ILogger;
import com.dell.cpsd.service.common.client.callback.IServiceCallback;
import com.dell.cpsd.service.common.client.callback.ServiceCallback;
import com.dell.cpsd.service.common.client.callback.ServiceTimeout;
import com.dell.cpsd.service.common.client.exception.ServiceTimeoutException;
import com.dell.cpsd.service.common.client.log.SCCLLoggingManager;
import com.dell.cpsd.service.common.client.log.SCCLMessageCode;
import com.dell.cpsd.service.common.client.task.ITimeoutTaskManager;
import com.dell.cpsd.service.common.client.task.ServiceTask;
import com.dell.cpsd.service.common.client.task.TimeoutTask;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* This class is responsible for handling service callbacks at the client.
*
*
* Copyright © 2017 Dell Inc. or its subsidiaries. All Rights Reserved.
* Dell EMC Confidential/Proprietary Information
*
*
* @version 1.0
*
* @since 1.0
*/
public abstract class AbstractServiceCallbackManager implements ITimeoutTaskManager
{
/*
* The logger for this class.
*/
private static final ILogger LOGGER = SCCLLoggingManager
.getLogger(AbstractServiceCallbackManager.class);
/*
* The infinite timeout for a request.
*/
private static final long INFINITE_TIMEOUT = -1l;
/*
* The flag to indicate that this manager is shutting down.
*/
private volatile boolean shutdown = false;
/*
* The map of correlation identifier to IServiceCallbacks
*/
private Map>> requests = null;
/*
* The ScheduledExecutorService used to check for timed out tasks.
*/
private ScheduledExecutorService executorService = null;
/**
* AbstractServiceCallbackManager constructor.
*
* @since 1.0
*/
public AbstractServiceCallbackManager()
{
super();
this.requests = new HashMap>>();
this.executorService = this.makeScheduledExecutorService(1000l, 1000l, TimeUnit.MILLISECONDS);
}
/**
* This returns true if this manager is shutting down.
*
* @return True if this manager is shutting down.
*
* @since 1.0
*/
public boolean isShutDown()
{
return this.shutdown;
}
/**
* This adds a service task, with its corresponding request identifier, to the managed requests.
*
* @param requestId
* The request identifier.
* @param serviceTask
* The service task to add.
*
* @since 1.0
*/
public void addServiceTask(final String requestId, final ServiceTask> serviceTask)
{
if (requestId == null)
{
return;
}
if (serviceTask == null)
{
return;
}
// add the callback using the requestId identifier as key
synchronized (this.requests)
{
this.requests.put(requestId, serviceTask);
}
}
/**
* This removes the service task with the specified request identifier
*
* @param requestId
* The request identifier.
*
* @return The serivce task with the specified identifier, or null.
*
* @since 1.0
*/
public ServiceTask> removeServiceTask(final String requestId)
{
synchronized (this.requests)
{
return this.requests.remove(requestId);
}
}
/**
* This returns the service task using the specified request identifier
*
* @param requestId
* The request identifier.
*
* @return The serivce task with the specified identifier, or null.
*
* @since 1.0
*/
public ServiceTask> getServiceTask(final String requestId)
{
synchronized (this.requests)
{
return this.requests.get(requestId);
}
}
/**
* This returns the IServiceCallback for the specified request identifier, or null.
*
* @param requestId
* The request identifier.
*
* @return The service callback for the identifier, or null.
*
* @since 1.0
*/
public IServiceCallback> removeServiceCallback(final String requestId)
{
if (requestId == null)
{
return null;
}
ServiceTask> task = null;
synchronized (this.requests)
{
task = this.requests.remove(requestId);
}
if (task == null)
{
return null;
}
return task.getServiceCallback();
}
/**
* This cancels the request with the specified identifier.
*
* @param requestId
* The request identifier
* @return whether the request was cancelled or not
*/
public boolean cancel(final String requestId)
{
if (requestId == null)
{
return false;
}
ServiceTask> task = null;
synchronized (this.requests)
{
task = this.requests.remove(requestId);
}
return (task != null);
}
/**
* This releases any resources associated with this manager.
*
* @since 1.0
*/
public void release()
{
// if the manager has already been shutdown then return
if (this.shutdown)
{
return;
}
// set the shutdown flag which will cause requests to be rejected
this.shutdown = true;
LOGGER.info(SCCLMessageCode.EXECUTOR_SHUTDOWN_I.getMessageCode());
this.shutdown(this.executorService);
// wait for the current set of requests to complete and clear down
LOGGER.info(SCCLMessageCode.WAIT_ON_REQUESTS_I.getMessageCode());
this.waitForRequests(10000l);
}
/**
* {@inheritDoc}
*/
@Override
public void checkForTimedoutTasks()
{
final List>> timedOutTasks = new ArrayList>>();
String[] keyArray = null;
synchronized (this.requests)
{
final Set keySet = this.requests.keySet();
keyArray = keySet.toArray(new String[keySet.size()]);
}
long currentTime = System.currentTimeMillis();
for (int i = 0; i < keyArray.length; i++)
{
final String requestId = keyArray[i];
ServiceTask> task = this.requests.get(requestId);
if (task == null)
{
continue;
}
if (task.hasTimedout(currentTime))
{
synchronized (this.requests)
{
task = this.requests.remove(requestId);
if (task != null)
{
timedOutTasks.add(task);
}
}
}
}
for (int i = 0; i < timedOutTasks.size(); i++)
{
final ServiceTask> task = timedOutTasks.get(i);
final IServiceCallback> callback = task.getServiceCallback();
final ServiceTimeout timeout = new ServiceTimeout(task.getRequestId(), task.getTimeout());
// TODO : Take the callback processing off the timeout thread
try
{
callback.handleServiceTimeout(timeout);
}
catch (Exception exception)
{
// log the exception thrown by the callback
Object[] lparams = {"handleServiceTimeout", exception.getMessage()};
LOGGER.error(SCCLMessageCode.ERROR_CALLBACK_FAIL_E.getMessageCode(), lparams, exception);
}
}
}
/**
* This creates the ScheduledExecutorService for this manager.
*
* @param initialDelay
* The time to delay first execution.
* @param delay
* The period between successive executions.
* @param timeUnit
* The TimeUnit for the delays.
*
* @return The ScheduledExecutorService for this manager.
*
* @since 1.0
*/
protected ScheduledExecutorService makeScheduledExecutorService(long initialDelay, long delay, TimeUnit timeUnit)
{
TimeoutTask timeoutTask = new TimeoutTask(this);
final ScheduledExecutorService newExecutorService = Executors.newSingleThreadScheduledExecutor();
newExecutorService.scheduleWithFixedDelay(timeoutTask, initialDelay, delay, TimeUnit.MILLISECONDS);
return newExecutorService;
}
/**
* This waits for any currently running requests to complete and clear down.
*
* @param timeout
* The time in milliseconds to wait.
*
* @return True if all requests were completed, otherwise false.
*
* @since 1.0
*/
protected boolean waitForRequests(long timeout)
{
if ((this.requests == null) || (this.requests.size() == 0))
{
return true;
}
long timeLimit = timeout;
long sleepTime = 250l;
long elapsedTime = 0;
// wait for the requests to complete and clear down
while (this.requests.size() > 0)
{
try
{
Thread.sleep(sleepTime);
}
catch (InterruptedException exception)
{
}
elapsedTime += sleepTime;
if (elapsedTime >= timeLimit)
{
// clear the requests
this.requests.clear();
return false;
}
}
return true;
}
/**
* This shuts down the specified ExecutorService.
*
* @param executorService
* The ExecutorService to shutdown.
*
* @since 1.0
*/
protected void shutdown(final ExecutorService executorService)
{
if (executorService == null)
{
return;
}
// stop new tasks from being submitted
executorService.shutdown();
try
{
boolean graceful = executorService.awaitTermination(3, TimeUnit.SECONDS);
// allow pending tasks to finish
if (!graceful)
{
// cancel currently executing tasks
executorService.shutdownNow();
executorService.awaitTermination(3, TimeUnit.SECONDS);
}
}
catch (InterruptedException ie)
{
// (re-)cancel if current thread also interrupted
executorService.shutdownNow();
// preserve interrupt status
Thread.currentThread().interrupt();
}
}
/**
* This waits the specified timeout for the service callback.
*
* @param serviceCallback
* The service callback.
* @param requestId
* The request identifier.
* @param timeout
* The wait time period.
*
* @throws ServiceTimeoutException
* Thrown if there is a timeout.
*
* @since 1.0
*/
protected void waitForServiceCallback(final ServiceCallback> serviceCallback, final String requestId, long timeout)
throws ServiceTimeoutException
{
if (serviceCallback == null)
{
return;
}
// wait from the response from the service
long timeLimit = timeout;
long sleepTime = 10l;
long elapsedTime = 0;
// the callback is done if a response or error is handled by the manager
while (!serviceCallback.isDone())
{
try
{
Thread.sleep(sleepTime);
}
catch (InterruptedException exception)
{
}
// if the timeout is greater than zero then check for elapsed time
if (timeLimit > 0l)
{
elapsedTime += sleepTime;
if (elapsedTime >= timeLimit)
{
synchronized (this.requests)
{
this.requests.remove(requestId);
}
Object[] lparams = {requestId, "" + timeLimit};
String lmessage = LOGGER.error(SCCLMessageCode.MESSAGE_TIMEOUT_E.getMessageCode(), lparams);
throw new ServiceTimeoutException(lmessage);
}
}
}
}
} © 2015 - 2025 Weber Informatics LLC | Privacy Policy