/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
* 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
*******************************************************************************/
//B''H
package org.ebayopensource.turmeric.runtime.sif.service;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.xml.ws.Response;
import org.ebayopensource.turmeric.runtime.common.exceptions.ServiceInvocationException;
/**
*
* Helper to do asynchronous poll across multiple service calls.
*
*/
public class InvokerUtil {
/**
* Poll all the services and return the responses. the method is BLOCKED
* until all the outstanding responses are available.
*
* @param services
* the services to be polled
* @return the map containing all the responses.
* @throws ServiceInvocationException
* throws this exception when the invocation failed
* @throws InterruptedException
* throws this exception when the failed to wait until all the
* responses return.
*/
public static Map<Service, List<Response<?>>> pollGetAll(
List<Service> services) throws ServiceInvocationException,
InterruptedException {
return pollInternal(services, false, false);
}
/**
* Poll all the services and return the responses. the method is BLOCKED
* until all the outstanding responses are available or the timeout is
* reached.
*
* @param services
* the services to be polled
* @param timeout
* timeout in milliseconds
* @return the map containing all the responses.
* @throws ServiceInvocationException
* throws this exception when the invocation failed
* @throws InterruptedException
* throws this exception when the failed to wait
* @throws ExecutionException
* throws this exception if the thread pool executor failed
*/
static Map<Service, List<Response<?>>> pollGetAll(List<Service> services,
long timeout) throws ServiceInvocationException,
InterruptedException, ExecutionException {
return pollGetAll(services, timeout, Service.getDefaultExecutor());
}
/**
* Poll all the services and return the responses. the method is BLOCKED
* until all the outstanding responses are available or the timeout is
* reached.
*
* @param services
* the services to be polled
* @param timeout
* timeout in milliseconds
* @param executor
* the thread pool executor
* @return the map containing all the responses
* @throws ServiceInvocationException
* throws this exception when the invocation failed
* @throws InterruptedException
* throws this exception when the failed to wait
* @throws ExecutionException
* throws this exception if the thread pool executor failed
*/
public static Map<Service, List<Response<?>>> pollGetAll(
List<Service> services, long timeout, Executor executor)
throws ServiceInvocationException, InterruptedException,
ExecutionException {
return pollInternal(services, false, false, timeout, executor);
}
/**
* Poll all the services and return the responses. If block is true, the
* method is BLOCKED until all the outstanding responses are available. If
* block is false, the method returns immediately with all available
* responses
*
* @param services
* the services to be polled
* @param block
* blocking or non-blocking call
* @return the map containing all the responses
* @throws ServiceInvocationException
* throws this exception when the invocation failed
* @throws InterruptedException
* throws this exception when the failed to wait
*/
static Map<Service, List<Response<?>>> poll(List<Service> services,
boolean block) throws ServiceInvocationException,
InterruptedException {
return pollInternal(services, block, true);
}
/**
* Poll all the services and return the responses. If block is true, the
* method is BLOCKED until all the outstanding responses are available or
* timeout is reached. If block is false, the method returns immediately
* with all available responses
*
* @param services
* the services to be polled
* @param block
* blocking or non-blocking call
* @param timeout
* timeout in milliseconds
* @return the map containing all the responses
* @throws ServiceInvocationException
* throws this exception when the invocation failed
* @throws InterruptedException
* throws this exception when the failed to wait
* @throws ExecutionException
* throws this exception if the thread pool executor failed
*/
static Map<Service, List<Response<?>>> poll(List<Service> services,
boolean block, long timeout) throws ServiceInvocationException,
InterruptedException, ExecutionException {
return poll(services, block, timeout, Service.getDefaultExecutor());
}
/**
* Poll all the services and return the responses. If block is true, the
* method is BLOCKED until all the outstanding responses are available or
* timeout is reached. If block is false, the method returns immediately
* with all available responses
*
* @param services
* the services to be polled
* @param block
* blocking or non-blocking call
* @param timeout
* timeout in milliseconds
* @param executor
* the thread executor
* @return the map containing all the responses
* @throws ServiceInvocationException
* throws this exception when the invocation failed
* @throws InterruptedException
* throws this exception when the failed to wait
* @throws ExecutionException
* throws this exception if the thread pool executor failed
*/
static Map<Service, List<Response<?>>> poll(List<Service> services,
boolean block, long timeout, Executor executor)
throws ServiceInvocationException, InterruptedException,
ExecutionException {
return pollInternal(services, block, true, timeout, executor);
}
private static Map<Service, List<Response<?>>> pollInternal(
List<Service> services, boolean block, boolean partial)
throws InterruptedException {
Map<Service, List<Response<?>>> responses = new HashMap<Service, List<Response<?>>>();
for (Service service : services) {
responses.put(service, service.poll(block, partial));
}
return responses;
}
private static Map<Service, List<Response<?>>> pollInternal(
List<Service> services, boolean block, boolean partial,
long timeout, Executor executor) throws InterruptedException,
ExecutionException {
Map<Service, List<Response<?>>> responses = new HashMap<Service, List<Response<?>>>();
List<PollTask> pollTasks = new LinkedList<PollTask>();
for (Service service : services) {
PollTask task = new PollTask(service, block, partial, timeout);
executor.execute(task);
pollTasks.add(task);
}
for (PollTask pollTask : pollTasks) {
responses.put(pollTask.getService(), pollTask.get());
}
return responses;
}
private static class PollTask implements Runnable,
Future<List<Response<?>>> {
private final Service m_service;
private final boolean m_block;
private final boolean m_partial;
private final long m_timeout;
private boolean m_isDone = false;
private final List<Response<?>> responses = new LinkedList<Response<?>>();
private InterruptedException m_interruptedException = null;
public PollTask(Service service, boolean block, boolean partial,
long timeout) {
m_service = service;
m_block = block;
m_partial = partial;
m_timeout = timeout;
}
public Service getService() {
return m_service;
}
public void run() {
synchronized (responses) {
try {
responses.addAll(m_service.poll(m_block, m_partial,
m_timeout));
} catch (InterruptedException e) {
m_interruptedException = e;
} finally {
m_isDone = true;
responses.notify();
}
}
}
// Cancel will not work, false by default
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
public List<Response<?>> get() throws InterruptedException,
ExecutionException {
synchronized (responses) {
if (!isDone())
responses.wait();
if (m_interruptedException != null) {
throw m_interruptedException;
}
return responses;
}
}
public List<Response<?>> get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException,
TimeoutException {
return get();
}
public boolean isCancelled() {
return false;
}
public boolean isDone() {
return m_isDone;
}
}
}