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

hu.icellmobilsoft.coffee.module.redis.manager.RedisManager Maven / Gradle / Ivy

/*-
 * #%L
 * Coffee
 * %%
 * Copyright (C) 2020 - 2021 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.module.redis.manager;

import java.util.Optional;

import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.spi.CDI;
import jakarta.inject.Inject;

import org.apache.commons.lang3.StringUtils;

import hu.icellmobilsoft.coffee.cdi.trace.annotation.Traced;
import hu.icellmobilsoft.coffee.cdi.trace.constants.SpanAttribute;
import hu.icellmobilsoft.coffee.dto.exception.InvalidParameterException;
import hu.icellmobilsoft.coffee.dto.exception.TechnicalException;
import hu.icellmobilsoft.coffee.dto.exception.enums.CoffeeFaultType;
import hu.icellmobilsoft.coffee.module.redis.annotation.RedisConnection;
import hu.icellmobilsoft.coffee.se.api.exception.BaseException;
import hu.icellmobilsoft.coffee.se.function.BaseExceptionFunction;
import hu.icellmobilsoft.coffee.se.function.BaseExceptionFunction2;
import hu.icellmobilsoft.coffee.se.function.BaseExceptionFunction3;
import hu.icellmobilsoft.coffee.se.function.BaseExceptionFunction4;
import hu.icellmobilsoft.coffee.se.function.BaseExceptionFunction5;
import hu.icellmobilsoft.coffee.se.logging.Logger;
import redis.clients.jedis.Jedis;

/**
 * Handle redis operations, jedis connection, exceptions and logging
 *
 * @author czenczl
 * @since 1.7.0
 *
 */
@Dependent
public class RedisManager {

    private static final String JEDIS_NOT_INITIALIZED_MSG = "jedis is not initialized";

    @Inject
    private Logger log;

    private String configKey;
    private String poolConfigKey;
    private Instance jedisInstance;
    private Jedis jedis;

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

    /**
     * Adds log entry for method enter if trace is enabled.
     *
     * @param functionName
     *            method info format {@link String} with method and param names, and placeholders for param values
     * @param params
     *            params for redis function
     */
    protected void logEnter(String functionName, Object... params) {
        if (log.isTraceEnabled()) {
            log.trace(">>" + getCalledMethodWithParamsType(functionName, params));
        }
    }

    /**
     * Adds log entry for method return if trace is enabled.
     *
     * @param functionName
     *            referenced function name
     * @param params
     *            params for redis function
     */
    protected void logReturn(String functionName, Object... params) {
        if (log.isTraceEnabled()) {
            log.trace("<<" + getCalledMethodWithParamsType(functionName, params));
        }
    }

    /**
     * Build string from functionName and parameters
     *
     * @param functionName
     *            called redis function name
     * @param params
     *            params for redis function
     * @return concatenated log string
     */
    protected String getCalledMethodWithParamsType(String functionName, Object... params) {
        StringBuilder functionInfo = new StringBuilder(" ").append(functionName).append("(");
        int index = 0;
        if (params != null) {
            for (Object param : params) {
                if (index > 0) {
                    functionInfo.append(", ");
                }
                if (param != null) {
                    functionInfo.append(param.getClass().getTypeName());
                } else {
                    functionInfo.append(param);
                }
                index++;
            }
        }
        return functionInfo.append(")").toString();
    }

    /**
     * Creates {@link TechnicalException} with {@link CoffeeFaultType#REDIS_OPERATION_FAILED} fault type.
     *
     * @param e
     *            cause {@link Exception}
     * @param functionInfo
     *            method info format {@link String} with method and param type names
     * @return {@link TechnicalException} with message from functionInfo.
     */
    protected TechnicalException repositoryFailed(Exception e, String functionInfo) {
        String message = "Error occurred when calling redis operation " + functionInfo + " : [" + e.getLocalizedMessage() + "]";
        return new TechnicalException(CoffeeFaultType.REDIS_OPERATION_FAILED, message, e);
    }

    /**
     * Runs the business logic method call in order to handle common logging and exception handling.
     *
     * @param 
     *            response object type
     * @param function
     *            the function doing business logic
     * @param functionName
     *            the function name
     * @return what the function returns
     * @throws BaseException
     *             in case of any exception caught inside
     */
    @Traced(component = SpanAttribute.Redis.Jedis.COMPONENT, kind = SpanAttribute.Redis.Jedis.KIND, dbType = SpanAttribute.Redis.DB_TYPE)
    public  Optional run(BaseExceptionFunction function, String functionName) throws BaseException {
        if (jedis == null) {
            throw new TechnicalException(CoffeeFaultType.REDIS_OPERATION_FAILED, JEDIS_NOT_INITIALIZED_MSG);
        }
        logEnter(functionName);
        try {
            R response = function.apply(jedis);
            logReturn(functionName);
            return Optional.ofNullable(response);
        } catch (Exception e) {
            throw repositoryFailed(e, functionName);
        }
    }

    /**
     * Runs the business logic method call in order to handle common logging and exception handling.
     *
     * @param 
     *            response object type
     * @param 
     *            first parameter type of the function call
     * @param function
     *            the function doing business logic
     * @param functionName
     *            the function name
     * @param p1
     *            parameter of the function call
     * @return what the function returns
     * @throws BaseException
     *             in case of any exception caught inside
     */
    @Traced(component = SpanAttribute.Redis.Jedis.COMPONENT, kind = SpanAttribute.Redis.Jedis.KIND, dbType = SpanAttribute.Redis.DB_TYPE)
    public  Optional run(BaseExceptionFunction2 function, String functionName, P1 p1) throws BaseException {
        if (jedis == null) {
            throw new TechnicalException(CoffeeFaultType.REDIS_OPERATION_FAILED, JEDIS_NOT_INITIALIZED_MSG);
        }
        logEnter(functionName, p1);
        if (isNullOrBlankAnyParameter(p1)) {
            throw newInvalidParameterException(functionName);
        }
        try {
            R response = function.apply(jedis, p1);
            logReturn(functionName, p1);
            return Optional.ofNullable(response);
        } catch (Exception e) {
            throw repositoryFailed(e, functionName);
        }
    }

    /**
     * Runs the business logic method call in order to handle common logging and exception handling.
     *
     * @param 
     *            response object type
     * @param 
     *            first parameter type of the function call
     * @param 
     *            second parameter type of the function call
     * @param function
     *            the function doing business logic
     * @param functionName
     *            the function name
     * @param p1
     *            parameter of the function call
     * @param p2
     *            parameter of the function call
     * @return what the function returns
     * @throws BaseException
     *             in case of any exception caught inside
     */
    @Traced(component = SpanAttribute.Redis.Jedis.COMPONENT, kind = SpanAttribute.Redis.Jedis.KIND, dbType = SpanAttribute.Redis.DB_TYPE)
    public  Optional run(BaseExceptionFunction3 function, String functionName, P1 p1, P2 p2) throws BaseException {
        if (jedis == null) {
            throw new TechnicalException(CoffeeFaultType.REDIS_OPERATION_FAILED, JEDIS_NOT_INITIALIZED_MSG);
        }
        logEnter(functionName, p1, p2);
        if (isNullOrBlankAnyParameter(p1, p2)) {
            throw newInvalidParameterException(functionName);
        }
        try {
            R response = function.apply(jedis, p1, p2);
            logReturn(functionName, p1, p2);
            return Optional.ofNullable(response);
        } catch (Exception e) {
            throw repositoryFailed(e, functionName);
        }
    }

    /**
     * Runs the business logic method call in order to handle common logging and exception handling.
     *
     * @param 
     *            response object type
     * @param 
     *            first parameter type of the function call
     * @param 
     *            second parameter type of the function call
     * @param 
     *            third parameter type of the function call
     * @param function
     *            the function doing business logic
     * @param functionName
     *            the function name
     * @param p1
     *            parameter of the function call
     * @param p2
     *            parameter of the function call
     * @param p3
     *            parameter of the function call
     * @return what the function returns
     * @throws BaseException
     *             in case of any exception caught inside
     */
    @Traced(component = SpanAttribute.Redis.Jedis.COMPONENT, kind = SpanAttribute.Redis.Jedis.KIND, dbType = SpanAttribute.Redis.DB_TYPE)
    public  Optional run(BaseExceptionFunction4 function, String functionName, P1 p1, P2 p2, P3 p3)
            throws BaseException {
        if (jedis == null) {
            throw new TechnicalException(CoffeeFaultType.REDIS_OPERATION_FAILED, JEDIS_NOT_INITIALIZED_MSG);
        }
        logEnter(functionName, p1, p2, p3);
        if (isNullOrBlankAnyParameter(p1, p2, p3)) {
            throw newInvalidParameterException(functionName);
        }
        try {
            R response = function.apply(jedis, p1, p2, p3);
            logReturn(functionName, p1, p2, p3);
            return Optional.ofNullable(response);
        } catch (Exception e) {
            throw repositoryFailed(e, functionName);
        }
    }

    /**
     * Runs the business logic method call in order to handle common logging and exception handling.
     *
     * @param 
     *            response object type
     * @param 
     *            first parameter type of the function call
     * @param 
     *            second parameter type of the function call
     * @param 
     *            third parameter type of the function call
     * @param 
     *            fourth parameter type of the function call
     * @param function
     *            the function doing business logic
     * @param functionName
     *            the function name
     * @param p1
     *            parameter of the function call
     * @param p2
     *            parameter of the function call
     * @param p3
     *            parameter of the function call
     * @param p4
     *            parameter of the function call
     * @return what the function returns
     * @throws BaseException
     *             in case of any exception caught inside
     */
    @Traced(component = SpanAttribute.Redis.Jedis.COMPONENT, kind = SpanAttribute.Redis.Jedis.KIND, dbType = SpanAttribute.Redis.DB_TYPE)
    public  Optional run(BaseExceptionFunction5 function, String functionName, P1 p1, P2 p2, P3 p3,
            P4 p4) throws BaseException {
        if (jedis == null) {
            throw new TechnicalException(CoffeeFaultType.REDIS_OPERATION_FAILED, JEDIS_NOT_INITIALIZED_MSG);
        }
        logEnter(functionName, p1, p2, p3, p4);
        if (isNullOrBlankAnyParameter(p1, p2, p3, p4)) {
            throw newInvalidParameterException(functionName);
        }
        try {
            R response = function.apply(jedis, p1, p2, p3, p4);
            logReturn(functionName, p1, p2, p3, p4);
            return Optional.ofNullable(response);
        } catch (Exception e) {
            throw repositoryFailed(e, functionName);
        }
    }

    /**
     * Runs the business logic method call in order to handle jedis connection init and close, common logging and exception handling.
     *
     * @param 
     *            response object type
     * @param function
     *            the function doing business logic
     * @param functionName
     *            the function name
     * @return what the function returns
     * @throws BaseException
     *             in case of any exception caught inside
     */
    @Traced(component = SpanAttribute.Redis.Jedis.COMPONENT, kind = SpanAttribute.Redis.Jedis.KIND, dbType = SpanAttribute.Redis.DB_TYPE)
    public  Optional runWithConnection(BaseExceptionFunction function, String functionName) throws BaseException {
        try (RedisManagerConnection ignored = initConnection()) {
            return run(function, functionName);
        }
    }

    /**
     * Runs the business logic method call in order to handle jedis connection init and close, common logging and exception handling with one
     * parameter
     *
     * @param 
     *            response object type
     * @param 
     *            first parameter
     * @param function
     *            the function doing business logic
     * @param functionName
     *            the function name
     * @param p1
     *            parameter of the function call
     * @return what the function returns
     * @throws BaseException
     *             in case of any exception caught inside
     */
    @Traced(component = SpanAttribute.Redis.Jedis.COMPONENT, kind = SpanAttribute.Redis.Jedis.KIND, dbType = SpanAttribute.Redis.DB_TYPE)
    public  Optional runWithConnection(BaseExceptionFunction2 function, String functionName, P1 p1) throws BaseException {
        try (RedisManagerConnection ignored = initConnection()) {
            return run(function, functionName, p1);
        }
    }

    /**
     * Runs the business logic method call in order to handle jedis connection init and close, common logging and exception handling with two
     * parameters
     *
     * @param 
     *            response object type
     * @param 
     *            first parameter
     * @param 
     *            second parameter
     * @param function
     *            the function doing business logic
     * @param functionName
     *            the function name
     * @param p1
     *            parameter of the function call
     * @param p2
     *            parameter of the function call
     * @return what the function returns
     * @throws BaseException
     *             in case of any exception caught inside
     */
    @Traced(component = SpanAttribute.Redis.Jedis.COMPONENT, kind = SpanAttribute.Redis.Jedis.KIND, dbType = SpanAttribute.Redis.DB_TYPE)
    public  Optional runWithConnection(BaseExceptionFunction3 function, String functionName, P1 p1, P2 p2)
            throws BaseException {
        try (RedisManagerConnection ignored = initConnection()) {
            return run(function, functionName, p1, p2);
        }
    }

    /**
     * Runs the business logic method call in order to handle jedis connection init and close, common logging and exception handling with three
     * parameters
     *
     * @param 
     *            response object type
     * @param 
     *            first parameter
     * @param 
     *            second parameter
     * @param 
     *            third parameter
     * @param function
     *            the function doing business logic
     * @param functionName
     *            the function name
     * @param p1
     *            parameter of the function call
     * @param p2
     *            parameter of the function call
     * @param p3
     *            parameter of the function call
     * @return what the function returns
     * @throws BaseException
     *             in case of any exception caught inside
     */
    @Traced(component = SpanAttribute.Redis.Jedis.COMPONENT, kind = SpanAttribute.Redis.Jedis.KIND, dbType = SpanAttribute.Redis.DB_TYPE)
    public  Optional runWithConnection(BaseExceptionFunction4 function, String functionName, P1 p1, P2 p2,
            P3 p3) throws BaseException {
        try (RedisManagerConnection ignored = initConnection()) {
            return run(function, functionName, p1, p2, p3);
        }
    }

    /**
     * Runs the business logic method call in order to handle jedis connection init and close, common logging and exception handling with four
     * parameters
     *
     * @param 
     *            response object type
     * @param 
     *            first parameter
     * @param 
     *            second parameter
     * @param 
     *            third parameter
     * @param 
     *            fourth parameter
     * @param function
     *            the function doing business logic
     * @param functionName
     *            the function name
     * @param p1
     *            parameter of the function call
     * @param p2
     *            parameter of the function call
     * @param p3
     *            parameter of the function call
     * @param p4
     *            parameter of the function call
     * @return what the function returns
     * @throws BaseException
     *             in case of any exception caught inside
     */
    @Traced(component = SpanAttribute.Redis.Jedis.COMPONENT, kind = SpanAttribute.Redis.Jedis.KIND, dbType = SpanAttribute.Redis.DB_TYPE)
    public  Optional runWithConnection(BaseExceptionFunction5 function, String functionName, P1 p1,
            P2 p2, P3 p3, P4 p4) throws BaseException {
        try (RedisManagerConnection ignored = initConnection()) {
            return run(function, functionName, p1, p2, p3, p4);
        }
    }

    /**
     * Initialize jedis
     *
     * @return object representing the connection and used for automatic close
     */
    public RedisManagerConnection initConnection() {
        if (jedisInstance == null) {
            jedisInstance = CDI.current().select(Jedis.class, new RedisConnection.Literal(configKey, poolConfigKey));
        }
        if (jedis == null) {
            jedis = jedisInstance.get();
        }
        return new RedisManagerConnection(this);
    }

    /**
     * Close the initialized jedis
     */
    public void closeConnection() {
        if (jedis != null) {
            jedisInstance.destroy(jedis);
            jedis = null;
        }
    }

    /**
     * set config key for jedis initialization
     *
     * @param configKey
     *            for jedis initialization
     */
    public void setConfigKey(String configKey) {
        this.configKey = configKey;
    }

    /**
     * set poolConfig key for jedis initialization
     *
     * @param poolConfigKey
     *            for jedis initialization
     */
    public void setPoolConfigKey(String poolConfigKey) {
        this.poolConfigKey = poolConfigKey;
    }

    private BaseException newInvalidParameterException(String functionName) {
        return new InvalidParameterException("At least one incoming parameter in " + functionName + " is null or blank!");
    }

    private boolean isNullOrBlankAnyParameter(Object... params) {
        for (Object param : params) {
            if (param == null || (param instanceof String && StringUtils.isBlank((String) param))) {
                return true;
            }
        }
        return false;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy