X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-runtime-api%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fruntime%2Fapi%2FAbstractBindingRuntimeContext.java;h=dbed269c4af0d895127351403becc4af7433da88;hb=refs%2Fchanges%2F45%2F98245%2F100;hp=96b5db7ab23d76644de9d85539e715fe8e80874e;hpb=b74c242b4eec43f2ec14a7f22019ca73f0077969;p=mdsal.git
diff --git a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/AbstractBindingRuntimeContext.java b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/AbstractBindingRuntimeContext.java
index 96b5db7ab2..dbed269c4a 100644
--- a/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/AbstractBindingRuntimeContext.java
+++ b/binding/mdsal-binding-runtime-api/src/main/java/org/opendaylight/mdsal/binding/runtime/api/AbstractBindingRuntimeContext.java
@@ -8,320 +8,100 @@
package org.opendaylight.mdsal.binding.runtime.api;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
import com.google.common.annotations.Beta;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import java.util.AbstractMap.SimpleEntry;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.Set;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.model.api.DefaultType;
-import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.model.api.MethodSignature;
-import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
-import org.opendaylight.mdsal.binding.model.api.Type;
-import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
import org.opendaylight.yangtools.yang.binding.Action;
import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.binding.RpcInput;
+import org.opendaylight.yangtools.yang.binding.RpcOutput;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
-import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
-import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
-import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Runtime Context for Java YANG Binding classes. It provides information derived from the backing effective model,
* which is not captured in generated classes (and hence cannot be obtained from {@code BindingReflections}.
- *
- *
Some of this information are for example list of all available children for cases
- * {@link #getChoiceCaseChildren(DataNodeContainer)}, since choices are augmentable and new choices may be introduced
- * by additional models. Same goes for all possible augmentations.
*/
@Beta
public abstract class AbstractBindingRuntimeContext implements BindingRuntimeContext {
- private static final Logger LOG = LoggerFactory.getLogger(AbstractBindingRuntimeContext.class);
-
private final LoadingCache> identityClasses = CacheBuilder.newBuilder().weakValues().build(
new CacheLoader>() {
@Override
public Class> load(final QName key) {
- final Optional identityType = getTypes().findIdentity(key);
- checkArgument(identityType.isPresent(), "Supplied QName %s is not a valid identity", key);
+ final var type = getTypes().findIdentity(key).orElseThrow(
+ () -> new IllegalArgumentException("Supplied QName " + key + " is not a valid identity"));
try {
- return loadClass(identityType.get());
+ return loadClass(type.getIdentifier());
} catch (final ClassNotFoundException e) {
- throw new IllegalArgumentException("Required class " + identityType + "was not found.", e);
+ throw new IllegalArgumentException("Required class " + type + " was not found.", e);
}
}
});
@Override
- public final > AugmentationSchemaNode getAugmentationDefinition(final Class augClass) {
- return getTypes().findAugmentation(DefaultType.of(augClass)).orElse(null);
+ public final > AugmentRuntimeType getAugmentationDefinition(final Class augClass) {
+ return getTypes().findSchema(JavaTypeName.create(augClass))
+ .filter(AugmentRuntimeType.class::isInstance)
+ .map(AugmentRuntimeType.class::cast)
+ .orElse(null);
}
@Override
- public final DataSchemaNode getSchemaDefinition(final Class> cls) {
+ public final CompositeRuntimeType getSchemaDefinition(final Class> cls) {
checkArgument(!Augmentation.class.isAssignableFrom(cls), "Supplied class must not be an augmentation (%s is)",
cls);
checkArgument(!Action.class.isAssignableFrom(cls), "Supplied class must not be an action (%s is)", cls);
- return (DataSchemaNode) getTypes().findSchema(DefaultType.of(cls)).orElse(null);
- }
-
- @Override
- public final ActionDefinition getActionDefinition(final Class extends Action, ?, ?>> cls) {
- return (ActionDefinition) getTypes().findSchema(DefaultType.of(cls)).orElse(null);
+ checkArgument(!Notification.class.isAssignableFrom(cls), "Supplied class must not be a notification (%s is)",
+ cls);
+ return (CompositeRuntimeType) getTypes().findSchema(JavaTypeName.create(cls)).orElse(null);
}
@Override
- public final Absolute getActionIdentifier(final Class extends Action, ?, ?>> cls) {
- return getTypes().findSchemaNodeIdentifier(DefaultType.of(cls)).orElse(null);
+ public final ActionRuntimeType getActionDefinition(final Class extends Action, ?, ?>> cls) {
+ return (ActionRuntimeType) getTypes().findSchema(JavaTypeName.create(cls)).orElse(null);
}
@Override
- public final Entry getResolvedAugmentationSchema(
- final DataNodeContainer target, final Class extends Augmentation>> aug) {
- final AugmentationSchemaNode origSchema = getAugmentationDefinition(aug);
- checkArgument(origSchema != null, "Augmentation %s is not known in current schema context", aug);
- /*
- * FIXME: Validate augmentation schema lookup
- *
- * Currently this algorithm, does not verify if instantiated child nodes
- * are real one derived from augmentation schema. The problem with
- * full validation is, if user used copy builders, he may use
- * augmentation which was generated for different place.
- *
- * If this augmentations have same definition, we emit same identifier
- * with data and it is up to underlying user to validate data.
- *
- */
- final Set childNames = new HashSet<>();
- final Set realChilds = new HashSet<>();
- for (final DataSchemaNode child : origSchema.getChildNodes()) {
- final DataSchemaNode dataChildQNname = target.getDataChildByName(child.getQName());
- final String childLocalName = child.getQName().getLocalName();
- if (dataChildQNname == null) {
- for (DataSchemaNode dataSchemaNode : target.getChildNodes()) {
- if (childLocalName.equals(dataSchemaNode.getQName().getLocalName())) {
- realChilds.add(dataSchemaNode);
- childNames.add(dataSchemaNode.getQName());
- }
- }
- } else {
- realChilds.add(dataChildQNname);
- childNames.add(child.getQName());
- }
- }
-
- final AugmentationIdentifier identifier = AugmentationIdentifier.create(childNames);
- final AugmentationSchemaNode proxy = new EffectiveAugmentationSchema(origSchema, realChilds);
- return new SimpleEntry<>(identifier, proxy);
+ public final RuntimeType getTypeWithSchema(final Class> type) {
+ return getTypes().findSchema(JavaTypeName.create(type))
+ .orElseThrow(() -> new IllegalArgumentException("Failed to find schema for " + type));
}
@Override
- public final Optional getCaseSchemaDefinition(final ChoiceSchemaNode schema,
- final Class> childClass) {
- final DataSchemaNode origSchema = getSchemaDefinition(childClass);
- checkArgument(origSchema instanceof CaseSchemaNode, "Supplied schema %s is not case.", origSchema);
-
- /* FIXME: Make sure that if there are multiple augmentations of same
- * named case, with same structure we treat it as equals
- * this is due property of Binding specification and copy builders
- * that user may be unaware that he is using incorrect case
- * which was generated for choice inside grouping.
- */
- return findInstantiatedCase(schema, (CaseSchemaNode) origSchema);
+ public final Class> getClassForSchema(final Absolute schema) {
+ final var child = getTypes().schemaTreeChild(schema);
+ checkArgument(child != null, "Failed to find binding type for %s", schema);
+ return loadClass(child);
}
@Override
- public final Entry getTypeWithSchema(final Class> type) {
- return getTypeWithSchema(getTypes(), DefaultType.of(type));
- }
-
- private static @NonNull Entry getTypeWithSchema(final BindingRuntimeTypes types,
- final Type referencedType) {
- final WithStatus schema = types.findSchema(referencedType).orElseThrow(
- () -> new NullPointerException("Failed to find schema for type " + referencedType));
- final Type definedType = types.findType(schema).orElseThrow(
- () -> new NullPointerException("Failed to find defined type for " + referencedType + " schema " + schema));
-
- if (definedType instanceof GeneratedTypeBuilder) {
- return new SimpleEntry<>(((GeneratedTypeBuilder) definedType).build(), schema);
- }
- checkArgument(definedType instanceof GeneratedType, "Type %s is not a GeneratedType", referencedType);
- return new SimpleEntry<>((GeneratedType) definedType, schema);
+ public final Class> getIdentityClass(final QName input) {
+ return identityClasses.getUnchecked(input);
}
@Override
- public final Map> getChoiceCaseChildren(final DataNodeContainer schema) {
- return getChoiceCaseChildren(getTypes(), schema);
- }
-
- private static @NonNull ImmutableMap> getChoiceCaseChildren(final BindingRuntimeTypes types,
- final DataNodeContainer schema) {
- final Map> childToCase = new HashMap<>();
-
- for (final ChoiceSchemaNode choice : Iterables.filter(schema.getChildNodes(), ChoiceSchemaNode.class)) {
- final ChoiceSchemaNode originalChoice = getOriginalSchema(choice);
- final Optional optType = types.findType(originalChoice);
- checkState(optType.isPresent(), "Failed to find generated type for choice %s", originalChoice);
- final Type choiceType = optType.get();
-
- for (Type caze : types.findCases(choiceType)) {
- final Entry caseIdentifier = new SimpleEntry<>(choiceType, caze);
- final HashSet caseChildren = new HashSet<>();
- if (caze instanceof GeneratedTypeBuilder) {
- caze = ((GeneratedTypeBuilder) caze).build();
- }
- collectAllContainerTypes((GeneratedType) caze, caseChildren);
- for (final Type caseChild : caseChildren) {
- childToCase.put(caseChild, caseIdentifier);
- }
- }
- }
- return ImmutableMap.copyOf(childToCase);
+ public final Class extends RpcInput> getRpcInput(final QName rpcName) {
+ return loadClass(getTypes().findRpcInput(rpcName)
+ .orElseThrow(() -> new IllegalArgumentException("Failed to find RpcInput for " + rpcName)))
+ .asSubclass(RpcInput.class);
}
@Override
- public final Set> getCases(final Class> choice) {
- final Collection cazes = getTypes().findCases(DefaultType.of(choice));
- final Set> ret = new HashSet<>(cazes.size());
- for (final Type caze : cazes) {
- try {
- ret.add(loadClass(caze));
- } catch (final ClassNotFoundException e) {
- LOG.warn("Failed to load class for case {}, ignoring it", caze, e);
- }
- }
- return ret;
+ public final Class extends RpcOutput> getRpcOutput(final QName rpcName) {
+ return loadClass(getTypes().findRpcOutput(rpcName)
+ .orElseThrow(() -> new IllegalArgumentException("Failed to find RpcOutput for " + rpcName)))
+ .asSubclass(RpcOutput.class);
}
- @Override
- public final Class> getClassForSchema(final SchemaNode childSchema) {
- final SchemaNode origSchema = getOriginalSchema(childSchema);
- final Optional clazzType = getTypes().findType(origSchema);
- checkArgument(clazzType.isPresent(), "Failed to find binding type for %s (original %s)",
- childSchema, origSchema);
-
+ private Class> loadClass(final RuntimeType type) {
try {
- return loadClass(clazzType.get());
+ return loadClass(type.javaType());
} catch (final ClassNotFoundException e) {
throw new IllegalStateException(e);
}
}
-
- @Override
- public final ImmutableMap getAvailableAugmentationTypes(
- final DataNodeContainer container) {
- final Map identifierToType = new HashMap<>();
- if (container instanceof AugmentationTarget) {
- final BindingRuntimeTypes types = getTypes();
- for (final AugmentationSchemaNode augment : ((AugmentationTarget) container).getAvailableAugmentations()) {
- // Augmentation must have child nodes if is to be used with Binding classes
- AugmentationSchemaNode augOrig = augment;
- while (augOrig.getOriginalDefinition().isPresent()) {
- augOrig = augOrig.getOriginalDefinition().get();
- }
-
- if (!augment.getChildNodes().isEmpty()) {
- final Optional augType = types.findType(augOrig);
- if (augType.isPresent()) {
- identifierToType.put(getAugmentationIdentifier(augment), augType.get());
- }
- }
- }
- }
-
- return ImmutableMap.copyOf(identifierToType);
- }
-
- @Override
- public final Class> getIdentityClass(final QName input) {
- return identityClasses.getUnchecked(input);
- }
-
- private static AugmentationIdentifier getAugmentationIdentifier(final AugmentationSchemaNode augment) {
- // FIXME: use DataSchemaContextNode.augmentationIdentifierFrom() once it does caching
- return AugmentationIdentifier.create(augment.getChildNodes().stream().map(DataSchemaNode::getQName)
- .collect(ImmutableSet.toImmutableSet()));
- }
-
- private static Set collectAllContainerTypes(final GeneratedType type, final Set collection) {
- for (final MethodSignature definition : type.getMethodDefinitions()) {
- Type childType = definition.getReturnType();
- if (childType instanceof ParameterizedType) {
- childType = ((ParameterizedType) childType).getActualTypeArguments()[0];
- }
- if (childType instanceof GeneratedType || childType instanceof GeneratedTypeBuilder) {
- collection.add(childType);
- }
- }
- for (final Type parent : type.getImplements()) {
- if (parent instanceof GeneratedType) {
- collectAllContainerTypes((GeneratedType) parent, collection);
- }
- }
- return collection;
- }
-
- private static T getOriginalSchema(final T choice) {
- @SuppressWarnings("unchecked")
- final T original = (T) SchemaNodeUtils.getRootOriginalIfPossible(choice);
- if (original != null) {
- return original;
- }
- return choice;
- }
-
- private static @NonNull Optional findInstantiatedCase(final ChoiceSchemaNode instantiatedChoice,
- final CaseSchemaNode originalDefinition) {
- CaseSchemaNode potential = instantiatedChoice.findCase(originalDefinition.getQName()).orElse(null);
- if (originalDefinition.equals(potential)) {
- return Optional.of(potential);
- }
- if (potential != null) {
- SchemaNode potentialRoot = SchemaNodeUtils.getRootOriginalIfPossible(potential);
- if (originalDefinition.equals(potentialRoot)) {
- return Optional.of(potential);
- }
- }
-
- // We try to find case by name, then lookup its root definition
- // and compare it with original definition
- // This solves case, if choice was inside grouping
- // which was used in different module and thus namespaces are
- // different, but local names are still same.
- //
- // Still we need to check equality of definition, because local name is not
- // sufficient to uniquelly determine equality of cases
- //
- for (CaseSchemaNode caze : instantiatedChoice.findCaseNodes(originalDefinition.getQName().getLocalName())) {
- if (originalDefinition.equals(SchemaNodeUtils.getRootOriginalIfPossible(caze))) {
- return Optional.of(caze);
- }
- }
- return Optional.empty();
- }
}