import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
+import com.google.common.base.Verify;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
+import java.lang.reflect.Type;
+import java.util.List;
import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.ChoiceIn;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
}
});
+ private final LoadingCache<Class<? extends DataObject>, ChoiceNodeCodecContext<?>> choicesByClass =
+ CacheBuilder.newBuilder().build(new CacheLoader<Class<? extends DataObject>, ChoiceNodeCodecContext<?>>() {
+ @Override
+ public ChoiceNodeCodecContext<?> load(final Class<? extends DataObject> key) {
+ return createChoiceDataContext(key);
+ }
+ });
+
private final LoadingCache<QName, DataContainerCodecContext<?,?>> childrenByQName = CacheBuilder.newBuilder().build(
new CacheLoader<QName, DataContainerCodecContext<?,?>>() {
@Override
return new NotificationCodecContext<>(notificationType, schema, factory());
}
+ ChoiceNodeCodecContext<?> createChoiceDataContext(final Class<? extends DataObject> caseType) {
+ final Class<?> choiceClass = findCaseChoice(caseType);
+ Preconditions.checkArgument(choiceClass != null, "Class %s is not a valid case representation", caseType);
+ final DataSchemaNode schema = factory().getRuntimeContext().getSchemaDefinition(choiceClass);
+ Preconditions.checkArgument(schema instanceof ChoiceSchemaNode, "Class %s does not refer to a choice",
+ caseType);
+
+ final DataContainerCodecContext<?, ChoiceSchemaNode> choice = DataContainerCodecPrototype.from(choiceClass,
+ (ChoiceSchemaNode)schema, factory()).get();
+ Verify.verify(choice instanceof ChoiceNodeCodecContext);
+ return (ChoiceNodeCodecContext<?>) choice;
+ }
+
@Override
protected Object deserializeObject(final NormalizedNode<?, ?> normalizedNode) {
throw new UnsupportedOperationException("Unable to deserialize root");
return null;
}
+ @Override
+ public DataContainerCodecContext<?, ?> bindingPathArgumentChild(final InstanceIdentifier.PathArgument arg,
+ final List<PathArgument> builder) {
+ final java.util.Optional<? extends Class<? extends DataObject>> caseType = arg.getCaseType();
+ if (caseType.isPresent()) {
+ final Class<? extends DataObject> type = caseType.get();
+ final ChoiceNodeCodecContext<?> choice = choicesByClass.getUnchecked(type);
+ choice.addYangPathArgument(arg, builder);
+ final DataContainerCodecContext<?, ?> caze = choice.streamChild(type);
+ caze.addYangPathArgument(arg, builder);
+ return caze.bindingPathArgumentChild(arg, builder);
+ }
+
+ return super.bindingPathArgumentChild(arg, builder);
+ }
+
+ private static Class<?> findCaseChoice(final Class<? extends DataObject> caseClass) {
+ for (Type type : caseClass.getGenericInterfaces()) {
+ if (type instanceof Class) {
+ final Class<?> typeClass = (Class<?>) type;
+ if (ChoiceIn.class.isAssignableFrom(typeClass)) {
+ return typeClass.asSubclass(ChoiceIn.class);
+ }
+ }
+ }
+
+ return null;
+ }
+
private static <K,V> V getOrRethrow(final LoadingCache<K, V> cache, final K key) {
try {
return cache.getUnchecked(key);
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelListKey;
import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.aug.norev.cont.cont.choice.ContAug;
+import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.aug.norev.root.RootAug;
import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.Cont;
+import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.Root;
import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.cont.ContChoice;
import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.cont.cont.choice.ContBase;
import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.grp.GrpCont;
+import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.root.RootBase;
import org.opendaylight.yangtools.yang.binding.Identifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.QName;
assertEquals(1, ContBase.class.getCanonicalName().compareTo(ContAug.class.getCanonicalName()));
final YangInstanceIdentifier contAugLegacy = registry.toYangInstanceIdentifier(
InstanceIdentifier.builder(Cont.class).child((Class) GrpCont.class).build());
- assertEquals(YangInstanceIdentifier.create(NodeIdentifier.create(Cont.QNAME),
- NodeIdentifier.create(ContChoice.QNAME),
- NodeIdentifier.create(GrpCont.QNAME.withModule(ContAug.QNAME.getModule()))), contAugLegacy);
+ assertEquals(contAug, contAugLegacy);
+
+ final YangInstanceIdentifier rootBase = registry.toYangInstanceIdentifier(
+ InstanceIdentifier.builder(RootBase.class, GrpCont.class).build());
+ assertEquals(YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME),
+ NodeIdentifier.create(GrpCont.QNAME)), rootBase);
- // FIXME: root choice handling is busted
- // final YangInstanceIdentifier rootAugLegacy = registry.toYangInstanceIdentifier(
- // InstanceIdentifier.create((Class) GrpCont.class));
+ final YangInstanceIdentifier rootAug = registry.toYangInstanceIdentifier(
+ InstanceIdentifier.builder(RootAug.class, GrpCont.class).build());
+ assertEquals(YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME),
+ NodeIdentifier.create(GrpCont.QNAME.withModule(RootAug.QNAME.getModule()))), rootAug);
}
@Test
YangInstanceIdentifier.create(NodeIdentifier.create(Cont.QNAME), NodeIdentifier.create(ContChoice.QNAME),
NodeIdentifier.create(GrpCont.QNAME.withModule(ContAug.QNAME.getModule()))));
assertEquals(InstanceIdentifier.builder(Cont.class).child(ContAug.class, GrpCont.class).build(), contAug);
+
+ final InstanceIdentifier<?> rootBase = registry.fromYangInstanceIdentifier(
+ YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME), NodeIdentifier.create(GrpCont.QNAME)));
+ assertEquals(InstanceIdentifier.builder(RootBase.class, GrpCont.class).build(), rootBase);
+
+ final InstanceIdentifier<?> rootAug = registry.fromYangInstanceIdentifier(
+ YangInstanceIdentifier.create(NodeIdentifier.create(Root.QNAME),
+ NodeIdentifier.create(GrpCont.QNAME.withModule(RootAug.QNAME.getModule()))));
+ assertEquals(InstanceIdentifier.builder(RootAug.class, GrpCont.class).build(), rootAug);
}
}
return new InstanceIdentifierBuilderImpl<T>().addWildNode(Item.of(container));
}
+ /**
+ * Create an InstanceIdentifierBuilder for a specific type of InstanceIdentifier as specified by container in
+ * a {@code grouping} used in the {@code case} statement.
+ *
+ * @param caze Choice case class
+ * @param container Base container
+ * @param <C> Case type
+ * @param <T> Type of the container
+ * @return A new {@link InstanceIdentifierBuilder}
+ * @throws NullPointerException if any argument is null
+ */
+ public static <C extends ChoiceIn<? extends DataRoot> & DataObject, T extends ChildOf<? super C>>
+ InstanceIdentifierBuilder<T> builder(final Class<C> caze, final Class<T> container) {
+ return new InstanceIdentifierBuilderImpl<T>().addWildNode(Item.of(caze, container));
+ }
+
/**
* Create an InstanceIdentifierBuilder for a specific type of InstanceIdentifier which represents an
* {@link IdentifiableItem}.
return new InstanceIdentifierBuilderImpl<N>().addNode(IdentifiableItem.of(listItem, listKey));
}
+ /**
+ * Create an InstanceIdentifierBuilder for a specific type of InstanceIdentifier which represents an
+ * {@link IdentifiableItem} in a {@code grouping} used in the {@code case} statement.
+ *
+ * @param caze Choice case class
+ * @param listItem list item class
+ * @param listKey key value
+ * @param <C> Case type
+ * @param <N> List type
+ * @param <K> List key
+ * @return A new {@link InstanceIdentifierBuilder}
+ * @throws NullPointerException if any argument is null
+ */
+ public static <C extends ChoiceIn<? extends DataRoot> & DataObject,
+ N extends Identifiable<K> & ChildOf<? super C>, K extends Identifier<N>>
+ InstanceIdentifierBuilder<N> builder(final Class<C> caze, final Class<N> listItem, final K listKey) {
+ return new InstanceIdentifierBuilderImpl<N>().addNode(IdentifiableItem.of(caze, listItem, listKey));
+ }
+
/**
* Create an instance identifier for a very specific object type. This method implements {@link #create(Iterable)}
* semantics, except it is used by internal callers, which have assured that the argument is an immutable Iterable.