com.catchpoint.trace.lambda.integrations.spring.SpringLambdaHandlerPlugin Maven / Gradle / Ivy
The newest version!
package com.catchpoint.trace.lambda.integrations.spring;
import com.catchpoint.trace.common.instance.InstanceProvider;
import com.catchpoint.trace.common.instance.InstanceScope;
import com.catchpoint.trace.common.util.ExceptionUtils;
import com.catchpoint.trace.lambda.core.handler.LambdaContext;
import com.catchpoint.trace.lambda.core.handler.LambdaHandler;
import com.catchpoint.trace.lambda.core.handler.LambdaHandlerConfig;
import com.catchpoint.trace.lambda.core.handler.plugin.LambdaHandlerPlugin;
import com.catchpoint.trace.lambda.core.handler.ResponseHolder;
import org.slf4j.Logger;
import com.catchpoint.trace.common.logger.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidatorFactory;
import javax.validation.executable.ExecutableValidator;
import java.lang.reflect.*;
import java.util.*;
/**
* @author serkan
*/
public class SpringLambdaHandlerPlugin implements LambdaHandlerPlugin {
private static final Logger LOGGER = LoggerFactory.getLogger(SpringLambdaHandlerPlugin.class);
private final Class> configClass;
private final String configFile;
private final SpringLambdaHandlerPluginConfig pluginConfig;
private SpringContextSupplier contextSupplier;
private LambdaHandler handler;
private boolean validate = true;
private ValidatorFactory validatorFactory;
private ExecutableValidator executableValidator;
private Method doHandleRequestMethod;
private List extensions = new ArrayList<>();
public SpringLambdaHandlerPlugin(Class> configClass) {
this.configClass = configClass;
this.configFile = null;
this.pluginConfig = null;
}
public SpringLambdaHandlerPlugin(Class> configClass, boolean validate, ValidatorFactory validatorFactory) {
this.configClass = configClass;
this.configFile = null;
this.validate = validate;
this.validatorFactory = validatorFactory;
this.pluginConfig = null;
}
public SpringLambdaHandlerPlugin(String configFile) {
this.configClass = null;
this.configFile = configFile;
this.pluginConfig = null;
}
public SpringLambdaHandlerPlugin(String configFile, boolean validate, ValidatorFactory validatorFactory) {
this.configClass = null;
this.configFile = configFile;
this.validate = validate;
this.validatorFactory = validatorFactory;
this.pluginConfig = null;
}
public SpringLambdaHandlerPlugin(SpringLambdaHandlerPluginConfig pluginConfig) {
this.configClass = pluginConfig.configClass();
this.configFile = pluginConfig.configFile();
this.pluginConfig = pluginConfig;
this.validate = pluginConfig.validate();
if (!pluginConfig.validatorFactory().equals(ValidatorFactory.class)) {
this.validatorFactory = InstanceProvider.getInstance(pluginConfig.validatorFactory(), InstanceScope.GLOBAL);
}
}
public SpringContextSupplier getSpringContextSupplier() {
return contextSupplier;
}
private ApplicationContext retrieveApplicationContext(boolean createIfNotExist) {
ApplicationContext applicationContext = null;
try {
if (!configClass.equals(Object.class)) {
applicationContext =
createIfNotExist
? SpringContextManager.getOrCreateContext(configClass)
: SpringContextManager.getContext(configClass);
} else if (!configFile.equals("")) {
applicationContext =
createIfNotExist
? SpringContextManager.getOrCreateContext(configFile)
: SpringContextManager.getContext(configFile);
} else {
throw new IllegalArgumentException("One of the 'configClass' or `configFile` properties must be configured!");
}
if (pluginConfig != null) {
for (Class extends SpringLambdaHandlerPluginExtension> extensionClass : pluginConfig.extensions()) {
SpringLambdaHandlerPluginExtension extension = extensionClass.newInstance();
extensions.add(extension);
}
}
} catch (Throwable t) {
LOGGER.error("Unable to instantiate SpringLambdaHandlerPlugin!", t);
ExceptionUtils.sneakyThrow(t);
}
return applicationContext;
}
@Override
public String name() {
return "spring";
}
@Override
public void onInit(LambdaHandler handler, LambdaHandlerConfig config) {
if (this.handler != null) {
throw new IllegalStateException("Plugin already initiated with handler " + this.handler.toString());
}
this.handler = handler;
ApplicationContext applicationContext = retrieveApplicationContext(true);
applicationContext.getAutowireCapableBeanFactory().autowireBean(handler);
contextSupplier = new SyncSpringContextSupplier(applicationContext);
if (validate) {
initValidation();
}
if (!extensions.isEmpty()) {
for (SpringLambdaHandlerPluginExtension extension : extensions) {
extension.onInit(contextSupplier, handler);
}
}
}
private void initValidation() {
if (validatorFactory == null) {
try {
validatorFactory = (ValidatorFactory) contextSupplier.get().getBean("validator");
} catch (NoSuchBeanDefinitionException e) {
}
} else {
processValidatorFactory(validatorFactory);
}
if (validatorFactory == null) {
validatorFactory = createDefaultValidatorFactory();
processValidatorFactory(validatorFactory);
}
executableValidator = validatorFactory.getValidator().forExecutables();
Method[] methods = handler.getClass().getMethods();
for (Method method : methods) {
if (method.getName().equals("doHandleRequest") && !method.isBridge()) {
doHandleRequestMethod = method;
break;
}
}
if (doHandleRequestMethod == null) {
throw new IllegalStateException("There is no available 'doHandleRequest' to be used for validation");
}
LOGGER.info("Activated validation support");
}
private void processValidatorFactory(ValidatorFactory validatorFactory) {
if (validatorFactory instanceof InitializingBean) {
try {
((InitializingBean) validatorFactory).afterPropertiesSet();
} catch (Exception e) {
ExceptionUtils.sneakyThrow(e);
}
}
}
private ValidatorFactory createDefaultValidatorFactory() {
return new LocalValidatorFactoryBean() {
@Override
public boolean supports(Class> clazz) {
if (!super.supports(clazz)) {
return false;
}
if (AnnotatedElementUtils.isAnnotated(clazz, Validated.class)) {
return true;
}
return false;
}
};
}
private String generateValidationExceptionMessage(String message, Set constraintViolations) {
StringBuilder sb = new StringBuilder();
if (constraintViolations != null) {
for (ConstraintViolation constraintViolation : constraintViolations) {
if (!sb.toString().isEmpty()) {
sb.append("\n");
}
sb.append(constraintViolation.getMessage());
}
} else if (message != null) {
sb.append(message);
}
return sb.toString();
}
private void handleValidation(Req request, LambdaContext lambdaContext) {
if (validate && executableValidator != null) {
Set constraintViolations =
(Set) ((Object)
executableValidator.validateParameters(
handler, doHandleRequestMethod, new Object[]{request, lambdaContext}));
if (constraintViolations.size() > 0) {
throw new ConstraintViolationException(
generateValidationExceptionMessage(null, constraintViolations),
(Set extends ConstraintViolation>>) ((Object) constraintViolations));
}
}
}
@Override
public boolean onRequest(LambdaHandler lambdaHandler, Req request,
LambdaContext lambdaContext, ResponseHolder responseHolder) {
if (!extensions.isEmpty()) {
for (SpringLambdaHandlerPluginExtension extension : extensions) {
if (!extension.onRequest(request, lambdaContext)) {
return false;
}
}
}
handleValidation(request, lambdaContext);
return true;
}
@Override
public void onResponse(LambdaHandler lambdaHandler, Res response, LambdaContext lambdaContext) {
if (!extensions.isEmpty()) {
for (SpringLambdaHandlerPluginExtension extension : extensions) {
extension.onResponse(response, lambdaContext);
}
}
}
@Override
public boolean onError(LambdaHandler lambdaHandler, Req request, LambdaContext lambdaContext, Throwable error, ResponseHolder responseHolder) {
if (!extensions.isEmpty()) {
for (SpringLambdaHandlerPluginExtension extension : extensions) {
extension.onError(request, lambdaContext, error);
}
}
return true;
}
private static class SyncSpringContextSupplier implements SpringContextSupplier {
private final ApplicationContext applicationContext;
public SyncSpringContextSupplier(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public ApplicationContext get() {
return applicationContext;
}
@Override
public ApplicationContext getNow() {
return applicationContext;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy