mirror of https://github.com/apache/nifi.git
NIFI-12573 Improved support for Enums in PropertyDescriptor.Builder
NIFI-12574 Add clearDefaultValue to PropertyDescriptor.Builder This closes #8211 Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
parent
281a28c5d4
commit
4588c6c37e
|
@ -43,9 +43,8 @@ public class AllowableValue implements DescribedValue {
|
||||||
* Constructs a new AllowableValue with the given value and display name and
|
* Constructs a new AllowableValue with the given value and display name and
|
||||||
* no description
|
* no description
|
||||||
*
|
*
|
||||||
* @param value that is allowed
|
* @param value that is allowed
|
||||||
* @param displayName to display for the value
|
* @param displayName to display for the value
|
||||||
*
|
|
||||||
* @throws NullPointerException if either argument is null
|
* @throws NullPointerException if either argument is null
|
||||||
*/
|
*/
|
||||||
public AllowableValue(final String value, final String displayName) {
|
public AllowableValue(final String value, final String displayName) {
|
||||||
|
@ -56,10 +55,9 @@ public class AllowableValue implements DescribedValue {
|
||||||
* Constructs a new AllowableValue with the given value, display name, and
|
* Constructs a new AllowableValue with the given value, display name, and
|
||||||
* description
|
* description
|
||||||
*
|
*
|
||||||
* @param value that is valid
|
* @param value that is valid
|
||||||
* @param displayName to show for the value
|
* @param displayName to show for the value
|
||||||
* @param description of the value
|
* @param description of the value
|
||||||
*
|
|
||||||
* @throws NullPointerException if identifier or value is null
|
* @throws NullPointerException if identifier or value is null
|
||||||
*/
|
*/
|
||||||
public AllowableValue(final String value, final String displayName, final String description) {
|
public AllowableValue(final String value, final String displayName, final String description) {
|
||||||
|
@ -68,6 +66,14 @@ public class AllowableValue implements DescribedValue {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AllowableValue fromDescribedValue(final DescribedValue describedValue) {
|
||||||
|
if (describedValue instanceof AllowableValue allowableValue) {
|
||||||
|
return allowableValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AllowableValue(describedValue.getValue(), describedValue.getDisplayName(), describedValue.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the value of this AllowableValue
|
* @return the value of this AllowableValue
|
||||||
*/
|
*/
|
||||||
|
@ -106,8 +112,7 @@ public class AllowableValue implements DescribedValue {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof AllowableValue) {
|
if (obj instanceof AllowableValue other) {
|
||||||
final AllowableValue other = (AllowableValue) obj;
|
|
||||||
return (this.value.equals(other.getValue()));
|
return (this.value.equals(other.getValue()));
|
||||||
} else if (obj instanceof String) {
|
} else if (obj instanceof String) {
|
||||||
return this.value.equals(obj);
|
return this.value.equals(obj);
|
||||||
|
|
|
@ -19,9 +19,9 @@ package org.apache.nifi.components;
|
||||||
import org.apache.nifi.components.resource.ResourceCardinality;
|
import org.apache.nifi.components.resource.ResourceCardinality;
|
||||||
import org.apache.nifi.components.resource.ResourceDefinition;
|
import org.apache.nifi.components.resource.ResourceDefinition;
|
||||||
import org.apache.nifi.components.resource.ResourceReference;
|
import org.apache.nifi.components.resource.ResourceReference;
|
||||||
import org.apache.nifi.components.resource.StandardResourceReferenceFactory;
|
|
||||||
import org.apache.nifi.components.resource.ResourceType;
|
import org.apache.nifi.components.resource.ResourceType;
|
||||||
import org.apache.nifi.components.resource.StandardResourceDefinition;
|
import org.apache.nifi.components.resource.StandardResourceDefinition;
|
||||||
|
import org.apache.nifi.components.resource.StandardResourceReferenceFactory;
|
||||||
import org.apache.nifi.controller.ControllerService;
|
import org.apache.nifi.controller.ControllerService;
|
||||||
import org.apache.nifi.expression.ExpressionLanguageScope;
|
import org.apache.nifi.expression.ExpressionLanguageScope;
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@ import java.util.Set;
|
||||||
/**
|
/**
|
||||||
* An immutable object for holding information about a type of component
|
* An immutable object for holding information about a type of component
|
||||||
* property.
|
* property.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public final class PropertyDescriptor implements Comparable<PropertyDescriptor> {
|
public final class PropertyDescriptor implements Comparable<PropertyDescriptor> {
|
||||||
|
|
||||||
|
@ -123,15 +122,15 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
this.name = builder.name;
|
this.name = builder.name;
|
||||||
this.description = builder.description;
|
this.description = builder.description;
|
||||||
this.defaultValue = builder.defaultValue;
|
this.defaultValue = builder.defaultValue;
|
||||||
this.allowableValues = builder.allowableValues == null ? null : Collections.unmodifiableList(new ArrayList<>(builder.allowableValues));
|
this.allowableValues = builder.allowableValues == null ? null : List.copyOf(builder.allowableValues);
|
||||||
this.required = builder.required;
|
this.required = builder.required;
|
||||||
this.sensitive = builder.sensitive;
|
this.sensitive = builder.sensitive;
|
||||||
this.dynamic = builder.dynamic;
|
this.dynamic = builder.dynamic;
|
||||||
this.dynamicallyModifiesClasspath = builder.dynamicallyModifiesClasspath;
|
this.dynamicallyModifiesClasspath = builder.dynamicallyModifiesClasspath;
|
||||||
this.expressionLanguageScope = builder.expressionLanguageScope;
|
this.expressionLanguageScope = builder.expressionLanguageScope;
|
||||||
this.controllerServiceDefinition = builder.controllerServiceDefinition;
|
this.controllerServiceDefinition = builder.controllerServiceDefinition;
|
||||||
this.validators = Collections.unmodifiableList(new ArrayList<>(builder.validators));
|
this.validators = List.copyOf(builder.validators);
|
||||||
this.dependencies = builder.dependencies == null ? Collections.emptySet() : Collections.unmodifiableSet(new HashSet<>(builder.dependencies));
|
this.dependencies = builder.dependencies == null ? Collections.emptySet() : Set.copyOf(builder.dependencies);
|
||||||
this.resourceDefinition = builder.resourceDefinition;
|
this.resourceDefinition = builder.resourceDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +147,7 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
* If this descriptor has a set of allowable values then the given value is
|
* If this descriptor has a set of allowable values then the given value is
|
||||||
* only checked against the allowable values.
|
* only checked against the allowable values.
|
||||||
*
|
*
|
||||||
* @param input the value to validate
|
* @param input the value to validate
|
||||||
* @param context the context of validation
|
* @param context the context of validation
|
||||||
* @return the result of validating the input
|
* @return the result of validating the input
|
||||||
*/
|
*/
|
||||||
|
@ -188,15 +187,15 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
final ControllerService service = context.getControllerServiceLookup().getControllerService(input);
|
final ControllerService service = context.getControllerServiceLookup().getControllerService(input);
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
return new ValidationResult.Builder()
|
return new ValidationResult.Builder()
|
||||||
.input(input)
|
.input(input)
|
||||||
.subject(getDisplayName())
|
.subject(getDisplayName())
|
||||||
.valid(false)
|
.valid(false)
|
||||||
.explanation("Property references a Controller Service that does not exist")
|
.explanation("Property references a Controller Service that does not exist")
|
||||||
.build();
|
.build();
|
||||||
} else {
|
} else {
|
||||||
return new ValidationResult.Builder()
|
return new ValidationResult.Builder()
|
||||||
.valid(true)
|
.valid(true)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,15 +292,13 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the initial value and the default value that will be used
|
* Specifies the initial value and the default value that will be used if the user does not specify a value.
|
||||||
* if the user does not specify a value. When {@link #build()} is
|
* <p>
|
||||||
* called, if Allowable Values have been set (see
|
* When {@link #build()} is called, if Allowable Values have been set (see {@link #allowableValues(DescribedValue...)} and overloads)
|
||||||
* {@link #allowableValues(AllowableValue...)}) and this value is not
|
* and this value is not one of those Allowable Values, an Exception will be thrown.
|
||||||
* one of those Allowable Values, an Exception will be thrown. If the
|
* If the Allowable Values have been set, the default value should be set to
|
||||||
* Allowable Values have been set using the
|
* the "Value" of the {@link DescribedValue} object (see {@link DescribedValue#getValue()}).
|
||||||
* {@link #allowableValues(AllowableValue...)} method, the default value
|
* There's an overload available for this (see {@link #defaultValue(DescribedValue)}).
|
||||||
* should be set to the "Value" of the {@link AllowableValue} object
|
|
||||||
* (see {@link AllowableValue#getValue()}).
|
|
||||||
*
|
*
|
||||||
* @param value default value
|
* @param value default value
|
||||||
* @return the builder
|
* @return the builder
|
||||||
|
@ -314,15 +311,12 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the initial value and the default value that will be used
|
* Specifies the initial value and the default value that will be used if the user does not specify a value.
|
||||||
* if the user does not specify a value. When {@link #build()} is
|
* <p>
|
||||||
* called, if Allowable Values have been set (see
|
* Sets the default value to the "Value" of the {@link DescribedValue} object.
|
||||||
* {@link #allowableValues(AllowableValue...)})
|
* When {@link #build()} is called, if Allowable Values have been set (see {@link #allowableValues(DescribedValue...)} and overloads)
|
||||||
* and the "Value" of the {@link DescribedValue} object is not
|
* and this value is not one of those Allowable Values, an Exception will be thrown.
|
||||||
* the "Value" of one of those Allowable Values, an Exception will be thrown.
|
* In case there is not a restricted set of Allowable Values {@link #defaultValue(String)} may be used.
|
||||||
* If the Allowable Values have been set using the
|
|
||||||
* {@link #allowableValues(AllowableValue...)} method, the default value
|
|
||||||
* should be set providing the {@link AllowableValue} to this method.
|
|
||||||
*
|
*
|
||||||
* @param value default value holder
|
* @param value default value holder
|
||||||
* @return the builder
|
* @return the builder
|
||||||
|
@ -331,6 +325,16 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
return defaultValue(value != null ? value.getValue() : null);
|
return defaultValue(value != null ? value.getValue() : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the initial value and default value from this Property.
|
||||||
|
*
|
||||||
|
* @return the builder
|
||||||
|
*/
|
||||||
|
public Builder clearDefaultValue() {
|
||||||
|
this.defaultValue = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder dynamic(final boolean dynamic) {
|
public Builder dynamic(final boolean dynamic) {
|
||||||
this.dynamic = dynamic;
|
this.dynamic = dynamic;
|
||||||
return this;
|
return this;
|
||||||
|
@ -342,17 +346,17 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
* libraries for the given component.
|
* libraries for the given component.
|
||||||
* <p/>
|
* <p/>
|
||||||
* NOTE: If a component contains a PropertyDescriptor where dynamicallyModifiesClasspath is set to true,
|
* NOTE: If a component contains a PropertyDescriptor where dynamicallyModifiesClasspath is set to true,
|
||||||
* the component may also be annotated with @RequiresInstanceClassloading, in which case every class will
|
* the component may also be annotated with @RequiresInstanceClassloading, in which case every class will
|
||||||
* be loaded by a separate InstanceClassLoader for each processor instance.<br/>
|
* be loaded by a separate InstanceClassLoader for each processor instance.<br/>
|
||||||
* It also allows to load native libraries from the extra classpath.
|
* It also allows to load native libraries from the extra classpath.
|
||||||
* <p/>
|
* <p/>
|
||||||
* One can chose to omit the annotation. In this case the loading of native libraries from the extra classpath
|
* One can choose to omit the annotation. In this case the loading of native libraries from the extra classpath
|
||||||
* is not supported.
|
* is not supported.
|
||||||
* Also by default, classes will be loaded by a common NarClassLoader, however it's possible to acquire an
|
* Also by default, classes will be loaded by a common NarClassLoader, however it's possible to acquire an
|
||||||
* InstanceClassLoader by calling Thread.currentThread().getContextClassLoader() which can be used manually
|
* InstanceClassLoader by calling Thread.currentThread().getContextClassLoader() which can be used manually
|
||||||
* to load required classes on an instance-by-instance basis
|
* to load required classes on an instance-by-instance basis
|
||||||
* (by calling {@link Class#forName(String, boolean, ClassLoader)} for example).
|
* (by calling {@link Class#forName(String, boolean, ClassLoader)} for example).
|
||||||
*
|
* <p>
|
||||||
* Any property descriptor that dynamically modifies the classpath should also make use of the {@link #identifiesExternalResource(ResourceCardinality, ResourceType, ResourceType...)} method
|
* Any property descriptor that dynamically modifies the classpath should also make use of the {@link #identifiesExternalResource(ResourceCardinality, ResourceType, ResourceType...)} method
|
||||||
* to indicate that the property descriptor references external resources and optionally restrict which types of resources and how many resources the property allows.
|
* to indicate that the property descriptor references external resources and optionally restrict which types of resources and how many resources the property allows.
|
||||||
*
|
*
|
||||||
|
@ -365,68 +369,99 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param values contrained set of values
|
* Sets the Allowable Values for this Property.
|
||||||
|
*
|
||||||
|
* @param values constrained set of values
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
public Builder allowableValues(final Set<String> values) {
|
public Builder allowableValues(final Set<String> values) {
|
||||||
if (null != values) {
|
if (null != values) {
|
||||||
this.allowableValues = new ArrayList<>();
|
this.allowableValues = values.stream().map(AllowableValue::new).toList();
|
||||||
|
|
||||||
for (final String value : values) {
|
|
||||||
this.allowableValues.add(new AllowableValue(value, value));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Allowable Values for this Property.
|
||||||
|
* <p>
|
||||||
|
* Uses the {@link Enum#name()} of each value as "Value" for the {@link AllowableValue}.
|
||||||
|
* In case the enum value is a {@link DescribedValue}, uses the information provided instead
|
||||||
|
* (see {@link DescribedValue#getValue()}, {@link DescribedValue#getDisplayName()}, {@link DescribedValue#getDescription()}).
|
||||||
|
*
|
||||||
|
* @param values constrained set of values
|
||||||
|
* @return the builder
|
||||||
|
*/
|
||||||
public <E extends Enum<E>> Builder allowableValues(final E[] values) {
|
public <E extends Enum<E>> Builder allowableValues(final E[] values) {
|
||||||
if (null != values) {
|
if (null != values) {
|
||||||
this.allowableValues = new ArrayList<>();
|
this.allowableValues = Arrays.stream(values)
|
||||||
for (final E value : values) {
|
.map(enumValue -> enumValue instanceof DescribedValue describedValue
|
||||||
allowableValues.add(new AllowableValue(value.name(), value.name()));
|
? AllowableValue.fromDescribedValue(describedValue) : new AllowableValue(enumValue.name()))
|
||||||
}
|
.toList();
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores allowable values from an enum class.
|
* Sets the Allowable Values for this Property.
|
||||||
* @param enumClass an enum class that implements the DescribedValue interface and contains a set of values
|
* <p>
|
||||||
* @param <E> generic parameter for an enum class that implements the DescribedValue interface
|
* Uses the {@link Enum#name()} of each value from {@link Class#getEnumConstants()} as "Value" for the {@link AllowableValue}.
|
||||||
|
* In case the enum value is a {@link DescribedValue}, uses the information provided instead
|
||||||
|
* (see {@link DescribedValue#getValue()}, {@link DescribedValue#getDisplayName()}, {@link DescribedValue#getDescription()}).
|
||||||
|
*
|
||||||
|
* @param enumClass an enum class that contains a set of values and optionally implements the DescribedValue interface
|
||||||
|
* @param <E> generic parameter for an enum class, that may implement the DescribedValue interface
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
public <E extends Enum<E> & DescribedValue> Builder allowableValues(final Class<E> enumClass) {
|
public <E extends Enum<E>> Builder allowableValues(final Class<E> enumClass) {
|
||||||
this.allowableValues = new ArrayList<>();
|
return allowableValues(enumClass.getEnumConstants());
|
||||||
for (E enumValue : enumClass.getEnumConstants()) {
|
|
||||||
this.allowableValues.add(new AllowableValue(enumValue.getValue(), enumValue.getDisplayName(), enumValue.getDescription()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores allowable values from a set of enum values.
|
* Sets the Allowable Values for this Property.
|
||||||
* @param enumValues a set of enum values that implements the DescribedValue interface
|
* <p>
|
||||||
* @param <E> generic parameter for the enum values' class that implements the DescribedValue interface
|
* Uses the {@link Enum#name()} of each value of the {@link EnumSet} as "Value" for the {@link AllowableValue}.
|
||||||
|
* In case the enum value is a {@link DescribedValue}, uses the information provided instead
|
||||||
|
* (see {@link DescribedValue#getValue()}, {@link DescribedValue#getDisplayName()}, {@link DescribedValue#getDescription()}).
|
||||||
|
*
|
||||||
|
* @param enumValues an enum set that contains a set of values and optionally implements the DescribedValue interface
|
||||||
|
* @param <E> generic parameter for an enum class, that may implement the DescribedValue interface
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
public <E extends Enum<E> & DescribedValue> Builder allowableValues(final EnumSet<E> enumValues) {
|
public <E extends Enum<E>> Builder allowableValues(final EnumSet<E> enumValues) {
|
||||||
this.allowableValues = new ArrayList<>();
|
if (null != enumValues) {
|
||||||
for (E enumValue : enumValues) {
|
this.allowableValues = enumValues.stream()
|
||||||
this.allowableValues.add(new AllowableValue(enumValue.getValue(), enumValue.getDisplayName(), enumValue.getDescription()));
|
.map(enumValue -> enumValue instanceof DescribedValue describedValue
|
||||||
|
? AllowableValue.fromDescribedValue(describedValue) : new AllowableValue(enumValue.name()))
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Sets the Allowable Values for this Property.
|
||||||
|
*
|
||||||
* @param values constrained set of values
|
* @param values constrained set of values
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
public Builder allowableValues(final String... values) {
|
public Builder allowableValues(final String... values) {
|
||||||
if (null != values) {
|
if (null != values) {
|
||||||
this.allowableValues = new ArrayList<>();
|
this.allowableValues = Arrays.stream(values).map(AllowableValue::new).toList();
|
||||||
for (final String value : values) {
|
}
|
||||||
allowableValues.add(new AllowableValue(value, value));
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Allowable Values for this Property.
|
||||||
|
* <p>
|
||||||
|
* Uses the information provided by each {@link DescribedValue} (see {@link DescribedValue#getValue()}, {@link DescribedValue#getDisplayName()},
|
||||||
|
* {@link DescribedValue#getDescription()}) to populate the {@link AllowableValue}s.
|
||||||
|
*
|
||||||
|
* @param values constrained set of values
|
||||||
|
* @return the builder
|
||||||
|
*/
|
||||||
|
public Builder allowableValues(final DescribedValue... values) {
|
||||||
|
if (null != values) {
|
||||||
|
this.allowableValues = Arrays.stream(values).map(AllowableValue::fromDescribedValue).toList();
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -441,19 +476,6 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the Allowable Values for this Property
|
|
||||||
*
|
|
||||||
* @param values contrained set of values
|
|
||||||
* @return the builder
|
|
||||||
*/
|
|
||||||
public Builder allowableValues(final AllowableValue... values) {
|
|
||||||
if (null != values) {
|
|
||||||
this.allowableValues = Arrays.asList(values);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param required true if yes; false otherwise
|
* @param required true if yes; false otherwise
|
||||||
* @return the builder
|
* @return the builder
|
||||||
|
@ -498,7 +520,7 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
* Service that implements the given interface
|
* Service that implements the given interface
|
||||||
*
|
*
|
||||||
* @param controllerServiceDefinition the interface that is implemented
|
* @param controllerServiceDefinition the interface that is implemented
|
||||||
* by the Controller Service
|
* by the Controller Service
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
public Builder identifiesControllerService(final Class<? extends ControllerService> controllerServiceDefinition) {
|
public Builder identifiesControllerService(final Class<? extends ControllerService> controllerServiceDefinition) {
|
||||||
|
@ -533,12 +555,12 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
* </li>
|
* </li>
|
||||||
* <li>If the ResourceCardinality is MULTIPLE, the given property value may consist of one or more resources, each separted by a comma and optional white space.</li>
|
* <li>If the ResourceCardinality is MULTIPLE, the given property value may consist of one or more resources, each separted by a comma and optional white space.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
* <p>
|
||||||
* Generally, any property descriptor that makes use of the {@link #dynamicallyModifiesClasspath(boolean)} method to dynamically update its classpath should also
|
* Generally, any property descriptor that makes use of the {@link #dynamicallyModifiesClasspath(boolean)} method to dynamically update its classpath should also
|
||||||
* make use of this method, specifying which types of resources are allowed and how many.
|
* make use of this method, specifying which types of resources are allowed and how many.
|
||||||
*
|
*
|
||||||
* @param cardinality specifies how many resources the property should allow
|
* @param cardinality specifies how many resources the property should allow
|
||||||
* @param resourceType the type of resource that is allowed
|
* @param resourceType the type of resource that is allowed
|
||||||
* @param additionalResourceTypes if more than one type of resource is allowed, any resource type in addition to the given resource type may be provided
|
* @param additionalResourceTypes if more than one type of resource is allowed, any resource type in addition to the given resource type may be provided
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
|
@ -558,15 +580,15 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
* Establishes a relationship between this Property and the given property by declaring that this Property is only relevant if the given Property has a non-null value.
|
* Establishes a relationship between this Property and the given property by declaring that this Property is only relevant if the given Property has a non-null value.
|
||||||
* Furthermore, if one or more explicit Allowable Values are provided, this Property will not be relevant unless the given Property's value is equal to one of the given Allowable Values.
|
* Furthermore, if one or more explicit Allowable Values are provided, this Property will not be relevant unless the given Property's value is equal to one of the given Allowable Values.
|
||||||
* If this method is called multiple times, each with a different dependency, then a relationship is established such that this Property is relevant only if all dependencies are satisfied.
|
* If this method is called multiple times, each with a different dependency, then a relationship is established such that this Property is relevant only if all dependencies are satisfied.
|
||||||
*
|
* <p>
|
||||||
* In the case that this property is NOT considered to be relevant (meaning that it depends on a property whose value is not specified, or whose value does not match one of the given
|
* In the case that this property is NOT considered to be relevant (meaning that it depends on a property whose value is not specified, or whose value does not match one of the given
|
||||||
* Allowable Values), the property will not be shown in the component's configuration in the User Interface. Additionally, this property's value will not be considered for
|
* Allowable Values), the property will not be shown in the component's configuration in the User Interface. Additionally, this property's value will not be considered for
|
||||||
* validation. That is, if this property is configured with an invalid value and this property depends on Property Foo, and Property Foo does not have a value set, then the component
|
* validation. That is, if this property is configured with an invalid value and this property depends on Property Foo, and Property Foo does not have a value set, then the component
|
||||||
* will still be valid, because the value of this property is irrelevant.
|
* will still be valid, because the value of this property is irrelevant.
|
||||||
*
|
* <p>
|
||||||
* If the given property is not relevant (because its dependencies are not satisfied), this property is also considered not to be valid.
|
* If the given property is not relevant (because its dependencies are not satisfied), this property is also considered not to be valid.
|
||||||
*
|
*
|
||||||
* @param property the property that must be set in order for this property to become relevant
|
* @param property the property that must be set in order for this property to become relevant
|
||||||
* @param dependentValues the possible values for the given property for which this Property is relevant
|
* @param dependentValues the possible values for the given property for which this Property is relevant
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
|
@ -593,16 +615,16 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
* Establishes a relationship between this Property and the given property by declaring that this Property is only relevant if the given Property has a value equal to one of the given
|
* Establishes a relationship between this Property and the given property by declaring that this Property is only relevant if the given Property has a value equal to one of the given
|
||||||
* <code>String</code> arguments.
|
* <code>String</code> arguments.
|
||||||
* If this method is called multiple times, each with a different dependency, then a relationship is established such that this Property is relevant only if all dependencies are satisfied.
|
* If this method is called multiple times, each with a different dependency, then a relationship is established such that this Property is relevant only if all dependencies are satisfied.
|
||||||
*
|
* <p>
|
||||||
* In the case that this property is NOT considered to be relevant (meaning that it depends on a property whose value is not specified, or whose value does not match one of the given
|
* In the case that this property is NOT considered to be relevant (meaning that it depends on a property whose value is not specified, or whose value does not match one of the given
|
||||||
* Allowable Values), the property will not be shown in the component's configuration in the User Interface. Additionally, this property's value will not be considered for
|
* Allowable Values), the property will not be shown in the component's configuration in the User Interface. Additionally, this property's value will not be considered for
|
||||||
* validation. That is, if this property is configured with an invalid value and this property depends on Property Foo, and Property Foo does not have a value set, then the component
|
* validation. That is, if this property is configured with an invalid value and this property depends on Property Foo, and Property Foo does not have a value set, then the component
|
||||||
* will still be valid, because the value of this property is irrelevant.
|
* will still be valid, because the value of this property is irrelevant.
|
||||||
*
|
* <p>
|
||||||
* If the given property is not relevant (because its dependencies are not satisfied), this property is also considered not to be valid.
|
* If the given property is not relevant (because its dependencies are not satisfied), this property is also considered not to be valid.
|
||||||
*
|
*
|
||||||
* @param property the property that must be set in order for this property to become relevant
|
* @param property the property that must be set in order for this property to become relevant
|
||||||
* @param firstDependentValue the first value for the given property for which this Property is relevant
|
* @param firstDependentValue the first value for the given property for which this Property is relevant
|
||||||
* @param additionalDependentValues any other values for the given property for which this Property is relevant
|
* @param additionalDependentValues any other values for the given property for which this Property is relevant
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
|
@ -621,25 +643,25 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
* Establishes a relationship between this Property and the given property by declaring that this Property is only relevant if the given Property has a value equal to one of the given
|
* Establishes a relationship between this Property and the given property by declaring that this Property is only relevant if the given Property has a value equal to one of the given
|
||||||
* {@link DescribedValue} arguments.
|
* {@link DescribedValue} arguments.
|
||||||
* If this method is called multiple times, each with a different dependency, then a relationship is established such that this Property is relevant only if all dependencies are satisfied.
|
* If this method is called multiple times, each with a different dependency, then a relationship is established such that this Property is relevant only if all dependencies are satisfied.
|
||||||
*
|
* <p>
|
||||||
* In the case that this property is NOT considered to be relevant (meaning that it depends on a property whose value is not specified, or whose value does not match one of the given
|
* In the case that this property is NOT considered to be relevant (meaning that it depends on a property whose value is not specified, or whose value does not match one of the given
|
||||||
* Described Values), the property will not be shown in the component's configuration in the User Interface. Additionally, this property's value will not be considered for
|
* Described Values), the property will not be shown in the component's configuration in the User Interface. Additionally, this property's value will not be considered for
|
||||||
* validation. That is, if this property is configured with an invalid value and this property depends on Property Foo, and Property Foo does not have a value set, then the component
|
* validation. That is, if this property is configured with an invalid value and this property depends on Property Foo, and Property Foo does not have a value set, then the component
|
||||||
* will still be valid, because the value of this property is irrelevant.
|
* will still be valid, because the value of this property is irrelevant.
|
||||||
*
|
* <p>
|
||||||
* If the given property is not relevant (because its dependencies are not satisfied), this property is also considered not to be valid.
|
* If the given property is not relevant (because its dependencies are not satisfied), this property is also considered not to be valid.
|
||||||
*
|
*
|
||||||
* @param property the property that must be set in order for this property to become relevant
|
* @param property the property that must be set in order for this property to become relevant
|
||||||
* @param firstDependentValue the first value for the given property for which this Property is relevant
|
* @param firstDependentValue the first value for the given property for which this Property is relevant
|
||||||
* @param additionalDependentValues any other values for the given property for which this Property is relevant
|
* @param additionalDependentValues any other values for the given property for which this Property is relevant
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
public Builder dependsOn(final PropertyDescriptor property, final DescribedValue firstDependentValue, final DescribedValue... additionalDependentValues) {
|
public Builder dependsOn(final PropertyDescriptor property, final DescribedValue firstDependentValue, final DescribedValue... additionalDependentValues) {
|
||||||
final AllowableValue[] dependentValues = new AllowableValue[additionalDependentValues.length + 1];
|
final AllowableValue[] dependentValues = new AllowableValue[additionalDependentValues.length + 1];
|
||||||
dependentValues[0] = toAllowableValue(firstDependentValue);
|
dependentValues[0] = AllowableValue.fromDescribedValue(firstDependentValue);
|
||||||
int i = 1;
|
int i = 1;
|
||||||
for (final DescribedValue additionalDependentValue : additionalDependentValues) {
|
for (final DescribedValue additionalDependentValue : additionalDependentValues) {
|
||||||
dependentValues[i++] = toAllowableValue(additionalDependentValue);
|
dependentValues[i++] = AllowableValue.fromDescribedValue(additionalDependentValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dependsOn(property, dependentValues);
|
return dependsOn(property, dependentValues);
|
||||||
|
@ -655,16 +677,11 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AllowableValue toAllowableValue(DescribedValue describedValue) {
|
|
||||||
return new AllowableValue(describedValue.getValue(), describedValue.getDisplayName(), describedValue.getDescription());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a PropertyDescriptor as configured
|
* @return a PropertyDescriptor as configured
|
||||||
*
|
|
||||||
* @throws IllegalStateException if allowable values are configured but
|
* @throws IllegalStateException if allowable values are configured but
|
||||||
* no default value is set, or the default value is not contained within
|
* no default value is set, or the default value is not contained within
|
||||||
* the allowable values.
|
* the allowable values.
|
||||||
*/
|
*/
|
||||||
public PropertyDescriptor build() {
|
public PropertyDescriptor build() {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
|
@ -740,18 +757,14 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object other) {
|
public boolean equals(final Object other) {
|
||||||
if (other == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(other instanceof PropertyDescriptor)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (this == other) {
|
if (this == other) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (other instanceof PropertyDescriptor otherPropertyDescriptor) {
|
||||||
|
return this.name.equals(otherPropertyDescriptor.name);
|
||||||
|
}
|
||||||
|
|
||||||
final PropertyDescriptor desc = (PropertyDescriptor) other;
|
return false;
|
||||||
return this.name.equals(desc.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -768,7 +781,7 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
|
|
||||||
private static final String POSITIVE_EXPLANATION = "Given value found in allowed set";
|
private static final String POSITIVE_EXPLANATION = "Given value found in allowed set";
|
||||||
private static final String NEGATIVE_EXPLANATION = "Given value not found in allowed set '%1$s'";
|
private static final String NEGATIVE_EXPLANATION = "Given value not found in allowed set '%1$s'";
|
||||||
private static final String VALUE_DEMARCATOR = ", ";
|
private static final String VALUE_DELIMITER = ", ";
|
||||||
private final String validStrings;
|
private final String validStrings;
|
||||||
private final Collection<String> validValues;
|
private final Collection<String> validValues;
|
||||||
|
|
||||||
|
@ -780,20 +793,8 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
* @throws NullPointerException if the given validValues is null
|
* @throws NullPointerException if the given validValues is null
|
||||||
*/
|
*/
|
||||||
private ConstrainedSetValidator(final Collection<AllowableValue> validValues) {
|
private ConstrainedSetValidator(final Collection<AllowableValue> validValues) {
|
||||||
String validVals = "";
|
this.validValues = validValues.stream().map(AllowableValue::getValue).toList();
|
||||||
if (!validValues.isEmpty()) {
|
this.validStrings = String.join(VALUE_DELIMITER, this.validValues);
|
||||||
final StringBuilder valuesBuilder = new StringBuilder();
|
|
||||||
for (final AllowableValue value : validValues) {
|
|
||||||
valuesBuilder.append(value).append(VALUE_DEMARCATOR);
|
|
||||||
}
|
|
||||||
validVals = valuesBuilder.substring(0, valuesBuilder.length() - VALUE_DEMARCATOR.length());
|
|
||||||
}
|
|
||||||
validStrings = validVals;
|
|
||||||
|
|
||||||
this.validValues = new ArrayList<>(validValues.size());
|
|
||||||
for (final AllowableValue value : validValues) {
|
|
||||||
this.validValues.add(value.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -824,13 +825,13 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
@Override
|
@Override
|
||||||
public ValidationResult validate(final String subject, final String configuredInput, final ValidationContext context) {
|
public ValidationResult validate(final String subject, final String configuredInput, final ValidationContext context) {
|
||||||
final ValidationResult.Builder resultBuilder = new ValidationResult.Builder()
|
final ValidationResult.Builder resultBuilder = new ValidationResult.Builder()
|
||||||
.input(configuredInput)
|
.input(configuredInput)
|
||||||
.subject(subject);
|
.subject(subject);
|
||||||
|
|
||||||
if (configuredInput == null) {
|
if (configuredInput == null) {
|
||||||
return resultBuilder.valid(false)
|
return resultBuilder.valid(false)
|
||||||
.explanation("No value specified")
|
.explanation("No value specified")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Expression Language is supported and is used in the property value, we cannot perform validation against the configured
|
// If Expression Language is supported and is used in the property value, we cannot perform validation against the configured
|
||||||
|
@ -843,8 +844,8 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
resultBuilder.input(input);
|
resultBuilder.input(input);
|
||||||
} else {
|
} else {
|
||||||
return resultBuilder.valid(true)
|
return resultBuilder.valid(true)
|
||||||
.explanation("Expression Language is present, so validation of property value cannot be performed")
|
.explanation("Expression Language is present, so validation of property value cannot be performed")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,15 +855,15 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
final boolean allowsText = resourceDefinition.getResourceTypes().contains(ResourceType.TEXT);
|
final boolean allowsText = resourceDefinition.getResourceTypes().contains(ResourceType.TEXT);
|
||||||
if (allowsText) {
|
if (allowsText) {
|
||||||
return resultBuilder.valid(true)
|
return resultBuilder.valid(true)
|
||||||
.explanation("Property allows for Resource Type of Text, so validation of property value cannot be performed")
|
.explanation("Property allows for Resource Type of Text, so validation of property value cannot be performed")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
final String[] splits = input.split(",");
|
final String[] splits = input.split(",");
|
||||||
if (resourceDefinition.getCardinality() == ResourceCardinality.SINGLE && splits.length > 1) {
|
if (resourceDefinition.getCardinality() == ResourceCardinality.SINGLE && splits.length > 1) {
|
||||||
return resultBuilder.valid(false)
|
return resultBuilder.valid(false)
|
||||||
.explanation("Property only supports a single Resource but " + splits.length + " resources were specified")
|
.explanation("Property only supports a single Resource but " + splits.length + " resources were specified")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
final Set<ResourceType> resourceTypes = resourceDefinition.getResourceTypes();
|
final Set<ResourceType> resourceTypes = resourceDefinition.getResourceTypes();
|
||||||
|
@ -885,25 +886,25 @@ public final class PropertyDescriptor implements Comparable<PropertyDescriptor>
|
||||||
|
|
||||||
if (!resourceTypes.contains(resourceReference.getResourceType())) {
|
if (!resourceTypes.contains(resourceReference.getResourceType())) {
|
||||||
return resultBuilder.valid(false)
|
return resultBuilder.valid(false)
|
||||||
.explanation("Specified Resource is a " + resourceReference.getResourceType().name() + " but this property does not allow this type of resource")
|
.explanation("Specified Resource is a " + resourceReference.getResourceType().name() + " but this property does not allow this type of resource")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
return resultBuilder.valid(false)
|
return resultBuilder.valid(false)
|
||||||
.explanation("No resources were specified")
|
.explanation("No resources were specified")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nonExistentResources.isEmpty()) {
|
if (!nonExistentResources.isEmpty()) {
|
||||||
return resultBuilder.valid(false)
|
return resultBuilder.valid(false)
|
||||||
.explanation("The specified resource(s) do not exist or could not be accessed: " + nonExistentResources)
|
.explanation("The specified resource(s) do not exist or could not be accessed: " + nonExistentResources)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultBuilder.valid(true)
|
return resultBuilder.valid(true)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.components;
|
package org.apache.nifi.components;
|
||||||
|
|
||||||
public enum EnumAllowableValue implements DescribedValue {
|
public enum EnumDescribedValue implements DescribedValue {
|
||||||
|
|
||||||
GREEN {
|
GREEN {
|
||||||
@Override
|
@Override
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.nifi.components;
|
||||||
|
|
||||||
|
public enum EnumNotDescribedValue {
|
||||||
|
GREEN, RED, BLUE;
|
||||||
|
}
|
|
@ -20,17 +20,16 @@ import org.apache.nifi.components.PropertyDescriptor.Builder;
|
||||||
import org.apache.nifi.components.resource.ResourceCardinality;
|
import org.apache.nifi.components.resource.ResourceCardinality;
|
||||||
import org.apache.nifi.components.resource.ResourceType;
|
import org.apache.nifi.components.resource.ResourceType;
|
||||||
import org.apache.nifi.expression.ExpressionLanguageScope;
|
import org.apache.nifi.expression.ExpressionLanguageScope;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
@ -40,77 +39,180 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
|
||||||
/**
|
|
||||||
* Regression test for issue NIFI-49, to ensure that if a Processor's Property's
|
|
||||||
* Default Value is not allowed, the Exception thrown should indicate what the
|
|
||||||
* default value is
|
|
||||||
*/
|
|
||||||
public class TestPropertyDescriptor {
|
public class TestPropertyDescriptor {
|
||||||
|
|
||||||
private static Builder invalidDescriptorBuilder;
|
|
||||||
private static Builder validDescriptorBuilder;
|
|
||||||
private static final String DEFAULT_VALUE = "Default Value";
|
private static final String DEFAULT_VALUE = "Default Value";
|
||||||
private static final String DEPENDENT_PROPERTY_NAME = "dependentProperty";
|
private static final String DEPENDENT_PROPERTY_NAME = "dependentProperty";
|
||||||
|
|
||||||
@BeforeAll
|
@Nested
|
||||||
public static void setUp() {
|
class RegardingDefaultValue {
|
||||||
validDescriptorBuilder = new PropertyDescriptor.Builder().name("").allowableValues("Allowable Value", "Another Allowable Value").defaultValue("Allowable Value");
|
@Test
|
||||||
invalidDescriptorBuilder = new PropertyDescriptor.Builder().name("").allowableValues("Allowable Value", "Another Allowable Value").defaultValue(DEFAULT_VALUE);
|
void supportsStringValues() {
|
||||||
|
final PropertyDescriptor descriptor = builder().defaultValue(DEFAULT_VALUE).build();
|
||||||
|
|
||||||
|
assertEquals(DEFAULT_VALUE, descriptor.getDefaultValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void supportsDescribedValuesValues() {
|
||||||
|
final PropertyDescriptor descriptor = builder().defaultValue(EnumDescribedValue.GREEN).build();
|
||||||
|
|
||||||
|
assertEquals(EnumDescribedValue.GREEN.getValue(), descriptor.getDefaultValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regression test for issue NIFI-49, to ensure that if a Processor's Property's
|
||||||
|
* Default Value is not allowed, the Exception thrown should indicate what the default value is
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void throwsIllegalStateExceptionWhenDefaultValueNotInAllowableValues() {
|
||||||
|
IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
|
||||||
|
builder().allowableValues("NOT DEFAULT", "OTHER NOT DEFAULT").defaultValue(DEFAULT_VALUE).build();
|
||||||
|
});
|
||||||
|
assertTrue(exception.getMessage().contains("[" + DEFAULT_VALUE + "]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canBeCleared() {
|
||||||
|
final PropertyDescriptor descriptorWithDefault = builder().defaultValue(DEFAULT_VALUE).build();
|
||||||
|
final PropertyDescriptor resetDescriptor = builder(descriptorWithDefault).clearDefaultValue().build();
|
||||||
|
|
||||||
|
assertNull(resetDescriptor.getDefaultValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Nested
|
||||||
void testExceptionThrownByDescriptorWithInvalidDefaultValue() {
|
class RegardingAllowableValues {
|
||||||
IllegalStateException exception = assertThrows(IllegalStateException.class, () -> invalidDescriptorBuilder.build());
|
|
||||||
assertTrue(exception.getMessage().contains("[" + DEFAULT_VALUE + "]") );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
private static final Comparator<AllowableValue> allowableValueComparator = Comparator.comparing(AllowableValue::getValue);
|
||||||
void testNoExceptionThrownByPropertyDescriptorWithValidDefaultValue() {
|
private final List<AllowableValue> expectedMinimalAllowableValues =
|
||||||
assertNotNull(validDescriptorBuilder.build());
|
List.of(new AllowableValue("GREEN"), new AllowableValue("RED"), new AllowableValue("BLUE"));
|
||||||
}
|
private final List<AllowableValue> expectedAllowableValuesWithDescription =
|
||||||
|
Arrays.stream(EnumDescribedValue.values()).map(AllowableValue::fromDescribedValue).toList();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testDefaultValueWithDescribedValue() {
|
void supportsStringVarArgValues() {
|
||||||
final PropertyDescriptor propertyDescriptor = new PropertyDescriptor.Builder()
|
final List<AllowableValue> expected = expectedMinimalAllowableValues;
|
||||||
.name("defaultDescribedValueDescriptor")
|
|
||||||
.defaultValue(EnumAllowableValue.GREEN)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
assertNotNull(propertyDescriptor);
|
final PropertyDescriptor descriptor = builder().allowableValues("GREEN", "RED", "BLUE").build();
|
||||||
assertEquals(EnumAllowableValue.GREEN.getValue(), propertyDescriptor.getDefaultValue());
|
final List<AllowableValue> actual = descriptor.getAllowableValues();
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
assertEquals(expected, actual); // equals only compares getValue()
|
||||||
void testAllowableValuesWithEnumClass() {
|
assertEquals(displayNamesOf(expected), displayNamesOf(actual));
|
||||||
final PropertyDescriptor propertyDescriptor = new PropertyDescriptor.Builder()
|
assertEquals(descriptionsOf(expected), descriptionsOf(actual));
|
||||||
.name("enumAllowableValueDescriptor")
|
}
|
||||||
.allowableValues(EnumAllowableValue.class)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
assertNotNull(propertyDescriptor);
|
@Test
|
||||||
|
void supportsStringSetValues() {
|
||||||
|
final List<AllowableValue> expected = sort(expectedMinimalAllowableValues);
|
||||||
|
|
||||||
final List<AllowableValue> expectedAllowableValues = Arrays.stream(EnumAllowableValue.values())
|
final PropertyDescriptor descriptor = builder().allowableValues(Set.of("GREEN", "RED", "BLUE")).build();
|
||||||
.map(enumValue -> new AllowableValue(enumValue.getValue(), enumValue.getDisplayName(), enumValue.getDescription()))
|
// the iteration order of sets is not guaranteed by all implementations, thus we unify the order here
|
||||||
.collect(Collectors.toList());
|
final List<AllowableValue> actual = sort(descriptor.getAllowableValues());
|
||||||
assertEquals(expectedAllowableValues, propertyDescriptor.getAllowableValues());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
assertEquals(expected, actual); // equals only compares getValue()
|
||||||
void testAllowableValuesWithEnumSet() {
|
assertEquals(displayNamesOf(expected), displayNamesOf(actual));
|
||||||
final PropertyDescriptor propertyDescriptor = new PropertyDescriptor.Builder()
|
assertEquals(descriptionsOf(expected), descriptionsOf(actual));
|
||||||
.name("enumAllowableValueDescriptor")
|
}
|
||||||
.allowableValues(EnumSet.of(
|
|
||||||
EnumAllowableValue.GREEN,
|
|
||||||
EnumAllowableValue.BLUE
|
|
||||||
))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
assertNotNull(propertyDescriptor);
|
@Test
|
||||||
|
void supportsEnumArrayValues() {
|
||||||
|
final List<AllowableValue> expected = expectedMinimalAllowableValues;
|
||||||
|
|
||||||
final List<AllowableValue> expectedAllowableValues = Stream.of(EnumAllowableValue.GREEN, EnumAllowableValue.BLUE)
|
final PropertyDescriptor descriptor = builder().allowableValues(EnumNotDescribedValue.values()).build();
|
||||||
.map(enumValue -> new AllowableValue(enumValue.getValue(), enumValue.getDisplayName(), enumValue.getDescription()))
|
final List<AllowableValue> actual = descriptor.getAllowableValues();
|
||||||
.collect(Collectors.toList());
|
|
||||||
assertEquals(expectedAllowableValues, propertyDescriptor.getAllowableValues());
|
assertEquals(expected, actual); // equals only compares getValue()
|
||||||
|
assertEquals(displayNamesOf(expected), displayNamesOf(actual));
|
||||||
|
assertEquals(descriptionsOf(expected), descriptionsOf(actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
void supportsDescribedValueEnumArrayValues() {
|
||||||
|
final List<AllowableValue> expected = expectedAllowableValuesWithDescription;
|
||||||
|
|
||||||
|
final Enum[] enumArray = EnumDescribedValue.values();
|
||||||
|
final PropertyDescriptor descriptor = builder().allowableValues(enumArray).build();
|
||||||
|
final List<AllowableValue> actual = descriptor.getAllowableValues();
|
||||||
|
|
||||||
|
assertEquals(expected, actual); // equals only compares getValue()
|
||||||
|
assertEquals(displayNamesOf(expected), displayNamesOf(actual));
|
||||||
|
assertEquals(descriptionsOf(expected), descriptionsOf(actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void supportsEnumClassValues() {
|
||||||
|
final List<AllowableValue> expected = expectedMinimalAllowableValues;
|
||||||
|
|
||||||
|
final PropertyDescriptor descriptor = builder().allowableValues(EnumNotDescribedValue.class).build();
|
||||||
|
final List<AllowableValue> actual = descriptor.getAllowableValues();
|
||||||
|
|
||||||
|
assertEquals(expected, actual); // equals only compares getValue()
|
||||||
|
assertEquals(displayNamesOf(expected), displayNamesOf(actual));
|
||||||
|
assertEquals(descriptionsOf(expected), descriptionsOf(actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void supportsDescribedValueEnumClassValues() {
|
||||||
|
final List<AllowableValue> expected = expectedAllowableValuesWithDescription;
|
||||||
|
|
||||||
|
final PropertyDescriptor descriptor = builder().allowableValues(EnumDescribedValue.class).build();
|
||||||
|
final List<AllowableValue> actual = descriptor.getAllowableValues();
|
||||||
|
|
||||||
|
assertEquals(expected, actual); // equals only compares getValue()
|
||||||
|
assertEquals(displayNamesOf(expected), displayNamesOf(actual));
|
||||||
|
assertEquals(descriptionsOf(expected), descriptionsOf(actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void supportsEnumSetValues() {
|
||||||
|
final List<AllowableValue> expected = expectedMinimalAllowableValues;
|
||||||
|
|
||||||
|
final PropertyDescriptor descriptor = builder().allowableValues(EnumSet.allOf(EnumNotDescribedValue.class)).build();
|
||||||
|
final List<AllowableValue> actual = descriptor.getAllowableValues();
|
||||||
|
|
||||||
|
assertEquals(expected, actual); // equals only compares getValue()
|
||||||
|
assertEquals(displayNamesOf(expected), displayNamesOf(actual));
|
||||||
|
assertEquals(descriptionsOf(expected), descriptionsOf(actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void supportsDescribedValueEnumSetValues() {
|
||||||
|
final List<AllowableValue> expected = expectedAllowableValuesWithDescription;
|
||||||
|
|
||||||
|
final PropertyDescriptor descriptor = builder().allowableValues(EnumSet.allOf(EnumDescribedValue.class)).build();
|
||||||
|
final List<AllowableValue> actual = descriptor.getAllowableValues();
|
||||||
|
|
||||||
|
assertEquals(expected, actual); // equals only compares getValue()
|
||||||
|
assertEquals(displayNamesOf(expected), displayNamesOf(actual));
|
||||||
|
assertEquals(descriptionsOf(expected), descriptionsOf(actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void supportsDescribedValueVarArgValues() {
|
||||||
|
final List<AllowableValue> expected = expectedAllowableValuesWithDescription;
|
||||||
|
|
||||||
|
final PropertyDescriptor descriptor = builder()
|
||||||
|
.allowableValues(EnumDescribedValue.GREEN, EnumDescribedValue.RED, EnumDescribedValue.BLUE).build();
|
||||||
|
final List<AllowableValue> actual = descriptor.getAllowableValues();
|
||||||
|
|
||||||
|
assertEquals(expected, actual); // equals only compares getValue()
|
||||||
|
assertEquals(displayNamesOf(expected), displayNamesOf(actual));
|
||||||
|
assertEquals(descriptionsOf(expected), descriptionsOf(actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<AllowableValue> sort(final List<AllowableValue> allowableValues) {
|
||||||
|
return allowableValues.stream().sorted(allowableValueComparator).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> displayNamesOf(final List<AllowableValue> allowableValues) {
|
||||||
|
return allowableValues.stream().map(AllowableValue::getDisplayName).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> descriptionsOf(final List<AllowableValue> allowableValues) {
|
||||||
|
return allowableValues.stream().map(AllowableValue::getDescription).toList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -121,7 +223,7 @@ public class TestPropertyDescriptor {
|
||||||
|
|
||||||
final PropertyDescriptor propertyDescriptor = new PropertyDescriptor.Builder()
|
final PropertyDescriptor propertyDescriptor = new PropertyDescriptor.Builder()
|
||||||
.name("enumDependsOnDescriptor")
|
.name("enumDependsOnDescriptor")
|
||||||
.dependsOn(dependentPropertyDescriptor, EnumAllowableValue.RED)
|
.dependsOn(dependentPropertyDescriptor, EnumDescribedValue.RED)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
assertNotNull(propertyDescriptor);
|
assertNotNull(propertyDescriptor);
|
||||||
|
@ -133,17 +235,17 @@ public class TestPropertyDescriptor {
|
||||||
final Set<String> dependentValues = dependency.getDependentValues();
|
final Set<String> dependentValues = dependency.getDependentValues();
|
||||||
assertEquals(1, dependentValues.size());
|
assertEquals(1, dependentValues.size());
|
||||||
final String dependentValue = dependentValues.iterator().next();
|
final String dependentValue = dependentValues.iterator().next();
|
||||||
assertEquals(EnumAllowableValue.RED.getValue(), dependentValue);
|
assertEquals(EnumDescribedValue.RED.getValue(), dependentValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testExternalResourceIgnoredIfELWithAttributesPresent() {
|
void testExternalResourceIgnoredIfELWithAttributesPresent() {
|
||||||
final PropertyDescriptor descriptor = new PropertyDescriptor.Builder()
|
final PropertyDescriptor descriptor = new PropertyDescriptor.Builder()
|
||||||
.name("dir")
|
.name("dir")
|
||||||
.identifiesExternalResource(ResourceCardinality.SINGLE, ResourceType.FILE)
|
.identifiesExternalResource(ResourceCardinality.SINGLE, ResourceType.FILE)
|
||||||
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
|
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
|
||||||
.required(false)
|
.required(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final ValidationContext validationContext = Mockito.mock(ValidationContext.class);
|
final ValidationContext validationContext = Mockito.mock(ValidationContext.class);
|
||||||
Mockito.when(validationContext.isExpressionLanguagePresent(anyString())).thenReturn(true);
|
Mockito.when(validationContext.isExpressionLanguagePresent(anyString())).thenReturn(true);
|
||||||
|
@ -159,11 +261,11 @@ public class TestPropertyDescriptor {
|
||||||
@Test
|
@Test
|
||||||
void testExternalResourceConsideredIfELVarRegistryPresent() {
|
void testExternalResourceConsideredIfELVarRegistryPresent() {
|
||||||
final PropertyDescriptor descriptor = new PropertyDescriptor.Builder()
|
final PropertyDescriptor descriptor = new PropertyDescriptor.Builder()
|
||||||
.name("dir")
|
.name("dir")
|
||||||
.identifiesExternalResource(ResourceCardinality.SINGLE, ResourceType.FILE, ResourceType.DIRECTORY)
|
.identifiesExternalResource(ResourceCardinality.SINGLE, ResourceType.FILE, ResourceType.DIRECTORY)
|
||||||
.expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT)
|
.expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT)
|
||||||
.required(false)
|
.required(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final AtomicReference<String> variable = new AtomicReference<>("__my_var__");
|
final AtomicReference<String> variable = new AtomicReference<>("__my_var__");
|
||||||
final ValidationContext validationContext = Mockito.mock(ValidationContext.class);
|
final ValidationContext validationContext = Mockito.mock(ValidationContext.class);
|
||||||
|
@ -190,9 +292,9 @@ public class TestPropertyDescriptor {
|
||||||
// Consider if Expression Language is not supported.
|
// Consider if Expression Language is not supported.
|
||||||
Mockito.when(validationContext.isExpressionLanguageSupported(anyString())).thenReturn(false);
|
Mockito.when(validationContext.isExpressionLanguageSupported(anyString())).thenReturn(false);
|
||||||
final PropertyDescriptor withElNotAllowed = new PropertyDescriptor.Builder()
|
final PropertyDescriptor withElNotAllowed = new PropertyDescriptor.Builder()
|
||||||
.fromPropertyDescriptor(descriptor)
|
.fromPropertyDescriptor(descriptor)
|
||||||
.expressionLanguageSupported(ExpressionLanguageScope.NONE)
|
.expressionLanguageSupported(ExpressionLanguageScope.NONE)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Expression will not be evaluated, so the directory being looked at will literally be ${TestPropertyDescriptor.Var1}
|
// Expression will not be evaluated, so the directory being looked at will literally be ${TestPropertyDescriptor.Var1}
|
||||||
assertFalse(withElNotAllowed.validate("${TestPropertyDescriptor.Var1}", validationContext).isValid());
|
assertFalse(withElNotAllowed.validate("${TestPropertyDescriptor.Var1}", validationContext).isValid());
|
||||||
|
@ -232,4 +334,12 @@ public class TestPropertyDescriptor {
|
||||||
assertTrue(pd2.getDependencies().isEmpty());
|
assertTrue(pd2.getDependencies().isEmpty());
|
||||||
assertNull(pd2.getAllowableValues());
|
assertNull(pd2.getAllowableValues());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Builder builder() {
|
||||||
|
return new PropertyDescriptor.Builder().name("propertyName");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Builder builder(final PropertyDescriptor propertyDescriptor) {
|
||||||
|
return new PropertyDescriptor.Builder().fromPropertyDescriptor(propertyDescriptor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue