/*
* 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.capability.xml.description;
import static org.mule.runtime.extension.api.util.NameUtils.hyphenize;
import org.mule.runtime.api.meta.model.ExtensionModel;
import org.mule.runtime.api.meta.model.declaration.fluent.ConfigurationDeclaration;
import org.mule.runtime.api.meta.model.declaration.fluent.ExtensionDeclaration;
import org.mule.runtime.extension.api.annotation.Configuration;
import org.mule.runtime.extension.api.annotation.Extension;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.TypeElement;
/**
* {@link AbstractDescriptionDocumenter} implementation that picks a {@link ExtensionDeclaration} on which a {@link ExtensionModel}
* has already been described.
*
* @since 4.0
*/
final class ExtensionDescriptionDocumenter extends AbstractDescriptionDocumenter<ExtensionDeclaration> {
private final RoundEnvironment roundEnv;
private final ConfigurationDescriptionDocumenter configDeclarer;
private final OperationDescriptionDocumenter operationDeclarer;
private final SourcesDescriptionDocumenter sourceDeclarer;
ExtensionDescriptionDocumenter(ProcessingEnvironment processingEnvironment, RoundEnvironment roundEnvironment) {
super(processingEnvironment);
this.roundEnv = roundEnvironment;
this.operationDeclarer = new OperationDescriptionDocumenter(processingEnv);
this.sourceDeclarer = new SourcesDescriptionDocumenter(processingEnv);
this.configDeclarer = new ConfigurationDescriptionDocumenter(processingEnvironment);
}
/**
* Sets the description of the given {@link ExtensionDeclaration} and its inner configs and operations by extracting information
* of the AST tree represented by {@code extensionElement} and {@code roundEnvironment}
*
* @param extensionDeclaration a {@link ExtensionDeclaration} on which configurations and operations have already been declared
* @param extensionElement a {@link TypeElement} generated by an annotation {@link Processor}
*/
void document(ExtensionDeclaration extensionDeclaration, TypeElement extensionElement) {
Extension annotation = extensionElement.getAnnotation(Extension.class);
extensionDeclaration.setDescription(annotation.description());
sourceDeclarer.document(extensionDeclaration, extensionElement);
operationDeclarer.document(extensionDeclaration, extensionElement);
documentConfigurations(extensionDeclaration, extensionElement);
}
private void documentConfigurations(ExtensionDeclaration declaration, TypeElement extensionElement) {
Set<TypeElement> configurations = processor.getTypeElementsAnnotatedWith(Configuration.class, roundEnv);
if (!configurations.isEmpty()) {
configurations
.forEach(config -> findMatchingConfiguration(declaration, config)
.ifPresent(configDeclaration -> configDeclarer.document(configDeclaration, config)));
} else {
configDeclarer.document(declaration.getConfigurations().get(0), extensionElement);
}
}
private Optional<ConfigurationDeclaration> findMatchingConfiguration(ExtensionDeclaration declaration, TypeElement element) {
List<ConfigurationDeclaration> configurations = declaration.getConfigurations();
if (configurations.size() == 1) {
return Optional.of(configurations.get(0));
}
return configurations.stream()
.filter(config -> {
Configuration configurationAnnotation = element.getAnnotation(Configuration.class);
String name = config.getName();
String annotationName = configurationAnnotation != null ? configurationAnnotation.name() : "";
String defaultNaming = hyphenize(element.getSimpleName().toString().replace("Configuration", ""));
return name.equals(defaultNaming) || name.equals(annotationName);
})
.findAny();
}
}