/*
* 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.runtime.module.extension.internal.manager;
import static org.mule.runtime.api.component.ComponentIdentifier.builder;
import static org.mule.runtime.api.meta.model.error.ErrorModelBuilder.newError;
import static org.mule.runtime.core.exception.Errors.Identifiers.CONNECTIVITY_ERROR_IDENTIFIER;
import static org.mule.runtime.core.exception.Errors.Identifiers.RETRY_EXHAUSTED_ERROR_IDENTIFIER;
import static org.mule.runtime.module.extension.internal.util.MuleExtensionUtils.getExtensionsErrorNamespace;
import org.mule.runtime.api.component.ComponentIdentifier;
import org.mule.runtime.api.connection.ConnectionException;
import org.mule.runtime.api.message.ErrorType;
import org.mule.runtime.api.meta.model.ExtensionModel;
import org.mule.runtime.api.meta.model.error.ErrorModel;
import org.mule.runtime.api.meta.model.operation.OperationModel;
import org.mule.runtime.api.meta.model.util.ExtensionWalker;
import org.mule.runtime.api.meta.model.util.IdempotentExtensionWalker;
import org.mule.runtime.core.exception.ErrorTypeLocator;
import org.mule.runtime.core.exception.ErrorTypeRepository;
import org.mule.runtime.core.exception.ExceptionMapper;
import org.mule.runtime.core.retry.RetryPolicyExhaustedException;
import org.mule.runtime.extension.api.dsl.syntax.resolver.DslSyntaxResolver;
import org.mule.runtime.extension.api.dsl.syntax.resolver.SingleExtensionImportTypesStrategy;
import java.util.Optional;
import java.util.Set;
/**
* Extension's {@link ErrorType} registrant.
* <p>
* For each {@link OperationModel} from an {@link ExtensionModel} consumes the declared {@link ErrorModel}s converts these to
* {@link ErrorType}s using the {@link ErrorTypeRepository}, and finally register an {@link ExceptionMapper} for the operation.
*
* @see ErrorModel
* @see ErrorType
* @see ErrorTypeRepository
* @see ErrorTypeLocator
* @since 4.0
*/
class ExtensionErrorsRegistrant {
public static final String MULE = org.mule.runtime.core.exception.Errors.CORE_NAMESPACE_NAME;
private final ErrorTypeRepository errorTypeRepository;
private final ErrorTypeLocator errorTypeLocator;
ExtensionErrorsRegistrant(ErrorTypeRepository errorTypeRepository, ErrorTypeLocator errorTypeLocator) {
this.errorTypeRepository = errorTypeRepository;
this.errorTypeLocator = errorTypeLocator;
}
/**
* Registers the found {@link ErrorModel} from each {@link OperationModel} into the {@link ErrorTypeRepository} and creates an
* {@link ExceptionMapper} for each {@link OperationModel} that declares {@link ErrorModel}s.
*
* @param extensionModel from where get the {@link ErrorModel} from each {@link OperationModel}
*/
void registerErrors(ExtensionModel extensionModel) {
Set<ErrorModel> errorTypes = extensionModel.getErrorModels();
String extensionNamespace = extensionModel.getXmlDslModel().getPrefix();
String errorExtensionNamespace = getExtensionsErrorNamespace(extensionModel);
DslSyntaxResolver syntaxResolver = DslSyntaxResolver.getDefault(extensionModel, new SingleExtensionImportTypesStrategy());
ErrorModel connectivityErrorModel = newError(CONNECTIVITY_ERROR_IDENTIFIER, errorExtensionNamespace)
.withParent(newError(CONNECTIVITY_ERROR_IDENTIFIER, MULE).build()).build();
ErrorModel retryExhaustedError = newError(RETRY_EXHAUSTED_ERROR_IDENTIFIER, errorExtensionNamespace)
.withParent(newError(RETRY_EXHAUSTED_ERROR_IDENTIFIER, MULE).build()).build();
errorTypes.forEach(this::getErrorType);
ExtensionWalker extensionWalker = new IdempotentExtensionWalker() {
@Override
protected void onOperation(OperationModel model) {
if (!errorTypes.isEmpty()) {
ExceptionMapper.Builder builder = ExceptionMapper.builder();
builder.addExceptionMapping(ConnectionException.class, getErrorType(connectivityErrorModel));
builder.addExceptionMapping(RetryPolicyExhaustedException.class, getErrorType(retryExhaustedError));
String elementName = syntaxResolver.resolve(model).getElementName();
errorTypeLocator.addComponentExceptionMapper(createIdentifier(elementName, extensionNamespace),
builder.build());
}
}
};
extensionWalker.walk(extensionModel);
}
private ErrorType getErrorType(ErrorModel errorModel) {
ComponentIdentifier identifier = createIdentifier(errorModel.getType(), errorModel.getNamespace());
Optional<ErrorType> optionalError = errorTypeRepository.lookupErrorType(identifier);
return optionalError.orElseGet(() -> createErrorType(errorModel, identifier));
}
private ErrorType createErrorType(ErrorModel errorModel, ComponentIdentifier identifier) {
final ErrorType errorType;
if (errorModel.getParent().isPresent()) {
errorType = errorTypeRepository.addErrorType(identifier, getErrorType(errorModel.getParent().get()));
} else {
errorType = errorTypeRepository.addErrorType(identifier, null);
}
return errorType;
}
private static ComponentIdentifier createIdentifier(String name, String namespace) {
return builder().withName(name).withNamespace(namespace).build();
}
}