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

org.smartdeveloperhub.jenkins.client.JenkinsResourceProxy Maven / Gradle / Ivy

Go to download

The Client for the Jenkins integration for the Continuous Integration Harvester of the Smart Developer Hub project

The newest version!
/**
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   This file is part of the Smart Developer Hub Project:
 *     http://www.smartdeveloperhub.org/
 *
 *   Center for Open Middleware
 *     http://www.centeropenmiddleware.com/
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Copyright (C) 2015-2016 Center for Open Middleware.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   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.
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 *   Artifact    : org.smartdeveloperhub.harvesters.ci.jenkins:ci-jenkins-client:0.3.0
 *   Bundle      : ci-jenkins-client-0.3.0.jar
 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
 */
package org.smartdeveloperhub.jenkins.client;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smartdeveloperhub.jenkins.JenkinsArtifactType;
import org.smartdeveloperhub.jenkins.JenkinsEntityType;
import org.smartdeveloperhub.jenkins.JenkinsResource;
import org.smartdeveloperhub.jenkins.JenkinsResource.Metadata.Filter;
import org.smartdeveloperhub.jenkins.Status;
import org.smartdeveloperhub.util.xml.XmlUtils;
import org.w3c.dom.Document;

import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

public final class JenkinsResourceProxy {

	private static final class ImmutableFilter implements Filter {

		private final Object value;
		private final String parameter;

		private ImmutableFilter(final String parameter, final Object value) {
			this.value = value;
			this.parameter = parameter;
		}

		@Override
		public String expression() {
			return this.parameter+"="+this.value;
		}

		@Override
		public String toString() {
			return expression();
		}

	}

	private static final Logger LOGGER=LoggerFactory.getLogger(JenkinsResourceProxy.class);

	private final URI location;

	private final JenkinsEntityType entity;

	private final Map filters;

	private JenkinsResourceProxy(final URI location, final JenkinsEntityType entity, final Map filters) {
		this.location = location;
		this.entity = entity;
		this.filters=Maps.newLinkedHashMap(filters);
	}

	public JenkinsResourceProxy withLocation(final URI location) {
		checkNotNull(location,"Resource location cannot be null");
		return new JenkinsResourceProxy(location,this.entity,this.filters);
	}

	public JenkinsResourceProxy withDepth(final long depth) {
		checkArgument(depth>0,"Depth must be greater than 0 (%d)",depth);
		this.filters.put(1,new ImmutableFilter("depth",depth));
		return new JenkinsResourceProxy(this.location,this.entity,this.filters);
	}

	public JenkinsResourceProxy withTree(final String tree) {
		checkNotNull(tree,"Tree cannot be null");
		this.filters.put(1,new ImmutableFilter("tree",tree));
		return new JenkinsResourceProxy(this.location,this.entity,this.filters);
	}

	public JenkinsResourceProxy withWrapper(final String wrapper) {
		checkNotNull(wrapper,"Wrapper cannot be null");
		this.filters.put(2,new ImmutableFilter("wrapper",wrapper));
		return new JenkinsResourceProxy(this.location,this.entity,this.filters);
	}

	public JenkinsResourceProxy withXPath(final String xpath) {
		checkNotNull(xpath,"XPath cannot be null");
		this.filters.put(3,new ImmutableFilter("xpath", xpath));
		return new JenkinsResourceProxy(this.location,this.entity,this.filters);
	}

	public JenkinsResourceProxy withEntity(final JenkinsEntityType entity) {
		checkNotNull(entity,"Resource entity cannot be null");
		return new JenkinsResourceProxy(this.location,entity,this.filters);
	}

	public URI location() {
		return this.location;
	}

	public JenkinsResource get(final JenkinsArtifactType artifact) throws IOException {
		checkNotNull(artifact,"Artifact cannot be null");
		final InMemoryJenkinsResource resource=
			new InMemoryJenkinsResource(new Date()).
				withFilters(filters()).
				withEntity(this.entity).
				withLocation(this.location).
				withArtifact(artifact);
		final CloseableHttpClient httpClient=HttpClients.createDefault();
		CloseableHttpResponse httpResponse=null;
		final HttpGet httpGet = createGetMethod(resource.effectiveLocation());
		try {
			httpResponse = httpClient.execute(httpGet);
			final int statusCode = httpResponse.getStatusLine().getStatusCode();
			resource.
				metadata().
					withServerVersion(HttpResponseUtil.retrieveServiceVersion(httpResponse)).
					response().
						withStatusCode(statusCode).
						withEtag(HttpResponseUtil.retrieveEntityTag(httpResponse)).
						withLastModified(HttpResponseUtil.retrieveLastModified(httpResponse));

			final ContentType contentType=processResponseBody(resource,httpResponse.getEntity());

			if(statusCode!=200) {
				resource.
					withStatus(
						Status.fromHttpStatusCode(statusCode),
						HttpResponseUtil.getInvalidResponseFailureMessage(httpResponse));
			} else {
				processResourceEntity(
					resource,
					contentType);
			}
		} catch (final Exception cause) {
			LOGGER.error("Communication with {} failed",this.location,cause);
			throw new IOException("Communication with "+this.location+" failed",cause);
		} finally {
			IOUtils.closeQuietly(httpResponse);
			IOUtils.closeQuietly(httpClient);
		}
		return resource;
	}

