/* * 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.Optional.empty; import static java.util.Optional.of; import static org.mule.runtime.api.util.Preconditions.checkState; import org.mule.runtime.core.util.ClassUtils; import org.mule.runtime.extension.api.annotation.Extension; import org.mule.runtime.extension.api.annotation.OnException; import org.mule.runtime.extension.api.annotation.param.display.Password; import org.mule.runtime.extension.api.annotation.param.display.Placement; import org.mule.runtime.extension.api.annotation.param.display.Text; import org.mule.runtime.api.meta.model.declaration.fluent.BaseDeclaration; import org.mule.runtime.api.meta.model.display.LayoutModel.LayoutModelBuilder; import org.mule.runtime.extension.api.runtime.exception.ExceptionHandlerFactory; import org.mule.runtime.api.meta.model.display.LayoutModel; import org.mule.runtime.module.extension.internal.loader.java.type.WithAnnotations; import org.mule.runtime.module.extension.internal.loader.java.property.DeclaringMemberModelProperty; import org.mule.runtime.module.extension.internal.runtime.exception.DefaultExceptionHandlerFactory; import org.mule.runtime.module.extension.internal.util.IntrospectionUtils; import com.google.common.collect.ImmutableList; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utilities for reading annotations as a mean to describe extensions * * @since 3.7.0 */ public final class MuleExtensionAnnotationParser { private static final Logger logger = LoggerFactory.getLogger(MuleExtensionAnnotationParser.class); public static String getMemberName(BaseDeclaration<?> declaration, String defaultName) { return declaration.getModelProperty(DeclaringMemberModelProperty.class).map(p -> p.getDeclaringField().getName()) .orElse(defaultName); } public static Extension getExtension(Class<?> extensionType) { try { Extension extension = extensionType.getAnnotation(Extension.class); checkState(extension != null, format("%s is not a Mule extension since it's not annotated with %s", extensionType.getName(), Extension.class.getName())); return extension; } catch (Exception e) { logger.error(format("%s getting '@Extension' annotation from %s", e.getClass().getName(), extensionType.getName()), e); throw e; } } public static <T extends Annotation> List<T> parseRepeatableAnnotation(Class<?> extensionType, Class<T> annotation, Function<Annotation, T[]> containerConsumer) { List<T> annotationDeclarations = ImmutableList.of(); Repeatable repeatableContainer = annotation.getAnnotation(Repeatable.class); if (repeatableContainer != null) { Annotation container = IntrospectionUtils.getAnnotation(extensionType, repeatableContainer.value()); if (container != null) { annotationDeclarations = ImmutableList.copyOf(containerConsumer.apply(container)); } } T singleDeclaration = IntrospectionUtils.getAnnotation(extensionType, annotation); if (singleDeclaration != null) { annotationDeclarations = ImmutableList.of(singleDeclaration); } return annotationDeclarations; } public static List<String> getParamNames(Method method) { ImmutableList.Builder<String> paramNames = ImmutableList.builder(); for (java.lang.reflect.Parameter parameter : method.getParameters()) { paramNames.add(parameter.getName()); } return paramNames.build(); } public static Map<Class<? extends Annotation>, Annotation> toMap(Annotation[] annotations) { Map<Class<? extends Annotation>, Annotation> map = new HashMap<>(); for (Annotation annotation : annotations) { map.put(ClassUtils.resolveAnnotationClass(annotation), annotation); } return map; } private static void doParseLayoutAnnotations(AnnotatedElement annotatedElement, LayoutModelBuilder builder) { Password passwordAnnotation = annotatedElement.getAnnotation(Password.class); if (passwordAnnotation != null) { builder.asPassword(); } Text textAnnotation = annotatedElement.getAnnotation(Text.class); if (textAnnotation != null) { builder.asText(); } } private static void doParseLayoutAnnotations(WithAnnotations annotatedElement, LayoutModelBuilder builder) { java.util.Optional<Password> passwordAnnotation = annotatedElement.getAnnotation(Password.class); if (passwordAnnotation.isPresent()) { builder.asPassword(); } java.util.Optional<Text> textAnnotation = annotatedElement.getAnnotation(Text.class); if (textAnnotation.isPresent()) { builder.asText(); } } private static void parsePlacementAnnotation(WithAnnotations annotatedElement, LayoutModelBuilder builder) { java.util.Optional<Placement> placementAnnotation = annotatedElement.getAnnotation(Placement.class); if (placementAnnotation.isPresent()) { Placement placement = placementAnnotation.get(); builder.order(placement.order()).tabName(placement.tab()); } } private static void parsePlacementAnnotation(AnnotatedElement annotatedElement, LayoutModelBuilder builder) { Placement placement = annotatedElement.getAnnotation(Placement.class); if (placement != null) { builder.order(placement.order()).tabName(placement.tab()); } } public static Optional<LayoutModel> parseLayoutAnnotations(AnnotatedElement annotatedElement) { return parseLayoutAnnotations(annotatedElement, LayoutModel.builder()); } public static Optional<LayoutModel> parseLayoutAnnotations(WithAnnotations annotatedElement) { return parseLayoutAnnotations(annotatedElement, LayoutModel.builder()); } public static Optional<LayoutModel> parseLayoutAnnotations(WithAnnotations annotatedElement, LayoutModelBuilder builder) { if (isDisplayAnnotationPresent(annotatedElement)) { doParseLayoutAnnotations(annotatedElement, builder); parsePlacementAnnotation(annotatedElement, builder); return of(builder.build()); } return empty(); } public static Optional<LayoutModel> parseLayoutAnnotations(AnnotatedElement annotatedElement, LayoutModelBuilder builder) { if (isDisplayAnnotationPresent(annotatedElement)) { doParseLayoutAnnotations(annotatedElement, builder); parsePlacementAnnotation(annotatedElement, builder); return of(builder.build()); } return empty(); } private static boolean isDisplayAnnotationPresent(AnnotatedElement annotatedElement) { List<Class> displayAnnotations = Arrays.asList(Password.class, Text.class, Placement.class); return displayAnnotations.stream().anyMatch(annotation -> annotatedElement.getAnnotation(annotation) != null); } private static boolean isDisplayAnnotationPresent(WithAnnotations annotatedElement) { List<Class> displayAnnotations = Arrays.asList(Password.class, Text.class, Placement.class); return displayAnnotations.stream().anyMatch(annotation -> annotatedElement.getAnnotation(annotation) != null); } static java.util.Optional<ExceptionHandlerFactory> getExceptionEnricherFactory(WithAnnotations element) { final java.util.Optional<OnException> onExceptionAnnotation = element.getAnnotation(OnException.class); if (onExceptionAnnotation.isPresent()) { return of(new DefaultExceptionHandlerFactory(onExceptionAnnotation.get().value())); } return java.util.Optional.empty(); } }