v2client/src/main/java/com/yubico/client/v2/VerificationRequester.java
public VerificationResponse fetch(List<String> urls, String userAgent) throws YubicoVerificationException {
	    List<Future<VerificationResponse>> tasks = new ArrayList<Future<VerificationResponse>>();
	    for(String url : urls) {
			tasks.add(completionService.submit(createTask(userAgent, url)));
	    }
	    VerificationResponse response = null;
		try {
			int tasksDone = 0;
			Throwable savedException = null;
			Future<VerificationResponse> futureResponse = completionService.poll(1L, MINUTES);
			while(futureResponse != null) {
				try {
					tasksDone++;
					tasks.remove(futureResponse);
					response = futureResponse.get();
					/**
					 * If the response returned is REPLAYED_REQUEST keep looking at responses
					 * and hope we get something else. REPLAYED_REQUEST will be returned if a
					 * validation server got sync before it parsed our query (otp and nonce is
					 * the same).
					 * @see https://forum.yubico.com/viewtopic21be.html
					 *
					 * Also if the response is BACKEND_ERROR, keep looking for a server that
					 * sends a valid response
					 * @see https://github.com/Yubico/yubico-java-client/issues/12
					 */
					if(!response.getStatus().equals(REPLAYED_REQUEST) && !response.getStatus().equals(BACKEND_ERROR)) {
						break;
					}
				} catch (CancellationException ignored) {
					// this would be thrown by old cancelled calls.
					tasksDone--;
				} catch (ExecutionException e) {
					// tuck the real exception away and use it if we don't get any valid answers.
					savedException = e.getCause();
				}
				if(tasksDone >= urls.size()) {
					break;
				}
				futureResponse = completionService.poll(1L, MINUTES);
			}
			if(futureResponse == null || response == null) {
				if(savedException != null) {
					throw new YubicoVerificationException(
							"Exception while executing validation.", savedException);
				} else {
					throw new YubicoVerificationException("Validation timeout.");
				}
			}
		} catch (InterruptedException e) {
			throw new YubicoVerificationException("Validation interrupted.", e);
		}
	    
		for(Future<VerificationResponse> task : tasks) {
			task.cancel(true);
		}
		
	    return response;
	}
public VerificationResponse fetch(List<String> urls, String userAgent) throws YubicoVerificationException {
	    List<Future<VerificationResponse>> tasks = new ArrayList<Future<VerificationResponse>>();
	    for(String url : urls) {
			tasks.add(completionService.submit(createTask(userAgent, url)));
	    }
	    VerificationResponse response = null;
		try {
			int tasksDone = 0;
			Throwable savedException = null;
			Future<VerificationResponse> futureResponse = completionService.poll(1L, MINUTES);
			while(futureResponse != null) {
				try {
					tasksDone++;
					tasks.remove(futureResponse);
					response = futureResponse.get();
					/**
					 * If the response returned is REPLAYED_REQUEST keep looking at responses
					 * and hope we get something else. REPLAYED_REQUEST will be returned if a
					 * validation server got sync before it parsed our query (otp and nonce is
					 * the same).
					 * @see https://forum.yubico.com/viewtopic21be.html
					 *
					 * Also if the response is BACKEND_ERROR, keep looking for a server that
					 * sends a valid response
					 * @see https://github.com/Yubico/yubico-java-client/issues/12
					 */
					if(!response.getStatus().equals(REPLAYED_REQUEST) && !response.getStatus().equals(BACKEND_ERROR)) {
						break;
					}
				} catch (CancellationException ignored) {
					// this would be thrown by old cancelled calls.
					tasksDone--;
				} catch (ExecutionException e) {
					// tuck the real exception away and use it if we don't get any valid answers.
					savedException = e.getCause();
				}
				if(tasksDone >= urls.size()) {
					break;
				}
				futureResponse = completionService.poll(1L, MINUTES);
			}
			if(futureResponse == null || response == null) {
				if(savedException != null) {
					throw new YubicoVerificationException(
							"Exception while executing validation.", savedException);
				} else {
					throw new YubicoVerificationException("Validation timeout.");
				}
			}
		} catch (InterruptedException e) {
			throw new YubicoVerificationException("Validation interrupted.", e);
		}
	    
		for(Future<VerificationResponse> task : tasks) {
			task.cancel(true);
		}
		
	    return response;
	}
Fires off a validation request to each url in the list, returning the first one
that is not {@link ResponseStatus#REPLAYED_REQUEST}

@param urls a list of validation urls to be contacted
@param userAgent userAgent to send in request, if null one will be generated
@return {@link VerificationResponse} object from the first server response that is not
{@link ResponseStatus#REPLAYED_REQUEST}
@throws com.yubico.client.v2.exceptions.YubicoVerificationException if validation fails on all urls