/* * 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.loader.java; import static java.lang.String.format; import static java.util.Arrays.stream; import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.apache.commons.lang.ArrayUtils.EMPTY_CLASS_ARRAY; import static org.mule.runtime.api.util.Preconditions.checkArgument; import static org.mule.runtime.core.util.StringUtils.ifNotBlank; import static org.mule.runtime.extension.api.declaration.type.ExtensionsTypeLoaderFactory.getDefault; import org.mule.metadata.api.ClassTypeLoader; import org.mule.runtime.api.meta.MuleVersion; import org.mule.runtime.api.meta.model.ExtensionModel; import org.mule.runtime.api.meta.model.ExternalLibraryModel; import org.mule.runtime.api.meta.model.ExternalLibraryModel.ExternalLibraryModelBuilder; import org.mule.runtime.api.meta.model.declaration.fluent.Declarer; import org.mule.runtime.api.meta.model.declaration.fluent.DeclaresExternalLibraries; import org.mule.runtime.api.meta.model.declaration.fluent.ExtensionDeclarer; import org.mule.runtime.api.meta.model.declaration.fluent.HasModelProperties; import org.mule.runtime.api.metadata.TypedValue; import org.mule.runtime.extension.api.annotation.Extension; import org.mule.runtime.extension.api.annotation.ExternalLib; import org.mule.runtime.extension.api.annotation.ExternalLibs; import org.mule.runtime.extension.api.annotation.Operations; import org.mule.runtime.extension.api.annotation.param.Connection; import org.mule.runtime.extension.api.annotation.param.Config; import org.mule.runtime.extension.api.loader.ExtensionLoadingContext; import org.mule.runtime.extension.api.runtime.parameter.Literal; import org.mule.runtime.extension.api.runtime.parameter.ParameterResolver; import org.mule.runtime.module.extension.internal.loader.java.contributor.InfrastructureFieldContributor; import org.mule.runtime.module.extension.internal.loader.java.contributor.ParameterDeclarerContributor; import org.mule.runtime.module.extension.internal.loader.java.contributor.ParameterTypeUnwrapperContributor; import org.mule.runtime.module.extension.internal.loader.java.property.ExceptionHandlerModelProperty; import org.mule.runtime.module.extension.internal.loader.java.property.ImplementingTypeModelProperty; import org.mule.runtime.extension.internal.property.LiteralModelProperty; import org.mule.runtime.module.extension.internal.loader.java.property.ParameterResolverTypeModelProperty; import org.mule.runtime.module.extension.internal.loader.java.property.TypedValueTypeModelProperty; import org.mule.runtime.module.extension.internal.loader.java.type.ExtensionElement; import org.mule.runtime.module.extension.internal.loader.java.type.ExtensionParameter; import org.mule.runtime.module.extension.internal.loader.java.type.ExtensionTypeFactory; import org.mule.runtime.module.extension.internal.loader.java.type.WithAnnotations; import org.mule.runtime.module.extension.internal.loader.java.type.WithParameters; import com.google.common.collect.ImmutableList; import java.util.List; import java.util.Optional; import java.util.stream.Stream; /** * Describes an {@link ExtensionModel} by analyzing the annotations in the class * provided in the constructor * * @since 4.0 */ public class DefaultJavaModelLoaderDelegate implements ModelLoaderDelegate { protected final Class<?> extensionType; protected final ClassTypeLoader typeLoader; protected final String version; private final ConfigModelLoaderDelegate configLoaderDelegate = new ConfigModelLoaderDelegate(this); private final OperationModelLoaderDelegate operationLoaderDelegate = new OperationModelLoaderDelegate(this); private final SourceModelLoaderDelegate sourceModelLoaderDelegate = new SourceModelLoaderDelegate(this); private final ConnectionProviderModelLoaderDelegate connectionProviderModelLoaderDelegate = new ConnectionProviderModelLoaderDelegate(this); private final ParameterModelsLoaderDelegate fieldParametersLoader; private final ParameterModelsLoaderDelegate methodParametersLoader; public DefaultJavaModelLoaderDelegate(Class<?> extensionType, String version) { checkArgument(extensionType != null, format("describer %s does not specify an extension type", getClass().getName())); this.extensionType = extensionType; this.version = version; this.typeLoader = getDefault().createTypeLoader(extensionType.getClassLoader()); this.fieldParametersLoader = new ParameterModelsLoaderDelegate(getParameterFieldsContributors(), typeLoader); this.methodParametersLoader = new ParameterModelsLoaderDelegate(getParameterMethodsContributors(), typeLoader); } private List<ParameterDeclarerContributor> getParameterMethodsContributors() { return ImmutableList .of(new ParameterTypeUnwrapperContributor(typeLoader, TypedValue.class, new TypedValueTypeModelProperty()), new ParameterTypeUnwrapperContributor(typeLoader, ParameterResolver.class, new ParameterResolverTypeModelProperty()), new ParameterTypeUnwrapperContributor(typeLoader, Literal.class, new LiteralModelProperty())); } private ImmutableList<ParameterDeclarerContributor> getParameterFieldsContributors() { return ImmutableList .of(new InfrastructureFieldContributor(), new ParameterTypeUnwrapperContributor(typeLoader, TypedValue.class, new TypedValueTypeModelProperty()), new ParameterTypeUnwrapperContributor(typeLoader, ParameterResolver.class, new ParameterResolverTypeModelProperty()), new ParameterTypeUnwrapperContributor(typeLoader, Literal.class, new LiteralModelProperty())); } /** * {@inheritDoc} */ @Override public ExtensionDeclarer declare(ExtensionLoadingContext context) { final ExtensionElement extensionElement = ExtensionTypeFactory.getExtensionType(extensionType); Extension extension = MuleExtensionAnnotationParser.getExtension(extensionType); ExtensionDeclarer declarer = context.getExtensionDeclarer() .named(extension.name()) .onVersion(version) .fromVendor(extension.vendor()) .withCategory(extension.category()) .withMinMuleVersion(new MuleVersion(extension.minMuleVersion())) .describedAs(extension.description()) .withModelProperty(new ImplementingTypeModelProperty(extensionType)); parseExternalLibs(extensionElement, declarer); addExceptionEnricher(extensionElement, declarer); configLoaderDelegate.declareConfigurations(declarer, extensionElement); connectionProviderModelLoaderDelegate.declareConnectionProviders(declarer, extensionElement); if (!isEmpty(extensionElement.getConfigurations())) { operationLoaderDelegate .declareOperations(declarer, declarer, null, extensionElement.getOperations(), false); extensionElement.getSources() .forEach(source -> sourceModelLoaderDelegate.declareMessageSource(declarer, declarer, source, false)); } return declarer; } void parseExternalLibs(WithAnnotations withAnnotations, DeclaresExternalLibraries declarer) { Optional<ExternalLibs> externalLibs = withAnnotations.getAnnotation(ExternalLibs.class); if (externalLibs.isPresent()) { stream(externalLibs.get().value()).forEach(lib -> parseExternalLib(declarer, lib)); } else { withAnnotations.getAnnotation(ExternalLib.class).ifPresent(lib -> parseExternalLib(declarer, lib)); } } private void parseExternalLib(DeclaresExternalLibraries declarer, ExternalLib externalLibAnnotation) { ExternalLibraryModelBuilder builder = ExternalLibraryModel.builder() .withName(externalLibAnnotation.name()) .withDescription(externalLibAnnotation.description()); ifNotBlank(externalLibAnnotation.fileName(), builder::withFileName); ifNotBlank(externalLibAnnotation.requiredClassName(), builder::withRequiredClassName); declarer.withExternalLibrary(builder.build()); } <M extends WithAnnotations> HasModelProperties addExceptionEnricher(M model, HasModelProperties declarer) { MuleExtensionAnnotationParser.getExceptionEnricherFactory(model).map(ExceptionHandlerModelProperty::new) .ifPresent(declarer::withModelProperty); return declarer; } Class<?>[] getOperationClasses(Class<?> extensionType) { Operations operations = extensionType.getAnnotation(Operations.class); return operations == null ? EMPTY_CLASS_ARRAY : operations.value(); } boolean isInvalidConfigSupport(boolean supportsConfig, Optional<ExtensionParameter>... parameters) { return !supportsConfig && Stream.of(parameters).anyMatch(Optional::isPresent); } Declarer selectDeclarerBasedOnConfig(ExtensionDeclarer extensionDeclarer, Declarer declarer, Optional<ExtensionParameter>... parameters) { for (Optional<ExtensionParameter> parameter : parameters) { if (parameter.isPresent()) { return declarer; } } return extensionDeclarer; } Optional<ExtensionParameter> getConfigParameter(WithParameters element) { return element.getParametersAnnotatedWith(Config.class).stream().findFirst(); } Optional<ExtensionParameter> getConnectionParameter(WithParameters element) { return element.getParametersAnnotatedWith(Connection.class).stream().findFirst(); } ConfigModelLoaderDelegate getConfigLoaderDelegate() { return configLoaderDelegate; } OperationModelLoaderDelegate getOperationLoaderDelegate() { return operationLoaderDelegate; } SourceModelLoaderDelegate getSourceModelLoaderDelegate() { return sourceModelLoaderDelegate; } ConnectionProviderModelLoaderDelegate getConnectionProviderModelLoaderDelegate() { return connectionProviderModelLoaderDelegate; } ClassTypeLoader getTypeLoader() { return typeLoader; } Class<?> getExtensionType() { return extensionType; } protected ParameterModelsLoaderDelegate getFieldParametersLoader() { return fieldParametersLoader; } protected ParameterModelsLoaderDelegate getMethodParametersLoader() { return methodParametersLoader; } }