Java tutorial
/** * Copyright (C) 2011 Red Hat, Inc. (jdcasey@commonjava.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.commonjava.aprox.client.core; import static org.commonjava.aprox.client.core.helper.HttpResources.cleanupResources; import static org.commonjava.aprox.client.core.helper.HttpResources.entityToString; import static org.commonjava.aprox.client.core.util.UrlUtils.buildUrl; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.apache.http.Header; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpHead; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.HttpClientConnectionManager; import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.commonjava.aprox.client.core.helper.CloseBlockingConnectionManager; import org.commonjava.aprox.client.core.helper.HttpResources; import org.commonjava.aprox.model.core.ArtifactStore; import org.commonjava.aprox.model.core.io.AproxObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.type.TypeReference; public class AproxClientHttp implements Closeable { private static final int GLOBAL_MAX_CONNECTIONS = 20; private final Logger logger = LoggerFactory.getLogger(getClass()); private final String baseUrl; private final AproxObjectMapper objectMapper; private CloseBlockingConnectionManager connectionManager; public AproxClientHttp(final String baseUrl) { this.baseUrl = baseUrl; this.objectMapper = new AproxObjectMapper(true); } public AproxClientHttp(final String baseUrl, final AproxObjectMapper mapper) { this.baseUrl = baseUrl; this.objectMapper = mapper; } public void connect(final HttpClientConnectionManager connectionManager) throws AproxClientException { if (this.connectionManager != null) { throw new AproxClientException("Already connected! (Possibly when you called a client " + "API method previously.) Call close before connecting again."); } this.connectionManager = new CloseBlockingConnectionManager(connectionManager); } public synchronized void connect() { if (this.connectionManager == null) { final PoolingHttpClientConnectionManager pcm = new PoolingHttpClientConnectionManager(); pcm.setDefaultMaxPerRoute(GLOBAL_MAX_CONNECTIONS); this.connectionManager = new CloseBlockingConnectionManager(pcm); } } public Map<String, String> head(final String path) throws AproxClientException { return head(path, HttpStatus.SC_OK); } public Map<String, String> head(final String path, final int... responseCodes) throws AproxClientException { connect(); HttpHead request = null; CloseableHttpResponse response = null; CloseableHttpClient client = null; try { request = newJsonHead(buildUrl(baseUrl, path)); client = newClient(); response = client.execute(request); final StatusLine sl = response.getStatusLine(); if (!validResponseCode(sl.getStatusCode(), responseCodes)) { if (sl.getStatusCode() == HttpStatus.SC_NOT_FOUND) { return null; } throw new AproxClientException("Error executing HEAD: %s. Status was: %d %s (%s)", path, sl.getStatusCode(), sl.getReasonPhrase(), sl.getProtocolVersion()); } final Map<String, String> headers = new HashMap<>(); for (final Header header : response.getAllHeaders()) { final String name = header.getName().toLowerCase(); if (!headers.containsKey(name)) { headers.put(name, header.getValue()); } } return headers; } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } finally { cleanupResources(request, response, client); } } public <T> T get(final String path, final Class<T> type) throws AproxClientException { connect(); HttpGet request = null; CloseableHttpResponse response = null; CloseableHttpClient client = null; try { client = newClient(); request = newJsonGet(buildUrl(baseUrl, path)); response = client.execute(request); final StatusLine sl = response.getStatusLine(); if (sl.getStatusCode() != 200) { if (sl.getStatusCode() == 404) { return null; } throw new AproxClientException("Error retrieving %s from: %s. Status was: %d %s (%s)", type.getSimpleName(), path, sl.getStatusCode(), sl.getReasonPhrase(), sl.getProtocolVersion()); } final String json = entityToString(response); logger.info("Got JSON:\n\n{}\n\n", json); return objectMapper.readValue(json, type); } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } finally { cleanupResources(request, response, client); } } public <T> T get(final String path, final TypeReference<T> typeRef) throws AproxClientException { connect(); HttpGet request = null; CloseableHttpResponse response = null; CloseableHttpClient client = null; try { client = newClient(); request = newJsonGet(buildUrl(baseUrl, path)); response = client.execute(request); final StatusLine sl = response.getStatusLine(); if (sl.getStatusCode() != 200) { if (sl.getStatusCode() == 404) { return null; } throw new AproxClientException("Error retrieving %s from: %s. Status was: %d %s (%s)", typeRef.getType(), path, sl.getStatusCode(), sl.getReasonPhrase(), sl.getProtocolVersion()); } final String json = entityToString(response); final T value = objectMapper.readValue(json, typeRef); return value; } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } finally { cleanupResources(request, response, client); } } public HttpResources getRaw(final HttpGet req) throws AproxClientException { connect(); CloseableHttpResponse response = null; try { final CloseableHttpClient client = newClient(); response = client.execute(req); return new HttpResources(req, response, client); } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } finally { // DO NOT CLOSE!!!! We're handing off control of the response to the caller! // closeQuietly( response ); } } public HttpResources getRaw(final String path) throws AproxClientException { return getRaw(path, Collections.singletonMap("Accept", "*")); } public HttpResources getRaw(final String path, final Map<String, String> headers) throws AproxClientException { connect(); CloseableHttpResponse response = null; try { final HttpGet req = newRawGet(buildUrl(baseUrl, path)); final CloseableHttpClient client = newClient(); response = client.execute(req); return new HttpResources(req, response, client); } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } finally { // DO NOT CLOSE!!!! We're handing off control of the response to the caller! // closeQuietly( response ); } } public void putWithStream(final String path, final InputStream stream) throws AproxClientException { putWithStream(path, stream, HttpStatus.SC_CREATED); } public void putWithStream(final String path, final InputStream stream, final int... responseCodes) throws AproxClientException { connect(); final HttpPut put = newRawPut(buildUrl(baseUrl, path)); final CloseableHttpClient client = newClient(); try { put.setEntity(new InputStreamEntity(stream)); client.execute(put, new ResponseHandler<Void>() { @Override public Void handleResponse(final HttpResponse response) throws ClientProtocolException, IOException { try { final StatusLine sl = response.getStatusLine(); if (!validResponseCode(sl.getStatusCode(), responseCodes)) { throw new ClientProtocolException( String.format("Error in response from: %s. Status was: %d %s (%s)", path, sl.getStatusCode(), sl.getReasonPhrase(), sl.getProtocolVersion())); } return null; } finally { cleanupResources(put, response, client); } } }); } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } } public boolean put(final String path, final Object value) throws AproxClientException { return put(path, value, HttpStatus.SC_OK, HttpStatus.SC_CREATED); } public boolean put(final String path, final Object value, final int... responseCodes) throws AproxClientException { connect(); HttpPut put = null; CloseableHttpResponse response = null; CloseableHttpClient client = null; try { client = newClient(); put = newJsonPut(buildUrl(baseUrl, path)); put.setEntity(new StringEntity(objectMapper.writeValueAsString(value))); response = client.execute(put); final StatusLine sl = response.getStatusLine(); if (!validResponseCode(sl.getStatusCode(), responseCodes)) { logger.error("Error in response from: %s. Status was: %d %s (%s)", path, sl.getStatusCode(), sl.getReasonPhrase(), sl.getProtocolVersion()); return false; } } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } finally { cleanupResources(put, response, client); } return true; } public <T> T postWithResponse(final String path, final Object value, final Class<T> type) throws AproxClientException { return postWithResponse(path, value, type, HttpStatus.SC_CREATED); } public <T> T postWithResponse(final String path, final Object value, final Class<T> type, final int... responseCodes) throws AproxClientException { connect(); HttpPost post = null; CloseableHttpResponse response = null; CloseableHttpClient client = null; try { client = newClient(); post = newJsonPost(buildUrl(baseUrl, path)); post.setEntity(new StringEntity(objectMapper.writeValueAsString(value))); response = client.execute(post); final StatusLine sl = response.getStatusLine(); if (!validResponseCode(sl.getStatusCode(), responseCodes)) { throw new AproxClientException("Error retrieving %s from: %s. Status was: %d %s (%s)", type.getSimpleName(), path, sl.getStatusCode(), sl.getReasonPhrase(), sl.getProtocolVersion()); } final String json = entityToString(response); return objectMapper.readValue(json, type); } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } finally { cleanupResources(post, response, client); } } public boolean validResponseCode(final int statusCode, final int[] responseCodes) { for (final int code : responseCodes) { if (code == statusCode) { return true; } } return false; } public <T> T postWithResponse(final String path, final Object value, final TypeReference<T> typeRef) throws AproxClientException { return postWithResponse(path, value, typeRef, HttpStatus.SC_CREATED); } public <T> T postWithResponse(final String path, final Object value, final TypeReference<T> typeRef, final int... responseCodes) throws AproxClientException { connect(); HttpPost post = null; CloseableHttpResponse response = null; CloseableHttpClient client = null; try { client = newClient(); post = newJsonPost(buildUrl(baseUrl, path)); post.setEntity(new StringEntity(objectMapper.writeValueAsString(value))); response = client.execute(post); final StatusLine sl = response.getStatusLine(); if (!validResponseCode(sl.getStatusCode(), responseCodes)) { throw new AproxClientException("Error retrieving %s from: %s. Status was: %d %s (%s)", typeRef.getType(), path, sl.getStatusCode(), sl.getReasonPhrase(), sl.getProtocolVersion()); } final String json = entityToString(response); return objectMapper.readValue(json, typeRef); } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } finally { cleanupResources(post, response, client); } } @Override public void close() { logger.info("Shutting down aprox client HTTP manager"); connectionManager.reallyShutdown(); } public void delete(final String path) throws AproxClientException { delete(path, HttpStatus.SC_NO_CONTENT); } public void delete(final String path, final int... responseCodes) throws AproxClientException { connect(); HttpDelete delete = null; CloseableHttpResponse response = null; CloseableHttpClient client = null; try { client = newClient(); delete = newDelete(buildUrl(baseUrl, path)); response = client.execute(delete); final StatusLine sl = response.getStatusLine(); if (!validResponseCode(sl.getStatusCode(), responseCodes)) { throw new AproxClientException("Error deleting: %s. Status was: %d %s (%s)", path, sl.getStatusCode(), sl.getReasonPhrase(), sl.getProtocolVersion()); } } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } finally { cleanupResources(delete, response, client); } } public void deleteWithChangelog(final String path, final String changelog) throws AproxClientException { deleteWithChangelog(path, changelog, HttpStatus.SC_NO_CONTENT); } public void deleteWithChangelog(final String path, final String changelog, final int... responseCodes) throws AproxClientException { connect(); HttpDelete delete = null; CloseableHttpResponse response = null; CloseableHttpClient client = null; try { client = newClient(); delete = newDelete(buildUrl(baseUrl, path)); delete.setHeader(ArtifactStore.METADATA_CHANGELOG, changelog); response = client.execute(delete); final StatusLine sl = response.getStatusLine(); if (!validResponseCode(sl.getStatusCode(), responseCodes)) { throw new AproxClientException("Error deleting: %s. Status was: %d %s (%s)", path, sl.getStatusCode(), sl.getReasonPhrase(), sl.getProtocolVersion()); } } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } finally { cleanupResources(delete, response, client); } } public boolean exists(final String path) throws AproxClientException { return exists(path, HttpStatus.SC_OK); } public boolean exists(final String path, final int... responseCodes) throws AproxClientException { connect(); HttpHead request = null; CloseableHttpResponse response = null; CloseableHttpClient client = null; try { client = newClient(); request = newJsonHead(buildUrl(baseUrl, path)); response = client.execute(request); final StatusLine sl = response.getStatusLine(); if (validResponseCode(sl.getStatusCode(), responseCodes)) { return true; } else if (sl.getStatusCode() == HttpStatus.SC_NOT_FOUND) { return false; } throw new AproxClientException("Error checking existence of: %s. Error was: %s", path, sl); } catch (final IOException e) { throw new AproxClientException("AProx request failed: %s", e, e.getMessage()); } finally { cleanupResources(request, response, client); } } public void cleanup(final HttpRequest request, final HttpResponse response, final CloseableHttpClient client) { cleanupResources(request, response, client); } public String toAproxUrl(final String... path) { return buildUrl(baseUrl, path); } public String getBaseUrl() { return baseUrl; } public CloseableHttpClient newClient() { // return HttpClients.createDefault(); return HttpClients.custom().setConnectionManager(connectionManager).build(); } public HttpGet newRawGet(final String url) { final HttpGet req = new HttpGet(url); return req; } public HttpGet newJsonGet(final String url) { final HttpGet req = new HttpGet(url); addJsonHeaders(req); return req; } public HttpHead newJsonHead(final String url) { final HttpHead req = new HttpHead(url); addJsonHeaders(req); return req; } public void addJsonHeaders(final HttpUriRequest req) { req.addHeader("Accept", "application/json"); req.addHeader("Content-Type", "application/json"); } public HttpDelete newDelete(final String url) { final HttpDelete req = new HttpDelete(url); return req; } public HttpPut newJsonPut(final String url) { final HttpPut req = new HttpPut(url); addJsonHeaders(req); return req; } public HttpPut newRawPut(final String url) { final HttpPut req = new HttpPut(url); return req; } public HttpPost newJsonPost(final String url) { final HttpPost req = new HttpPost(url); addJsonHeaders(req); return req; } }