2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.binding.data.codec.impl;
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ImmutableMap;
12 import com.google.common.collect.Iterables;
14 import java.util.List;
15 import java.util.Map.Entry;
17 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
18 import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
19 import org.opendaylight.yangtools.sal.binding.model.api.Type;
20 import org.opendaylight.yangtools.yang.binding.Augmentation;
21 import org.opendaylight.yangtools.yang.binding.DataObject;
22 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.common.QNameModule;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
27 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
28 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
29 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
30 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
31 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
32 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
34 abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataContainerCodecContext<T> {
36 protected final ImmutableMap<String, LeafNodeCodecContext> leafChild;
37 protected final ImmutableMap<Type, Entry<Type, Type>> choiceCaseChildren;
38 protected final ImmutableMap<AugmentationIdentifier, Type> augIdentifierToType;
40 protected DataObjectCodecContext(final Class<?> cls, final QNameModule namespace, final T nodeSchema,
41 final CodecContextFactory loader) {
42 super(cls, namespace, nodeSchema, loader);
43 this.leafChild = loader.getLeafNodes(cls, nodeSchema);
44 this.choiceCaseChildren = factory.getRuntimeContext().getChoiceCaseChildren(schema);
45 this.augIdentifierToType = factory.getRuntimeContext().getAvailableAugmentationTypes(nodeSchema);
49 protected DataContainerCodecContext<?> getIdentifierChild(final InstanceIdentifier.PathArgument arg,
50 final List<YangInstanceIdentifier.PathArgument> builder) {
51 if (choiceCaseChildren.isEmpty()) {
52 return super.getIdentifierChild(arg, builder);
54 // Lookup in choiceCase
55 Class<? extends DataObject> argument = arg.getType();
56 ReferencedTypeImpl ref = new ReferencedTypeImpl(argument.getPackage().getName(), argument.getSimpleName());
57 Entry<Type, Type> cazeId = choiceCaseChildren.get(ref);
59 return super.getIdentifierChild(arg, builder);
61 ClassLoadingStrategy loader = factory.getRuntimeContext().getStrategy();
63 Class<?> choice = loader.loadClass(cazeId.getKey());
64 Class<?> caze = loader.loadClass(cazeId.getValue());
65 ChoiceNodeCodecContext choiceNode = (ChoiceNodeCodecContext) getStreamChild(choice);
66 choiceNode.addYangPathArgument(arg, builder);
67 CaseNodeCodecContext cazeNode = (CaseNodeCodecContext) choiceNode.getStreamChild(caze);
68 cazeNode.addYangPathArgument(arg, builder);
69 return cazeNode.getIdentifierChild(arg, builder);
71 } catch (ClassNotFoundException e) {
72 throw new IllegalArgumentException("Required class not found.", e);
78 protected NodeCodecContext getYangIdentifierChild(final YangInstanceIdentifier.PathArgument arg) {
79 if (arg instanceof YangInstanceIdentifier.AugmentationIdentifier) {
80 return getChildByAugmentationIdentifier((YangInstanceIdentifier.AugmentationIdentifier) arg);
83 QName childQName = arg.getNodeType();
84 DataSchemaNode childSchema = schema.getDataChildByName(childQName);
85 Preconditions.checkArgument(childSchema != null, "Argument %s is not valid child of %s", arg, schema);
86 if (childSchema instanceof DataNodeContainer || childSchema instanceof ChoiceNode) {
87 Class<?> childCls = factory.getRuntimeContext().getClassForSchema(childSchema);
88 DataContainerCodecContext<?> childNode = getStreamChild(childCls);
91 return getLeafChild(childQName.getLocalName());
95 protected NodeCodecContext getChildByAugmentationIdentifier(final YangInstanceIdentifier.AugmentationIdentifier arg) {
96 final Type augType = augIdentifierToType.get(arg);
98 Class<?> augClass = factory.getRuntimeContext().getStrategy().loadClass(augType);
99 return getStreamChild(augClass);
100 } catch (ClassNotFoundException e) {
101 throw new IllegalStateException("Unable to load referenced augmentation.", e);
105 protected final LeafNodeCodecContext getLeafChild(final String name) {
106 final LeafNodeCodecContext value = leafChild.get(name);
107 Preconditions.checkArgument(value != null, "Leaf %s is not valid for %s", name, bindingClass);
112 protected DataContainerCodecContext<?> loadChild(final Class<?> childClass) {
113 if (Augmentation.class.isAssignableFrom(childClass)) {
114 return loadAugmentation(childClass);
117 DataSchemaNode origDef = factory.getRuntimeContext().getSchemaDefinition(childClass);
118 // Direct instantiation or use in same module in which grouping
120 DataSchemaNode sameName = schema.getDataChildByName(origDef.getQName());
121 final DataSchemaNode childSchema;
122 if (sameName != null) {
123 // Exactly same schema node
124 if (origDef.equals(sameName)) {
125 childSchema = sameName;
126 // We check if instantiated node was added via uses
127 // statement and is an instantiation of same grouping
128 } else if (origDef.equals(SchemaNodeUtils.getRootOriginalIfPossible(sameName))) {
129 childSchema = sameName;
131 // Node has same name, but clearly is different
135 // We are looking for instantiation via uses in other module
136 QName instantiedName = QName.create(namespace, origDef.getQName().getLocalName());
137 DataSchemaNode potential = schema.getDataChildByName(instantiedName);
138 // We check if it is really instantiated from same
140 // as class was derived
141 if (potential != null && origDef.equals(SchemaNodeUtils.getRootOriginalIfPossible(potential))) {
142 childSchema = potential;
148 .checkArgument(childSchema != null, "Node %s does not have child named %s", schema, childClass);
149 return DataContainerCodecContext.from(childClass, childSchema, factory);
152 @SuppressWarnings("rawtypes")
153 private AugmentationNode loadAugmentation(final Class childClass) {
154 Preconditions.checkArgument(schema instanceof AugmentationTarget);
155 @SuppressWarnings("unchecked")
156 Entry<AugmentationIdentifier, AugmentationSchema> augSchema = factory.getRuntimeContext()
157 .getResolvedAugmentationSchema(schema, childClass);
158 QNameModule namespace = Iterables.getFirst(augSchema.getKey().getPossibleChildNames(), null).getModule();
159 return new AugmentationNode(childClass, namespace, augSchema.getKey(), augSchema.getValue(), factory);