X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-dom-codec%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fdom%2Fcodec%2Fimpl%2FDataContainerCodecPrototype.java;h=614f4c4250e7bbb075335beaafc2726df3d8ff8b;hb=92b63c7819f73e531971c7d4b922e203611fd2a8;hp=31915601397bc52f187ec4aa12577b352e551e5f;hpb=721c7756a23554c1bd7249809b0ade749f76cb65;p=mdsal.git diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecPrototype.java index 3191560139..614f4c4250 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecPrototype.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecPrototype.java @@ -7,70 +7,100 @@ */ package org.opendaylight.mdsal.binding.dom.codec.impl; -import com.google.common.collect.Iterables; -import org.checkerframework.checker.lock.qual.Holding; +import static com.google.common.base.Verify.verify; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode.ChildAddressabilitySummary; import org.opendaylight.mdsal.binding.dom.codec.impl.NodeCodecContext.CodecContextFactory; +import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType; +import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeTypes; +import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType; +import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType; +import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType; +import org.opendaylight.mdsal.binding.runtime.api.ContainerLikeRuntimeType; +import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType; +import org.opendaylight.mdsal.binding.runtime.api.NotificationRuntimeType; +import org.opendaylight.mdsal.binding.runtime.api.RuntimeType; +import org.opendaylight.mdsal.binding.runtime.api.RuntimeTypeContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.DataRoot; import org.opendaylight.yangtools.yang.binding.Identifiable; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item; +import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; +import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode; import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; 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.ListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -final class DataContainerCodecPrototype implements NodeContextSupplier { +final class DataContainerCodecPrototype implements NodeContextSupplier { private static final Logger LOG = LoggerFactory.getLogger(DataContainerCodecPrototype.class); - private final T schema; + private static final VarHandle INSTANCE; + + static { + try { + INSTANCE = MethodHandles.lookup().findVarHandle(DataContainerCodecPrototype.class, + "instance", DataContainerCodecContext.class); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ExceptionInInitializerError(e); + } + } + + private final T type; private final QNameModule namespace; private final CodecContextFactory factory; private final Item bindingArg; private final PathArgument yangArg; private final ChildAddressabilitySummary childAddressabilitySummary; - private volatile DataContainerCodecContext instance = null; + // Accessed via INSTANCE + @SuppressWarnings("unused") + private volatile DataContainerCodecContext instance; @SuppressWarnings("unchecked") - private DataContainerCodecPrototype(final Class cls, final PathArgument arg, final T nodeSchema, + private DataContainerCodecPrototype(final Class cls, final PathArgument arg, final T type, final CodecContextFactory factory) { - this(Item.of((Class) cls), arg, nodeSchema, factory); + this(Item.of((Class) cls), arg, type, factory); } - private DataContainerCodecPrototype(final Item bindingArg, final PathArgument arg, final T nodeSchema, + private DataContainerCodecPrototype(final Item bindingArg, final PathArgument arg, final T type, final CodecContextFactory factory) { this.bindingArg = bindingArg; this.yangArg = arg; - this.schema = nodeSchema; + this.type = type; this.factory = factory; if (arg instanceof AugmentationIdentifier) { - this.namespace = Iterables.getFirst(((AugmentationIdentifier) arg).getPossibleChildNames(), null) - .getModule(); + final var childNames = ((AugmentationIdentifier) arg).getPossibleChildNames(); + verify(!childNames.isEmpty(), "Unexpected empty identifier for %s", type); + this.namespace = childNames.iterator().next().getModule(); } else { this.namespace = arg.getNodeType().getModule(); } - this.childAddressabilitySummary = computeChildAddressabilitySummary(nodeSchema); + this.childAddressabilitySummary = type instanceof RuntimeType + ? computeChildAddressabilitySummary(((RuntimeType) type).statement()) + // BindingRuntimeTypes, does not matter + : ChildAddressabilitySummary.MIXED; } - private static ChildAddressabilitySummary computeChildAddressabilitySummary(final WithStatus nodeSchema) { + private static ChildAddressabilitySummary computeChildAddressabilitySummary(final Object nodeSchema) { + // FIXME: rework this to work on EffectiveStatements if (nodeSchema instanceof DataNodeContainer) { boolean haveAddressable = false; boolean haveUnaddressable = false; @@ -83,7 +113,7 @@ final class DataContainerCodecPrototype implements NodeCon } else { haveAddressable = true; } - } else if (child instanceof AnyDataSchemaNode || child instanceof AnyXmlSchemaNode + } else if (child instanceof AnydataSchemaNode || child instanceof AnyxmlSchemaNode || child instanceof TypedDataSchemaNode) { haveUnaddressable = true; } else if (child instanceof ChoiceSchemaNode) { @@ -115,7 +145,7 @@ final class DataContainerCodecPrototype implements NodeCon } else if (nodeSchema instanceof ChoiceSchemaNode) { boolean haveAddressable = false; boolean haveUnaddressable = false; - for (CaseSchemaNode child : ((ChoiceSchemaNode) nodeSchema).getCases().values()) { + for (CaseSchemaNode child : ((ChoiceSchemaNode) nodeSchema).getCases()) { switch (computeChildAddressabilitySummary(child)) { case ADDRESSABLE: haveAddressable = true; @@ -143,100 +173,95 @@ final class DataContainerCodecPrototype implements NodeCon return ChildAddressabilitySummary.UNADDRESSABLE; } - static DataContainerCodecPrototype rootPrototype(final CodecContextFactory factory) { - final SchemaContext schema = factory.getRuntimeContext().getSchemaContext(); - final NodeIdentifier arg = NodeIdentifier.create(schema.getQName()); - return new DataContainerCodecPrototype<>(DataRoot.class, arg, schema, factory); + static DataContainerCodecPrototype rootPrototype(final CodecContextFactory factory) { + return new DataContainerCodecPrototype<>(DataRoot.class, NodeIdentifier.create(SchemaContext.NAME), + factory.getRuntimeContext().getTypes(), factory); } - @SuppressWarnings({ "unchecked", "rawtypes" }) - static DataContainerCodecPrototype from(final Class cls, final T schema, + static DataContainerCodecPrototype from(final Class cls, final T type, final CodecContextFactory factory) { - return new DataContainerCodecPrototype(cls, NodeIdentifier.create(schema.getQName()), schema, factory); + return new DataContainerCodecPrototype<>(cls, createIdentifier(type), type, factory); } - @SuppressWarnings({ "unchecked", "rawtypes" }) - static DataContainerCodecPrototype from(final Item bindingArg, final T schema, + static DataContainerCodecPrototype from(final Item bindingArg, final T type, final CodecContextFactory factory) { - return new DataContainerCodecPrototype(bindingArg, NodeIdentifier.create(schema.getQName()), schema, factory); + return new DataContainerCodecPrototype<>(bindingArg, createIdentifier(type), type, factory); } - @SuppressWarnings({ "rawtypes", "unchecked" }) - static DataContainerCodecPrototype from(final Class augClass, final AugmentationIdentifier arg, - final AugmentationSchemaNode schema, final CodecContextFactory factory) { - return new DataContainerCodecPrototype(augClass, arg, schema, factory); + static DataContainerCodecPrototype from(final Class augClass, + final AugmentationIdentifier arg, final AugmentRuntimeType schema, final CodecContextFactory factory) { + return new DataContainerCodecPrototype<>(augClass, arg, schema, factory); + } + + static DataContainerCodecPrototype from(final Class augClass, + final NotificationRuntimeType schema, final CodecContextFactory factory) { + final PathArgument arg = NodeIdentifier.create(schema.statement().argument()); + return new DataContainerCodecPrototype<>(augClass, arg, schema, factory); } - static DataContainerCodecPrototype from(final Class augClass, - final NotificationDefinition schema, final CodecContextFactory factory) { - final PathArgument arg = NodeIdentifier.create(schema.getQName()); - return new DataContainerCodecPrototype<>(augClass,arg, schema, factory); + private static @NonNull NodeIdentifier createIdentifier(final CompositeRuntimeType type) { + final Object arg = type.statement().argument(); + verify(arg instanceof QName, "Unexpected type %s argument %s", type, arg); + return NodeIdentifier.create((QName) arg); } - protected T getSchema() { - return schema; + @NonNull T getType() { + return type; } ChildAddressabilitySummary getChildAddressabilitySummary() { return childAddressabilitySummary; } - protected QNameModule getNamespace() { + QNameModule getNamespace() { return namespace; } - protected CodecContextFactory getFactory() { + CodecContextFactory getFactory() { return factory; } - protected Class getBindingClass() { + Class getBindingClass() { return bindingArg.getType(); } - protected Item getBindingArg() { + Item getBindingArg() { return bindingArg; } - protected PathArgument getYangArg() { + PathArgument getYangArg() { return yangArg; } @Override public DataContainerCodecContext get() { - DataContainerCodecContext tmp = instance; - if (tmp == null) { - synchronized (this) { - tmp = instance; - if (tmp == null) { - tmp = createInstance(); - instance = tmp; - } - } - } + final DataContainerCodecContext existing = (DataContainerCodecContext) INSTANCE.getAcquire(this); + return existing != null ? existing : loadInstance(); + } - return tmp; + private @NonNull DataContainerCodecContext loadInstance() { + final var tmp = createInstance(); + final var witness = (DataContainerCodecContext) INSTANCE.compareAndExchangeRelease(this, null, tmp); + return witness == null ? tmp : witness; } - @Holding("this") @SuppressWarnings({ "rawtypes", "unchecked" }) - private DataContainerCodecContext createInstance() { + // This method must allow concurrent loading, i.e. nothing in it may have effects outside of the loaded object + private @NonNull DataContainerCodecContext createInstance() { // FIXME: make protected abstract - if (schema instanceof ContainerSchemaNode) { + if (type instanceof ContainerLikeRuntimeType) { return new ContainerNodeCodecContext(this); - } else if (schema instanceof ListSchemaNode) { - return Identifiable.class.isAssignableFrom(getBindingClass()) ? new KeyedListNodeCodecContext(this) - : new ListNodeCodecContext(this); - } else if (schema instanceof ChoiceSchemaNode) { + } else if (type instanceof ListRuntimeType) { + return Identifiable.class.isAssignableFrom(getBindingClass()) + ? KeyedListNodeCodecContext.create((DataContainerCodecPrototype) this) + : new ListNodeCodecContext(this); + } else if (type instanceof ChoiceRuntimeType) { return new ChoiceNodeCodecContext(this); - } else if (schema instanceof AugmentationSchemaNode) { + } else if (type instanceof AugmentRuntimeType) { return new AugmentationNodeContext(this); - } else if (schema instanceof CaseSchemaNode) { + } else if (type instanceof CaseRuntimeType) { return new CaseNodeCodecContext(this); } - throw new IllegalArgumentException("Unsupported type " + getBindingClass() + " " + schema); - } - - boolean isChoice() { - return schema instanceof ChoiceSchemaNode; + throw new IllegalArgumentException("Unsupported type " + getBindingClass() + " " + type); } }