NIFI-11075 Add additional fields to C2 component definition model

Signed-off-by: Matthew Burgess <mattyb149@apache.org>

This closes #6872
This commit is contained in:
Bryan Bende 2023-01-20 11:55:30 -05:00 committed by Matthew Burgess
parent 2b8475a6f8
commit f339e4378d
No known key found for this signature in database
GPG Key ID: 05D3DEB8126DAD24
10 changed files with 424 additions and 3 deletions

View File

@ -0,0 +1,47 @@
/*
* 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.c2.protocol.component.api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel
public class Attribute {
private String name;
private String description;
@ApiModelProperty(value = "The name of the attribute")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ApiModelProperty(value = "The description of the attribute")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View File

@ -18,6 +18,7 @@
package org.apache.nifi.c2.protocol.component.api;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
@ -33,4 +34,7 @@ public interface ConfigurableComponentDefinition {
void setSupportsDynamicProperties(boolean supportsDynamicProperties);
List<DynamicProperty> getDynamicProperties();
void setDynamicProperties(List<DynamicProperty> dynamicProperties);
}

View File

@ -20,12 +20,15 @@ import io.swagger.annotations.ApiModelProperty;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public abstract class ConfigurableExtensionDefinition extends ExtensionComponent implements ConfigurableComponentDefinition {
private Map<String, PropertyDescriptor> propertyDescriptors;
private boolean supportsDynamicProperties;
private List<DynamicProperty> dynamicProperties;
@Override
@ApiModelProperty("Descriptions of configuration properties applicable to this component.")
@ -49,4 +52,14 @@ public abstract class ConfigurableExtensionDefinition extends ExtensionComponent
this.supportsDynamicProperties = supportsDynamicProperties;
}
@Override
@ApiModelProperty("Describes the dynamic properties supported by this component")
public List<DynamicProperty> getDynamicProperties() {
return dynamicProperties;
}
@Override
public void setDynamicProperties(List<DynamicProperty> dynamicProperties) {
this.dynamicProperties = dynamicProperties;
}
}

View File

@ -0,0 +1,67 @@
/*
* 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.c2.protocol.component.api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.apache.nifi.expression.ExpressionLanguageScope;
@ApiModel
public class DynamicProperty {
private String name;
private String value;
private String description;
private ExpressionLanguageScope expressionLanguageScope;
@ApiModelProperty(value = "The description of the dynamic property name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ApiModelProperty(value = "The description of the dynamic property value")
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@ApiModelProperty(value = "The description of the dynamic property")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@ApiModelProperty(value = "The scope of the expression language support")
public ExpressionLanguageScope getExpressionLanguageScope() {
return expressionLanguageScope;
}
public void setExpressionLanguageScope(ExpressionLanguageScope expressionLanguageScope) {
this.expressionLanguageScope = expressionLanguageScope;
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.c2.protocol.component.api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel
public class DynamicRelationship {
private String name;
private String description;
@ApiModelProperty(value = "The description of the dynamic relationship name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ApiModelProperty(value = "The description of the dynamic relationship")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View File

@ -37,15 +37,18 @@ public class ExtensionComponent extends DefinedType {
private List<DefinedType> providedApiImplementations;
private Set<String> tags;
private Set<String> seeAlso;
private Boolean deprecated;
private String deprecationReason;
private Set<String> deprecationAlternatives;
private Boolean restricted;
private String restrictedExplanation;
private Set<Restriction> explicitRestrictions;
private Stateful stateful;
private List<SystemResourceConsideration> systemResourceConsiderations;
private boolean additionalDetails;
@ -77,6 +80,15 @@ public class ExtensionComponent extends DefinedType {
this.tags = tags;
}
@ApiModelProperty("The names of other component types that may be related")
public Set<String> getSeeAlso() {
return seeAlso;
}
public void setSeeAlso(Set<String> seeAlso) {
this.seeAlso = seeAlso;
}
@ApiModelProperty("Whether or not the component has been deprecated")
public Boolean getDeprecated() {
return deprecated;
@ -95,6 +107,15 @@ public class ExtensionComponent extends DefinedType {
this.deprecationReason = deprecationReason;
}
@ApiModelProperty("If this component has been deprecated, this optional field provides alternatives to use")
public Set<String> getDeprecationAlternatives() {
return deprecationAlternatives;
}
public void setDeprecationAlternatives(Set<String> deprecationAlternatives) {
this.deprecationAlternatives = deprecationAlternatives;
}
@ApiModelProperty("Whether or not the component has a general restriction")
public Boolean isRestricted() {
return restricted;
@ -131,6 +152,15 @@ public class ExtensionComponent extends DefinedType {
this.stateful = stateful;
}
@ApiModelProperty("The system resource considerations for the given component")
public List<SystemResourceConsideration> getSystemResourceConsiderations() {
return systemResourceConsiderations;
}
public void setSystemResourceConsiderations(List<SystemResourceConsideration> systemResourceConsiderations) {
this.systemResourceConsiderations = systemResourceConsiderations;
}
@ApiModelProperty("Indicates if the component has additional details documentation")
public boolean isAdditionalDetails() {
return additionalDetails;

View File

@ -32,6 +32,7 @@ public class ProcessorDefinition extends ConfigurableExtensionDefinition {
private InputRequirement.Requirement inputRequirement;
private List<Relationship> supportedRelationships;
private boolean supportsDynamicRelationships;
private DynamicRelationship dynamicRelationship;
private boolean triggerSerially;
private boolean triggerWhenEmpty;
@ -50,6 +51,9 @@ public class ProcessorDefinition extends ConfigurableExtensionDefinition {
private String defaultYieldDuration;
private String defaultBulletinLevel;
private List<Attribute> readsAttributes;
private List<Attribute> writesAttributes;
@ApiModelProperty("Any input requirements this processor has.")
public InputRequirement.Requirement getInputRequirement() {
return inputRequirement;
@ -77,6 +81,15 @@ public class ProcessorDefinition extends ConfigurableExtensionDefinition {
this.supportsDynamicRelationships = supportsDynamicRelationships;
}
@ApiModelProperty("If the processor supports dynamic relationships, this describes the dynamic relationship")
public DynamicRelationship getDynamicRelationship() {
return dynamicRelationship;
}
public void setDynamicRelationship(DynamicRelationship dynamicRelationship) {
this.dynamicRelationship = dynamicRelationship;
}
@ApiModelProperty("Whether or not this processor should be triggered serially (i.e. no concurrent execution).")
public boolean getTriggerSerially() {
return triggerSerially;
@ -208,4 +221,22 @@ public class ProcessorDefinition extends ConfigurableExtensionDefinition {
public void setDefaultBulletinLevel(String defaultBulletinLevel) {
this.defaultBulletinLevel = defaultBulletinLevel;
}
@ApiModelProperty("The FlowFile attributes this processor reads")
public List<Attribute> getReadsAttributes() {
return readsAttributes;
}
public void setReadsAttributes(List<Attribute> readsAttributes) {
this.readsAttributes = readsAttributes;
}
@ApiModelProperty("The FlowFile attributes this processor writes/updates")
public List<Attribute> getWritesAttributes() {
return writesAttributes;
}
public void setWritesAttributes(List<Attribute> writesAttributes) {
this.writesAttributes = writesAttributes;
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.c2.protocol.component.api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel
public class SystemResourceConsideration {
private String resource;
private String description;
@ApiModelProperty(value = "The resource to consider")
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
@ApiModelProperty(value = "The description of how the resource is affected")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View File

@ -38,11 +38,14 @@ import org.apache.nifi.components.resource.ResourceType;
import org.apache.nifi.components.state.Scope;
import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.extension.manifest.AllowableValue;
import org.apache.nifi.extension.manifest.Attribute;
import org.apache.nifi.extension.manifest.DefaultSchedule;
import org.apache.nifi.extension.manifest.DefaultSettings;
import org.apache.nifi.extension.manifest.Dependency;
import org.apache.nifi.extension.manifest.DependentValues;
import org.apache.nifi.extension.manifest.DeprecationNotice;
import org.apache.nifi.extension.manifest.DynamicProperty;
import org.apache.nifi.extension.manifest.DynamicRelationship;
import org.apache.nifi.extension.manifest.Extension;
import org.apache.nifi.extension.manifest.ExtensionManifest;
import org.apache.nifi.extension.manifest.Property;
@ -50,6 +53,7 @@ import org.apache.nifi.extension.manifest.ProvidedServiceAPI;
import org.apache.nifi.extension.manifest.ResourceDefinition;
import org.apache.nifi.extension.manifest.Restricted;
import org.apache.nifi.extension.manifest.Stateful;
import org.apache.nifi.extension.manifest.SystemResourceConsideration;
import org.apache.nifi.logging.LogLevel;
import org.apache.nifi.runtime.manifest.ComponentManifestBuilder;
import org.apache.nifi.runtime.manifest.ExtensionManifestContainer;
@ -63,6 +67,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
/**
@ -208,7 +213,6 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
// processor specific fields
processorDefinition.setInputRequirement(getInputRequirement(extension.getInputRequirement()));
processorDefinition.setSupportedRelationships(getSupportedRelationships(extension.getRelationships()));
processorDefinition.setSupportsDynamicRelationships(extension.getDynamicRelationship() != null);
processorDefinition.setTriggerWhenEmpty(extension.getTriggerWhenEmpty());
processorDefinition.setTriggerSerially(extension.getTriggerSerially());
processorDefinition.setTriggerWhenAnyDestinationAvailable(extension.getTriggerWhenAnyDestinationAvailable());
@ -217,6 +221,12 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
processorDefinition.setPrimaryNodeOnly(extension.getPrimaryNodeOnly());
processorDefinition.setSideEffectFree(extension.getSideEffectFree());
final DynamicRelationship dynamicRelationship = extension.getDynamicRelationship();
if (dynamicRelationship != null) {
processorDefinition.setSupportsDynamicRelationships(true);
processorDefinition.setDynamicRelationship(getDynamicRelationship(dynamicRelationship));
}
final DefaultSettings defaultSettings = extension.getDefaultSettings();
processorDefinition.setDefaultPenaltyDuration(defaultSettings == null ? DEFAULT_PENALIZATION_PERIOD : defaultSettings.getPenaltyDuration());
processorDefinition.setDefaultYieldDuration(defaultSettings == null ? DEFAULT_YIELD_PERIOD : defaultSettings.getYieldDuration());
@ -256,9 +266,41 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
processorDefinition.setDefaultConcurrentTasksBySchedulingStrategy(defaultConcurrentTasks);
processorDefinition.setDefaultSchedulingPeriodBySchedulingStrategy(defaultSchedulingPeriods);
final List<Attribute> readsAttributes = extension.getReadsAttributes();
if (isNotEmpty(readsAttributes)) {
processorDefinition.setReadsAttributes(
readsAttributes.stream()
.map(this::getAttribute)
.collect(Collectors.toList())
);
}
final List<Attribute> writesAttributes = extension.getWritesAttributes();
if (isNotEmpty(writesAttributes)) {
processorDefinition.setWritesAttributes(
writesAttributes.stream()
.map(this::getAttribute)
.collect(Collectors.toList())
);
}
componentManifestBuilder.addProcessor(processorDefinition);
}
private org.apache.nifi.c2.protocol.component.api.Attribute getAttribute(final Attribute attribute) {
final org.apache.nifi.c2.protocol.component.api.Attribute c2Attribute = new org.apache.nifi.c2.protocol.component.api.Attribute();
c2Attribute.setName(attribute.getName());
c2Attribute.setDescription(attribute.getDescription());
return c2Attribute;
}
private org.apache.nifi.c2.protocol.component.api.DynamicRelationship getDynamicRelationship(final DynamicRelationship dynamicRelationship) {
final org.apache.nifi.c2.protocol.component.api.DynamicRelationship c2DynamicRelationship = new org.apache.nifi.c2.protocol.component.api.DynamicRelationship();
c2DynamicRelationship.setName(dynamicRelationship.getName());
c2DynamicRelationship.setDescription(dynamicRelationship.getDescription());
return c2DynamicRelationship;
}
private InputRequirement.Requirement getInputRequirement(final org.apache.nifi.extension.manifest.InputRequirement inputRequirement) {
if (inputRequirement == null) {
return null;
@ -351,7 +393,12 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
final List<String> tags = extension.getTags();
if (isNotEmpty(tags)) {
extensionComponent.setTags(new HashSet<>(tags));
extensionComponent.setTags(new TreeSet<>(tags));
}
final List<String> seeAlso = extension.getSeeAlso();
if (isNotEmpty(seeAlso)) {
extensionComponent.setSeeAlso(new TreeSet<>(seeAlso));
}
// the extension-manifest.xml will have <deprecationNotice/> for non-deprecated components which unmarshalls into
@ -360,6 +407,10 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
if (deprecationNotice != null && deprecationNotice.getReason() != null) {
extensionComponent.setDeprecated(true);
extensionComponent.setDeprecationReason(deprecationNotice.getReason());
final List<String> alternatives = deprecationNotice.getAlternatives();
if (isNotEmpty(alternatives)) {
extensionComponent.setDeprecationAlternatives(new TreeSet<>(alternatives));
}
}
final List<ProvidedServiceAPI> providedServiceApis = extension.getProvidedServiceAPIs();
@ -394,11 +445,27 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
}
}
final List<SystemResourceConsideration> systemResourceConsiderations = extension.getSystemResourceConsiderations();
if (isNotEmpty(systemResourceConsiderations)) {
extensionComponent.setSystemResourceConsiderations(
systemResourceConsiderations.stream()
.map(this::getSystemResourceConsideration)
.collect(Collectors.toList())
);
}
if (additionalDetails != null) {
extensionComponent.setAdditionalDetails(true);
}
}
private org.apache.nifi.c2.protocol.component.api.SystemResourceConsideration getSystemResourceConsideration(final SystemResourceConsideration systemResourceConsideration) {
final org.apache.nifi.c2.protocol.component.api.SystemResourceConsideration c2consideration = new org.apache.nifi.c2.protocol.component.api.SystemResourceConsideration();
c2consideration.setResource(systemResourceConsideration.getResource());
c2consideration.setDescription(systemResourceConsideration.getDescription());
return c2consideration;
}
private Scope getScope(final org.apache.nifi.extension.manifest.Scope sourceScope) {
switch (sourceScope) {
case LOCAL:
@ -434,11 +501,26 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
configurableComponentDefinition.setPropertyDescriptors(propertyDescriptors);
}
if (isNotEmpty(extension.getDynamicProperties())) {
final List<DynamicProperty> dynamicProperties = extension.getDynamicProperties();
if (isNotEmpty(dynamicProperties)) {
configurableComponentDefinition.setSupportsDynamicProperties(true);
configurableComponentDefinition.setDynamicProperties(
dynamicProperties.stream()
.map(this::getDynamicProperty)
.collect(Collectors.toList())
);
}
}
private org.apache.nifi.c2.protocol.component.api.DynamicProperty getDynamicProperty(final DynamicProperty dynamicProperty) {
final org.apache.nifi.c2.protocol.component.api.DynamicProperty c2DynamicProperty = new org.apache.nifi.c2.protocol.component.api.DynamicProperty();
c2DynamicProperty.setName(dynamicProperty.getName());
c2DynamicProperty.setValue(dynamicProperty.getValue());
c2DynamicProperty.setDescription(dynamicProperty.getDescription());
c2DynamicProperty.setExpressionLanguageScope(getELScope(dynamicProperty.getExpressionLanguageScope()));
return c2DynamicProperty;
}
private void addPropertyDescriptor(final Map<String, PropertyDescriptor> propertyDescriptors, final Property property) {
final PropertyDescriptor propertyDescriptor = createPropertyDescriptor(property);
propertyDescriptors.put(propertyDescriptor.getName(), propertyDescriptor);

View File

@ -105,9 +105,22 @@ class TestRuntimeManifest {
assertFalse(listHdfsDefinition.getSideEffectFree());
assertFalse(listHdfsDefinition.getTriggerWhenAnyDestinationAvailable());
assertFalse(listHdfsDefinition.getSupportsDynamicProperties());
assertNull(listHdfsDefinition.getDynamicProperties());
assertFalse(listHdfsDefinition.getSupportsDynamicRelationships());
assertNull(listHdfsDefinition.getDynamicRelationship());
assertEquals(InputRequirement.Requirement.INPUT_FORBIDDEN, listHdfsDefinition.getInputRequirement());
assertTrue(listHdfsDefinition.isAdditionalDetails());
assertNull(listHdfsDefinition.getReadsAttributes());
assertNotNull(listHdfsDefinition.getWritesAttributes());
assertFalse(listHdfsDefinition.getWritesAttributes().isEmpty());
assertNotNull(listHdfsDefinition.getWritesAttributes().get(0).getName());
assertNotNull(listHdfsDefinition.getWritesAttributes().get(0).getDescription());
assertNotNull(listHdfsDefinition.getSeeAlso());
assertFalse(listHdfsDefinition.getSeeAlso().isEmpty());
assertNull(listHdfsDefinition.getSystemResourceConsiderations());
assertNull(listHdfsDefinition.getDeprecated());
assertNull(listHdfsDefinition.getDeprecationReason());
assertNull(listHdfsDefinition.getDeprecationAlternatives());
assertEquals("30 sec", listHdfsDefinition.getDefaultPenaltyDuration());
assertEquals("1 sec", listHdfsDefinition.getDefaultYieldDuration());
@ -230,6 +243,48 @@ class TestRuntimeManifest {
assertEquals(2, joltTransformDefaultSchedulingPeriods.size());
assertEquals(LIST_HDFS_DEFAULT_SCHEDULE_TIME, joltTransformDefaultSchedulingPeriods.get(SchedulingStrategy.TIMER_DRIVEN.name()));
assertEquals(SchedulingStrategy.CRON_DRIVEN.getDefaultSchedulingPeriod(), joltTransformDefaultSchedulingPeriods.get(SchedulingStrategy.CRON_DRIVEN.name()));
// Verify ExecuteSQL has readsAttributes
final ProcessorDefinition executeSqlDef = getProcessorDefinition(bundles, "nifi-standard-nar",
"org.apache.nifi.processors.standard.ExecuteSQL");
assertNotNull(executeSqlDef.getReadsAttributes());
assertFalse(executeSqlDef.getReadsAttributes().isEmpty());
assertNotNull(executeSqlDef.getReadsAttributes().get(0).getName());
assertNotNull(executeSqlDef.getReadsAttributes().get(0).getDescription());
// Verify RouteOnAttribute dynamic relationships and dynamic properties
final ProcessorDefinition routeOnAttributeDef = getProcessorDefinition(bundles, "nifi-standard-nar",
"org.apache.nifi.processors.standard.RouteOnAttribute");
assertTrue(routeOnAttributeDef.getSupportsDynamicRelationships());
assertNotNull(routeOnAttributeDef.getDynamicRelationship());
assertNotNull(routeOnAttributeDef.getDynamicRelationship().getName());
assertNotNull(routeOnAttributeDef.getDynamicRelationship().getDescription());
assertTrue(routeOnAttributeDef.getSupportsDynamicProperties());
assertNotNull(routeOnAttributeDef.getDynamicProperties());
assertFalse(routeOnAttributeDef.getDynamicProperties().isEmpty());
assertNotNull(routeOnAttributeDef.getDynamicProperties().get(0).getName());
assertNotNull(routeOnAttributeDef.getDynamicProperties().get(0).getDescription());
assertNotNull(routeOnAttributeDef.getDynamicProperties().get(0).getValue());
assertNotNull(routeOnAttributeDef.getDynamicProperties().get(0).getExpressionLanguageScope());
// Verify DeleteAzureBlobStorage is deprecated
final ProcessorDefinition deleteAzureBlobDef = getProcessorDefinition(bundles, "nifi-azure-nar",
"org.apache.nifi.processors.azure.storage.DeleteAzureBlobStorage");
assertNotNull(deleteAzureBlobDef.getDeprecated());
assertTrue(deleteAzureBlobDef.getDeprecated().booleanValue());
assertNotNull(deleteAzureBlobDef.getDeprecationReason());
assertNotNull(deleteAzureBlobDef.getDeprecationAlternatives());
assertFalse(deleteAzureBlobDef.getDeprecationAlternatives().isEmpty());
// Verify SplitJson has @SystemResourceConsiderations
final ProcessorDefinition splitJsonDef = getProcessorDefinition(bundles, "nifi-standard-nar",
"org.apache.nifi.processors.standard.SplitJson");
assertNotNull(splitJsonDef.getSystemResourceConsiderations());
assertFalse(splitJsonDef.getSystemResourceConsiderations().isEmpty());
assertNotNull(splitJsonDef.getSystemResourceConsiderations().get(0).getResource());
assertNotNull(splitJsonDef.getSystemResourceConsiderations().get(0).getDescription());
}
private PropertyDescriptor getPropertyDescriptor(final ProcessorDefinition processorDefinition, final String propName) {