/* * 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.dsl.api.component; import static com.google.common.base.Preconditions.checkState; import static java.util.Optional.ofNullable; import java.util.Optional; /** * Defines how to build an attribute from an object. * <p/> * An attribute may be configured to be set by using a constructor or a setter. * <p/> * The {@link AttributeDefinition.Builder} allows to create an {@code AttributeDefinition} * from many different sources. * * @since 4.0 */ public class AttributeDefinition { private String configParameterName; private Object defaultValue; private boolean hasDefaultValue; private boolean undefinedSimpleParametersHolder; private Class<?> referenceObject; private String referenceFixedParameter; private Class<?> childObjectType; private boolean undefinedComplexParametersHolder; private String referenceSimpleParameter; private boolean collection; private boolean map; private Class<?> mapKeyType; private boolean valueFromTextContent; private TypeConverter typeConverter; private KeyAttributeDefinitionPair[] definitions; private String wrapperIdentifier; private String childIdentifier; private AttributeDefinition() {} /** * @param visitor handler for the configuration option set for this parameter. */ public void accept(AttributeDefinitionVisitor visitor) { if (configParameterName != null) { visitor.onConfigurationParameter(configParameterName, defaultValue, ofNullable(typeConverter)); } else if (referenceObject != null) { visitor.onReferenceObject(referenceObject); } else if (undefinedSimpleParametersHolder) { visitor.onUndefinedSimpleParameters(); } else if (undefinedComplexParametersHolder) { visitor.onUndefinedComplexParameters(); } else if (referenceSimpleParameter != null) { visitor.onReferenceSimpleParameter(referenceSimpleParameter); } else if (referenceFixedParameter != null) { visitor.onReferenceFixedParameter(referenceFixedParameter); } else if (childObjectType != null && collection) { visitor.onComplexChildCollection(childObjectType, ofNullable(wrapperIdentifier)); } else if (childObjectType != null && map) { visitor.onComplexChildMap(mapKeyType, childObjectType, wrapperIdentifier); } else if (childObjectType != null) { Optional<String> wrapperIdentifier = ofNullable(this.wrapperIdentifier); Optional<String> childIdentifier = ofNullable(this.childIdentifier); visitor.onComplexChild(childObjectType, wrapperIdentifier, childIdentifier); } else if (valueFromTextContent) { visitor.onValueFromTextContent(); } else if (definitions != null) { visitor.onMultipleValues(definitions); } else if (hasDefaultValue) { visitor.onFixedValue(defaultValue); } else { throw new RuntimeException(); } } public static class Builder { private AttributeDefinition attributeDefinition = new AttributeDefinition(); private Builder() {} /** * @param configParameterName name of the configuration parameter from which this attribute value will be extracted. * @return the builder */ public static Builder fromSimpleParameter(String configParameterName) { Builder builder = new Builder(); builder.attributeDefinition.configParameterName = configParameterName; return builder; } /** * @param configParameterName name of the configuration parameter from which this attribute value will be extracted. * @param typeConverter converter from the configuration value to a custom type. * @return the builder */ public static Builder fromSimpleParameter(String configParameterName, TypeConverter typeConverter) { Builder builder = new Builder(); builder.attributeDefinition.configParameterName = configParameterName; builder.attributeDefinition.typeConverter = typeConverter; return builder; } /** * @param defaultValue defines the default value to be used for the attribute if no other value is provided. * @return the builder */ public Builder withDefaultValue(Object defaultValue) { attributeDefinition.hasDefaultValue = true; attributeDefinition.defaultValue = defaultValue; return this; } /** * Defines the parent identifier used to wrap a child element. Useful when there are children with the same type and we need * to make a distinction to know how to do injection over multiple attributes with the same type. The identifier provided does * not require a component definition since it will be just for qualifying a child. * * i.e.: * * <pre> * <parent-component> * <first-wrapper> * <child-component> * </first-wrapper> * <second-wrapper> * <child-component> * </second-wrapper> * </parent-component> * </pre> * * The first-wrapper and second-wrapper elements are just used to univocally identify the object attribute in which the * child-component object must be injected. * * @param identifier component identifier in the configuration for the parent element wrapping the child component * @return */ public Builder withWrapperIdentifier(String identifier) { checkState(attributeDefinition.childObjectType != null, "Identifier can only be used with children component definitions"); attributeDefinition.wrapperIdentifier = identifier; return this; } /** * @param value a fixed value which will be assigned to the attribute. * @return the builder */ public static Builder fromFixedValue(Object value) { Builder builder = new Builder(); builder.attributeDefinition.hasDefaultValue = true; builder.attributeDefinition.defaultValue = value; return builder; } /** * Use when the reference is fixed (and not configurable), not the value. * * @param reference a fixed reference object which will be assigned to the attribute. * @return the builder */ public static Builder fromFixedReference(String reference) { Builder builder = new Builder(); builder.attributeDefinition.referenceFixedParameter = reference; return builder; } /** * Calling this method declares that the attribute will be assigned with all declared simple configuration attribute and its * value. By simple attribute we consider those with a key and a string value as content. * <p/> * The simple attributes are store in a {@code java.util.Map} so the attribute type must also be a {@code java.util.Map}. * * @return the builder */ public static Builder fromUndefinedSimpleAttributes() { Builder builder = new Builder(); builder.attributeDefinition.undefinedSimpleParametersHolder = true; return builder; } /** * Used when attribute an attribute must be set with an object provided by the runtime. For instance when the object requires * access to the {@code org.mule.runtime.core.api.MuleContext} or a {@code org.mule.runtime.core.time.TimeSupplier}. * * @param referenceObjectType type of the object expected to be injected. * @return the builder */ public static Builder fromReferenceObject(Class<?> referenceObjectType) { Builder builder = new Builder(); builder.attributeDefinition.referenceObject = referenceObjectType; return builder; } /** * Used when an attribute must be set with a complex object created from the user configuration. * * @param childType type of the required complex object. * @return the builder */ public static Builder fromChildConfiguration(Class<?> childType) { Builder builder = new Builder(); builder.attributeDefinition.childObjectType = childType; return builder; } /** * Calling this method declares that the attribute will be assigned with all declared complex configuration object that did * not were map by other {@code AttributeDefinition}s. By complex attribute we consider those that are represented by complex * object types. * <p/> * The complex attributes are store in a {@code java.util.List} so the attribute type must also be a {@code java.util.List}. * * @return the builder */ public static Builder fromUndefinedComplexAttribute() { Builder builder = new Builder(); builder.attributeDefinition.undefinedComplexParametersHolder = true; return builder; } /** * @param referenceSimpleParameter configuration attribute that holds a reference to another configuration object. * @return the builder */ public static Builder fromSimpleReferenceParameter(String referenceSimpleParameter) { Builder builder = new Builder(); builder.attributeDefinition.referenceSimpleParameter = referenceSimpleParameter; return builder; } /** * Used when an attribute must be set with a collection of objects created from the user configuration. * * @param type the collection object type. * @return the builder */ public static Builder fromChildCollectionConfiguration(Class<?> type) { Builder builder = new Builder(); builder.attributeDefinition.childObjectType = type; builder.attributeDefinition.collection = true; return builder; } /** * Used when an attribute must be set with a map of objects created from the user configuration. * * @param keyType the map key type. * @param valueType the map value type. * @return the builder */ public static Builder fromChildMapConfiguration(Class<?> keyType, Class<?> valueType) { Builder builder = new Builder(); builder.attributeDefinition.childObjectType = valueType; builder.attributeDefinition.mapKeyType = keyType; builder.attributeDefinition.map = true; return builder; } /** * Used when an attribute must be created with the inner content of the configuration element. * * @return the builder */ public static Builder fromTextContent() { Builder builder = new Builder(); builder.attributeDefinition.valueFromTextContent = true; return builder; } /** * Used when several attributes or child components needs to be mapped to a single attribute. The attribute must be of type * Map where the key are the attribute name or the child element name and the value is the actual object. * * @param definitions the set of attribute definitions along with its keys * @return the builder */ public static Builder fromMultipleDefinitions(KeyAttributeDefinitionPair... definitions) { Builder builder = new Builder(); builder.attributeDefinition.definitions = definitions; return builder; } public Builder withIdentifier(String childIdentifier) { attributeDefinition.childIdentifier = childIdentifier; return this; } /** * @return the {@code AttributeDefinition} created based on the defined configuration. */ public AttributeDefinition build() { return attributeDefinition; } } }