com.vmware.photon.controller.api.common.Responses.java Source code

Java tutorial

Introduction

Here is the source code for com.vmware.photon.controller.api.common.Responses.java

Source

/*
 * Copyright 2015 VMware, Inc. All Rights Reserved.
 *
 * 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 com.vmware.photon.controller.api.common;

import com.vmware.photon.controller.api.ApiError;
import com.vmware.photon.controller.api.ResourceList;
import com.vmware.photon.controller.api.Version;
import com.vmware.photon.controller.api.base.Base;
import com.vmware.photon.controller.api.common.exceptions.external.ErrorCode;
import com.vmware.photon.controller.api.common.exceptions.external.ExternalException;
import com.vmware.photon.controller.common.logging.LoggingUtils;

import com.google.inject.Singleton;
import org.apache.commons.lang3.StringUtils;
import org.glassfish.jersey.server.ContainerRequest;
import static com.google.common.base.Preconditions.checkNotNull;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;

import java.net.URI;

/**
 * This class is responsible for generating ALL API responses.
 */
@Singleton
public class Responses {

    /**
     * Header field that will contain the request id.
     */
    public static final String REQUEST_ID_HEADER = "REQUEST-ID";

    /**
     * Header filed that will contain the name.
     */
    public static final String VERSION_HEADER = "X-API-VERSION";

    /**
     * Return a Response object that reflects a specified HTTP status and serialized body.
     *
     * @param responseStatus The status to send out
     * @param entity         The entity object to serialize and return in response
     * @return - a response object suitable for return to the caller
     */
    public static Response generateCustomResponse(Response.Status responseStatus, Base entity) {
        return generateCustomResponse(responseStatus, entity, null, null);
    }

    public static Response generateCustomResponse(Response.Status responseStatus, Base entity,
            ContainerRequest request, String selfLinkTemplate) {
        setEntitySelfLink(entity, request, selfLinkTemplate);

        return buildResponse(responseStatus, entity);
    }

    public static Response generateCustomResponseFromServlet(Response.Status responseStatus, Base entity,
            HttpServletRequest request, String selfLinkTemplate) {
        setEntitySelfLink(entity, request, selfLinkTemplate);

        return buildResponse(responseStatus, entity);
    }

    public static Response generateCustomResponse(Response.Status responseStatus, Object entity) {
        return buildResponse(responseStatus, entity);
    }

    public static <T extends Base> Response generateResourceListResponse(Response.Status responseStatus,
            ResourceList<T> entities, ContainerRequest request, String selfLinkTemplate) {
        checkNotNull(entities);
        for (T entity : entities.getItems()) {
            setEntitySelfLink(entity, request, selfLinkTemplate);
        }

        return generateResourceListResponse(responseStatus, entities);
    }

    public static <T> Response generateResourceListResponse(Response.Status responseStatus,
            ResourceList<T> entities) {
        checkNotNull(entities);

        Response.ResponseBuilder builder = Response.status(responseStatus).entity(entities)
                .type(MediaType.APPLICATION_JSON);

        addResponseHeaders(builder);
        return builder.build();
    }

    /**
     * return a Response object that reflects the fact that an externally
     * visible exception occurred while processing the request.
     *
     * @param e - supplies the exception that generated the problem
     * @return - a response object suitable for return to the caller
     */
    public static Response externalException(ExternalException e) {
        ApiError error = new ApiError(e.getErrorCode(), e.getMessage(), e.getData());
        Response.ResponseBuilder builder = Response.status(e.getHttpStatus()).entity(error)
                .type(MediaType.APPLICATION_JSON);

        addResponseHeaders(builder);
        return builder.build();
    }

