public static synchronized <T, E extends Throwable> T getProperty(Program program, Object key,
			SCOPE scope, Class<? extends T> clazz, PropertyValueSupplier<T, E> supplier) throws E {
		if (scope == SCOPE.ANALYSIS_SESSION &&
			(!AutoAnalysisManager.hasAutoAnalysisManager(program) ||
				!AutoAnalysisManager.getAnalysisManager(program).isAnalyzing())) {
			throw new IllegalArgumentException("No active analysis session");
		}

		PerProgramProperties perProgramProps =
			properties.computeIfAbsent(program, PerProgramProperties::new);

		Property property = perProgramProps.props.get(key);
		if (property == null) {
			T supplierVal = supplier.get();
			if (supplierVal == null) {
				return null;
			}
			property = perProgramProps.addProperty(key, supplierVal, scope);
		}
		if (property.scope != scope) {
			throw new IllegalArgumentException("Mismatched Program property scope");
		}
		return clazz.isInstance(property.value) ? clazz.cast(property.value) : null;
	}
Returns a property value that has been associated with the specified program.
<p>
If the property wasn't present, the {@link PropertyValueSupplier} will be used to 
create the value and associate it with the program.

@param <T> type of the property value.  If the property value is {@link Closeable}, it
will be {@link Closeable#close() closed} when released.
@param <E> type of the exception the supplier throws
@param program {@link Program}
@param key property key
@param scope {@link SCOPE} lifetime of property.  If an analysis session is NOT active,
requesting {@link SCOPE#ANALYSIS_SESSION} will throw an IllegalArgumentException.  If the
requested scope does not match the scope of the already existing value, an 
IllegalArgumentException will be thrown.
@param clazz type of the property value
@param supplier {@link PropertyValueSupplier} callback that will create the property 
value if it is not present
@return property value
@throws IllegalArgumentException if scope == ANALYSIS_SESSION and there is no active analysis
session, OR, if the requested scope does not match the scope used to an earlier call for
the same property
@throws E same exception type that the supplier throws
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/TransientProgramProperties.java