2 * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.binding.generator.impl.rt;
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.base.Functions;
14 import com.google.common.base.VerifyException;
15 import com.google.common.collect.ImmutableMap;
16 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.List;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
22 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
23 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
24 import org.opendaylight.mdsal.binding.runtime.api.GeneratedRuntimeType;
25 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
28 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
30 abstract class AbstractCompositeRuntimeType<S extends EffectiveStatement<?, ?>>
31 extends AbstractRuntimeType<S, GeneratedType> implements CompositeRuntimeType {
32 private static final RuntimeType[] EMPTY = new RuntimeType[0];
34 private final ImmutableMap<JavaTypeName, GeneratedRuntimeType> byClass;
35 private final Object bySchemaTree;
37 @SuppressFBWarnings(value = "SE_COMPARATOR_SHOULD_BE_SERIALIZABLE",
38 justification = "https://github.com/spotbugs/spotbugs/issues/1985")
39 AbstractCompositeRuntimeType(final GeneratedType bindingType, final S statement, final List<RuntimeType> children) {
40 super(bindingType, statement);
42 byClass = children.stream()
43 .filter(GeneratedRuntimeType.class::isInstance)
44 .map(GeneratedRuntimeType.class::cast)
45 .collect(ImmutableMap.toImmutableMap(GeneratedRuntimeType::getIdentifier, Functions.identity()));
47 final var tmp = children.stream()
48 .filter(child -> child.statement() instanceof SchemaTreeEffectiveStatement)
49 .toArray(RuntimeType[]::new);
50 bySchemaTree = switch (tmp.length) {
54 Arrays.sort(tmp, (o1, o2) -> {
55 final int cmp = extractQName(o1).compareTo(extractQName(o2));
56 verify(cmp != 0, "Type %s conflicts with %s on schema tree", o1, o2);
65 public final RuntimeType schemaTreeChild(final QName qname) {
66 if (bySchemaTree instanceof RuntimeType tmp) {
67 return qname.equals(tmp.statement().argument()) ? tmp : null;
70 final var tmp = (RuntimeType[]) bySchemaTree;
71 @SuppressFBWarnings(value = "SE_COMPARATOR_SHOULD_BE_SERIALIZABLE",
72 justification = "https://github.com/spotbugs/spotbugs/issues/1985")
73 final int offset = Arrays.binarySearch(tmp, null, (o1, o2) -> {
74 // We make assumptions about how Arrays.binarySearch() is implemented: o2 is expected to be the provided
75 // key -- which is null. This helps CHA by not introducing a fake RuntimeType class and the
76 // corresponding instanceof checks.
77 verify(o2 == null, "Unexpected key %s", o2);
78 return extractQName(o1).compareTo(qname);
80 return offset < 0 ? null : tmp[offset];
84 public final GeneratedRuntimeType bindingChild(final JavaTypeName typeName) {
85 return byClass.get(requireNonNull(typeName));
88 // Makes an assertion of all types being of specified type
89 @SuppressWarnings("unchecked")
90 final <T extends RuntimeType> @NonNull List<T> schemaTree(final Class<T> expectedType) {
91 if (expectedType.isInstance(bySchemaTree)) {
92 return List.of(expectedType.cast(bySchemaTree));
95 final var tmp = (RuntimeType[]) bySchemaTree;
96 for (var item : tmp) {
97 verify(expectedType.isInstance(item), "Unexpected schema tree child %s", item);
99 return (List<T>) Collections.unmodifiableList(Arrays.asList(tmp));
102 private static @NonNull QName extractQName(final RuntimeType type) {
103 final var stmt = type.statement();
104 if (stmt instanceof SchemaTreeEffectiveStatement<?> schemaTreeStmt) {
105 return schemaTreeStmt.argument();
107 throw new VerifyException("Unexpected statement " + stmt + " in " + type);