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

io.smilego.tenant.aspect.TenantAspect Maven / Gradle / Ivy

package io.smilego.tenant.aspect;

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.smilego.tenant.TenantContext;
import io.smilego.tenant.enumeration.RunJobOnAllTenants;
import io.smilego.tenant.logging.LogContextHolder;
import io.smilego.tenant.logging.LogUtils;
import io.smilego.tenant.logging.amqp.AmqpListenerLog;
import io.smilego.tenant.logging.schedule.ScheduleLog;
import io.smilego.tenant.model.Application;
import io.smilego.tenant.model.Tenant;
import io.smilego.tenant.persistence.ApplicationRepository;
import io.smilego.tenant.persistence.TenantRepository;
import io.smilego.tenant.service.ParameterCacheableService;
import io.smilego.tenant.util.LogBuilder;
import lombok.AllArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.stream.Collectors;

@Aspect
@Component
@AllArgsConstructor
public class TenantAspect implements Ordered {

    protected final Logger log = LoggerFactory.getLogger(this.getClass());

    private final ParameterCacheableService parameterCacheableService;
    private final ApplicationRepository applicationRepository;
    private final String applicationName;
    private final String TENANT_ARG_NAME = "tenantId";
    private boolean espheroLoggingContext;

    /*
        Annotation feita para ser utilizada em jobs dos servicos (@Scheduled).
        O método em questão será executado para todos os tenants caso esteja anotado com @RunJobOnAllTenants.
     */
    @Around("@annotation(io.smilego.tenant.enumeration.RunJobOnAllTenants)")
    public Object runJobOnAllTenants(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed = null;
        MethodSignature method = (MethodSignature) joinPoint.getSignature();
        RunJobOnAllTenants runJobOnAllTenants = method.getMethod().getAnnotation(RunJobOnAllTenants.class);
        String nameClass  = method.getMethod().getDeclaringClass().getSimpleName();
        String nameMethod = method.getMethod().getName().replace(method.getMethod().getDeclaringClass().getName().concat("."),"");
        String jobName    = nameClass.concat("-").concat(nameMethod);
        Collection tenants = applicationRepository.findApplicationByName(applicationName)
                .orElseThrow(() -> new RuntimeException("Application not found"))
                .getTenants()
                .stream()
                .filter(Tenant::isActive)
                .collect(Collectors.toList());
        for(Tenant t : tenants) {
            if(parameterCacheableService.workerRunning(t.getTenantId(), jobName)){
                continue;
            }
            parameterCacheableService.startWorker(t.getTenantId(), jobName);
            TenantContext.setTenantId(t.getTenantId());
            log.debug(LogBuilder.of()
                    .header("========== Execucao de JOB para Todos os Tenants ==========")
                    .row("Job name:", runJobOnAllTenants.jobName())
                    .row("Tenant: ", t.getTenantId())
                    .build());

            Span currentSpan = Span.current();
            SpanContext spanContext = currentSpan.getSpanContext();
            String traceId = spanContext.getTraceId();

            ScheduleLog scheduleLog = (ScheduleLog) LogContextHolder.getInstance().initSchedule(traceId, jobName);
            try {
                MDC.put("tenantId", TenantContext.getTenantId());
                currentSpan.setAttribute("tenantId", TenantContext.getTenantId());
                proceed = joinPoint.proceed();
            } catch (Throwable ex) {
                scheduleLog.setStackTrace(String.format("%s.%s:%s", ex.getClass().getName(), ex.getMessage(), LogUtils.getStackTrace(ex)));
                log.error(LogBuilder.of()
                        .header("========== Erro na Execucao de JOB para Todos os Tenants ==========")
                        .row("Job name:", runJobOnAllTenants.jobName())
                        .row("Tenant: ", t.getTenantId())
                        .row("Error Message: ", ex.getMessage())
                        .build());
            }finally {
                if(espheroLoggingContext && (!scheduleLog.getLogs().isEmpty() || scheduleLog.getStackTrace() != null)) scheduleLog.write();
                TenantContext.clear();
                MDC.clear();
            }
            parameterCacheableService.stopWorker(t.getTenantId(), jobName);
        }
        return proceed;
    }

    @Around("@annotation(org.springframework.amqp.rabbit.annotation.RabbitListener)")
    public Object interceptListener(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        try {
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Object[] parameters = joinPoint.getArgs();
            if(Objects.nonNull(parameters)
                    && parameters.length > 0
                    && Arrays.stream(methodSignature.getParameterNames()).anyMatch(p -> p.equalsIgnoreCase(TENANT_ARG_NAME))
            )
                TenantContext.setTenantId(parameters[0].toString());
            result = joinPoint.proceed();
        } catch (Exception e){
            log.error("Error inside rabbitMQ listener", e);
            throw e;
        }
        finally {
            TenantContext.clear();
        }
        return result;
    }

    @Override
    public int getOrder() {
        return 4;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy