/******************************************************************************* * Copyright (c) 2012-2015 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.api.core.rest; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.UnauthorizedException; import org.eclipse.che.api.core.rest.shared.dto.Link; import org.eclipse.che.api.core.rest.shared.dto.ServiceError; import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.lang.Pair; import org.eclipse.che.commons.user.User; import org.eclipse.che.dto.server.DtoFactory; import com.google.common.io.CharStreams; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.List; /** * Provides helper method to send HTTP requests with JSON content. * * @author andrew00x */ public class HttpJsonHelper { @SuppressWarnings("unchecked") private static final Pair<String, ?>[] EMPTY = new Pair[0]; /** * Implementation HttpJsonHelper methods. */ private static HttpJsonHelperImpl httpJsonHelperImpl = new HttpJsonHelperImpl(); //============================================================== public static <DTO> DTO request(Class<DTO> dtoInterface, Link link, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, link.getHref(), link.getMethod(), body, parameters); } public static <DTO> DTO request(Class<DTO> dtoInterface, int timeout, Link link, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, timeout, link.getHref(), link.getMethod(), body, parameters); } public static <DTO> DTO request(Class<DTO> dtoInterface, Link link, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { return request(dtoInterface, link, null, parameters); } public static <DTO> DTO request(Class<DTO> dtoInterface, int timeout, Link link, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { return request(dtoInterface, timeout, link, null, parameters); } public static <DTO> DTO request(Class<DTO> dtoInterface, Link link) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, link, EMPTY); } public static <DTO> DTO request(Class<DTO> dtoInterface, int timeout, Link link) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, timeout, link, EMPTY); } public static <DTO> List<DTO> requestArray(Class<DTO> dtoInterface, Link link, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return requestArray(dtoInterface, link.getHref(), link.getMethod(), body, parameters); } public static <DTO> List<DTO> requestArray(Class<DTO> dtoInterface, int timeout, Link link, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return requestArray(dtoInterface, timeout, link.getHref(), link.getMethod(), body, parameters); } public static <DTO> List<DTO> requestArray(Class<DTO> dtoInterface, Link link, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { return requestArray(dtoInterface, link, null, parameters); } public static <DTO> List<DTO> requestArray(Class<DTO> dtoInterface, int timeout, Link link, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { return requestArray(dtoInterface, timeout, link, null, parameters); } public static <DTO> List<DTO> requestArray(Class<DTO> dtoInterface, Link link) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return requestArray(dtoInterface, link, EMPTY); } public static <DTO> List<DTO> requestArray(Class<DTO> dtoInterface, int timeout, Link link) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return requestArray(dtoInterface, timeout, link, EMPTY); } public static String requestString(String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, ForbiddenException, NotFoundException, UnauthorizedException, ConflictException { return httpJsonHelperImpl.requestString(url, method, body, parameters); } public static String requestString(int timeout, String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, ForbiddenException, NotFoundException, UnauthorizedException, ConflictException { return httpJsonHelperImpl.requestString(timeout, url, method, body, parameters); } /** * Sends HTTP request to specified {@code url}. * <p/> * <p/> * type of expected response. If server returns some content we try parse it and restore object of the specified type from it. * Specified interface must be annotated with @DTO. * * @param url * URL to send request * @param method * HTTP method * @param body * body of request. Object must implements DTO interface (interface must be annotated with @DTO). * @param parameters * additional query parameters. * @return instance of {@code dtoInterface} which represents JSON response from the server * @throws ServerException * if server returns error response in supported JSON format, see {@link org.eclipse.che.api.core.rest.shared.dto.ServiceError} * @throws IOException * if any other error occurs * @see org.eclipse.che.dto.shared.DTO */ public static <DTO> DTO request(Class<DTO> dtoInterface, String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { return httpJsonHelperImpl.request(dtoInterface, url, method, body, parameters); } public static <DTO> DTO request(Class<DTO> dtoInterface, int timeout, String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { return httpJsonHelperImpl.request(dtoInterface, timeout, url, method, body, parameters); } public static <DTO> List<DTO> requestArray(Class<DTO> dtoInterface, String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { return httpJsonHelperImpl.requestArray(dtoInterface, url, method, body, parameters); } public static <DTO> List<DTO> requestArray(Class<DTO> dtoInterface, int timeout, String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { return httpJsonHelperImpl.requestArray(dtoInterface, timeout, url, method, body, parameters); } /** * Sends GET request to specified {@code url}. * * @param dtoInterface * type of expected response. If server returns some content we try parse it and restore object of the specified type from it. * Specified interface must be annotated with @DTO. * @param url * URL to send request * @param parameters * additional query parameters. * @return instance of {@code dtoInterface} which represents JSON response from the server * @throws ServerException * if server returns error response in supported JSON format, see {@link org.eclipse.che.api.core.rest.shared.dto.ServiceError} * @throws IOException * if any other error occurs * @see org.eclipse.che.dto.shared.DTO */ public static <DTO> DTO get(Class<DTO> dtoInterface, String url, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, url, "GET", null, parameters); } public static <DTO> DTO get(Class<DTO> dtoInterface, int timeout, String url, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, timeout, url, "GET", null, parameters); } /** * Sends POST request to specified {@code url}. * * @param dtoInterface * type of expected response. If server returns some content we try parse it and restore object of the specified type from it. * Specified interface must be annotated with @DTO. * @param url * URL to send request * @param body * body of request. Object must implements DTO interface (interface must be annotated with @DTO). * @param parameters * additional query parameters. * @return instance of {@code dtoInterface} which represents JSON response from the server * @throws ServerException * if server returns error response in supported JSON format, see {@link org.eclipse.che.api.core.rest.shared.dto.ServiceError} * @throws IOException * if any other error occurs * @see org.eclipse.che.dto.shared.DTO */ public static <DTO> DTO post(Class<DTO> dtoInterface, String url, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, url, "POST", body, parameters); } public static <DTO> DTO post(Class<DTO> dtoInterface, int timeout, String url, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, timeout, url, "POST", body, parameters); } /** * Sends PUT request to specified {@code url}. * * @param dtoInterface * type of expected response. If server returns some content we try parse it and restore object of the specified type from it. * Specified interface must be annotated with @DTO. * @param url * URL to send request * @param body * body of request. Object must implements DTO interface (interface must be annotated with @DTO). * @param parameters * additional query parameters. * @return instance of {@code dtoInterface} which represents JSON response from the server * @throws ServerException * if server returns error response in supported JSON format, see {@link org.eclipse.che.api.core.rest.shared.dto.ServiceError} * @throws IOException * if any other error occurs * @see org.eclipse.che.dto.shared.DTO */ public static <DTO> DTO put(Class<DTO> dtoInterface, String url, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, url, "PUT", body, parameters); } public static <DTO> DTO put(Class<DTO> dtoInterface, int timeout, String url, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, timeout, url, "PUT", body, parameters); } /** * Sends OPTIONS request to specified {@code url}. * * @param dtoInterface * type of expected response. If server returns some content we try parse it and restore object of the specified type from it. * Specified interface must be annotated with @DTO. * @param url * URL to send request * @param parameters * additional query parameters. * @return instance of {@code dtoInterface} which represents JSON response from the server * @throws ServerException * if server returns error response in supported JSON format, see {@link org.eclipse.che.api.core.rest.shared.dto.ServiceError} * @throws IOException * if any other error occurs * @see org.eclipse.che.dto.shared.DTO */ public static <DTO> DTO options(Class<DTO> dtoInterface, String url, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, url, "OPTIONS", null, parameters); } public static <DTO> DTO options(Class<DTO> dtoInterface, int timeout, String url, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, timeout, url, "OPTIONS", null, parameters); } /** * Sends DELETE request to specified {@code url}. * * @param dtoInterface * type of expected response. If server returns some content we try parse it and restore object of the specified type from it. * Specified interface must be annotated with @DTO. * @param url * URL to send request * @param parameters * additional query parameters. * @return instance of {@code dtoInterface} which represents JSON response from the server * @throws ServerException * if server returns error response in supported JSON format, see {@link org.eclipse.che.api.core.rest.shared.dto.ServiceError} * @throws IOException * if any other error occurs * @see org.eclipse.che.dto.shared.DTO */ public static <DTO> DTO delete(Class<DTO> dtoInterface, String url, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, url, "DELETE", null, parameters); } public static <DTO> DTO delete(Class<DTO> dtoInterface, int timeout, String url, Pair<String, ?>... parameters) throws IOException, ServerException, NotFoundException, ForbiddenException, UnauthorizedException, ConflictException { return request(dtoInterface, timeout, url, "DELETE", null, parameters); } private HttpJsonHelper() { } /** * Execute all request from HttpJsonHelper throw single method requestString. */ public static class HttpJsonHelperImpl { public <DTO> DTO request(Class<DTO> dtoInterface, String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { return request(dtoInterface, -1, url, method, body, parameters); } public <DTO> DTO request(Class<DTO> dtoInterface, int timeout, String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { final String str = requestString(timeout, url, method, body, parameters); if (dtoInterface != null) { return DtoFactory.getInstance().createDtoFromJson(str, dtoInterface); } return null; } public <DTO> List<DTO> requestArray(Class<DTO> dtoInterface, String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { return requestArray(dtoInterface, -1, url, method, body, parameters); } public <DTO> List<DTO> requestArray(Class<DTO> dtoInterface, int timeout, String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException { final String str = requestString(timeout, url, method, body, parameters); if (dtoInterface != null) { return DtoFactory.getInstance().createListDtoFromJson(str, dtoInterface); } return null; } private String getAuthenticationToken() { User user = EnvironmentContext.getCurrent().getUser(); if (user != null) { return user.getToken(); } return null; } public String requestString(String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, ForbiddenException, NotFoundException, UnauthorizedException, ConflictException { return requestString(-1, url, method, body, parameters); } public String requestString(int timeout, String url, String method, Object body, Pair<String, ?>... parameters) throws IOException, ServerException, ForbiddenException, NotFoundException, UnauthorizedException, ConflictException { final String authToken = getAuthenticationToken(); if ((parameters != null && parameters.length > 0) || authToken != null) { final UriBuilder ub = UriBuilder.fromUri(url); if (authToken != null) { ub.queryParam("token", authToken); } if (parameters != null && parameters.length > 0) { for (Pair<String, ?> parameter : parameters) { String name = URLEncoder.encode(parameter.first, "UTF-8"); String value = parameter.second == null ? null : URLEncoder .encode(String.valueOf(parameter.second), "UTF-8"); ub.replaceQueryParam(name, value); } } url = ub.build().toString(); } final HttpURLConnection conn = (HttpURLConnection)new URL(url).openConnection(); conn.setConnectTimeout(timeout > 0 ? timeout : 60000); conn.setReadTimeout(timeout > 0 ? timeout : 60000); try { conn.setRequestMethod(method); if (body != null) { conn.addRequestProperty("content-type", "application/json"); conn.setDoOutput(true); if ("DELETE".equals(method)) { //to avoid jdk bug described here http://bugs.java.com/view_bug.do?bug_id=7157360 conn.setRequestMethod("POST"); conn.setRequestProperty("X-HTTP-Method-Override", "DELETE"); } try (OutputStream output = conn.getOutputStream()) { output.write(DtoFactory.getInstance().toJson(body).getBytes()); } } final int responseCode = conn.getResponseCode(); if ((responseCode / 100) != 2) { InputStream in = conn.getErrorStream(); if (in == null) { in = conn.getInputStream(); } final InputStream fIn = in; final String str = CharStreams.toString(new InputStreamReader(fIn)); final String contentType = conn.getContentType(); if (contentType != null && contentType.startsWith("application/json")) { final ServiceError serviceError = DtoFactory.getInstance().createDtoFromJson(str, ServiceError.class); if (serviceError.getMessage() != null) { if (responseCode == Response.Status.FORBIDDEN.getStatusCode()) { throw new ForbiddenException(serviceError); } else if (responseCode == Response.Status.NOT_FOUND.getStatusCode()) { throw new NotFoundException(serviceError); } else if (responseCode == Response.Status.UNAUTHORIZED.getStatusCode()) { throw new UnauthorizedException(serviceError); } else if (responseCode == Response.Status.CONFLICT.getStatusCode()) { throw new ConflictException(serviceError); } else if (responseCode == Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) { throw new ServerException(serviceError); } throw new ServerException(serviceError); } } // Can't parse content as json or content has format other we expect for error. throw new IOException(String.format("Failed access: %s, method: %s, response code: %d, message: %s", UriBuilder.fromUri(url).replaceQuery("token").build(), method, responseCode, str)); } final String contentType = conn.getContentType(); if (!(contentType == null || contentType.startsWith("application/json"))) { throw new IOException("We received an error response from the Codenvy server." + " Retry the request. If this issue continues, contact. support."); } return CharStreams.toString(new InputStreamReader(conn.getInputStream())); } finally { conn.disconnect(); } } } }