/* * Sonar W3C Markup Validation Plugin * Copyright (C) 2010 Matthijs Galesloot * dev@sonar.codehaus.org * * 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 * * 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.sonar.plugins.web.markup.validation; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.UnknownHostException; import java.util.Properties; import org.apache.commons.configuration.Configuration; import org.apache.commons.io.IOUtils; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; import org.sonar.api.utils.SonarException; import org.sonar.plugins.web.markup.constants.MarkupValidatorConstants; /** * RemoteValidationService provides a framework for validators using a remote service. * * @author Matthijs Galesloot * @since 1.0 */ public abstract class RemoteValidationService { private static final long DEFAULT_PAUSE_BETWEEN_VALIDATIONS = 1000L; private static final Logger LOG = Logger.getLogger(RemoteValidationService.class); private HttpClient client; private final Configuration configuration; private Long waitBetweenRequests; // MILLISECONDS public RemoteValidationService(Configuration configuration) { this.configuration = configuration; waitBetweenRequests = configuration.getLong(MarkupValidatorConstants.PAUSE_BETWEEN_VALIDATIONS, DEFAULT_PAUSE_BETWEEN_VALIDATIONS); } /** * Execute post method to the remote validation service. On errors, the post is tried 3 times with a waiting time of 1 second. */ protected HttpResponse executePostMethod(HttpPost post) { int retries = 3; for (int i = 0; i < retries; i++) { HttpResponse response = null; try { response = getClient().execute(post); if (response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 302) { return response; } else { try { EntityUtils.consume(response.getEntity()); } catch (IOException e) { // ignore } LOG.warn("Bad http response: " + response.getStatusLine().getStatusCode() + ", retrying after 1 second..."); sleep(waitBetweenRequests); } } catch (UnknownHostException e) { if (useProxy()) { LOG.warn("Unknown host, retry without proxy..."); client.getConnectionManager().shutdown(); client = new DefaultHttpClient(); } } catch (IOException e) { throw new SonarException(e); } } return null; } private HttpClient getClient() { if (client == null) { client = new DefaultHttpClient(); if (useProxy()) { LOG.debug("Proxy " + getProxyHost() + ":" + getProxyPort()); HttpHost proxy = new HttpHost(getProxyHost(), getProxyPort()); client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); } } return client; } protected String getProperty(File file, String property) { File propertiesFile = new File(file.getPath() + ".txt"); if (propertiesFile.exists()) { Properties properties = new Properties(); InputStream in = null; try { in = new FileInputStream(propertiesFile); properties.load(in); if (properties.containsKey(property)) { return properties.getProperty(property); } } catch (IOException e) { return null; } finally { IOUtils.closeQuietly(in); } } return null; } /** * Returns the proxy host. * * @return proxy host */ private String getProxyHost() { return configuration.getString(MarkupValidatorConstants.PROXY_HOST, null); } /** * Returns the proxy port. */ private int getProxyPort() { return configuration.getInt(MarkupValidatorConstants.PROXY_PORT, -1); } protected Long getWaitBetweenRequests() { return waitBetweenRequests; } protected void setWaitBetweenRequests(Long waitBetweenRequests) { this.waitBetweenRequests = waitBetweenRequests; } protected void sleep(long sleepInterval) { try { Thread.sleep(sleepInterval); } catch (InterruptedException ie) { throw new SonarException(ie); } } /** * Returns whether or not to use a proxy. * * @return true/false */ private boolean useProxy() { return getProxyHost() != null && getProxyPort() > 0; } protected void waitBetweenValidationRequests() { sleep(waitBetweenRequests); } }