
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