*/
package org.opendaylight.mdsal.binding.dom.codec.impl;
-import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import java.lang.invoke.MethodHandle;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNull;
private final ImmutableMap<Class<?>, CommonDataObjectCodecPrototype<?>> byStreamClass;
private final ImmutableMap<NodeIdentifier, CodecContextSupplier> byYang;
private final ImmutableMap<String, ValueNodeCodecContext> leafChild;
- private final MethodHandle proxyConstructor;
AbstractDataObjectCodecContext(final CommonDataObjectCodecPrototype<T> prototype,
- final CodecDataObjectAnalysis<T> analysis) {
+ final DataContainerAnalysis<T> analysis) {
super(prototype);
byBindingArgClass = analysis.byBindingArgClass;
byStreamClass = analysis.byStreamClass;
byYang = analysis.byYang;
leafChild = analysis.leafNodes;
- proxyConstructor = analysis.proxyConstructor;
}
@Override
return byYang.get(arg);
}
- @SuppressWarnings("checkstyle:illegalCatch")
- final @NonNull D createBindingProxy(final DataContainerNode node) {
- try {
- return (D) proxyConstructor.invokeExact(this, node);
- } catch (final Throwable e) {
- Throwables.throwIfUnchecked(e);
- throw new IllegalStateException(e);
- }
- }
-
final ValueNodeCodecContext getLeafChild(final String name) {
final ValueNodeCodecContext value = leafChild.get(name);
if (value == null) {
*/
package org.opendaylight.mdsal.binding.dom.codec.impl;
+import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
import java.util.List;
import java.util.Map;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingAugmentationCodecTreeNode;
final class AugmentationCodecContext<D extends DataObject & Augmentation<?>>
extends AbstractDataObjectCodecContext<D, AugmentRuntimeType> implements BindingAugmentationCodecTreeNode<D> {
+ private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(void.class,
+ AbstractDataObjectCodecContext.class, DataContainerNode.class);
+ private static final MethodType DATAOBJECT_TYPE = MethodType.methodType(DataObject.class,
+ AugmentationCodecContext.class, DataContainerNode.class);
+
+ private final MethodHandle proxyConstructor;
+
+ private AugmentationCodecContext(final AugmentationCodecPrototype prototype,
+ final DataContainerAnalysis<AugmentRuntimeType> analysis) {
+ super(prototype, analysis);
+
+ final var bindingClass = CodecDataObjectGenerator.generate(prototype.getFactory().getLoader(),
+ prototype.getBindingClass(), analysis.leafContexts, analysis.daoProperties, null);
+
+ final MethodHandle ctor;
+ try {
+ ctor = MethodHandles.publicLookup().findConstructor(bindingClass, CONSTRUCTOR_TYPE);
+ } catch (NoSuchMethodException | IllegalAccessException e) {
+ throw new LinkageError("Failed to find contructor for class " + bindingClass, e);
+ }
+
+ proxyConstructor = ctor.asType(DATAOBJECT_TYPE);
+ }
+
AugmentationCodecContext(final AugmentationCodecPrototype prototype) {
- super(prototype, new CodecDataObjectAnalysis<>(prototype, CodecItemFactory.of(), null));
+ this(prototype, new DataContainerAnalysis<>(prototype, CodecItemFactory.of()));
}
@Override
return bindingArg();
}
+ @SuppressWarnings("checkstyle:illegalCatch")
@Override
public D filterFrom(final DataContainerNode parentData) {
for (var childArg : ((AugmentationCodecPrototype) prototype).getChildArgs()) {
if (parentData.childByArg(childArg) != null) {
- return createBindingProxy(parentData);
+ try {
+ return (D) proxyConstructor.invokeExact(this, parentData);
+ } catch (final Throwable e) {
+ Throwables.throwIfUnchecked(e);
+ throw new IllegalStateException(e);
+ }
}
}
return null;
checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type must be derived from DataContainer");
final var ret = new LinkedList<Class<? extends DataObject>>();
for (var method : type.getMethods()) {
- AbstractDataContainerAnalysis.getYangModeledReturnType(method, Naming.GETTER_PREFIX)
+ DataContainerAnalysis.getYangModeledReturnType(method, Naming.GETTER_PREFIX)
.ifPresent(entity -> ret.add((Class<? extends DataObject>) entity));
}
return ret;
+++ /dev/null
-/*
- * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.binding.dom.codec.impl;
-
-import com.google.common.base.VerifyException;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.reflect.Method;
-import java.util.List;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentableRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
-import org.opendaylight.yangtools.yang.binding.Augmentable;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
-
-/**
- * Analysis of a {@link DataObject} specialization class. The primary point of this class is to separate out creation
- * indices needed for {@link #proxyConstructor}. Since we want to perform as much indexing as possible in a single pass,
- * we also end up indexing things that are not strictly required to arrive at that constructor.
- */
-final class CodecDataObjectAnalysis<R extends CompositeRuntimeType> extends AbstractDataContainerAnalysis<R> {
- private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(void.class,
- AbstractDataObjectCodecContext.class, DataContainerNode.class);
- private static final MethodType DATAOBJECT_TYPE = MethodType.methodType(DataObject.class,
- AbstractDataObjectCodecContext.class, DataContainerNode.class);
-
- final @NonNull Class<? extends CodecDataObject<?>> generatedClass;
- final @NonNull List<AugmentRuntimeType> possibleAugmentations;
- final @NonNull MethodHandle proxyConstructor;
-
- CodecDataObjectAnalysis(final CommonDataObjectCodecPrototype<R> prototype, final CodecItemFactory itemFactory,
- final Method keyMethod) {
- this(prototype.getBindingClass(), prototype.getType(), prototype.getFactory(), itemFactory, keyMethod);
- }
-
- CodecDataObjectAnalysis(final Class<?> bindingClass, final R runtimeType, final CodecContextFactory factory,
- final CodecItemFactory itemFactory, final Method keyMethod) {
- super(bindingClass, runtimeType, factory, itemFactory);
-
- // Final bits: generate the appropriate class, As a side effect we identify what Augmentations are possible
- if (Augmentable.class.isAssignableFrom(bindingClass)) {
- // Verify we have the appropriate backing runtimeType
- if (!(runtimeType instanceof AugmentableRuntimeType augmentableRuntimeType)) {
- throw new VerifyException(
- "Unexpected type %s backing augmenable %s".formatted(runtimeType, bindingClass));
- }
-
- possibleAugmentations = augmentableRuntimeType.augments();
- generatedClass = CodecDataObjectGenerator.generateAugmentable(factory.getLoader(), bindingClass,
- leafContexts, daoProperties, keyMethod);
- } else {
- possibleAugmentations = List.of();
- generatedClass = CodecDataObjectGenerator.generate(factory.getLoader(), bindingClass, leafContexts,
- daoProperties, keyMethod);
- }
-
- // All done: acquire the constructor: it is supposed to be public
- final MethodHandle ctor;
- try {
- ctor = MethodHandles.publicLookup().findConstructor(generatedClass, CONSTRUCTOR_TYPE);
- } catch (NoSuchMethodException | IllegalAccessException e) {
- throw new LinkageError("Failed to find contructor for class " + generatedClass, e);
- }
-
- proxyConstructor = ctor.asType(DATAOBJECT_TYPE);
- }
-}
* Analysis of a {@link DataContainer} specialization class. This includes things needed for
* {@link DataContainerCodecContext}'s methods as well as the appropriate run-time generated class.
*/
-abstract class AbstractDataContainerAnalysis<R extends CompositeRuntimeType> {
- private static final Logger LOG = LoggerFactory.getLogger(AbstractDataContainerAnalysis.class);
+final class DataContainerAnalysis<R extends CompositeRuntimeType> {
+ private static final Logger LOG = LoggerFactory.getLogger(DataContainerAnalysis.class);
// Needed for DataContainerCodecContext
final @NonNull ImmutableMap<Class<?>, CommonDataObjectCodecPrototype<?>> byStreamClass;
final @NonNull ImmutableMap<Method, ValueNodeCodecContext> leafContexts;
final @NonNull ImmutableMap<Class<?>, PropertyInfo> daoProperties;
- AbstractDataContainerAnalysis(final Class<?> bindingClass, final R runtimeType, final CodecContextFactory factory,
+ DataContainerAnalysis(final CommonDataObjectCodecPrototype<R> prototype, final CodecItemFactory itemFactory) {
+ this(prototype.getBindingClass(), prototype.getType(), prototype.getFactory(), itemFactory);
+ }
+
+ DataContainerAnalysis(final Class<?> bindingClass, final R runtimeType, final CodecContextFactory factory,
final CodecItemFactory itemFactory) {
leafContexts = factory.getLeafNodes(bindingClass, runtimeType.statement());
return ret;
}
- static final Optional<Class<? extends DataContainer>> getYangModeledReturnType(final Method method,
+ static Optional<Class<? extends DataContainer>> getYangModeledReturnType(final Method method,
final String prefix) {
final String methodName = method.getName();
if ("getClass".equals(methodName) || !methodName.startsWith(prefix) || method.getParameterCount() > 0) {
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.annotations.Beta;
+import com.google.common.base.Throwables;
+import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Method;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.binding.model.api.GeneratedType;
import org.opendaylight.mdsal.binding.model.api.Type;
import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.AugmentableRuntimeType;
import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.BindingObject;
import org.opendaylight.yangtools.yang.binding.DataObject;
permits CaseCodecContext, ContainerLikeCodecContext, ListCodecContext, NotificationCodecContext {
private static final Logger LOG = LoggerFactory.getLogger(DataObjectCodecContext.class);
+ private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(void.class,
+ AbstractDataObjectCodecContext.class, DataContainerNode.class);
+ private static final MethodType DATAOBJECT_TYPE = MethodType.methodType(DataObject.class,
+ DataObjectCodecContext.class, DataContainerNode.class);
private static final VarHandle MISMATCHED_AUGMENTED;
static {
private final ImmutableMap<Class<?>, AugmentationCodecPrototype> augmentToPrototype;
private final ImmutableMap<NodeIdentifier, Class<?>> yangToAugmentClass;
private final @NonNull Class<? extends CodecDataObject<?>> generatedClass;
+ private final MethodHandle proxyConstructor;
// Note this the content of this field depends only of invariants expressed as this class's fields or
// BindingRuntimeContext. It is only accessed via MISMATCHED_AUGMENTED above.
}
DataObjectCodecContext(final CommonDataObjectCodecPrototype<T> prototype, final CodecItemFactory itemFactory) {
- this(prototype, new CodecDataObjectAnalysis<>(prototype, itemFactory, null));
+ this(prototype, new DataContainerAnalysis<>(prototype, itemFactory), null);
}
DataObjectCodecContext(final CommonDataObjectCodecPrototype<T> prototype, final Method keyMethod) {
- this(prototype, new CodecDataObjectAnalysis<>(prototype, CodecItemFactory.of(), keyMethod));
+ this(prototype, new DataContainerAnalysis<>(prototype, CodecItemFactory.of()), keyMethod);
}
private DataObjectCodecContext(final CommonDataObjectCodecPrototype<T> prototype,
- final CodecDataObjectAnalysis<T> analysis) {
+ final DataContainerAnalysis<T> analysis, final Method keyMethod) {
super(prototype, analysis);
- // Inherit analysis stuff
- generatedClass = analysis.generatedClass;
+ final var bindingClass = getBindingClass();
+
+ // Final bits: generate the appropriate class, As a side effect we identify what Augmentations are possible
+ final List<AugmentRuntimeType> possibleAugmentations;
+ if (Augmentable.class.isAssignableFrom(bindingClass)) {
+ // Verify we have the appropriate backing runtimeType
+ final var runtimeType = prototype.getType();
+ if (!(runtimeType instanceof AugmentableRuntimeType augmentableRuntimeType)) {
+ throw new VerifyException(
+ "Unexpected type %s backing augmenable %s".formatted(runtimeType, bindingClass));
+ }
+
+ possibleAugmentations = augmentableRuntimeType.augments();
+ generatedClass = CodecDataObjectGenerator.generateAugmentable(factory().getLoader(), bindingClass,
+ analysis.leafContexts, analysis.daoProperties, keyMethod);
+ } else {
+ possibleAugmentations = List.of();
+ generatedClass = CodecDataObjectGenerator.generate(factory().getLoader(), bindingClass,
+ analysis.leafContexts, analysis.daoProperties, keyMethod);
+ }
+
+ // All done: acquire the constructor: it is supposed to be public
+ final MethodHandle ctor;
+ try {
+ ctor = MethodHandles.publicLookup().findConstructor(generatedClass, CONSTRUCTOR_TYPE);
+ } catch (NoSuchMethodException | IllegalAccessException e) {
+ throw new LinkageError("Failed to find contructor for class " + generatedClass, e);
+ }
+
+ proxyConstructor = ctor.asType(DATAOBJECT_TYPE);
// Deal with augmentations, which are not something we analysis provides
final var augPathToBinding = new HashMap<NodeIdentifier, Class<?>>();
final var augClassToProto = new HashMap<Class<?>, AugmentationCodecPrototype>();
- for (var augment : analysis.possibleAugmentations) {
+ for (var augment : possibleAugmentations) {
final var augProto = loadAugmentPrototype(augment);
if (augProto != null) {
final var augBindingClass = augProto.getBindingClass();
return map;
}
- final @NonNull Class<? extends CodecDataObject<?>> generatedClass() {
- return generatedClass;
- }
-
@Override
public InstanceIdentifier.PathArgument deserializePathArgument(final PathArgument arg) {
checkArgument(getDomPathArgument().equals(arg));
final ImmutableCollection<Class<? extends BindingObject>> cacheSpecifier) {
return createCachingCodec(this, cacheSpecifier);
}
+
+ final @NonNull Class<? extends CodecDataObject<?>> generatedClass() {
+ return generatedClass;
+ }
+
+ @SuppressWarnings("checkstyle:illegalCatch")
+ final @NonNull D createBindingProxy(final DataContainerNode node) {
+ try {
+ return (D) proxyConstructor.invokeExact(this, node);
+ } catch (final Throwable e) {
+ Throwables.throwIfUnchecked(e);
+ throw new IllegalStateException(e);
+ }
+ }
}