package com.bansheeproject.features;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.bansheeproject.Response;
import com.bansheeproject.engine.BansheeDispatcher;
import com.bansheeproject.engine.InvocationContext;
import com.bansheeproject.exceptions.BansheeInvocationFaultException;
import com.bansheeproject.exceptions.InstallFeatureException;
import com.bansheeproject.exceptions.ServiceInvokeException;
import com.bansheeproject.features.security.CertificateCallback;
import com.bansheeproject.log.BansheeLogger;
/**
* Installs timeouts over dispatchers.
*
* @author Alexandre Saudate
* @since 1.0
*/
public class ServiceTimeout implements Feature{
private long requestTimeout;
public ServiceTimeout(long value) {
if (value <= 0) {
throw new IllegalArgumentException("The timeout value cannot be less or equal than zero.");
}
this.requestTimeout = value;
}
public void install(InvocationContext context)
throws InstallFeatureException {
BansheeDispatcher dispatcher = context.getDispatcher();
TimeoutDispatcher timeoutDispatcher = new TimeoutDispatcher(dispatcher, requestTimeout);
context.setDispatcher(timeoutDispatcher);
}
private static class InvokeTask implements Callable<String> {
private final BansheeDispatcher delegate;
private final String param;
public InvokeTask(BansheeDispatcher delegate, String param) {
this.delegate = delegate;
this.param = param;
}
public String call() throws Exception {
return delegate.invoke(param);
}
}
private static class InvokeOneWayTask implements Callable<Response> {
private final BansheeDispatcher delegate;
private final String param;
public InvokeOneWayTask(BansheeDispatcher delegate, String param) {
this.delegate = delegate;
this.param = param;
}
public Response call() throws Exception {
delegate.invokeOneWay(param);
return null;
}
}
private static class DaemonThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName(thread.getName() + " - Banshee");
return thread;
}
}
private static ExecutorService executorService = Executors.newCachedThreadPool(new DaemonThreadFactory());
private static class TimeoutDispatcher extends BansheeDispatcher {
private final BansheeDispatcher delegate;
public TimeoutDispatcher(BansheeDispatcher delegate, long timeout) {
this.delegate = delegate;
this.timeout = timeout;
}
private long timeout = Long.MAX_VALUE;
public void changeInvocationAddress(String address) {
delegate.changeInvocationAddress(address);
}
public String invoke(final String param) throws ServiceInvokeException,
BansheeInvocationFaultException {
try {
Future<String> task = executorService.submit(new InvokeTask(delegate, param));
return task.get(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
if (e.getCause() instanceof BansheeInvocationFaultException)
throw (BansheeInvocationFaultException)e.getCause();
else
throw new RuntimeException(e);
} catch (TimeoutException e) {
throw new ServiceInvokeException(e);
}
}
public void invokeOneWay(final String param)
throws ServiceInvokeException, BansheeInvocationFaultException {
try {
Future<Response> task = executorService.submit(new InvokeOneWayTask(delegate, param));
task.get(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
throw new ServiceInvokeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (TimeoutException e) {
throw new ServiceInvokeException(e);
}
}
public void setCertificateSelectors(String reference, InputStream keyStoreData,
String keyStorePassword, InputStream trustStoreData,
String trustStorePassword, CertificateCallback callback)
throws GeneralSecurityException, IOException {
delegate.setCertificateSelectors(reference, keyStoreData, keyStorePassword,
trustStoreData, trustStorePassword, callback);
}
public void setCertificateSelectors(String reference, InputStream keyStoreData,
String keyStorePassword, InputStream trustStoreData,
String trustStorePassword) throws GeneralSecurityException,
IOException {
delegate.setCertificateSelectors(reference, keyStoreData, keyStorePassword,
trustStoreData, trustStorePassword);
}
public void setLogger(BansheeLogger logger) {
delegate.setLogger(logger);
}
public void setTimeout(long timeout) {
this.timeout = timeout;
}
}
}