    /**
     * return an error response generated by a validation failure, invalid json, etc.
     *
     * @param e - the exception
     * @return - a response object suitable for return to the caller
     */
    public static Response invalidEntity(ConstraintViolationException e) {
        // hand create an external exception out of this and continue with normal
        // error response flow
        StringBuilder errorMessage = new StringBuilder();
        boolean firstPass = true;
        for (ConstraintViolation error : e.getConstraintViolations()) {
            if (!firstPass) {
                errorMessage.append(", ");
            }
            errorMessage.append(String.format("%s %s (was %s)", error.getPropertyPath(), error.getMessage(),
                    error.getInvalidValue()));
            firstPass = false;
        }
        ExternalException externalException = new ExternalException(ErrorCode.INVALID_ENTITY,
                errorMessage.toString(), null);
        return externalException(externalException);
    }

    /**
     * return generic server error response with no other information transfer.
     *
     * @return - a response object suitable for return to the caller
     */
    public static Response serverError() {
        Response.ResponseBuilder builder = Response.serverError().entity("");
        addResponseHeaders(builder);
        return builder.build();
    }

    /**
     * return an error response generated by the jersey framework. this is typically
     * routing/404 issues, etc.
     *
     * @param e - the exception
     * @return - a response object suitable for return to the caller
     */
    public static Response jerseyError(WebApplicationException e) {
        if (e instanceof NotFoundException) {
            NotFoundException notFoundException = (NotFoundException) e;
            String errorMessage = null;
            if (notFoundException.getResponse().getLocation() != null) {
                errorMessage = notFoundException.getResponse().getLocation().toString();
            }
            // map 404 to NOT_FOUND_404 error
            ExternalException externalException = new ExternalException(ErrorCode.NOT_FOUND, errorMessage, null);
            return externalException(externalException);
        } else {
            // return generic jersey error
            Response.ResponseBuilder builder = Response.status(e.getResponse().getStatus()).entity("");
            addResponseHeaders(builder);
            return builder.build();
        }
    }

    private static void setEntitySelfLink(Base entity, ContainerRequest request, String selfLinkTemplate) {
        checkNotNull(entity);
        if (request != null && StringUtils.isNotBlank(selfLinkTemplate)) {
            String selfLink = UriBuilder.fromUri(request.getBaseUri()).path(selfLinkTemplate)
                    .build(checkNotNull(entity.getId())).toString();
            entity.setSelfLink(selfLink);
        } else if (request != null || StringUtils.isNotBlank(selfLinkTemplate)) {
            throw new IllegalArgumentException("Both request and selfLinkTemplate need to be provided!");
        }
    }

    private static void setEntitySelfLink(Base entity, HttpServletRequest request, String selfLinkTemplate) {
        checkNotNull(entity);
        if (request != null && StringUtils.isNotBlank(selfLinkTemplate)) {
            String selfLink = UriBuilder.fromUri(getBaseUri(request)).path(selfLinkTemplate)
                    .build(checkNotNull(entity.getId())).toString();
            entity.setSelfLink(selfLink);
        } else if (request != null || StringUtils.isNotBlank(selfLinkTemplate)) {
            throw new IllegalArgumentException("Both request and selfLinkTemplate need to be provided!");
        }
    }

    private static void addResponseHeaders(Response.ResponseBuilder builder) {
        // add version header
        builder.header(VERSION_HEADER, Version.VERSION);

        // add request id
        String requestId = LoggingUtils.getRequestId();
        if (StringUtils.isNotBlank(requestId)) {
            builder.header(REQUEST_ID_HEADER, requestId);
        }
    }

    private static Response buildResponse(Response.Status responseStatus, Object entity) {
        Response.ResponseBuilder builder = Response.status(responseStatus).entity(entity)
                .type(MediaType.APPLICATION_JSON);

        addResponseHeaders(builder);
        return builder.build();
    }

    private static URI getBaseUri(HttpServletRequest request) throws IllegalArgumentException {
        String requestBaseUri = request.getScheme() + "://" + request.getServerName() + ":"
                + request.getServerPort();
        return UriBuilder.fromUri(requestBaseUri).build();
    }
}