exceptionfactory commented on code in PR #10327:
URL: https://github.com/apache/nifi/pull/10327#discussion_r2369816063
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -547,4 +577,302 @@ private static boolean isParameterContextChange(final
FlowDifference flowDiffere
private static boolean isLogFileSuffixChange(final FlowDifference
flowDifference) {
return flowDifference.getDifferenceType() ==
DifferenceType.LOG_FILE_SUFFIX_CHANGED;
}
+
+ public static EnvironmentalChangeContext
buildEnvironmentalChangeContext(final Collection<FlowDifference> differences,
final FlowManager flowManager) {
+ if (differences == null || differences.isEmpty() || flowManager ==
null) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ final Set<String> serviceIdsReferencedByNewProperties = new
HashSet<>();
+ final Map<String, List<PropertyDiffInfo>> parameterizedAddsByComponent
= new HashMap<>();
+ final Map<String, List<PropertyDiffInfo>>
parameterizationRemovalsByComponent = new HashMap<>();
+
+ for (final FlowDifference difference : differences) {
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_ADDED) {
+ final ComponentNode componentNode =
Optional.ofNullable(getComponent(flowManager, difference.getComponentB()))
+ .orElseGet(() -> getComponent(flowManager,
difference.getComponentA()));
+ if (componentNode != null) {
+ final Optional<String> fieldNameOptional =
difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final PropertyDescriptor propertyDescriptor =
componentNode.getPropertyDescriptor(fieldNameOptional.get());
+ if (propertyDescriptor != null &&
!propertyDescriptor.isDynamic() &&
propertyDescriptor.getControllerServiceDefinition() != null) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+
serviceIdsReferencedByNewProperties.add((String) valueB);
+ }
+ }
+ }
+ }
+ }
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED
+ || difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZATION_REMOVED) {
+
+ final Optional<String> propertyNameOptional =
difference.getFieldName();
+ final Optional<String> componentIdOptional =
getComponentInstanceIdentifier(difference);
+
+ if (!propertyNameOptional.isPresent() ||
!componentIdOptional.isPresent()) {
+ continue;
+ }
+
+ final String componentId = componentIdOptional.get();
+ final Optional<String> propertyValue =
difference.getDifferenceType() == DifferenceType.PROPERTY_PARAMETERIZED
+ ? getParameterReferenceValue(difference, false)
+ : getParameterReferenceValue(difference, true);
+
+ final PropertyDiffInfo diffInfo = new
PropertyDiffInfo(propertyValue, difference);
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED) {
+ parameterizedAddsByComponent.computeIfAbsent(componentId,
key -> new ArrayList<>()).add(diffInfo);
+ } else {
+
parameterizationRemovalsByComponent.computeIfAbsent(componentId, key -> new
ArrayList<>()).add(diffInfo);
+ }
+ }
+ }
+
+ Set<String> serviceIdsWithMatchingAdditions = Collections.emptySet();
+ if (!serviceIdsReferencedByNewProperties.isEmpty()) {
+ serviceIdsWithMatchingAdditions = differences.stream()
Review Comment:
I recommend declaring the Set `final` and setting it in an `else` block.
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -547,4 +577,302 @@ private static boolean isParameterContextChange(final
FlowDifference flowDiffere
private static boolean isLogFileSuffixChange(final FlowDifference
flowDifference) {
return flowDifference.getDifferenceType() ==
DifferenceType.LOG_FILE_SUFFIX_CHANGED;
}
+
+ public static EnvironmentalChangeContext
buildEnvironmentalChangeContext(final Collection<FlowDifference> differences,
final FlowManager flowManager) {
+ if (differences == null || differences.isEmpty() || flowManager ==
null) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ final Set<String> serviceIdsReferencedByNewProperties = new
HashSet<>();
+ final Map<String, List<PropertyDiffInfo>> parameterizedAddsByComponent
= new HashMap<>();
+ final Map<String, List<PropertyDiffInfo>>
parameterizationRemovalsByComponent = new HashMap<>();
+
+ for (final FlowDifference difference : differences) {
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_ADDED) {
+ final ComponentNode componentNode =
Optional.ofNullable(getComponent(flowManager, difference.getComponentB()))
+ .orElseGet(() -> getComponent(flowManager,
difference.getComponentA()));
+ if (componentNode != null) {
+ final Optional<String> fieldNameOptional =
difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final PropertyDescriptor propertyDescriptor =
componentNode.getPropertyDescriptor(fieldNameOptional.get());
+ if (propertyDescriptor != null &&
!propertyDescriptor.isDynamic() &&
propertyDescriptor.getControllerServiceDefinition() != null) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+
serviceIdsReferencedByNewProperties.add((String) valueB);
+ }
+ }
+ }
+ }
+ }
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED
+ || difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZATION_REMOVED) {
+
+ final Optional<String> propertyNameOptional =
difference.getFieldName();
+ final Optional<String> componentIdOptional =
getComponentInstanceIdentifier(difference);
+
+ if (!propertyNameOptional.isPresent() ||
!componentIdOptional.isPresent()) {
Review Comment:
The negated `isPresent()` can be changed to `isEmpty()`
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -547,4 +577,302 @@ private static boolean isParameterContextChange(final
FlowDifference flowDiffere
private static boolean isLogFileSuffixChange(final FlowDifference
flowDifference) {
return flowDifference.getDifferenceType() ==
DifferenceType.LOG_FILE_SUFFIX_CHANGED;
}
+
+ public static EnvironmentalChangeContext
buildEnvironmentalChangeContext(final Collection<FlowDifference> differences,
final FlowManager flowManager) {
+ if (differences == null || differences.isEmpty() || flowManager ==
null) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ final Set<String> serviceIdsReferencedByNewProperties = new
HashSet<>();
+ final Map<String, List<PropertyDiffInfo>> parameterizedAddsByComponent
= new HashMap<>();
+ final Map<String, List<PropertyDiffInfo>>
parameterizationRemovalsByComponent = new HashMap<>();
+
+ for (final FlowDifference difference : differences) {
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_ADDED) {
+ final ComponentNode componentNode =
Optional.ofNullable(getComponent(flowManager, difference.getComponentB()))
+ .orElseGet(() -> getComponent(flowManager,
difference.getComponentA()));
+ if (componentNode != null) {
+ final Optional<String> fieldNameOptional =
difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final PropertyDescriptor propertyDescriptor =
componentNode.getPropertyDescriptor(fieldNameOptional.get());
+ if (propertyDescriptor != null &&
!propertyDescriptor.isDynamic() &&
propertyDescriptor.getControllerServiceDefinition() != null) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+
serviceIdsReferencedByNewProperties.add((String) valueB);
+ }
+ }
+ }
+ }
+ }
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED
+ || difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZATION_REMOVED) {
+
+ final Optional<String> propertyNameOptional =
difference.getFieldName();
+ final Optional<String> componentIdOptional =
getComponentInstanceIdentifier(difference);
+
+ if (!propertyNameOptional.isPresent() ||
!componentIdOptional.isPresent()) {
+ continue;
+ }
+
+ final String componentId = componentIdOptional.get();
+ final Optional<String> propertyValue =
difference.getDifferenceType() == DifferenceType.PROPERTY_PARAMETERIZED
+ ? getParameterReferenceValue(difference, false)
+ : getParameterReferenceValue(difference, true);
+
+ final PropertyDiffInfo diffInfo = new
PropertyDiffInfo(propertyValue, difference);
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED) {
+ parameterizedAddsByComponent.computeIfAbsent(componentId,
key -> new ArrayList<>()).add(diffInfo);
+ } else {
+
parameterizationRemovalsByComponent.computeIfAbsent(componentId, key -> new
ArrayList<>()).add(diffInfo);
+ }
+ }
+ }
+
+ Set<String> serviceIdsWithMatchingAdditions = Collections.emptySet();
+ if (!serviceIdsReferencedByNewProperties.isEmpty()) {
+ serviceIdsWithMatchingAdditions = differences.stream()
+ .filter(diff -> diff.getDifferenceType() ==
DifferenceType.COMPONENT_ADDED)
+
.map(FlowDifferenceFilters::extractControllerServiceIdentifier)
+ .filter(Objects::nonNull)
+ .filter(serviceIdsReferencedByNewProperties::contains)
+ .collect(Collectors.toCollection(HashSet::new));
Review Comment:
Can `toSet()` be used instead of a new HashSet?
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -58,6 +71,12 @@ public class FlowDifferenceFilters {
* @return <code>true</code> if the change is an environment-specific
change, <code>false</code> otherwise
*/
public static boolean isEnvironmentalChange(final FlowDifference
difference, final VersionedProcessGroup localGroup, final FlowManager
flowManager) {
+ return isEnvironmentalChange(difference, localGroup, flowManager,
EnvironmentalChangeContext.empty());
+ }
+
+ public static boolean isEnvironmentalChange(final FlowDifference
difference, final VersionedProcessGroup localGroup, final FlowManager
flowManager,
+ final
EnvironmentalChangeContext context) {
+ final EnvironmentalChangeContext evaluatedContext = context == null ?
EnvironmentalChangeContext.empty() : context;
Review Comment:
I recommend requiring the `EnvironmentalChangeContext` for this method,
instead of substituting an `empty()` context.
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -547,4 +577,302 @@ private static boolean isParameterContextChange(final
FlowDifference flowDiffere
private static boolean isLogFileSuffixChange(final FlowDifference
flowDifference) {
return flowDifference.getDifferenceType() ==
DifferenceType.LOG_FILE_SUFFIX_CHANGED;
}
+
+ public static EnvironmentalChangeContext
buildEnvironmentalChangeContext(final Collection<FlowDifference> differences,
final FlowManager flowManager) {
+ if (differences == null || differences.isEmpty() || flowManager ==
null) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ final Set<String> serviceIdsReferencedByNewProperties = new
HashSet<>();
+ final Map<String, List<PropertyDiffInfo>> parameterizedAddsByComponent
= new HashMap<>();
+ final Map<String, List<PropertyDiffInfo>>
parameterizationRemovalsByComponent = new HashMap<>();
+
+ for (final FlowDifference difference : differences) {
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_ADDED) {
+ final ComponentNode componentNode =
Optional.ofNullable(getComponent(flowManager, difference.getComponentB()))
+ .orElseGet(() -> getComponent(flowManager,
difference.getComponentA()));
+ if (componentNode != null) {
+ final Optional<String> fieldNameOptional =
difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final PropertyDescriptor propertyDescriptor =
componentNode.getPropertyDescriptor(fieldNameOptional.get());
+ if (propertyDescriptor != null &&
!propertyDescriptor.isDynamic() &&
propertyDescriptor.getControllerServiceDefinition() != null) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+
serviceIdsReferencedByNewProperties.add((String) valueB);
+ }
+ }
+ }
+ }
+ }
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED
Review Comment:
It looks like this should be an `else if` instead of a standalone `if`
statement.
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -112,6 +133,15 @@ private static ComponentNode getComponent(final
FlowManager flowManager, final C
}
+ private static ComponentNode getComponent(final FlowManager flowManager,
final VersionedComponent component) {
+ if (!(component instanceof InstantiatedVersionedComponent)) {
+ return null;
+ }
+
+ final InstantiatedVersionedComponent instantiatedComponent =
(InstantiatedVersionedComponent) component;
+ return getComponent(flowManager, component.getComponentType(),
instantiatedComponent.getInstanceIdentifier());
Review Comment:
Minor implementation note, it looks like this could be adjusted to use
`instanceof InstantiatedVersionedComponent instantiated) { ...` and otherwise
return `null`, instead of the short-circuit return and casting.
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -547,4 +577,302 @@ private static boolean isParameterContextChange(final
FlowDifference flowDiffere
private static boolean isLogFileSuffixChange(final FlowDifference
flowDifference) {
return flowDifference.getDifferenceType() ==
DifferenceType.LOG_FILE_SUFFIX_CHANGED;
}
+
+ public static EnvironmentalChangeContext
buildEnvironmentalChangeContext(final Collection<FlowDifference> differences,
final FlowManager flowManager) {
+ if (differences == null || differences.isEmpty() || flowManager ==
null) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ final Set<String> serviceIdsReferencedByNewProperties = new
HashSet<>();
+ final Map<String, List<PropertyDiffInfo>> parameterizedAddsByComponent
= new HashMap<>();
+ final Map<String, List<PropertyDiffInfo>>
parameterizationRemovalsByComponent = new HashMap<>();
+
+ for (final FlowDifference difference : differences) {
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_ADDED) {
+ final ComponentNode componentNode =
Optional.ofNullable(getComponent(flowManager, difference.getComponentB()))
+ .orElseGet(() -> getComponent(flowManager,
difference.getComponentA()));
+ if (componentNode != null) {
+ final Optional<String> fieldNameOptional =
difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final PropertyDescriptor propertyDescriptor =
componentNode.getPropertyDescriptor(fieldNameOptional.get());
+ if (propertyDescriptor != null &&
!propertyDescriptor.isDynamic() &&
propertyDescriptor.getControllerServiceDefinition() != null) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+
serviceIdsReferencedByNewProperties.add((String) valueB);
+ }
+ }
+ }
+ }
+ }
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED
+ || difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZATION_REMOVED) {
+
+ final Optional<String> propertyNameOptional =
difference.getFieldName();
+ final Optional<String> componentIdOptional =
getComponentInstanceIdentifier(difference);
+
+ if (!propertyNameOptional.isPresent() ||
!componentIdOptional.isPresent()) {
+ continue;
+ }
+
+ final String componentId = componentIdOptional.get();
+ final Optional<String> propertyValue =
difference.getDifferenceType() == DifferenceType.PROPERTY_PARAMETERIZED
+ ? getParameterReferenceValue(difference, false)
+ : getParameterReferenceValue(difference, true);
+
+ final PropertyDiffInfo diffInfo = new
PropertyDiffInfo(propertyValue, difference);
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED) {
+ parameterizedAddsByComponent.computeIfAbsent(componentId,
key -> new ArrayList<>()).add(diffInfo);
+ } else {
+
parameterizationRemovalsByComponent.computeIfAbsent(componentId, key -> new
ArrayList<>()).add(diffInfo);
+ }
+ }
+ }
+
+ Set<String> serviceIdsWithMatchingAdditions = Collections.emptySet();
+ if (!serviceIdsReferencedByNewProperties.isEmpty()) {
+ serviceIdsWithMatchingAdditions = differences.stream()
+ .filter(diff -> diff.getDifferenceType() ==
DifferenceType.COMPONENT_ADDED)
+
.map(FlowDifferenceFilters::extractControllerServiceIdentifier)
+ .filter(Objects::nonNull)
+ .filter(serviceIdsReferencedByNewProperties::contains)
+ .collect(Collectors.toCollection(HashSet::new));
+ }
+
+ final Set<FlowDifference> parameterizedPropertyRenameDifferences = new
HashSet<>();
+ for (final Map.Entry<String, List<PropertyDiffInfo>> entry :
parameterizationRemovalsByComponent.entrySet()) {
+ final String componentId = entry.getKey();
+ final List<PropertyDiffInfo> removals = entry.getValue();
+ final List<PropertyDiffInfo> additions = new
ArrayList<>(parameterizedAddsByComponent.getOrDefault(componentId,
Collections.emptyList()));
+ if (additions.isEmpty()) {
+ continue;
+ }
+
+ for (final PropertyDiffInfo removalInfo : removals) {
+ final Optional<String> removalValue =
removalInfo.propertyValue();
+ if (removalValue.isPresent() &&
!isParameterReference(removalValue.get())) {
+ continue;
+ }
+
+ PropertyDiffInfo matchingAddition = null;
+ for (final Iterator<PropertyDiffInfo> iterator =
additions.iterator(); iterator.hasNext();) {
+ final PropertyDiffInfo additionInfo = iterator.next();
+ final Optional<String> additionValue =
additionInfo.propertyValue();
+ if (additionValue.isPresent() &&
!isParameterReference(additionValue.get())) {
+ continue;
+ }
+
+ if (valuesMatch(removalValue, additionValue)) {
+ matchingAddition = additionInfo;
+ iterator.remove();
+ break;
+ }
+ }
+
+ if (matchingAddition != null) {
+
parameterizedPropertyRenameDifferences.add(removalInfo.difference());
+
parameterizedPropertyRenameDifferences.add(matchingAddition.difference());
+ }
+ }
+ }
+
+ if (serviceIdsWithMatchingAdditions.isEmpty() &&
parameterizedPropertyRenameDifferences.isEmpty()) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ return new EnvironmentalChangeContext(serviceIdsWithMatchingAdditions,
parameterizedPropertyRenameDifferences);
Review Comment:
Minor, but since these are close to the end of the method, I recommend
declaring a `final EnvironmentChangeContext` and setting the value as opposed
to having multiple returns.
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -547,4 +577,302 @@ private static boolean isParameterContextChange(final
FlowDifference flowDiffere
private static boolean isLogFileSuffixChange(final FlowDifference
flowDifference) {
return flowDifference.getDifferenceType() ==
DifferenceType.LOG_FILE_SUFFIX_CHANGED;
}
+
+ public static EnvironmentalChangeContext
buildEnvironmentalChangeContext(final Collection<FlowDifference> differences,
final FlowManager flowManager) {
+ if (differences == null || differences.isEmpty() || flowManager ==
null) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ final Set<String> serviceIdsReferencedByNewProperties = new
HashSet<>();
+ final Map<String, List<PropertyDiffInfo>> parameterizedAddsByComponent
= new HashMap<>();
+ final Map<String, List<PropertyDiffInfo>>
parameterizationRemovalsByComponent = new HashMap<>();
+
+ for (final FlowDifference difference : differences) {
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_ADDED) {
+ final ComponentNode componentNode =
Optional.ofNullable(getComponent(flowManager, difference.getComponentB()))
+ .orElseGet(() -> getComponent(flowManager,
difference.getComponentA()));
+ if (componentNode != null) {
+ final Optional<String> fieldNameOptional =
difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final PropertyDescriptor propertyDescriptor =
componentNode.getPropertyDescriptor(fieldNameOptional.get());
+ if (propertyDescriptor != null &&
!propertyDescriptor.isDynamic() &&
propertyDescriptor.getControllerServiceDefinition() != null) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+
serviceIdsReferencedByNewProperties.add((String) valueB);
+ }
+ }
+ }
+ }
+ }
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED
+ || difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZATION_REMOVED) {
+
+ final Optional<String> propertyNameOptional =
difference.getFieldName();
+ final Optional<String> componentIdOptional =
getComponentInstanceIdentifier(difference);
+
+ if (!propertyNameOptional.isPresent() ||
!componentIdOptional.isPresent()) {
+ continue;
+ }
+
+ final String componentId = componentIdOptional.get();
+ final Optional<String> propertyValue =
difference.getDifferenceType() == DifferenceType.PROPERTY_PARAMETERIZED
+ ? getParameterReferenceValue(difference, false)
+ : getParameterReferenceValue(difference, true);
+
+ final PropertyDiffInfo diffInfo = new
PropertyDiffInfo(propertyValue, difference);
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED) {
+ parameterizedAddsByComponent.computeIfAbsent(componentId,
key -> new ArrayList<>()).add(diffInfo);
+ } else {
+
parameterizationRemovalsByComponent.computeIfAbsent(componentId, key -> new
ArrayList<>()).add(diffInfo);
+ }
+ }
+ }
+
+ Set<String> serviceIdsWithMatchingAdditions = Collections.emptySet();
+ if (!serviceIdsReferencedByNewProperties.isEmpty()) {
+ serviceIdsWithMatchingAdditions = differences.stream()
+ .filter(diff -> diff.getDifferenceType() ==
DifferenceType.COMPONENT_ADDED)
+
.map(FlowDifferenceFilters::extractControllerServiceIdentifier)
+ .filter(Objects::nonNull)
+ .filter(serviceIdsReferencedByNewProperties::contains)
+ .collect(Collectors.toCollection(HashSet::new));
+ }
+
+ final Set<FlowDifference> parameterizedPropertyRenameDifferences = new
HashSet<>();
+ for (final Map.Entry<String, List<PropertyDiffInfo>> entry :
parameterizationRemovalsByComponent.entrySet()) {
+ final String componentId = entry.getKey();
+ final List<PropertyDiffInfo> removals = entry.getValue();
+ final List<PropertyDiffInfo> additions = new
ArrayList<>(parameterizedAddsByComponent.getOrDefault(componentId,
Collections.emptyList()));
+ if (additions.isEmpty()) {
+ continue;
+ }
+
+ for (final PropertyDiffInfo removalInfo : removals) {
+ final Optional<String> removalValue =
removalInfo.propertyValue();
+ if (removalValue.isPresent() &&
!isParameterReference(removalValue.get())) {
+ continue;
+ }
+
+ PropertyDiffInfo matchingAddition = null;
+ for (final Iterator<PropertyDiffInfo> iterator =
additions.iterator(); iterator.hasNext();) {
+ final PropertyDiffInfo additionInfo = iterator.next();
+ final Optional<String> additionValue =
additionInfo.propertyValue();
+ if (additionValue.isPresent() &&
!isParameterReference(additionValue.get())) {
+ continue;
+ }
+
+ if (valuesMatch(removalValue, additionValue)) {
+ matchingAddition = additionInfo;
+ iterator.remove();
+ break;
+ }
+ }
+
+ if (matchingAddition != null) {
+
parameterizedPropertyRenameDifferences.add(removalInfo.difference());
+
parameterizedPropertyRenameDifferences.add(matchingAddition.difference());
+ }
+ }
+ }
+
+ if (serviceIdsWithMatchingAdditions.isEmpty() &&
parameterizedPropertyRenameDifferences.isEmpty()) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ return new EnvironmentalChangeContext(serviceIdsWithMatchingAdditions,
parameterizedPropertyRenameDifferences);
+ }
+
+ public static boolean isControllerServiceCreatedForNewProperty(final
FlowDifference difference, final EnvironmentalChangeContext context) {
+ return isControllerServiceCreatedForNewPropertyInternal(difference,
context == null ? EnvironmentalChangeContext.empty() : context);
+ }
+
+ private static boolean
isControllerServiceCreatedForNewPropertyInternal(final FlowDifference
difference, final EnvironmentalChangeContext context) {
+ if (context.serviceIdsCreatedForNewProperties().isEmpty()) {
+ return false;
+ }
+
+ if (difference.getDifferenceType() == DifferenceType.PROPERTY_ADDED) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+ return
context.serviceIdsCreatedForNewProperties().contains(valueB);
+ }
Review Comment:
The `instanceof` check seems unnecessary since it would be handled by
`contains`, unless `valueB` can be `null`.
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -547,4 +577,302 @@ private static boolean isParameterContextChange(final
FlowDifference flowDiffere
private static boolean isLogFileSuffixChange(final FlowDifference
flowDifference) {
return flowDifference.getDifferenceType() ==
DifferenceType.LOG_FILE_SUFFIX_CHANGED;
}
+
+ public static EnvironmentalChangeContext
buildEnvironmentalChangeContext(final Collection<FlowDifference> differences,
final FlowManager flowManager) {
+ if (differences == null || differences.isEmpty() || flowManager ==
null) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ final Set<String> serviceIdsReferencedByNewProperties = new
HashSet<>();
+ final Map<String, List<PropertyDiffInfo>> parameterizedAddsByComponent
= new HashMap<>();
+ final Map<String, List<PropertyDiffInfo>>
parameterizationRemovalsByComponent = new HashMap<>();
+
+ for (final FlowDifference difference : differences) {
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_ADDED) {
+ final ComponentNode componentNode =
Optional.ofNullable(getComponent(flowManager, difference.getComponentB()))
+ .orElseGet(() -> getComponent(flowManager,
difference.getComponentA()));
+ if (componentNode != null) {
+ final Optional<String> fieldNameOptional =
difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final PropertyDescriptor propertyDescriptor =
componentNode.getPropertyDescriptor(fieldNameOptional.get());
+ if (propertyDescriptor != null &&
!propertyDescriptor.isDynamic() &&
propertyDescriptor.getControllerServiceDefinition() != null) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+
serviceIdsReferencedByNewProperties.add((String) valueB);
+ }
+ }
+ }
+ }
+ }
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED
+ || difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZATION_REMOVED) {
+
+ final Optional<String> propertyNameOptional =
difference.getFieldName();
+ final Optional<String> componentIdOptional =
getComponentInstanceIdentifier(difference);
+
+ if (!propertyNameOptional.isPresent() ||
!componentIdOptional.isPresent()) {
+ continue;
+ }
+
+ final String componentId = componentIdOptional.get();
+ final Optional<String> propertyValue =
difference.getDifferenceType() == DifferenceType.PROPERTY_PARAMETERIZED
+ ? getParameterReferenceValue(difference, false)
+ : getParameterReferenceValue(difference, true);
+
+ final PropertyDiffInfo diffInfo = new
PropertyDiffInfo(propertyValue, difference);
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED) {
+ parameterizedAddsByComponent.computeIfAbsent(componentId,
key -> new ArrayList<>()).add(diffInfo);
+ } else {
+
parameterizationRemovalsByComponent.computeIfAbsent(componentId, key -> new
ArrayList<>()).add(diffInfo);
+ }
+ }
+ }
+
+ Set<String> serviceIdsWithMatchingAdditions = Collections.emptySet();
+ if (!serviceIdsReferencedByNewProperties.isEmpty()) {
+ serviceIdsWithMatchingAdditions = differences.stream()
+ .filter(diff -> diff.getDifferenceType() ==
DifferenceType.COMPONENT_ADDED)
+
.map(FlowDifferenceFilters::extractControllerServiceIdentifier)
+ .filter(Objects::nonNull)
+ .filter(serviceIdsReferencedByNewProperties::contains)
+ .collect(Collectors.toCollection(HashSet::new));
+ }
+
+ final Set<FlowDifference> parameterizedPropertyRenameDifferences = new
HashSet<>();
+ for (final Map.Entry<String, List<PropertyDiffInfo>> entry :
parameterizationRemovalsByComponent.entrySet()) {
+ final String componentId = entry.getKey();
+ final List<PropertyDiffInfo> removals = entry.getValue();
+ final List<PropertyDiffInfo> additions = new
ArrayList<>(parameterizedAddsByComponent.getOrDefault(componentId,
Collections.emptyList()));
+ if (additions.isEmpty()) {
+ continue;
+ }
+
+ for (final PropertyDiffInfo removalInfo : removals) {
+ final Optional<String> removalValue =
removalInfo.propertyValue();
+ if (removalValue.isPresent() &&
!isParameterReference(removalValue.get())) {
+ continue;
+ }
+
+ PropertyDiffInfo matchingAddition = null;
+ for (final Iterator<PropertyDiffInfo> iterator =
additions.iterator(); iterator.hasNext();) {
+ final PropertyDiffInfo additionInfo = iterator.next();
+ final Optional<String> additionValue =
additionInfo.propertyValue();
+ if (additionValue.isPresent() &&
!isParameterReference(additionValue.get())) {
+ continue;
+ }
+
+ if (valuesMatch(removalValue, additionValue)) {
+ matchingAddition = additionInfo;
+ iterator.remove();
+ break;
+ }
+ }
+
+ if (matchingAddition != null) {
+
parameterizedPropertyRenameDifferences.add(removalInfo.difference());
+
parameterizedPropertyRenameDifferences.add(matchingAddition.difference());
+ }
+ }
+ }
+
+ if (serviceIdsWithMatchingAdditions.isEmpty() &&
parameterizedPropertyRenameDifferences.isEmpty()) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ return new EnvironmentalChangeContext(serviceIdsWithMatchingAdditions,
parameterizedPropertyRenameDifferences);
+ }
+
+ public static boolean isControllerServiceCreatedForNewProperty(final
FlowDifference difference, final EnvironmentalChangeContext context) {
+ return isControllerServiceCreatedForNewPropertyInternal(difference,
context == null ? EnvironmentalChangeContext.empty() : context);
+ }
+
+ private static boolean
isControllerServiceCreatedForNewPropertyInternal(final FlowDifference
difference, final EnvironmentalChangeContext context) {
+ if (context.serviceIdsCreatedForNewProperties().isEmpty()) {
+ return false;
+ }
+
+ if (difference.getDifferenceType() == DifferenceType.PROPERTY_ADDED) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+ return
context.serviceIdsCreatedForNewProperties().contains(valueB);
+ }
+ }
+
+ if (difference.getDifferenceType() == DifferenceType.COMPONENT_ADDED) {
+ final String serviceIdentifier =
extractControllerServiceIdentifier(difference);
+ return serviceIdentifier != null &&
context.serviceIdsCreatedForNewProperties().contains(serviceIdentifier);
+ }
+
+ return false;
+ }
+
+ private static String extractControllerServiceIdentifier(final
FlowDifference difference) {
+ final String identifierFromComponentB =
extractControllerServiceIdentifier(difference.getComponentB());
+ if (identifierFromComponentB != null) {
+ return identifierFromComponentB;
+ }
+
+ return extractControllerServiceIdentifier(difference.getComponentA());
+ }
+
+ private static String extractControllerServiceIdentifier(final
VersionedComponent component) {
+ if (component instanceof InstantiatedVersionedControllerService) {
+ final InstantiatedVersionedControllerService
instantiatedControllerService = (InstantiatedVersionedControllerService)
component;
+ final String instanceIdentifier =
instantiatedControllerService.getInstanceIdentifier();
+ if (instanceIdentifier != null) {
+ return instanceIdentifier;
+ }
+ }
+
+ if (component instanceof VersionedControllerService) {
+ return component.getIdentifier();
+ }
+
+ return null;
+ }
+
+ public static boolean isPropertyParameterizationRename(final
FlowDifference difference, final EnvironmentalChangeContext context) {
+ return (context == null ||
context.parameterizedPropertyRenames().isEmpty()) ? false :
context.parameterizedPropertyRenames().contains(difference);
Review Comment:
See note on `null` possibility for `context`.
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -547,4 +577,302 @@ private static boolean isParameterContextChange(final
FlowDifference flowDiffere
private static boolean isLogFileSuffixChange(final FlowDifference
flowDifference) {
return flowDifference.getDifferenceType() ==
DifferenceType.LOG_FILE_SUFFIX_CHANGED;
}
+
+ public static EnvironmentalChangeContext
buildEnvironmentalChangeContext(final Collection<FlowDifference> differences,
final FlowManager flowManager) {
+ if (differences == null || differences.isEmpty() || flowManager ==
null) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ final Set<String> serviceIdsReferencedByNewProperties = new
HashSet<>();
+ final Map<String, List<PropertyDiffInfo>> parameterizedAddsByComponent
= new HashMap<>();
+ final Map<String, List<PropertyDiffInfo>>
parameterizationRemovalsByComponent = new HashMap<>();
+
+ for (final FlowDifference difference : differences) {
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_ADDED) {
+ final ComponentNode componentNode =
Optional.ofNullable(getComponent(flowManager, difference.getComponentB()))
+ .orElseGet(() -> getComponent(flowManager,
difference.getComponentA()));
+ if (componentNode != null) {
+ final Optional<String> fieldNameOptional =
difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final PropertyDescriptor propertyDescriptor =
componentNode.getPropertyDescriptor(fieldNameOptional.get());
+ if (propertyDescriptor != null &&
!propertyDescriptor.isDynamic() &&
propertyDescriptor.getControllerServiceDefinition() != null) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+
serviceIdsReferencedByNewProperties.add((String) valueB);
+ }
+ }
+ }
+ }
+ }
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED
+ || difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZATION_REMOVED) {
+
+ final Optional<String> propertyNameOptional =
difference.getFieldName();
+ final Optional<String> componentIdOptional =
getComponentInstanceIdentifier(difference);
+
+ if (!propertyNameOptional.isPresent() ||
!componentIdOptional.isPresent()) {
+ continue;
+ }
+
+ final String componentId = componentIdOptional.get();
+ final Optional<String> propertyValue =
difference.getDifferenceType() == DifferenceType.PROPERTY_PARAMETERIZED
+ ? getParameterReferenceValue(difference, false)
+ : getParameterReferenceValue(difference, true);
+
+ final PropertyDiffInfo diffInfo = new
PropertyDiffInfo(propertyValue, difference);
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED) {
+ parameterizedAddsByComponent.computeIfAbsent(componentId,
key -> new ArrayList<>()).add(diffInfo);
+ } else {
+
parameterizationRemovalsByComponent.computeIfAbsent(componentId, key -> new
ArrayList<>()).add(diffInfo);
+ }
+ }
+ }
+
+ Set<String> serviceIdsWithMatchingAdditions = Collections.emptySet();
+ if (!serviceIdsReferencedByNewProperties.isEmpty()) {
+ serviceIdsWithMatchingAdditions = differences.stream()
+ .filter(diff -> diff.getDifferenceType() ==
DifferenceType.COMPONENT_ADDED)
+
.map(FlowDifferenceFilters::extractControllerServiceIdentifier)
+ .filter(Objects::nonNull)
+ .filter(serviceIdsReferencedByNewProperties::contains)
+ .collect(Collectors.toCollection(HashSet::new));
+ }
+
+ final Set<FlowDifference> parameterizedPropertyRenameDifferences = new
HashSet<>();
+ for (final Map.Entry<String, List<PropertyDiffInfo>> entry :
parameterizationRemovalsByComponent.entrySet()) {
+ final String componentId = entry.getKey();
+ final List<PropertyDiffInfo> removals = entry.getValue();
+ final List<PropertyDiffInfo> additions = new
ArrayList<>(parameterizedAddsByComponent.getOrDefault(componentId,
Collections.emptyList()));
+ if (additions.isEmpty()) {
+ continue;
+ }
+
+ for (final PropertyDiffInfo removalInfo : removals) {
+ final Optional<String> removalValue =
removalInfo.propertyValue();
+ if (removalValue.isPresent() &&
!isParameterReference(removalValue.get())) {
+ continue;
+ }
+
+ PropertyDiffInfo matchingAddition = null;
+ for (final Iterator<PropertyDiffInfo> iterator =
additions.iterator(); iterator.hasNext();) {
+ final PropertyDiffInfo additionInfo = iterator.next();
+ final Optional<String> additionValue =
additionInfo.propertyValue();
+ if (additionValue.isPresent() &&
!isParameterReference(additionValue.get())) {
+ continue;
+ }
+
+ if (valuesMatch(removalValue, additionValue)) {
+ matchingAddition = additionInfo;
+ iterator.remove();
+ break;
+ }
+ }
+
+ if (matchingAddition != null) {
+
parameterizedPropertyRenameDifferences.add(removalInfo.difference());
+
parameterizedPropertyRenameDifferences.add(matchingAddition.difference());
+ }
+ }
+ }
+
+ if (serviceIdsWithMatchingAdditions.isEmpty() &&
parameterizedPropertyRenameDifferences.isEmpty()) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ return new EnvironmentalChangeContext(serviceIdsWithMatchingAdditions,
parameterizedPropertyRenameDifferences);
+ }
+
+ public static boolean isControllerServiceCreatedForNewProperty(final
FlowDifference difference, final EnvironmentalChangeContext context) {
+ return isControllerServiceCreatedForNewPropertyInternal(difference,
context == null ? EnvironmentalChangeContext.empty() : context);
+ }
+
+ private static boolean
isControllerServiceCreatedForNewPropertyInternal(final FlowDifference
difference, final EnvironmentalChangeContext context) {
+ if (context.serviceIdsCreatedForNewProperties().isEmpty()) {
+ return false;
+ }
+
+ if (difference.getDifferenceType() == DifferenceType.PROPERTY_ADDED) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+ return
context.serviceIdsCreatedForNewProperties().contains(valueB);
+ }
+ }
+
+ if (difference.getDifferenceType() == DifferenceType.COMPONENT_ADDED) {
+ final String serviceIdentifier =
extractControllerServiceIdentifier(difference);
+ return serviceIdentifier != null &&
context.serviceIdsCreatedForNewProperties().contains(serviceIdentifier);
+ }
+
+ return false;
+ }
+
+ private static String extractControllerServiceIdentifier(final
FlowDifference difference) {
+ final String identifierFromComponentB =
extractControllerServiceIdentifier(difference.getComponentB());
+ if (identifierFromComponentB != null) {
+ return identifierFromComponentB;
+ }
+
+ return extractControllerServiceIdentifier(difference.getComponentA());
+ }
+
+ private static String extractControllerServiceIdentifier(final
VersionedComponent component) {
+ if (component instanceof InstantiatedVersionedControllerService) {
+ final InstantiatedVersionedControllerService
instantiatedControllerService = (InstantiatedVersionedControllerService)
component;
+ final String instanceIdentifier =
instantiatedControllerService.getInstanceIdentifier();
+ if (instanceIdentifier != null) {
+ return instanceIdentifier;
+ }
+ }
+
+ if (component instanceof VersionedControllerService) {
+ return component.getIdentifier();
+ }
+
+ return null;
+ }
+
+ public static boolean isPropertyParameterizationRename(final
FlowDifference difference, final EnvironmentalChangeContext context) {
+ return (context == null ||
context.parameterizedPropertyRenames().isEmpty()) ? false :
context.parameterizedPropertyRenames().contains(difference);
+ }
+
+ private static Optional<String> getComponentInstanceIdentifier(final
FlowDifference difference) {
+ final Optional<String> identifierB =
getComponentInstanceIdentifier(difference.getComponentB());
+ if (identifierB.isPresent()) {
+ return identifierB;
+ }
+
+ return getComponentInstanceIdentifier(difference.getComponentA());
+ }
+
+ private static Optional<String> getComponentInstanceIdentifier(final
VersionedComponent component) {
+ if (component == null) {
+ return Optional.empty();
+ }
+
+ if (component instanceof InstantiatedVersionedComponent) {
+ final String instanceId = ((InstantiatedVersionedComponent)
component).getInstanceIdentifier();
+ if (instanceId != null) {
+ return Optional.of(instanceId);
+ }
+ }
+
+ return Optional.ofNullable(component.getIdentifier());
+ }
+
+ private static Optional<String> getParameterReferenceValue(final
FlowDifference difference, final boolean fromComponentA) {
+ final VersionedComponent primaryComponent = fromComponentA ?
difference.getComponentA() : difference.getComponentB();
+ final VersionedComponent secondaryComponent = fromComponentA ?
difference.getComponentB() : difference.getComponentA();
+
+ final Map<String, String> primaryProperties =
getProperties(primaryComponent);
+ if (primaryProperties.isEmpty()) {
+ return Optional.empty();
Review Comment:
This method is a bit longer, making the multiple return statements a bit
more complex. What do you think about refactoring to a single return?
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -547,4 +577,302 @@ private static boolean isParameterContextChange(final
FlowDifference flowDiffere
private static boolean isLogFileSuffixChange(final FlowDifference
flowDifference) {
return flowDifference.getDifferenceType() ==
DifferenceType.LOG_FILE_SUFFIX_CHANGED;
}
+
+ public static EnvironmentalChangeContext
buildEnvironmentalChangeContext(final Collection<FlowDifference> differences,
final FlowManager flowManager) {
+ if (differences == null || differences.isEmpty() || flowManager ==
null) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ final Set<String> serviceIdsReferencedByNewProperties = new
HashSet<>();
+ final Map<String, List<PropertyDiffInfo>> parameterizedAddsByComponent
= new HashMap<>();
+ final Map<String, List<PropertyDiffInfo>>
parameterizationRemovalsByComponent = new HashMap<>();
+
+ for (final FlowDifference difference : differences) {
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_ADDED) {
+ final ComponentNode componentNode =
Optional.ofNullable(getComponent(flowManager, difference.getComponentB()))
+ .orElseGet(() -> getComponent(flowManager,
difference.getComponentA()));
+ if (componentNode != null) {
+ final Optional<String> fieldNameOptional =
difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final PropertyDescriptor propertyDescriptor =
componentNode.getPropertyDescriptor(fieldNameOptional.get());
+ if (propertyDescriptor != null &&
!propertyDescriptor.isDynamic() &&
propertyDescriptor.getControllerServiceDefinition() != null) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+
serviceIdsReferencedByNewProperties.add((String) valueB);
+ }
+ }
+ }
+ }
+ }
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED
+ || difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZATION_REMOVED) {
+
+ final Optional<String> propertyNameOptional =
difference.getFieldName();
+ final Optional<String> componentIdOptional =
getComponentInstanceIdentifier(difference);
+
+ if (!propertyNameOptional.isPresent() ||
!componentIdOptional.isPresent()) {
+ continue;
+ }
+
+ final String componentId = componentIdOptional.get();
+ final Optional<String> propertyValue =
difference.getDifferenceType() == DifferenceType.PROPERTY_PARAMETERIZED
+ ? getParameterReferenceValue(difference, false)
+ : getParameterReferenceValue(difference, true);
+
+ final PropertyDiffInfo diffInfo = new
PropertyDiffInfo(propertyValue, difference);
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED) {
+ parameterizedAddsByComponent.computeIfAbsent(componentId,
key -> new ArrayList<>()).add(diffInfo);
+ } else {
+
parameterizationRemovalsByComponent.computeIfAbsent(componentId, key -> new
ArrayList<>()).add(diffInfo);
+ }
+ }
+ }
+
+ Set<String> serviceIdsWithMatchingAdditions = Collections.emptySet();
+ if (!serviceIdsReferencedByNewProperties.isEmpty()) {
+ serviceIdsWithMatchingAdditions = differences.stream()
+ .filter(diff -> diff.getDifferenceType() ==
DifferenceType.COMPONENT_ADDED)
+
.map(FlowDifferenceFilters::extractControllerServiceIdentifier)
+ .filter(Objects::nonNull)
+ .filter(serviceIdsReferencedByNewProperties::contains)
+ .collect(Collectors.toCollection(HashSet::new));
+ }
+
+ final Set<FlowDifference> parameterizedPropertyRenameDifferences = new
HashSet<>();
+ for (final Map.Entry<String, List<PropertyDiffInfo>> entry :
parameterizationRemovalsByComponent.entrySet()) {
+ final String componentId = entry.getKey();
+ final List<PropertyDiffInfo> removals = entry.getValue();
+ final List<PropertyDiffInfo> additions = new
ArrayList<>(parameterizedAddsByComponent.getOrDefault(componentId,
Collections.emptyList()));
+ if (additions.isEmpty()) {
+ continue;
+ }
+
+ for (final PropertyDiffInfo removalInfo : removals) {
+ final Optional<String> removalValue =
removalInfo.propertyValue();
+ if (removalValue.isPresent() &&
!isParameterReference(removalValue.get())) {
+ continue;
+ }
+
+ PropertyDiffInfo matchingAddition = null;
+ for (final Iterator<PropertyDiffInfo> iterator =
additions.iterator(); iterator.hasNext();) {
+ final PropertyDiffInfo additionInfo = iterator.next();
+ final Optional<String> additionValue =
additionInfo.propertyValue();
+ if (additionValue.isPresent() &&
!isParameterReference(additionValue.get())) {
+ continue;
+ }
+
+ if (valuesMatch(removalValue, additionValue)) {
+ matchingAddition = additionInfo;
+ iterator.remove();
+ break;
+ }
+ }
+
+ if (matchingAddition != null) {
+
parameterizedPropertyRenameDifferences.add(removalInfo.difference());
+
parameterizedPropertyRenameDifferences.add(matchingAddition.difference());
+ }
+ }
+ }
+
+ if (serviceIdsWithMatchingAdditions.isEmpty() &&
parameterizedPropertyRenameDifferences.isEmpty()) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ return new EnvironmentalChangeContext(serviceIdsWithMatchingAdditions,
parameterizedPropertyRenameDifferences);
+ }
+
+ public static boolean isControllerServiceCreatedForNewProperty(final
FlowDifference difference, final EnvironmentalChangeContext context) {
Review Comment:
Can `context` be null? Similar to other public methods, I recommend using
`Objects.requireNonNull()`
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -547,4 +577,302 @@ private static boolean isParameterContextChange(final
FlowDifference flowDiffere
private static boolean isLogFileSuffixChange(final FlowDifference
flowDifference) {
return flowDifference.getDifferenceType() ==
DifferenceType.LOG_FILE_SUFFIX_CHANGED;
}
+
+ public static EnvironmentalChangeContext
buildEnvironmentalChangeContext(final Collection<FlowDifference> differences,
final FlowManager flowManager) {
+ if (differences == null || differences.isEmpty() || flowManager ==
null) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ final Set<String> serviceIdsReferencedByNewProperties = new
HashSet<>();
+ final Map<String, List<PropertyDiffInfo>> parameterizedAddsByComponent
= new HashMap<>();
+ final Map<String, List<PropertyDiffInfo>>
parameterizationRemovalsByComponent = new HashMap<>();
+
+ for (final FlowDifference difference : differences) {
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_ADDED) {
+ final ComponentNode componentNode =
Optional.ofNullable(getComponent(flowManager, difference.getComponentB()))
+ .orElseGet(() -> getComponent(flowManager,
difference.getComponentA()));
+ if (componentNode != null) {
+ final Optional<String> fieldNameOptional =
difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final PropertyDescriptor propertyDescriptor =
componentNode.getPropertyDescriptor(fieldNameOptional.get());
+ if (propertyDescriptor != null &&
!propertyDescriptor.isDynamic() &&
propertyDescriptor.getControllerServiceDefinition() != null) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+
serviceIdsReferencedByNewProperties.add((String) valueB);
+ }
+ }
+ }
+ }
+ }
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED
+ || difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZATION_REMOVED) {
+
+ final Optional<String> propertyNameOptional =
difference.getFieldName();
+ final Optional<String> componentIdOptional =
getComponentInstanceIdentifier(difference);
+
+ if (!propertyNameOptional.isPresent() ||
!componentIdOptional.isPresent()) {
+ continue;
+ }
+
+ final String componentId = componentIdOptional.get();
+ final Optional<String> propertyValue =
difference.getDifferenceType() == DifferenceType.PROPERTY_PARAMETERIZED
+ ? getParameterReferenceValue(difference, false)
+ : getParameterReferenceValue(difference, true);
+
+ final PropertyDiffInfo diffInfo = new
PropertyDiffInfo(propertyValue, difference);
+
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_PARAMETERIZED) {
+ parameterizedAddsByComponent.computeIfAbsent(componentId,
key -> new ArrayList<>()).add(diffInfo);
+ } else {
+
parameterizationRemovalsByComponent.computeIfAbsent(componentId, key -> new
ArrayList<>()).add(diffInfo);
+ }
+ }
+ }
+
+ Set<String> serviceIdsWithMatchingAdditions = Collections.emptySet();
+ if (!serviceIdsReferencedByNewProperties.isEmpty()) {
+ serviceIdsWithMatchingAdditions = differences.stream()
+ .filter(diff -> diff.getDifferenceType() ==
DifferenceType.COMPONENT_ADDED)
+
.map(FlowDifferenceFilters::extractControllerServiceIdentifier)
+ .filter(Objects::nonNull)
+ .filter(serviceIdsReferencedByNewProperties::contains)
+ .collect(Collectors.toCollection(HashSet::new));
+ }
+
+ final Set<FlowDifference> parameterizedPropertyRenameDifferences = new
HashSet<>();
+ for (final Map.Entry<String, List<PropertyDiffInfo>> entry :
parameterizationRemovalsByComponent.entrySet()) {
+ final String componentId = entry.getKey();
+ final List<PropertyDiffInfo> removals = entry.getValue();
+ final List<PropertyDiffInfo> additions = new
ArrayList<>(parameterizedAddsByComponent.getOrDefault(componentId,
Collections.emptyList()));
+ if (additions.isEmpty()) {
+ continue;
+ }
+
+ for (final PropertyDiffInfo removalInfo : removals) {
+ final Optional<String> removalValue =
removalInfo.propertyValue();
+ if (removalValue.isPresent() &&
!isParameterReference(removalValue.get())) {
+ continue;
+ }
+
+ PropertyDiffInfo matchingAddition = null;
+ for (final Iterator<PropertyDiffInfo> iterator =
additions.iterator(); iterator.hasNext();) {
+ final PropertyDiffInfo additionInfo = iterator.next();
+ final Optional<String> additionValue =
additionInfo.propertyValue();
+ if (additionValue.isPresent() &&
!isParameterReference(additionValue.get())) {
+ continue;
+ }
+
+ if (valuesMatch(removalValue, additionValue)) {
+ matchingAddition = additionInfo;
+ iterator.remove();
+ break;
+ }
+ }
+
+ if (matchingAddition != null) {
+
parameterizedPropertyRenameDifferences.add(removalInfo.difference());
+
parameterizedPropertyRenameDifferences.add(matchingAddition.difference());
+ }
+ }
+ }
+
+ if (serviceIdsWithMatchingAdditions.isEmpty() &&
parameterizedPropertyRenameDifferences.isEmpty()) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ return new EnvironmentalChangeContext(serviceIdsWithMatchingAdditions,
parameterizedPropertyRenameDifferences);
+ }
+
+ public static boolean isControllerServiceCreatedForNewProperty(final
FlowDifference difference, final EnvironmentalChangeContext context) {
+ return isControllerServiceCreatedForNewPropertyInternal(difference,
context == null ? EnvironmentalChangeContext.empty() : context);
+ }
+
+ private static boolean
isControllerServiceCreatedForNewPropertyInternal(final FlowDifference
difference, final EnvironmentalChangeContext context) {
+ if (context.serviceIdsCreatedForNewProperties().isEmpty()) {
+ return false;
+ }
+
+ if (difference.getDifferenceType() == DifferenceType.PROPERTY_ADDED) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+ return
context.serviceIdsCreatedForNewProperties().contains(valueB);
+ }
+ }
+
+ if (difference.getDifferenceType() == DifferenceType.COMPONENT_ADDED) {
+ final String serviceIdentifier =
extractControllerServiceIdentifier(difference);
+ return serviceIdentifier != null &&
context.serviceIdsCreatedForNewProperties().contains(serviceIdentifier);
+ }
+
+ return false;
+ }
+
+ private static String extractControllerServiceIdentifier(final
FlowDifference difference) {
+ final String identifierFromComponentB =
extractControllerServiceIdentifier(difference.getComponentB());
+ if (identifierFromComponentB != null) {
+ return identifierFromComponentB;
+ }
+
+ return extractControllerServiceIdentifier(difference.getComponentA());
+ }
+
+ private static String extractControllerServiceIdentifier(final
VersionedComponent component) {
+ if (component instanceof InstantiatedVersionedControllerService) {
+ final InstantiatedVersionedControllerService
instantiatedControllerService = (InstantiatedVersionedControllerService)
component;
+ final String instanceIdentifier =
instantiatedControllerService.getInstanceIdentifier();
+ if (instanceIdentifier != null) {
+ return instanceIdentifier;
+ }
+ }
+
+ if (component instanceof VersionedControllerService) {
+ return component.getIdentifier();
+ }
+
+ return null;
+ }
+
+ public static boolean isPropertyParameterizationRename(final
FlowDifference difference, final EnvironmentalChangeContext context) {
+ return (context == null ||
context.parameterizedPropertyRenames().isEmpty()) ? false :
context.parameterizedPropertyRenames().contains(difference);
+ }
+
+ private static Optional<String> getComponentInstanceIdentifier(final
FlowDifference difference) {
+ final Optional<String> identifierB =
getComponentInstanceIdentifier(difference.getComponentB());
+ if (identifierB.isPresent()) {
+ return identifierB;
+ }
+
+ return getComponentInstanceIdentifier(difference.getComponentA());
+ }
+
+ private static Optional<String> getComponentInstanceIdentifier(final
VersionedComponent component) {
+ if (component == null) {
+ return Optional.empty();
+ }
+
+ if (component instanceof InstantiatedVersionedComponent) {
+ final String instanceId = ((InstantiatedVersionedComponent)
component).getInstanceIdentifier();
+ if (instanceId != null) {
+ return Optional.of(instanceId);
+ }
+ }
+
+ return Optional.ofNullable(component.getIdentifier());
+ }
+
+ private static Optional<String> getParameterReferenceValue(final
FlowDifference difference, final boolean fromComponentA) {
+ final VersionedComponent primaryComponent = fromComponentA ?
difference.getComponentA() : difference.getComponentB();
+ final VersionedComponent secondaryComponent = fromComponentA ?
difference.getComponentB() : difference.getComponentA();
+
+ final Map<String, String> primaryProperties =
getProperties(primaryComponent);
+ if (primaryProperties.isEmpty()) {
+ return Optional.empty();
+ }
+
+ final Map<String, String> secondaryProperties =
getProperties(secondaryComponent);
+
+ final Optional<String> fieldNameOptional = difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final String fieldName = fieldNameOptional.get();
+ final String propertyValue = primaryProperties.get(fieldName);
+ if (propertyValue != null) {
+ return Optional.of(propertyValue);
+ }
+ }
+
+ // Fallback: find a property unique to the primary component whose
value is a parameter reference.
+ for (Map.Entry<String, String> entry : primaryProperties.entrySet()) {
+ final String propertyName = entry.getKey();
+ final String propertyValue = entry.getValue();
+ if (!isParameterReference(propertyValue)) {
+ continue;
+ }
+
+ if (!secondaryProperties.containsKey(propertyName)) {
+ return Optional.of(propertyValue);
+ }
+ }
+
+ return Optional.empty();
+ }
+
+ private static Map<String, String> getProperties(final VersionedComponent
component) {
+ if (component == null) {
Review Comment:
Recommend refactoring this method to a single return an use of `if ... else
if ...`
##########
nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/util/FlowDifferenceFilters.java:
##########
@@ -547,4 +577,302 @@ private static boolean isParameterContextChange(final
FlowDifference flowDiffere
private static boolean isLogFileSuffixChange(final FlowDifference
flowDifference) {
return flowDifference.getDifferenceType() ==
DifferenceType.LOG_FILE_SUFFIX_CHANGED;
}
+
+ public static EnvironmentalChangeContext
buildEnvironmentalChangeContext(final Collection<FlowDifference> differences,
final FlowManager flowManager) {
+ if (differences == null || differences.isEmpty() || flowManager ==
null) {
+ return EnvironmentalChangeContext.empty();
+ }
+
+ final Set<String> serviceIdsReferencedByNewProperties = new
HashSet<>();
+ final Map<String, List<PropertyDiffInfo>> parameterizedAddsByComponent
= new HashMap<>();
+ final Map<String, List<PropertyDiffInfo>>
parameterizationRemovalsByComponent = new HashMap<>();
+
+ for (final FlowDifference difference : differences) {
+ if (difference.getDifferenceType() ==
DifferenceType.PROPERTY_ADDED) {
+ final ComponentNode componentNode =
Optional.ofNullable(getComponent(flowManager, difference.getComponentB()))
+ .orElseGet(() -> getComponent(flowManager,
difference.getComponentA()));
+ if (componentNode != null) {
+ final Optional<String> fieldNameOptional =
difference.getFieldName();
+ if (fieldNameOptional.isPresent()) {
+ final PropertyDescriptor propertyDescriptor =
componentNode.getPropertyDescriptor(fieldNameOptional.get());
+ if (propertyDescriptor != null &&
!propertyDescriptor.isDynamic() &&
propertyDescriptor.getControllerServiceDefinition() != null) {
+ final Object valueB = difference.getValueB();
+ if (valueB instanceof String) {
+
serviceIdsReferencedByNewProperties.add((String) valueB);
Review Comment:
Minor adjustment to remove the need for casting:
```suggestion
if (valueB instanceof String serviceId) {
serviceIdsReferencedByNewProperties.add(serviceId);
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]