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

org.mule.extension.validation.internal.DefaultExceptionFactory Maven / Gradle / Ivy

/*
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package org.mule.extension.validation.internal;

import static org.reflections.ReflectionUtils.getConstructors;
import static org.reflections.ReflectionUtils.withParameters;
import org.mule.api.MuleEvent;
import org.mule.api.MuleRuntimeException;
import org.mule.config.i18n.MessageFactory;
import org.mule.extension.validation.api.ExceptionFactory;
import org.mule.extension.validation.api.ValidationResult;
import org.mule.util.ClassUtils;
import org.mule.util.CollectionUtils;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.concurrent.ExecutionException;

/**
 * Default implementation of {@link ExceptionFactory}.
 * 

* In order to create the {@link Exception} instances, it scans * the requested {@link Class}es for a public {@link Constructor} * which receives two arguments assignable from {@link ValidationResult} * and {@link MuleEvent}. If it's not found, a new search is done * looking for a constructor with a single argument assignable from * {@link ValidationResult}. If such {@link Constructor} is not found * then it tries with a default one. If it's still not found then * an {@link IllegalArgumentException} exception is thrown because * the requested {@link Class} does not comply with the rules of this * factory. For performance reasons, the {@link Constructor} chosen * for each class are cached. * * @see ExceptionFactory * @since 3.7.0 */ public class DefaultExceptionFactory implements ExceptionFactory { private final LoadingCache, ConstructorDelegate> constructorCache = CacheBuilder.newBuilder().build(new CacheLoader, ConstructorDelegate>() { @Override public ConstructorDelegate load(Class exceptionType) throws Exception { return selectMostCompleteConstructor(exceptionType); } }); private final LoadingCache> classCache = CacheBuilder.newBuilder().build(new CacheLoader>() { @Override public Class load(String exceptionClassName) throws Exception { Class exceptionClass; try { exceptionClass = ClassUtils.getClass(exceptionClassName); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Could not find exception class " + exceptionClassName); } if (!Exception.class.isAssignableFrom(exceptionClass)) { throw new IllegalArgumentException(String.format( "Was expecting an exception type, %s found instead", exceptionClass.getCanonicalName())); } return exceptionClass; } }); @Override public T createException(ValidationResult result, Class exceptionClass, MuleEvent event) { ConstructorDelegate constructorDelegate = (ConstructorDelegate) get(constructorCache, exceptionClass); try { return constructorDelegate.createException(result, result.getMessage(), event); } catch (Exception e) { throw new MuleRuntimeException(MessageFactory.createStaticMessage( String.format("Could not create exception of type %s. Exception message was:\n%s", exceptionClass.getName(), result.getMessage()))); } } @Override public Exception createException(ValidationResult result, String exceptionClassName, MuleEvent event) { return createException(result, get(classCache, exceptionClassName), event); } private V get(LoadingCache cache, K key) { try { return cache.get(key); } catch (ExecutionException e) { if (e.getCause() instanceof IllegalArgumentException) { throw (IllegalArgumentException) e.getCause(); } throw new MuleRuntimeException(e); } } private ConstructorDelegate selectMostCompleteConstructor(Class exceptionType) { Collection candidate = getConstructors(exceptionType, withParameters(ValidationResult.class, MuleEvent.class)); if (!CollectionUtils.isEmpty(candidate)) { return new ValidationResultAndEventConstructorDelegate<>((Constructor) candidate.iterator().next()); } candidate = getConstructors(exceptionType, withParameters(ValidationResult.class)); if (!CollectionUtils.isEmpty(candidate)) { return new ValidationResultConstructorDelegate((Constructor) candidate.iterator().next()); } candidate = getConstructors(exceptionType, withParameters(String.class)); if (CollectionUtils.isEmpty(candidate)) { throw new IllegalArgumentException( String.format( "Exception type %s was expected to contain at least one accessible constructor with eia single String argument but a matching constructor " + "could not be found.", exceptionType.getCanonicalName())); } return new DirectMessageConstructorDelegate((Constructor) candidate.iterator().next()); } private interface ConstructorDelegate { T createException(ValidationResult validationResult, String message, MuleEvent event) throws Exception; } private class ValidationResultAndEventConstructorDelegate implements ConstructorDelegate { private final Constructor constructor; public ValidationResultAndEventConstructorDelegate(Constructor constructor) { this.constructor = constructor; } @Override public T createException(ValidationResult validationResult, String message, MuleEvent event) throws Exception { return constructor.newInstance(validationResult, event); } } private class ValidationResultConstructorDelegate implements ConstructorDelegate { private final Constructor constructor; private ValidationResultConstructorDelegate(Constructor constructor) { this.constructor = constructor; } @Override public T createException(ValidationResult validationResult, String message, MuleEvent event) throws Exception { return constructor.newInstance(validationResult); } } private class DirectMessageConstructorDelegate implements ConstructorDelegate { private final Constructor constructor; public DirectMessageConstructorDelegate(Constructor constructor) { this.constructor = constructor; } @Override public T createException(ValidationResult validationResult, String message, MuleEvent event) throws Exception { return constructor.newInstance(message); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy