/** * 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 org.apache.ambari.view.pig.templeton.client; import com.google.gson.Gson; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.core.util.MultivaluedMapImpl; import org.apache.ambari.view.AmbariHttpException; import org.apache.ambari.view.ViewContext; import org.apache.ambari.view.utils.ambari.AmbariApiException; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.util.HashMap; import java.util.Map; /** * Request handler, supports GET, POST, PUT, DELETE methods * @param <RESPONSE> data type to deserialize response from JSON */ public class JSONRequest<RESPONSE> { protected final Class<RESPONSE> responseClass; protected final ViewContext context; protected final WebResource resource; private String username; private String doAs; protected final Gson gson = new Gson(); protected final static Logger LOG = LoggerFactory.getLogger(JSONRequest.class); /** * Constructor * @param resource object that represents resource * @param responseClass model class * @param username will be used to auth as proxyuser * @param doAs run query from this user * @param context View Context instance */ public JSONRequest(WebResource resource, Class<RESPONSE> responseClass, String username, String doAs, ViewContext context) { this.resource = resource; this.responseClass = responseClass; this.username = username; this.context = context; this.doAs = doAs; } /** * Main implementation of GET request * @param resource resource * @return unmarshalled response data */ public RESPONSE get(WebResource resource) throws IOException { LOG.info("GET {}", resource); InputStream inputStream = readFrom(resource, "GET", null, new HashMap<String, String>()); recordLastCurlCommand(String.format("curl \"" + resource.toString() + "\"")); String responseJson = IOUtils.toString(inputStream); LOG.debug("RESPONSE {}", responseJson); return gson.fromJson(responseJson, responseClass); } /** * Make GET request * @see #get(WebResource) */ public RESPONSE get() throws IOException { return get(this.resource); } /** * Make GET request * @see #get(WebResource) */ public RESPONSE get(MultivaluedMapImpl params) throws IOException { return get(this.resource.queryParams(params)); } /** * Main implementation of POST request * @param resource resource * @param data post body * @return unmarshalled response data */ public RESPONSE post(WebResource resource, MultivaluedMapImpl data) throws IOException { LOG.info("POST: {}", resource); LOG.debug("data: {}", data); StringBuilder curlBuilder = new StringBuilder(); UriBuilder builder = getUriBuilder(data, curlBuilder); Map<String, String> headers = new HashMap<String, String>(); headers.put("Content-Type", "application/x-www-form-urlencoded"); recordLastCurlCommand(String.format("curl " + curlBuilder.toString() + " \"" + resource.toString() + "\"")); InputStream inputStream = readFrom(resource, "POST", builder.build().getRawQuery(), headers); String responseJson = IOUtils.toString(inputStream); LOG.debug("RESPONSE => {}", responseJson); return gson.fromJson(responseJson, responseClass); } /** * @see #post(WebResource, MultivaluedMapImpl) */ public RESPONSE post(MultivaluedMapImpl data) throws IOException { return post(resource, data); } /** * @see #post(WebResource, MultivaluedMapImpl) */ public RESPONSE post() throws IOException { return post(resource, new MultivaluedMapImpl()); } /** * @see #post(WebResource, MultivaluedMapImpl) */ public RESPONSE post(MultivaluedMapImpl params, MultivaluedMapImpl data) throws IOException { return post(resource.queryParams(params), data); } /** * Main implementation of PUT request * @param resource resource * @param data put body * @return unmarshalled response data */ public RESPONSE put(WebResource resource, MultivaluedMapImpl data) throws IOException { LOG.info("PUT {}", resource); StringBuilder curlBuilder = new StringBuilder(); UriBuilder builder = getUriBuilder(data, curlBuilder); Map<String, String> headers = new HashMap<String, String>(); headers.put("Content-Type", "application/x-www-form-urlencoded"); recordLastCurlCommand(String.format("curl -X PUT " + curlBuilder.toString() + " \"" + resource.toString() + "\"")); InputStream inputStream = readFrom(resource, "PUT", builder.build().getRawQuery(), headers); String responseJson = IOUtils.toString(inputStream); LOG.debug("RESPONSE => {}", responseJson); return gson.fromJson(responseJson, responseClass); } public UriBuilder getUriBuilder(MultivaluedMapImpl data, StringBuilder curlBuilder) { MultivaluedMapImpl effectiveData; if (data == null) effectiveData = new MultivaluedMapImpl(); else effectiveData = new MultivaluedMapImpl(data); effectiveData.putSingle("user.name", username); effectiveData.putSingle("doAs", doAs); UriBuilder builder = UriBuilder.fromPath("host/"); for(String key : effectiveData.keySet()) { for(String value : effectiveData.get(key)) { builder.queryParam(key, value); curlBuilder.append(String.format("-d %s=\"%s\" ", key, value.replace("\"", "\\\""))); } } if (data != null) LOG.debug("data: {}", builder.build().getRawQuery()); return builder; } /** * @see #put(WebResource, MultivaluedMapImpl) */ public RESPONSE put(MultivaluedMapImpl data) throws IOException { return put(resource, data); } /** * @see #put(WebResource, MultivaluedMapImpl) */ public RESPONSE put() throws IOException { return put(resource, new MultivaluedMapImpl()); } /** * @see #put(WebResource, MultivaluedMapImpl) */ public RESPONSE put(MultivaluedMapImpl params, MultivaluedMapImpl data) throws IOException { return put(resource.queryParams(params), data); } /** * Main implementation of DELETE request * @param resource resource * @param data delete body * @return unmarshalled response data */ public RESPONSE delete(WebResource resource, MultivaluedMapImpl data) throws IOException { LOG.info("DELETE {}", resource.toString()); StringBuilder curlBuilder = new StringBuilder(); UriBuilder builder = getUriBuilder(data, curlBuilder); Map<String, String> headers = new HashMap<String, String>(); headers.put("Content-Type", "application/x-www-form-urlencoded"); recordLastCurlCommand(String.format("curl -X DELETE " + curlBuilder.toString() + " \"" + resource.toString() + "\"")); InputStream inputStream = readFrom(resource, "DELETE", builder.build().getRawQuery(), headers); String responseJson = IOUtils.toString(inputStream); LOG.debug("RESPONSE => {}", responseJson); return gson.fromJson(responseJson, responseClass); } /** * @see #delete(WebResource, MultivaluedMapImpl) */ public RESPONSE delete(MultivaluedMapImpl data) throws IOException { return delete(resource, data); } /** * @see #delete(WebResource, MultivaluedMapImpl) */ public RESPONSE delete() throws IOException { return delete(resource, new MultivaluedMapImpl()); } /** * @see #delete(WebResource, MultivaluedMapImpl) */ public RESPONSE delete(MultivaluedMapImpl params, MultivaluedMapImpl data) throws IOException { return delete(resource.queryParams(params), data); } private static void recordLastCurlCommand(String curl) { LOG.info(curl); } public InputStream readFrom(WebResource resource, String method, String body, Map<String, String> headers) throws IOException { HttpURLConnection connection; resource = resource.queryParam("user.name", username) .queryParam("doAs", doAs); String path = resource.toString(); if (doAs == null) { connection = context.getURLConnectionProvider().getConnection(path, method, body, headers); } else { connection = context.getURLConnectionProvider().getConnectionAs(path, method, body, headers, doAs); } return getInputStream(connection); } private InputStream getInputStream(HttpURLConnection connection) throws IOException { int responseCode = connection.getResponseCode(); if (responseCode >= Response.Status.BAD_REQUEST.getStatusCode()) { String message = connection.getResponseMessage(); if (connection.getErrorStream() != null) { message = IOUtils.toString(connection.getErrorStream()); } LOG.error("Got error response for url {}. Response code:{}. {}", connection.getURL(), responseCode, message); throw new AmbariApiException(message); } return connection.getInputStream(); } }