+
+ /**
+ * Find augmentation target class from concrete Augmentation class. This method uses first generic argument of
+ * implemented {@link Augmentation} interface.
+ *
+ * @param augmentation {@link Augmentation} subclass for which we want to determine augmentation target.
+ * @return Augmentation target - class which augmentation provides additional extensions.
+ */
+ static final Class<? extends Augmentable<?>> findAugmentationTarget(
+ final Class<? extends Augmentation<?>> augmentation) {
+ final Optional<Class<Augmentable<?>>> opt = ClassLoaderUtils.findFirstGenericArgument(augmentation,
+ Augmentation.class);
+ return opt.orElse(null);
+ }
+
+ private static @NonNull ChildAddressabilitySummary computeChildAddressabilitySummary(final Object nodeSchema) {
+ // FIXME: rework this to work on EffectiveStatements
+ if (nodeSchema instanceof DataNodeContainer contaner) {
+ boolean haveAddressable = false;
+ boolean haveUnaddressable = false;
+ for (DataSchemaNode child : contaner.getChildNodes()) {
+ if (child instanceof ContainerSchemaNode || child instanceof AugmentationSchemaNode) {
+ haveAddressable = true;
+ } else if (child instanceof ListSchemaNode list) {
+ if (list.getKeyDefinition().isEmpty()) {
+ haveUnaddressable = true;
+ } else {
+ haveAddressable = true;
+ }
+ } else if (child instanceof AnydataSchemaNode || child instanceof AnyxmlSchemaNode
+ || child instanceof TypedDataSchemaNode) {
+ haveUnaddressable = true;
+ } else if (child instanceof ChoiceSchemaNode choice) {
+ switch (computeChildAddressabilitySummary(choice)) {
+ case ADDRESSABLE -> haveAddressable = true;
+ case UNADDRESSABLE -> haveUnaddressable = true;
+ case MIXED -> {
+ haveAddressable = true;
+ haveUnaddressable = true;
+ }
+ default -> throw new IllegalStateException("Unhandled accessibility summary for " + child);
+ }
+ } else {
+ LOG.warn("Unhandled child node {}", child);
+ }
+ }
+
+ if (!haveAddressable) {
+ // Empty or all are unaddressable
+ return ChildAddressabilitySummary.UNADDRESSABLE;
+ }
+
+ return haveUnaddressable ? ChildAddressabilitySummary.MIXED : ChildAddressabilitySummary.ADDRESSABLE;
+ } else if (nodeSchema instanceof ChoiceSchemaNode choice) {
+ return computeChildAddressabilitySummary(choice);
+ }
+
+ // No child nodes possible: return unaddressable
+ return ChildAddressabilitySummary.UNADDRESSABLE;
+ }
+
+ private static @NonNull ChildAddressabilitySummary computeChildAddressabilitySummary(
+ final ChoiceSchemaNode choice) {
+ boolean haveAddressable = false;
+ boolean haveUnaddressable = false;
+ for (CaseSchemaNode child : choice.getCases()) {
+ switch (computeChildAddressabilitySummary(child)) {
+ case ADDRESSABLE:
+ haveAddressable = true;
+ break;
+ case UNADDRESSABLE:
+ haveUnaddressable = true;
+ break;
+ case MIXED:
+ // A child is mixed, which means we are mixed, too
+ return ChildAddressabilitySummary.MIXED;
+ default:
+ throw new IllegalStateException("Unhandled accessibility summary for " + child);
+ }
+ }
+
+ if (!haveAddressable) {
+ // Empty or all are unaddressable
+ return ChildAddressabilitySummary.UNADDRESSABLE;
+ }
+
+ return haveUnaddressable ? ChildAddressabilitySummary.MIXED : ChildAddressabilitySummary.ADDRESSABLE;
+ }