import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
+import com.google.common.collect.Interner;
+import com.google.common.collect.Interners;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import javax.xml.transform.dom.DOMSource;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode.Builder;
import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeContainerBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUserLeafSetNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUserMapNodeBuilder;
import org.opendaylight.yangtools.yang.data.spi.node.InterningLeafNodeBuilder;
+import org.opendaylight.yangtools.yang.data.spi.node.InterningLeafSetNodeBuilder;
import org.opendaylight.yangtools.yang.data.util.LeafInterner;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
/**
* Implementation of {@link NormalizedNodeStreamWriter}, which constructs immutable instances of
* This class is not final for purposes of customization, normal users should not need to subclass it.
*/
public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
+ private static final Interner<LeafSetEntryNode<?>> ENTRY_INTERNER = Interners.newWeakInterner();
+
private final Deque<NormalizedNode.Builder> builders = new ArrayDeque<>();
private DataSchemaNode nextSchema;
@Override
public void startLeafSet(final NodeIdentifier name, final int childSizeHint) {
checkDataNodeContainer();
- enter(name, UNKNOWN_SIZE == childSizeHint ? InterningLeafSetNodeBuilder.create(nextSchema)
- : InterningLeafSetNodeBuilder.create(nextSchema, childSizeHint));
+ final var builder = UNKNOWN_SIZE == childSizeHint ? Builders.leafSetBuilder()
+ : Builders.leafSetBuilder(childSizeHint);
+ enter(name, leafSetNodeBuilder(builder, nextSchema));
+ }
+
+ private static <T> Builder<T> leafSetNodeBuilder(final Builder<T> delegate, final @Nullable DataSchemaNode schema) {
+ if (schema instanceof LeafListSchemaNode leafListSchema) {
+ final var type = leafListSchema.getType();
+ if (type instanceof BooleanTypeDefinition || type instanceof EnumTypeDefinition
+ || type instanceof IdentityrefTypeDefinition) {
+ return new InterningLeafSetNodeBuilder<>(delegate, (Interner) ENTRY_INTERNER);
+ }
+ }
+ return delegate;
}
@Override
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.yangtools.yang.data.impl.schema;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.Collection;
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode;
-import org.opendaylight.yangtools.yang.data.api.schema.builder.ListNodeBuilder;
-import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeContainerBuilder;
-import org.opendaylight.yangtools.yang.data.util.LeafsetEntryInterner;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-
-final class InterningLeafSetNodeBuilder<T> implements SystemLeafSetNode.Builder<T> {
- private final SystemLeafSetNode.Builder<T> delegate;
- private final LeafsetEntryInterner interner;
-
- private InterningLeafSetNodeBuilder(final SystemLeafSetNode.Builder<T> delegate,
- final LeafsetEntryInterner interner) {
- this.delegate = requireNonNull(delegate);
- this.interner = requireNonNull(interner);
- }
-
- private static @Nullable LeafsetEntryInterner getInterner(final @Nullable DataSchemaNode schema) {
- return schema instanceof LeafListSchemaNode leafListSchema ? LeafsetEntryInterner.forSchema(leafListSchema)
- : null;
- }
-
- static <T> ListNodeBuilder<T, SystemLeafSetNode<T>> create(final @Nullable DataSchemaNode schema) {
- final var delegate = Builders.<T>leafSetBuilder();
- final var interner = getInterner(schema);
- return interner == null ? delegate : new InterningLeafSetNodeBuilder<>(delegate, interner);
- }
-
- static <T> ListNodeBuilder<T, SystemLeafSetNode<T>> create(final @Nullable DataSchemaNode schema,
- final int sizeHint) {
- final var delegate = Builders.<T>leafSetBuilder(sizeHint);
- final var interner = getInterner(schema);
- return interner == null ? delegate : new InterningLeafSetNodeBuilder<>(delegate, interner);
- }
-
- @Override
- public ListNodeBuilder<T, SystemLeafSetNode<T>> withNodeIdentifier(final NodeIdentifier nodeIdentifier) {
- return delegate.withNodeIdentifier(nodeIdentifier);
- }
-
- @Override
- public ListNodeBuilder<T, SystemLeafSetNode<T>> withValue(final Collection<LeafSetEntryNode<T>> value) {
- // FIXME: pass through interner
- return delegate.withValue(value);
- }
-
- @Override
- public ListNodeBuilder<T, SystemLeafSetNode<T>> withChild(final LeafSetEntryNode<T> child) {
- return delegate.withChild(interner.intern(child));
- }
-
- @Override
- public ListNodeBuilder<T, SystemLeafSetNode<T>> withoutChild(final PathArgument key) {
- return delegate.withoutChild(key);
- }
-
- @Override
- public ListNodeBuilder<T, SystemLeafSetNode<T>> withChildValue(final T child) {
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException();
- }
-
- @Override
- public NormalizedNodeContainerBuilder<NodeIdentifier, PathArgument, LeafSetEntryNode<T>, SystemLeafSetNode<T>>
- addChild(final LeafSetEntryNode<T> child) {
- return withChild(child);
- }
-
- @Override
- public NormalizedNodeContainerBuilder<NodeIdentifier, PathArgument, LeafSetEntryNode<T>, SystemLeafSetNode<T>>
- removeChild(final PathArgument key) {
- return withoutChild(key);
- }
-
- @Override
- public SystemLeafSetNode<T> build() {
- return delegate.build();
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.yangtools.yang.data.spi.node;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.Interner;
+import java.util.Collection;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode.Builder;
+
+/**
+ * Utility class for sharing instances of {@link LeafSetEntryNode}s which have low cardinality -- e.g. those which hold
+ * boolean or enumeration values. Instances containing attributes are not interned.
+ *
+ * <p>
+ * Such objects have cardinality which is capped at the product of QNAMES * TYPE_CARDINALITY, where QNAMES is the total
+ * number of different QNames where the type is used and TYPE_CARDINALITY is the number of possible values for the type.
+ * Boolean has cardinality of 2, enumerations have cardinality equal to the number of enum statements.
+ *
+ * <p>
+ * The theory here is that we tend to have a large number (100K+) of entries in a few places, which could end up hogging
+ * the heap retained via the DataTree with duplicate objects (same QName, same value, different object). Using this
+ * utility, such objects will end up reusing the same object, preventing this overhead.
+ */
+public final class InterningLeafSetNodeBuilder<T> implements Builder<T> {
+ private final Interner<LeafSetEntryNode<T>> interner;
+ private final Builder<T> delegate;
+
+ public InterningLeafSetNodeBuilder(final Builder<T> delegate, final Interner<LeafSetEntryNode<T>> interner) {
+ this.delegate = requireNonNull(delegate);
+ this.interner = requireNonNull(interner);
+ }
+
+ @Override
+ public Builder<T> withNodeIdentifier(final NodeIdentifier nodeIdentifier) {
+ delegate.withNodeIdentifier(nodeIdentifier);
+ return this;
+ }
+
+ @Override
+ public Builder<T> withValue(final Collection<LeafSetEntryNode<T>> value) {
+ // FIXME: pass through interner
+ delegate.withValue(value);
+ return this;
+ }
+
+ @Override
+ public Builder<T> withChild(final LeafSetEntryNode<T> child) {
+ delegate.withChild(interner.intern(child));
+ return this;
+ }
+
+ @Override
+ public Builder<T> withoutChild(final PathArgument key) {
+ delegate.withoutChild(key);
+ return this;
+ }
+
+ @Override
+ public Builder<T> withChildValue(final T child) {
+ // FIXME: implement this
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Builder<T> addChild(final LeafSetEntryNode<T> child) {
+ return withChild(child);
+ }
+
+ @Override
+ public Builder<T> removeChild(final PathArgument key) {
+ return withoutChild(key);
+ }
+
+ @Override
+ public SystemLeafSetNode<T> build() {
+ return delegate.build();
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.yangtools.yang.data.util;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.Interner;
-import com.google.common.collect.Interners;
-import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Utility class for sharing instances of {@link LeafSetEntryNode}s which have low cardinality -- e.g. those which hold
- * boolean or enumeration values. Instances containing attributes are not interned.
- *
- * <p>
- * Such objects have cardinality which is capped at the product of QNAMES * TYPE_CARDINALITY, where QNAMES is the total
- * number of different QNames where the type is used and TYPE_CARDINALITY is the number of possible values for the type.
- * Boolean has cardinality of 2, enumerations have cardinality equal to the number of enum statements.
- *
- * <p>
- * The theory here is that we tend to have a large number (100K+) of entries in a few places, which could end up hogging
- * the heap retained via the DataTree with duplicate objects (same QName, same value, different object). Using this
- * utility, such objects will end up reusing the same object, preventing this overhead.
- */
-@Beta
-public final class LeafsetEntryInterner {
- private static final Logger LOG = LoggerFactory.getLogger(LeafsetEntryInterner.class);
- private static final LeafsetEntryInterner INSTANCE = new LeafsetEntryInterner();
- private static final Interner<Object> INTERNER = Interners.newWeakInterner();
-
- private LeafsetEntryInterner() {
-
- }
-
- @SuppressWarnings("static-method")
- public <T extends LeafSetEntryNode<?>> @NonNull T intern(final @NonNull T sample) {
- /*
- * We do not perform type checks here as they are implied by #forSchema(LeafListSchemaNode). Any misuse can
- * result in inappropriate candidates being interned, but the alternative would be quite a bit slower.
- */
- @SuppressWarnings("unchecked")
- final T ret = (T) INTERNER.intern(sample);
- LOG.trace("Interned object {} to {}", sample, ret);
- return ret;
- }
-
- /**
- * Return a {@link LeafsetEntryInterner} for a particular schema. Interner instances must be used only for leafset
- * entries for that particular schema, otherwise they may produce unexpected results.
- *
- * @param schema Schema of the parent leaf set
- * @return An interner instance, or null if the leafset's type should not be interned.
- */
- public static @Nullable LeafsetEntryInterner forSchema(final @Nullable LeafListSchemaNode schema) {
- if (schema != null) {
- final TypeDefinition<?> type = schema.getType();
- if (type instanceof BooleanTypeDefinition || type instanceof EnumTypeDefinition
- || type instanceof IdentityrefTypeDefinition) {
- return INSTANCE;
- }
- }
- return null;
- }
-}