Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2014 Spotify AB.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 com.spotify.helios.client;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.FutureFallback;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.spotify.helios.common.HeliosException;
import com.spotify.helios.common.Json;
import com.spotify.helios.common.Resolver;
import com.spotify.helios.common.Version;
import com.spotify.helios.common.VersionCompatibility;
import com.spotify.helios.common.VersionCompatibility.Status;
import com.spotify.helios.common.descriptors.Deployment;
import com.spotify.helios.common.descriptors.HostStatus;
import com.spotify.helios.common.descriptors.Job;
import com.spotify.helios.common.descriptors.JobId;
import com.spotify.helios.common.descriptors.JobStatus;
import com.spotify.helios.common.protocol.CreateJobResponse;
import com.spotify.helios.common.protocol.HostDeregisterResponse;
import com.spotify.helios.common.protocol.JobDeleteResponse;
import com.spotify.helios.common.protocol.JobDeployResponse;
import com.spotify.helios.common.protocol.JobUndeployResponse;
import com.spotify.helios.common.protocol.SetGoalResponse;
import com.spotify.helios.common.protocol.TaskStatusEvents;
import com.spotify.helios.common.protocol.VersionResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.GZIPInputStream;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.util.concurrent.Futures.immediateFuture;
import static com.google.common.util.concurrent.Futures.transform;
import static com.google.common.util.concurrent.Futures.withFallback;
import static com.google.common.util.concurrent.MoreExecutors.getExitingExecutorService;
import static com.spotify.helios.common.VersionCompatibility.HELIOS_SERVER_VERSION_HEADER;
import static com.spotify.helios.common.VersionCompatibility.HELIOS_VERSION_STATUS_HEADER;
import static java.lang.String.format;
import static java.lang.System.currentTimeMillis;
import static java.net.HttpURLConnection.HTTP_OK;
import static java.net.HttpURLConnection.HTTP_BAD_METHOD;
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
import static java.net.HttpURLConnection.HTTP_FORBIDDEN;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.asList;
import static java.util.concurrent.Executors.newFixedThreadPool;
import static java.util.concurrent.TimeUnit.SECONDS;
public class HeliosClient implements AutoCloseable {
private static final Logger log = LoggerFactory.getLogger(HeliosClient.class);
private static final long RETRY_TIMEOUT_MILLIS = SECONDS.toMillis(60);
private static final long HTTP_TIMEOUT_MILLIS = SECONDS.toMillis(10);
private final AtomicBoolean versionWarningLogged = new AtomicBoolean();
private final String user;
private final Supplier> endpointSupplier;
private final ListeningExecutorService executorService;
HeliosClient(final String user,
final Supplier> endpointSupplier,
final ListeningExecutorService executorService) {
this.user = checkNotNull(user);
this.endpointSupplier = checkNotNull(endpointSupplier);
this.executorService = checkNotNull(executorService);
}
HeliosClient(final String user, final List endpoints,
final ListeningExecutorService executorService) {
this(user, Suppliers.ofInstance(endpoints), executorService);
}
HeliosClient(final String user, final Supplier> endpointSupplier) {
this(user, endpointSupplier, MoreExecutors.listeningDecorator(getExitingExecutorService(
(ThreadPoolExecutor) newFixedThreadPool(4), 0, SECONDS)));
}
HeliosClient(final String user, final List endpoints) {
this(user, Suppliers.ofInstance(endpoints));
}
@Override
public void close() {
executorService.shutdownNow();
}
private URI uri(final String path) {
return uri(path, Collections.emptyMap());
}
private URI uri(final String path, final Map query) {
// TODO(dano): use a uri builder and clean this mess up
checkArgument(path.startsWith("/"));
final Map queryWithUser = Maps.newHashMap(query);
queryWithUser.put("user", user);
final String queryPart = Joiner.on('&').withKeyValueSeparator("=").join(queryWithUser);
try {
return new URI("http", "helios", path, queryPart, null);
} catch (URISyntaxException e) {
throw Throwables.propagate(e);
}
}
private String path(final String resource, final Object... params) {
final String path;
if (params.length == 0) {
path = resource;
} else {
final List encodedParams = Lists.newArrayList();
for (final Object param : params) {
final URI u;
try {
final String p = param.toString().replace("/", "%2F");
// URI does path encoding right, but using it is painful
u = new URI("http", "ignore", "/" + p, "");
} catch (URISyntaxException e) {
throw Throwables.propagate(e);
}
encodedParams.add(u.getRawPath().substring(1));
}
path = format(resource, encodedParams.toArray());
}
return path;
}
private ListenableFuture request(final URI uri, final String method) {
return request(uri, method, null);
}
private ListenableFuture request(final URI uri, final String method,
final Object entity) {
final Map> headers = Maps.newHashMap();
final byte[] entityBytes;
headers.put(VersionCompatibility.HELIOS_VERSION_HEADER, asList(Version.POM_VERSION));
if (entity != null) {
headers.put("Content-Type", asList("application/json"));
headers.put("Charset", asList("utf-8"));
entityBytes = Json.asBytesUnchecked(entity);
} else {
entityBytes = new byte[]{};
}
return executorService.submit(new Callable() {
@Override
public Response call() throws Exception {
final HttpURLConnection connection = connect(uri, method, entityBytes, headers);
final int status = connection.getResponseCode();
final InputStream rawStream;
if (status / 100 != 2) {
rawStream = connection.getErrorStream();
} else {
rawStream = connection.getInputStream();
}
final boolean gzip = isGzipCompressed(connection);
final InputStream stream = gzip ? new GZIPInputStream(rawStream) : rawStream;
final ByteArrayOutputStream payload = new ByteArrayOutputStream();
if (stream != null) {
int n;
byte[] buffer = new byte[4096];
while ((n = stream.read(buffer, 0, buffer.length)) != -1) {
payload.write(buffer, 0, n);
}
}
URI realUri = connection.getURL().toURI();
if (log.isTraceEnabled()) {
log.trace("rep: {} {} {} {} {} gzip:{}",
method, realUri, status, payload.size(), decode(payload), gzip);
} else {
log.debug("rep: {} {} {} {} gzip:{}",
method, realUri, status, payload.size(), gzip);
}
checkprotocolVersionStatus(connection);
return new Response(method, uri, status, payload.toByteArray());
}
private boolean isGzipCompressed(final HttpURLConnection connection) {
final List encodings = connection.getHeaderFields().get("Content-Encoding");
if (encodings == null) {
return false;
}
for (String encoding : encodings) {
if ("gzip".equals(encoding)) {
return true;
}
}
return false;
}
});
}
private void checkprotocolVersionStatus(final HttpURLConnection connection) {
final Status versionStatus = getVersionStatus(connection);
if (versionStatus == null) {
log.debug("Server didn't return a version header!");
return; // shouldn't happen really
}
final String serverVersion = connection.getHeaderField(HELIOS_SERVER_VERSION_HEADER);
if (versionStatus == VersionCompatibility.Status.MAYBE) {
if (versionWarningLogged.compareAndSet(false, true)) {
log.warn("Your Helios client version [{}] is ahead of the server [{}]. This will"
+ " probably work ok but there is the potential for weird things. If in doubt,"
+ " contact the Helios team if you think the cluster you're connecting to is out"
+ " of date and should be upgraded.", Version.POM_VERSION, serverVersion);
}
} else if (versionStatus == VersionCompatibility.Status.UPGRADE_SOON) {
if (versionWarningLogged.compareAndSet(false, true)) {
log.warn("Your Helios client is nearly out of date. Please upgrade to [{}]",
serverVersion);
}
}
}
private Status getVersionStatus(final HttpURLConnection connection) {
final String status = connection.getHeaderField(HELIOS_VERSION_STATUS_HEADER);
if (status != null) {
return VersionCompatibility.Status.valueOf(status);
}
return null;
}
private String decode(final ByteArrayOutputStream payload) {
final byte[] bytes = payload.toByteArray();
try {
return Json.asPrettyString(Json.read(bytes, new TypeReference