	@Override
	public String toString() {
		return
			MoreObjects.
				toStringHelper(getClass()).
					omitNullValues().
					add("filters",this.filters).
					add("location",this.location).
					add("entity",this.location).
					toString();
	}

	private List filters() {
		final List result=Lists.newArrayList();
		for(int i=1;i<4;i++) {
			final Filter value=this.filters.get(i);
			if(value!=null) {
				result.add(value);
			}
		}
		return result;
	}

	private ContentType processResponseBody(final InMemoryJenkinsResource resource, final HttpEntity httpEntity) throws IOException {
		if(httpEntity==null) {
			return null;
		}

		final ContentType contentType =
			ContentType.
				parse(httpEntity.getContentType().getValue());

		Charset charset = contentType.getCharset();
		if(charset==null) {
			LOGGER.debug(
				"No encoding specified for {} ({}). Resorting to UTF-8",
				resource.location(),
				contentType);
			charset=StandardCharsets.UTF_8;
		}

		resource.
			metadata().
				response().
					withBody(
						HttpResponseUtil.
							toResponseBody(
								httpEntity.getContent(),
								contentType.getMimeType(),
								charset));

		return contentType;
	}

	private void processResourceEntity(final InMemoryJenkinsResource resource, final ContentType contentType) {
		try {
			if(resource.metadata().serverVersion()==null && resource.artifact().isModelObject()) {
				resource.
					withStatus(
						Status.INCOMPATIBLE_RESOURCE,
						"Not a Jenkins resource");
			} else if(!ContentType.APPLICATION_XML.getMimeType().equals(contentType.getMimeType())) {
				resource.
					withStatus(
						Status.INCOMPATIBLE_RESOURCE,
						"Not an XML representation of a Jenkins resource (%s)",contentType);
			} else {
				updateRepresentationContent(resource);
			}
		} catch (final Exception cause) {
			resource.
				withStatus(
					Status.UNPROCESSABLE_RESOURCE,cause,"Could not process response body");
		}
	}

	private void updateRepresentationContent(final InMemoryJenkinsResource resource) {
		final String body = resource.metadata().response().body().get().content();
		try {
			final Document content = XmlUtils.toDocument(body);
			final String localName=content.getFirstChild().getNodeName();
			if(JenkinsArtifactType.RESOURCE.equals(resource.artifact())) {
				final JenkinsEntityType receivedEntity=JenkinsEntityType.fromNode(localName);
				if(receivedEntity==null) {
					resource.withStatus(
						Status.UNSUPPORTED_RESOURCE,
						"Unsupported Jenkins resource type '%s'",localName);
				} else if(!this.entity.isCompatible(receivedEntity)) {
					resource.withStatus(
						Status.INVALID_RESOURCE,
						"Invalid Jenkins entity type. Expected '%s' but got '%s'",this.entity,receivedEntity);
				} else {
					resource.
						withEntity(receivedEntity).
						withStatus(Status.AVAILABLE);
				}
			} else {
				resource.
					withStatus(Status.AVAILABLE);
			}
			resource.withContent(content);
		} catch (final Exception cause) {
			LOGGER.debug("Could not process response body {}",body,cause);
			resource.withStatus(Status.UNPROCESSABLE_RESOURCE,cause,"Could not process response body");
		}
	}

	private HttpGet createGetMethod(final URI buildLocation) {
		final HttpGet httpGet = new HttpGet(buildLocation.toString());
		httpGet.setHeader("Accept", "application/xml; charset=utf-8");
		httpGet.setHeader("User-Agent", " Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36");
		final RequestConfig config =
			RequestConfig.
				custom().
					setConnectTimeout(5000).
					setRedirectsEnabled(true).
					setCircularRedirectsAllowed(false).
					build();
		httpGet.setConfig(config);
		return httpGet;
	}

	public static JenkinsResourceProxy create(final URI location) {
		checkNotNull(location,"Resource location cannot be null");
		return new JenkinsResourceProxy(location,JenkinsEntityType.INSTANCE,Maps.newLinkedHashMap());
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy