All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kuali.common.http.DefaultHttpService Maven / Gradle / Ivy

There is a newer version: 1.0.8
Show newest version
/**
 * Copyright 2004-2013 The Kuali Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
 *
 * 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.kuali.common.http;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpMethodRetryHandler;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.kuali.common.util.Assert;
import org.kuali.common.util.FormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DefaultHttpService implements HttpService {

	private final Logger logger = LoggerFactory.getLogger(DefaultHttpService.class);

	@Override
	public HttpWaitResult wait(HttpContext context) {
		Assert.notBlank(context.getUrl(), "url is blank");
		logger.debug(context.getUrl());
		HttpClient client = getHttpClient(context);
		HttpWaitResult waitResult = new HttpWaitResult();
		waitResult.setStart(System.currentTimeMillis());
		long end = waitResult.getStart() + context.getOverallTimeoutMillis();
		List requestResults = new ArrayList();
		waitResult.setRequestResults(requestResults);
		logger.info("Determining status for {} - (Timeout in {})", context.getUrl(), FormatUtils.getTime(context.getOverallTimeoutMillis()));
		for (;;) {
			HttpRequestResult rr = doRequest(client, context);
			requestResults.add(rr);
			if (!isFinishState(context, rr, end)) {
				logHttpRequestResult(rr, context.getUrl(), end);
				sleep(context.getSleepIntervalMillis());
			} else {
				HttpStatus status = getResultStatus(context, rr, end);
				waitResult.setStatus(status);
				waitResult.setStop(rr.getStop());
				waitResult.setElapsed(waitResult.getStop() - waitResult.getStart());
				waitResult.setFinalRequestResult(rr);
				logWaitResult(waitResult, context.getUrl());
				return waitResult;
			}
		}
	}

	protected void logWaitResult(HttpWaitResult result, String url) {
		String status = result.getStatus().toString();
		String elapsed = FormatUtils.getTime(result.getStop() - result.getStart());
		String statusText = getStatusText(result.getFinalRequestResult());
		Object[] args = { url, status, statusText, elapsed };
		logger.info("{} - [{} - {}]  Total time: {}]", args);
	}

	protected void logHttpRequestResult(HttpRequestResult result, String url, long end) {
		String statusText = getStatusText(result);
		String timeout = FormatUtils.getTime(end - System.currentTimeMillis());
		Object[] args = { url, statusText, timeout };
		logger.info("{} - [{}] - (Timeout in {})", args);
	}

	protected String getStatusText(HttpRequestResult result) {
		if (result.getException() != null) {
			return result.getException().toString();
		} else {
			return result.getStatusCode() + " - " + result.getStatusText();
		}
	}

	protected HttpStatus getResultStatus(HttpContext context, HttpRequestResult rr, long end) {
		// If we've gone past our max allotted time, we've timed out
		if (rr.getStop() > end) {
			return HttpStatus.TIMEOUT;
		}

		// Don't think we'll ever fall into this. Logic always continues re-trying until timeout is exceeded if an IO exception is returned
		if (rr.getException() != null) {
			return HttpStatus.IO_EXCEPTION;
		}

		// If we have not timed out and there is no exception, we must have gotten a valid http response code back
		Integer statusCode = rr.getStatusCode();
		if (statusCode == null) {
			throw new IllegalStateException("statusCode should never be null here");
		}

		// If there is a status code and it matches a success code, we are done
		if (isSuccess(context.getSuccessCodes(), statusCode)) {
			return HttpStatus.SUCCESS;
		} else {
			return HttpStatus.INVALID_HTTP_STATUS_CODE;
		}
	}

	protected boolean isFinishState(HttpContext context, HttpRequestResult rr, long end) {
		// If we've gone past our max allotted time, we are done
		if (rr.getStop() > end) {
			return true;
		}

		// If there is no status code at all, we need to keep trying
		Integer statusCode = rr.getStatusCode();
		if (statusCode == null) {
			return false;
		}

		// If there is a status code and it matches a success code, we are done
		if (isSuccess(context.getSuccessCodes(), statusCode)) {
			return true;
		}

		// If there is a status code and it matches a continue waiting code, we need to keep trying
		if (isContinueWaiting(context.getContinueWaitingCodes(), statusCode)) {
			return false;
		} else {
			// We got an http status code, but it wasn't one we were expecting. We need to fail
			return true;
		}
	}

	protected HttpRequestResult doRequest(HttpClient client, HttpContext context) {
		HttpRequestResult result = new HttpRequestResult();
		result.setStart(System.currentTimeMillis());
		try {
			HttpMethod method = new GetMethod(context.getUrl());
			client.executeMethod(method);
			result.setStatusCode(method.getStatusCode());
			result.setStatusText(method.getStatusText());
		} catch (IOException e) {
			result.setException(e);
		}
		result.setStop(System.currentTimeMillis());
		result.setElapsed(result.getStop() - result.getStart());
		return result;
	}

	protected boolean isSuccess(List successCodes, int resultCode) {
		return isMatch(resultCode, successCodes);
	}

	protected boolean isContinueWaiting(List continueWaitingCodes, int resultCode) {
		return isMatch(resultCode, continueWaitingCodes);
	}

	protected boolean isMatch(int i, List integers) {
		for (int integer : integers) {
			if (i == integer) {
				return true;
			}
		}
		return false;
	}

	protected HttpClient getHttpClient(HttpContext context) {
		HttpClient client = new HttpClient();
		HttpClientParams clientParams = client.getParams();

		// Disable the automatic retry capability built into the http client software
		// We will be handling retries on our own
		HttpMethodRetryHandler retryHandler = new DefaultHttpMethodRetryHandler(0, false);
		clientParams.setParameter(HttpMethodParams.RETRY_HANDLER, retryHandler);

		// Set a hard timeout for this individual request so we get control back after a known amount of time
		clientParams.setParameter(HttpMethodParams.SO_TIMEOUT, context.getRequestTimeoutMillis());

		// Return the client configured with our preferences
		return client;
	}

	protected void sleep(long millis) {
		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {
			throw new IllegalStateException(e);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy