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

io.micrometer.core.ipc.http.HttpSender Maven / Gradle / Ivy

/**
 * Copyright 2018 VMware, Inc.
 * 

* 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 *

* https://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 io.micrometer.core.ipc.http; import io.micrometer.core.instrument.util.JsonUtils; import io.micrometer.core.instrument.util.StringUtils; import io.micrometer.core.lang.Nullable; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UncheckedIOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.LinkedHashMap; import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.zip.GZIPOutputStream; /** * A general-purpose interface for controlling how {@link io.micrometer.core.instrument.MeterRegistry} implementations * perform HTTP calls for various purposes. This interface can be used to inject more advanced customization like SSL * verification, key loading, etc. without requiring further additions to registry configurations. * * @author Jon Schneider * @since 1.1.0 */ public interface HttpSender { Response send(Request request) throws Throwable; default Request.Builder post(String uri) { return newRequest(uri).withMethod(Method.POST); } default Request.Builder head(String uri) { return newRequest(uri).withMethod(Method.HEAD); } default Request.Builder put(String uri) { return newRequest(uri).withMethod(Method.PUT); } default Request.Builder get(String uri) { return newRequest(uri).withMethod(Method.GET); } default Request.Builder delete(String uri) { return newRequest(uri).withMethod(Method.DELETE); } default Request.Builder options(String uri) { return newRequest(uri).withMethod(Method.OPTIONS); } default Request.Builder newRequest(String uri) { return new Request.Builder(uri, this); } class Request { private final URL url; private final byte[] entity; private final Method method; private final Map requestHeaders; public Request(URL url, byte[] entity, Method method, Map requestHeaders) { this.url = url; this.entity = entity; this.method = method; this.requestHeaders = requestHeaders; } public URL getUrl() { return url; } public byte[] getEntity() { return entity; } public Method getMethod() { return method; } public Map getRequestHeaders() { return requestHeaders; } public static Builder build(String uri, HttpSender sender) { return new Builder(uri, sender); } @Override public String toString() { StringBuilder printed = new StringBuilder(method.toString()).append(" ") .append(url.toString()).append("\n"); if (entity.length == 0) { printed.append(""); } else if ("application/json".equals(requestHeaders.get("Content-Type"))) { printed.append(JsonUtils.prettyPrint(new String(entity))); } else { printed.append(new String(entity)); } return printed.toString(); } public static class Builder { private static final String APPLICATION_JSON = "application/json"; private static final String TEXT_PLAIN = "text/plain"; private final URL url; private final HttpSender sender; private byte[] entity = new byte[0]; private Method method; private Map requestHeaders = new LinkedHashMap<>(); Builder(String uri, HttpSender sender) { try { this.url = URI.create(uri).toURL(); } catch (MalformedURLException ex) { throw new UncheckedIOException(ex); } this.sender = sender; } /** * Add a header to the request. * * @param name The name of the header. * @param value The value of the header. * @return This request builder. */ public final Builder withHeader(String name, String value) { requestHeaders.put(name, value); return this; } /** * If user and password are non-empty, set basic authentication on the request. * * @param user A user name, if available. * @param password A password, if available. * @return This request builder. */ public final Builder withBasicAuthentication(@Nullable String user, @Nullable String password) { if (user != null && StringUtils.isNotBlank(user)) { String encoded = Base64.getEncoder().encodeToString((user.trim() + ":" + (password == null ? "" : password.trim())) .getBytes(StandardCharsets.UTF_8)); withHeader("Authorization", "Basic " + encoded); } return this; } /** * Set the request body as JSON content type. * * @param content The request body. * @return This request builder. */ public final Builder withJsonContent(String content) { return withContent(APPLICATION_JSON, content); } /** * Set the request body as plain text content type. * * @param content The request body. * @return This request builder. */ public final Builder withPlainText(String content) { return withContent(TEXT_PLAIN, content); } /** * Set the request body. * * @param type The value of the "Content-Type" header to add. * @param content The request body. * @return This request builder. */ public final Builder withContent(String type, String content) { return withContent(type, content.getBytes(StandardCharsets.UTF_8)); } /** * Set the request body. * * @param type The value of the "Content-Type" header to add. * @param content The request body. * @return This request builder. */ public final Builder withContent(String type, byte[] content) { withHeader("Content-Type", type); entity = content; return this; } /** * Add header to accept {@code application/json} data. * * @return This request builder. */ public Builder acceptJson() { return accept(APPLICATION_JSON); } /** * Add accept header. * * @param type The value of the "Accept" header to add. * @return This request builder. */ public Builder accept(String type) { return withHeader("Accept", type); } /** * Set the request method. * * @param method An HTTP method. * @return This request builder. */ public final Builder withMethod(Method method) { this.method = method; return this; } /** * Add a "Content-Encoding" header of "gzip" and compress the request body. * * @return This request builder. * @throws IOException If compression fails. */ public final Builder compress() throws IOException { withHeader("Content-Encoding", "gzip"); this.entity = gzip(entity); return this; } /** * Add a "Content-Encoding" header of "gzip" and compress the request body when the supplied * condition is true. * * @param when Condition that governs when to compress the request body. * @return This request builder. * @throws IOException If compression fails. */ public final Builder compressWhen(Supplier when) throws IOException { if (when.get()) return compress(); return this; } private static byte[] gzip(byte[] data) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length); try (GZIPOutputStream out = new GZIPOutputStream(bos)) { out.write(data); } return bos.toByteArray(); } public final Builder print() { System.out.println(new Request(url, entity, method, requestHeaders)); return this; } public Response send() throws Throwable { return sender.send(new Request(url, entity, method, requestHeaders)); } } } class Response { public static final String NO_RESPONSE_BODY = ""; private final int code; private final String body; public Response(int code, @Nullable String body) { this.code = code; this.body = StringUtils.isBlank(body) ? NO_RESPONSE_BODY : body; } public int code() { return code; } public String body() { return body; } public Response onSuccess(Consumer onSuccess) { switch (HttpStatusClass.valueOf(code)) { case INFORMATIONAL: case SUCCESS: onSuccess.accept(this); } return this; } public Response onError(Consumer onError) { switch (HttpStatusClass.valueOf(code)) { case CLIENT_ERROR: case SERVER_ERROR: onError.accept(this); } return this; } public boolean isSuccessful() { switch (HttpStatusClass.valueOf(code)) { case INFORMATIONAL: case SUCCESS: return true; default: return false; } } } enum Method { GET, HEAD, POST, PUT, DELETE, OPTIONS } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy