Skip to content

Commit 95e1614

Browse files
committed
review
1 parent 77e1b56 commit 95e1614

File tree

1 file changed

+125
-25
lines changed
  • nifi-framework-bundle/nifi-framework-extensions/nifi-py4j-framework-bundle/nifi-python-extension-api/src/main/python/src/nifiapi

1 file changed

+125
-25
lines changed

nifi-framework-bundle/nifi-framework-extensions/nifi-py4j-framework-bundle/nifi-python-extension-api/src/main/python/src/nifiapi/properties.py

Lines changed: 125 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from enum import Enum
1717
import re
1818

19-
from py4j.protocol import Py4JJavaError
19+
from py4j.protocol import Py4JError
2020

2121
from nifiapi.componentstate import StateManager
2222
from nifiapi.__jvm__ import JvmHolder
@@ -254,6 +254,8 @@ def to_java_descriptor(self, gateway, cs_type_lookup):
254254
return builder.build()
255255

256256

257+
258+
257259
def __get_allowable_values(self, gateway):
258260
if self.allowableValues is None:
259261
return None
@@ -296,6 +298,106 @@ def __add_resource_definition(self, gateway, resource_definition, builder):
296298
builder.identifiesExternalResource(cardinality, types[0], types[1:])
297299

298300

301+
def _collect_descriptor_metadata(java_context):
302+
descriptor_list = []
303+
descriptor_lookup = {}
304+
value_lookup = {}
305+
306+
try:
307+
java_properties = java_context.getProperties()
308+
except AttributeError:
309+
java_properties = None
310+
311+
if java_properties is not None:
312+
for entry in java_properties.entrySet():
313+
descriptor = entry.getKey()
314+
name = descriptor.getName()
315+
if name not in descriptor_lookup:
316+
descriptor_list.append(descriptor)
317+
descriptor_lookup[name] = descriptor
318+
319+
configured_value = entry.getValue()
320+
value_lookup[name] = configured_value if configured_value is not None else descriptor.getDefaultValue()
321+
322+
try:
323+
supported_descriptor_supplier = getattr(java_context, 'getSupportedPropertyDescriptors')
324+
except AttributeError:
325+
supported_descriptor_supplier = None
326+
327+
supported_descriptors = None
328+
if callable(supported_descriptor_supplier):
329+
try:
330+
supported_descriptors = supported_descriptor_supplier()
331+
except Py4JError:
332+
supported_descriptors = None
333+
334+
if supported_descriptors is not None:
335+
for descriptor in supported_descriptors:
336+
name = descriptor.getName()
337+
if name not in descriptor_lookup:
338+
descriptor_list.append(descriptor)
339+
descriptor_lookup[name] = descriptor
340+
if name not in value_lookup:
341+
value_lookup[name] = descriptor.getDefaultValue()
342+
343+
return descriptor_list, descriptor_lookup, value_lookup
344+
345+
346+
def _dependent_values_iter(dependency):
347+
dependent_values = dependency.getDependentValues()
348+
if dependent_values is None:
349+
return None
350+
return [value for value in dependent_values]
351+
352+
353+
def _dependencies_satisfied(descriptor, descriptor_lookup, value_lookup, cache, visiting):
354+
name = descriptor.getName()
355+
if name in cache:
356+
return cache[name]
357+
358+
if name in visiting:
359+
# Circular dependency detected; treat as unsatisfied to avoid infinite recursion
360+
cache[name] = False
361+
return False
362+
363+
dependencies = descriptor.getDependencies()
364+
if dependencies is None or dependencies.isEmpty():
365+
cache[name] = True
366+
return True
367+
368+
visiting.add(name)
369+
370+
for dependency in dependencies:
371+
dependency_name = dependency.getPropertyName()
372+
dependency_descriptor = descriptor_lookup.get(dependency_name)
373+
if dependency_descriptor is None:
374+
cache[name] = False
375+
visiting.remove(name)
376+
return False
377+
378+
if not _dependencies_satisfied(dependency_descriptor, descriptor_lookup, value_lookup, cache, visiting):
379+
cache[name] = False
380+
visiting.remove(name)
381+
return False
382+
383+
dependency_value = value_lookup.get(dependency_name)
384+
dependent_values = _dependent_values_iter(dependency)
385+
if dependent_values is None:
386+
if dependency_value is None:
387+
cache[name] = False
388+
visiting.remove(name)
389+
return False
390+
else:
391+
if dependency_value not in dependent_values:
392+
cache[name] = False
393+
visiting.remove(name)
394+
return False
395+
396+
visiting.remove(name)
397+
cache[name] = True
398+
return True
399+
400+
299401
class PropertyContext:
300402
__trivial_attribute_reference__ = re.compile(r"\$\{([^${}\[\],:;/*\' \t\r\n\\d][^${}\[\],:;/*\' \t\r\n]*)}")
301403
__escaped_attribute_reference__ = re.compile(r"\$\{'([^${}\[\],:;/*\' \t\r\n\\d][^${}\[\],:;/*\'\t\r\n]*)'}")
@@ -331,25 +433,25 @@ class ProcessContext(PropertyContext):
331433

332434
def __init__(self, java_context):
333435
self.java_context = java_context
436+
descriptors, descriptor_lookup, value_lookup = _collect_descriptor_metadata(java_context)
437+
dependency_cache = {}
334438

335-
try:
336-
descriptors = java_context.getProperties().keySet()
337-
except AttributeError:
338-
descriptors = getattr(java_context, 'getSupportedPropertyDescriptors')()
339-
self.name = java_context.getName()
439+
get_name = getattr(java_context, 'getName', None)
440+
self.name = get_name() if callable(get_name) else None
340441
self.property_values = {}
341442
self.descriptor_value_map = {}
342443

343444
for descriptor in descriptors:
344-
string_value = None
345-
property_value = None
346-
try:
347-
property_value = java_context.getProperty(descriptor.getName())
348-
string_value = property_value.getValue()
349-
except (AssertionError, Py4JJavaError):
350-
# Dependencies for this property are not satisfied; skip adding it
445+
if not _dependencies_satisfied(descriptor, descriptor_lookup, value_lookup, dependency_cache, set()):
351446
continue
352447

448+
property_value = java_context.getProperty(descriptor.getName())
449+
string_value = property_value.getValue()
450+
if string_value is None:
451+
string_value = value_lookup.get(descriptor.getName())
452+
else:
453+
value_lookup[descriptor.getName()] = string_value
454+
353455
property_value = self.create_python_property_value(descriptor.isExpressionLanguageSupported(), property_value, string_value)
354456
self.property_values[descriptor.getName()] = property_value
355457

@@ -370,24 +472,22 @@ class ValidationContext(PropertyContext):
370472

371473
def __init__(self, java_context):
372474
self.java_context = java_context
373-
374-
try:
375-
descriptors = java_context.getProperties().keySet()
376-
except AttributeError:
377-
descriptors = getattr(java_context, 'getSupportedPropertyDescriptors')()
475+
descriptors, descriptor_lookup, value_lookup = _collect_descriptor_metadata(java_context)
476+
dependency_cache = {}
378477
self.property_values = {}
379478
self.descriptor_value_map = {}
380479

381480
for descriptor in descriptors:
382-
string_value = None
383-
property_value = None
384-
try:
385-
property_value = java_context.getProperty(descriptor)
386-
string_value = property_value.getValue()
387-
except (AssertionError, Py4JJavaError):
388-
# Dependencies for this property are not satisfied; skip adding it
481+
if not _dependencies_satisfied(descriptor, descriptor_lookup, value_lookup, dependency_cache, set()):
389482
continue
390483

484+
property_value = java_context.getProperty(descriptor)
485+
string_value = property_value.getValue()
486+
if string_value is None:
487+
string_value = value_lookup.get(descriptor.getName())
488+
else:
489+
value_lookup[descriptor.getName()] = string_value
490+
391491
property_value = self.create_python_property_value(descriptor.isExpressionLanguageSupported(), property_value, string_value)
392492
self.property_values[descriptor.getName()] = property_value
393493

0 commit comments

Comments
 (0)