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

hu.icellmobilsoft.coffee.grpc.server.mapper.GrpcGeneralExceptionMapper Maven / Gradle / Ivy

The newest version!
/*-
 * #%L
 * Coffee
 * %%
 * Copyright (C) 2020 - 2024 i-Cell Mobilsoft Zrt.
 * %%
 * 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.
 * #L%
 */
package hu.icellmobilsoft.coffee.grpc.server.mapper;

import java.util.Arrays;
import java.util.Locale;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.ForbiddenException;
import jakarta.ws.rs.NotAuthorizedException;

import org.apache.commons.lang3.exception.ExceptionUtils;

import com.google.protobuf.Any;
import com.google.rpc.Code;
import com.google.rpc.DebugInfo;
import com.google.rpc.ErrorInfo;
import com.google.rpc.LocalizedMessage;
import com.google.rpc.Status;

import hu.icellmobilsoft.coffee.dto.exception.enums.CoffeeFaultType;
import hu.icellmobilsoft.coffee.grpc.base.exception.ExceptionMapper;
import hu.icellmobilsoft.coffee.grpc.base.metadata.GrpcHeaderHelper;
import hu.icellmobilsoft.coffee.rest.projectstage.ProjectStage;
import hu.icellmobilsoft.coffee.se.logging.Logger;
import io.grpc.Metadata;

/**
 * Implementation of {@link ExceptionMapper} that maps general Exceptions to gRPC {@link Status}. If the exception is not recognized, it maps it to
 * {@link Code#INTERNAL}.
 * 
 * It uses {@link IGrpcExceptionTranslator} to translate exceptions to GRPC statuses.
 *
 * @author mark.petrenyi
 * @author Imre Scheffer
 * @since 2.7.0
 */
@ApplicationScoped
public class GrpcGeneralExceptionMapper implements ExceptionMapper {

    @Inject
    private Logger log;

    @Inject
    private IGrpcExceptionTranslator grpcExceptionTranslator;

    @Inject
    private ProjectStage projectStage;

    /**
     * Default constructor, constructs a new object.
     */
    public GrpcGeneralExceptionMapper() {
        super();
    }

    @Override
    public Status toStatus(Metadata requestHeaders, Exception e) {
        Status.Builder statusB = null;
        Locale locale = getRequestLocale(requestHeaders);
        if (e instanceof NotAuthorizedException) {
            statusB = createStatus(locale, Code.UNAUTHENTICATED, CoffeeFaultType.NOT_AUTHORIZED, e);
        } else if (e instanceof ForbiddenException) {
            statusB = createStatus(locale, Code.PERMISSION_DENIED, CoffeeFaultType.FORBIDDEN, e);
        } else if (e instanceof IllegalArgumentException || e.getCause() instanceof IllegalArgumentException) {
            statusB = createStatus(locale, Code.INVALID_ARGUMENT, CoffeeFaultType.ILLEGAL_ARGUMENT_EXCEPTION, e);
        }

        if (statusB != null) {
            log.error("Known error: ", e);
        } else {
            log.error("Unknown error: ", e);
            statusB = createStatus(locale, Code.INTERNAL, CoffeeFaultType.GENERIC_EXCEPTION, e);
        }
        return statusB.build();
    }

    /**
     * Get Locale parameter from Grpc request metadata
     * 
     * @param requestHeaders
     *            Grpc request metadata
     * @return Locale from request
     */
    protected Locale getRequestLocale(Metadata requestHeaders) {
        return GrpcHeaderHelper.getRequestLocale(requestHeaders);
    }

    /**
     * Create Proto Error info object from given parameter
     * 
     * @param faultEnum
     *            Application Error code packaged into result
     * @return Proto Error info object
     */
    public static ErrorInfo.Builder toErrorInfo(Enum faultEnum) {
        ErrorInfo.Builder result = ErrorInfo.newBuilder();
        if (faultEnum != null) {
            result.setReason(faultEnum.name());
            result.setDomain(faultEnum.getClass().getName());
        }
        return result;
    }

    /**
     * Create Proto Debug info object from given parameters
     * 
     * @param throwable
     *            Throwable packaged into result
     * @return Proto Debug info object
     */
    public static DebugInfo.Builder toDebugInfo(Throwable throwable) {
        DebugInfo.Builder result = DebugInfo.newBuilder();
        if (throwable != null) {
            String[] frames = ExceptionUtils.getStackFrames(throwable);
            result.addAllStackEntries(Arrays.asList(frames));
            result.setDetail(ExceptionUtils.getMessage(throwable));
        }
        return result;
    }

    /**
     * Create Proto {@code com.google.rpc.Status} object from given parameters
     * 
     * @param locale
     *            Locale to translate response error message
     * @param grpcStatus
     *            Response Grpc status
     * @param faultType
     *            Error code
     * @param exception
     *            Exception to packaged into Grpc response metadata
     * @return Proto Status object
     */
    protected Status.Builder createStatus(Locale locale, Code grpcStatus, Enum faultType, Exception exception) {
        Status.Builder result = Status.newBuilder();
        LocalizedMessage.Builder localizedMessageB = grpcExceptionTranslator.toLocalizedMessage(locale, faultType);
        ErrorInfo.Builder errorInfoBuilder = toErrorInfo(faultType);
        result.setCode(grpcStatus.getNumber());
        result.setMessage(exception.getLocalizedMessage());
        result.addDetails(Any.pack(localizedMessageB.build()));
        result.addDetails(Any.pack(errorInfoBuilder.build()));
        if (!projectStage.isProductionStage()) {
            DebugInfo.Builder debugInfoBuilder = toDebugInfo(exception);
            result.addDetails(Any.pack(debugInfoBuilder.build()));
        }
        return result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy