import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.Identifier;
public interface CodecRegistry {
InstanceIdentifierCodec getInstanceIdentifierCodec();
+
+ IdentitityCodec<?> getIdentityCodec();
<T extends DataContainer> DataContainerCodec<T> getCodecForDataObject(Class<T> object);
<T extends Identifier<?>> IdentifierCodec<T> getCodecForIdentifier(Class<T> object);
<T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object);
+
+ <T extends BaseIdentity> IdentitityCodec<T> getCodecForIdentity(Class<T> codec);
Class<?> getClassForPath(List<QName> names);
--- /dev/null
+package org.opendaylight.controller.sal.binding.dom.serializer.api;
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.BindingCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public interface IdentitityCodec<T extends BaseIdentity> extends BindingCodec<QName, Class<T>>{
+
+ @Override
+ public QName serialize(Class<T> input);
+
+ @Override
+ public Class<T> deserialize(QName input);
+}
import java.lang.reflect.Field;
import java.util.Map;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentitityCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec;
import org.opendaylight.yangtools.yang.binding.BindingCodec;
import org.opendaylight.yangtools.yang.common.QName;
private static final Logger LOG = LoggerFactory.getLogger(CodecMapping.class);
public static final String INSTANCE_IDENTIFIER_CODEC = "INSTANCE_IDENTIFIER_CODEC";
+ public static final String IDENTITYREF_CODEC = "IDENTITYREF_CODEC";
+
public static final String CLASS_TO_CASE_MAP = "CLASS_TO_CASE";
public static final String COMPOSITE_TO_CASE = "COMPOSITE_TO_CASE";
public static final String AUGMENTATION_CODEC = "AUGMENTATION_CODEC";
instanceIdField.set(null, codec);
}
} catch (NoSuchFieldException e) {
- LOG.debug("Instance identifier codec is not needed for {}",obj.getName(),e);
+ LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e);
+ } catch (SecurityException | IllegalAccessException e) {
+ LOG.error("Instance identifier could not be set for {}",obj.getName(),e);
+ }
+ }
+
+
+ public static void setIdentityRefCodec(Class<?> obj,IdentitityCodec<?> codec) {
+ Field instanceIdField;
+ try {
+ instanceIdField = obj.getField(IDENTITYREF_CODEC);
+ if(obj != null) {
+ instanceIdField.set(null, codec);
+ }
+ } catch (NoSuchFieldException e) {
+ LOG.trace("Instance identifier codec is not needed for {}",obj.getName(),e);
} catch (SecurityException | IllegalAccessException e) {
LOG.error("Instance identifier could not be set for {}",obj.getName(),e);
}
LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e);
}
}
+
+
+ public static BindingCodec<?,?> getAugmentationCodec(Class<? extends BindingCodec<?,?>> dataCodec) {
+ Field instanceIdField;
+ try {
+ instanceIdField = dataCodec.getField(AUGMENTATION_CODEC);
+ return (BindingCodec<?,?>) instanceIdField.get(null);
+ } catch (NoSuchFieldException e) {
+ LOG.debug("BUG: Augmentation codec is not needed for {}",dataCodec.getName(),e);
+ } catch (SecurityException | IllegalAccessException e) {
+ LOG.error("Augmentation codec could not be set for {}",dataCodec.getName(),e);
+ }
+ return null;
+ }
}
- static def Node<?> toNode(Map map) {
+ static def Node<?> toNode(Map<?,?> map) {
+ if(map instanceof Node<?>) {
+ return map as Node<?>;
+ }
val nodeMap = map as Map<QName,Object>;
Preconditions.checkArgument(map.size == 1);
val elem = nodeMap.entrySet.iterator.next;
toNodeImpl(qname, value);
}
+
static def dispatch Node<?> toNodeImpl(QName name, List<?> objects) {
val values = new ArrayList<Node<?>>(objects.size);
for (obj : objects) {
- values.add(toNode(obj as Map));
+ if(obj instanceof Node<?>) {
+ values.add(obj as Node<?>);
+ } else if(obj instanceof Map<?,?>) {
+ values.add(toNode(obj as Map<?,?>));
+ }
}
return new CompositeNodeTOImpl(name, null, values);
}
package org.opendaylight.controller.sal.binding.dom.serializer.impl;
+import java.awt.CompositeContext;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.Set;
import java.util.WeakHashMap;
+import org.apache.commons.lang3.text.translate.AggregateTranslator;
import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCaseCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.ChoiceCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.DomCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentifierCodec;
+import org.opendaylight.controller.sal.binding.dom.serializer.api.IdentitityCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.InstanceIdentifierCodec;
import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName;
import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.binding.Augmentable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
import org.opendaylight.yangtools.yang.binding.BindingCodec;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleContext;
import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType;
import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import com.google.common.collect.FluentIterable;
import com.google.common.util.concurrent.CycleDetectingLockFactory.WithExplicitOrdering;
public class LazyGeneratedCodecRegistry implements //
private final static LateMixinCodec NOT_READY_CODEC = new LateMixinCodec();
private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this);
+ private final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec();
private TransformerGenerator generator;
// Concrete class to codecs
- private Map<Class<?>, DataContainerCodec<?>> containerCodecs = new WeakHashMap<>();
- private Map<Class<?>, IdentifierCodec<?>> identifierCodecs = new WeakHashMap<>();
- private Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = new WeakHashMap<>();
- private Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = new WeakHashMap<>();
- private Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>();
-
+ private static final Map<Class<?>, DataContainerCodec<?>> containerCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, IdentifierCodec<?>> identifierCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, AugmentationCodec<?>> augmentationCodecs = new WeakHashMap<>();
+ private static final Map<Class<?>, QName> identityQNames = new WeakHashMap<>();
+ private static final Map<QName, Type> qnamesToIdentityMap = new ConcurrentHashMap<>();
/** Binding type to encountered classes mapping **/
@SuppressWarnings("rawtypes")
- Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
+ private static final Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
@SuppressWarnings("rawtypes")
- private ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
+ private static final ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
private CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
- Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
- Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
+ private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
+ private static final Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
+ private static final Map<Type, QName> typeToQname = new ConcurrentHashMap<>();
private SchemaContext currentSchema;
@Override
public <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object) {
- // TODO Auto-generated method stub
- return null;
+ AugmentationCodec<T> codec = null;
+ @SuppressWarnings("rawtypes")
+ AugmentationCodec potentialCodec = augmentationCodecs.get(object);
+ if (potentialCodec != null) {
+ codec = potentialCodec;
+ } else
+ try {
+ Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentRawCodec = generator
+ .augmentationTransformerFor(object);
+ BindingCodec<Map<QName, Object>, Object> rawCodec = augmentRawCodec.newInstance();
+ codec = new AugmentationCodecWrapper<T>(rawCodec);
+ augmentationCodecs.put(augmentRawCodec, codec);
+ } catch (InstantiationException e) {
+ LOG.error("Can not instantiate raw augmentation codec {}", object.getSimpleName(), e);
+ } catch (IllegalAccessException e) {
+ LOG.debug("BUG: Constructor for {} is not accessible.", object.getSimpleName(), e);
+ }
+ Class<? extends Augmentable<?>> objectSupertype = getAugmentableArgumentFrom(object);
+ if (objectSupertype != null) {
+ getAugmentableCodec(objectSupertype).addAugmentationCodec(object, codec);
+ } else {
+ LOG.warn("Could not find augmentation target for augmentation {}", object);
+ }
+ return codec;
+ }
+
+ private static Class<? extends Augmentable<?>> getAugmentableArgumentFrom(
+ final Class<? extends Augmentation<?>> augmentation) {
+ try {
+ Class<? extends Augmentable<?>> ret = ClassLoaderUtils.withClassLoader(augmentation.getClassLoader(),
+ new Callable<Class<? extends Augmentable<?>>>() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public Class<? extends Augmentable<?>> call() throws Exception {
+ for (java.lang.reflect.Type supertype : augmentation.getGenericInterfaces()) {
+ if (supertype instanceof ParameterizedType
+ && Augmentation.class.equals(((ParameterizedType) supertype).getRawType())) {
+ ParameterizedType augmentationGeneric = (ParameterizedType) supertype;
+ return (Class<? extends Augmentable<?>>) augmentationGeneric
+ .getActualTypeArguments()[0];
+ }
+ }
+ return null;
+ }
+ });
+ return ret;
+ } catch (Exception e) {
+ LOG.error("Could not find augmentable for {}", augmentation, e);
+ return null;
+ }
}
@Override
return newWrapper;
}
- @Override
@SuppressWarnings("rawtypes")
public void bindingClassEncountered(Class cls) {
return newWrapper;
}
+ @Override
+ public IdentitityCodec<?> getIdentityCodec() {
+ return identityRefCodec;
+ }
+
+ @Override
+ public <T extends BaseIdentity> IdentitityCodec<T> getCodecForIdentity(Class<T> codec) {
+ bindingClassEncountered(codec);
+ return identityRefCodec;
+ }
+
@Override
public void onCodecCreated(Class<?> cls) {
CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec);
+ CodecMapping.setIdentityRefCodec(cls, identityRefCodec);
}
@Override
public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) {
pathToType.putAll(context.getChildNodes());
+ qnamesToIdentityMap.putAll(context.getIdentities());
+ for(Entry<QName, GeneratedTOBuilder> identity : context.getIdentities().entrySet()) {
+ typeToQname.put(new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),identity.getKey());
+ }
captureCases(context.getCases(), schemaContext);
}
ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode
.getValue().getName());
- LOG.info("Case path: {} Type : {}", caseNode.getKey(), caseNode.getValue().getFullyQualifiedName());
pathToType.put(caseNode.getKey(), caseNode.getValue());
ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey());
if (path != null && (type = pathToType.get(path)) != null) {
ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
ChoiceCaseCodecImpl partialCodec = typeToCaseCodecs.get(typeref);
- if(partialCodec.getSchema() == null ) {
+ if (partialCodec.getSchema() == null) {
partialCodec.setSchema(caseNode);
}
-
+
Class<?> caseClass = ClassLoaderUtils.tryToLoadClassWithTCCL(type.getFullyQualifiedName());
if (caseClass != null) {
getCaseCodecFor(caseClass);
}
- private AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
+ public AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
AugmentableCompositeCodec ret = augmentableCodecs.get(dataClass);
if (ret != null) {
return ret;
private final Class augmentableType;
- Map<Class, BindingCodec> rawAugmentationCodecs = new WeakHashMap<>();
+ Map<Class, AugmentationCodec<?>> localAugmentationCodecs = new WeakHashMap<>();
public AugmentableCompositeCodec(Class type) {
checkArgument(Augmentable.class.isAssignableFrom(type));
private List serializeImpl(Map<Class, Augmentation> input) {
List ret = new ArrayList<>();
for (Entry<Class, Augmentation> entry : input.entrySet()) {
- BindingCodec codec = getRawCodecForAugmentation(entry.getKey());
- List output = (List) codec.serialize(new ValueWithQName(null, entry.getValue()));
- ret.addAll(output);
+ AugmentationCodec codec = getCodecForAugmentation(entry.getKey());
+ CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue()));
+ ret.addAll(node.getChildren());
}
return ret;
}
- private BindingCodec getRawCodecForAugmentation(Class key) {
- BindingCodec ret = rawAugmentationCodecs.get(key);
- if (ret != null) {
- return ret;
- }
- try {
- Class<? extends BindingCodec> retClass = generator.augmentationTransformerFor(key);
- ret = retClass.newInstance();
- rawAugmentationCodecs.put(key, ret);
- return ret;
- } catch (InstantiationException e) {
- LOG.error("Can not instantiate raw augmentation codec {}", key.getSimpleName(), e);
- } catch (IllegalAccessException e) {
- LOG.debug("BUG: Constructor for {} is not accessible.", key.getSimpleName(), e);
- }
- return null;
+ public synchronized <T extends Augmentation<?>> void addAugmentationCodec(Class<T> augmentationClass,
+ AugmentationCodec<T> value) {
+ localAugmentationCodecs.put(augmentationClass, value);
}
@Override
public Map<Class, Augmentation> deserialize(Object input) {
Map<Class, Augmentation> ret = new HashMap<>();
if (input instanceof CompositeNode) {
- for (Entry<Class, BindingCodec> codec : rawAugmentationCodecs.entrySet()) {
- Augmentation value = (Augmentation) codec.getValue().deserialize(input);
- if (value != null) {
- ret.put(codec.getKey(), value);
+ List<Entry<Class, AugmentationCodec<?>>> codecs = new ArrayList<>(localAugmentationCodecs.entrySet());
+ for (Entry<Class, AugmentationCodec<?>> codec : codecs) {
+ ValueWithQName<?> value = codec.getValue().deserialize((CompositeNode) input);
+ if (value != null && value.getValue() != null) {
+ ret.put(codec.getKey(), (Augmentation) value.getValue());
}
}
}
return ret;
}
- public Map<Class, BindingCodec> getRawAugmentationCodecs() {
- return rawAugmentationCodecs;
- }
-
- public void setRawAugmentationCodecs(Map<Class, BindingCodec> rawAugmentationCodecs) {
- this.rawAugmentationCodecs = rawAugmentationCodecs;
- }
-
public Class getAugmentableType() {
return augmentableType;
}
return getDelegate().serialize(input);
}
}
+
+ private static class AugmentationCodecWrapper<T extends Augmentation<?>> implements AugmentationCodec<T>,
+ Delegator<BindingCodec> {
+
+ private BindingCodec delegate;
+
+ public AugmentationCodecWrapper(BindingCodec<Map<QName, Object>, Object> rawCodec) {
+ this.delegate = rawCodec;
+ }
+
+ @Override
+ public BindingCodec getDelegate() {
+ return delegate;
+ }
+
+ @Override
+ public CompositeNode serialize(ValueWithQName<T> input) {
+ @SuppressWarnings("unchecked")
+ List<Map<QName, Object>> rawValues = (List<Map<QName, Object>>) getDelegate().serialize(input);
+ List<Node<?>> serialized = new ArrayList<>(rawValues.size());
+ for (Map<QName, Object> val : rawValues) {
+ serialized.add(toNode(val));
+ }
+ return new CompositeNodeTOImpl(input.getQname(), null, serialized);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public ValueWithQName<T> deserialize(Node<?> input) {
+ Object rawCodecValue = getDelegate().deserialize((Map<QName, Object>) input);
+ return new ValueWithQName<T>(input.getNodeType(), (T) rawCodecValue);
+ }
+ }
+
+ private class IdentityCompositeCodec implements IdentitityCodec {
+
+ @Override
+ public Object deserialize(Object input) {
+ checkArgument(input instanceof QName);
+ return deserialize((QName) input);
+ }
+
+ @Override
+ public Class<?> deserialize(QName input) {
+ Type type = qnamesToIdentityMap.get(input);
+ if(type == null) {
+ return null;
+ }
+ ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
+ WeakReference<Class> softref = typeToClass.get(typeref);
+ if(softref == null) {
+ return null;
+ }
+ return softref.get();
+ }
+
+ @Override
+ public QName serialize(Class input) {
+ checkArgument(BaseIdentity.class.isAssignableFrom(input));
+ bindingClassEncountered(input);
+ QName qname = identityQNames.get(input);
+ if(qname != null) {
+ return qname;
+ }
+ ConcreteType typeref = Types.typeForClass(input);
+ qname = typeToQname.get(typeref);
+ if(qname != null) {
+ identityQNames.put(input, qname);
+ }
+ return qname;
+ }
+
+ @Override
+ public Object serialize(Object input) {
+ checkArgument(input instanceof Class);
+ return serialize((Class) input);
+ }
+ }
}
\ No newline at end of file
import java.util.concurrent.Callable
import org.opendaylight.yangtools.yang.binding.Augmentation
import org.opendaylight.controller.sal.binding.impl.util.YangSchemaUtils
+import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import java.util.ArrayList
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
+
+ try {
val key = toDataDom(entry.key)
- val data = toCompositeNodeImpl(entry.value);
+ var CompositeNode data;
+ if(Augmentation.isAssignableFrom(entry.key.targetType)) {
+ data = toCompositeNodeImpl(key,entry.value);
+ } else {
+ data = toCompositeNodeImpl(entry.value);
+ }
return new SimpleEntry(key, data);
+
+ } catch (Exception e) {
+ LOG.error("Error during serialization for {}.", entry.key,e);
+ throw e;
+ }
}
private def CompositeNode toCompositeNodeImpl(DataObject object) {
val ret = codec.serialize(new ValueWithQName(null, object));
return ret as CompositeNode;
}
+
+
+ private def CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,DataObject object) {
+
+ //val cls = object.implementedInterface;
+ //waitForSchema(cls);
+ val last = identifier.path.last;
+ val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec;
+ val ret = codec.serialize(new ValueWithQName(last.nodeType, object));
+ if(last instanceof NodeIdentifierWithPredicates) {
+ val predicates = last as NodeIdentifierWithPredicates;
+ val newNodes = new ArrayList<Node<?>>(predicates.keyValues.size);
+ for(predicate : predicates.keyValues.entrySet) {
+ newNodes.add(new SimpleNodeTOImpl(predicate.key,null,predicate.value));
+ }
+ newNodes.addAll(ret.children);
+ return new CompositeNodeTOImpl(last.nodeType,null,newNodes);
+ }
+ return ret as CompositeNode;
+ }
private def void waitForSchema(Class<? extends DataContainer> class1) {
if(Augmentation.isAssignableFrom(class1)) {
@Property
var GeneratorListener listener;
+
+ public static val CLASS_TYPE = Types.typeForClass(Class);
public new(ClassPool pool) {
classPool = pool;
val ctCls = createClass(inputType.codecClassName) [
//staticField(Map,"AUGMENTATION_SERIALIZERS");
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
staticQNameField(node.QName);
implementsType(BINDING_CODEC)
method(Object, "toDomStatic", QName, Object) [
staticQNameField(node.QName);
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
staticField(it, AUGMENTATION_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
method(Object, "toDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
body = '''
//staticField(Map,"AUGMENTATION_SERIALIZERS");
staticQNameField(node.QName);
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
staticField(it, AUGMENTATION_CODEC, BindingCodec)
implementsType(BINDING_CODEC)
method(Object, "toDomStatic", QName, Object) [
staticQNameField(node.augmentationQName);
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
staticField(it, AUGMENTATION_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
implementsType(BINDING_CODEC)
method(Object, "toDomStatic", QName, Object) [
modifiers = PUBLIC + FINAL + STATIC
{
//System.out.println("Qname " + $1);
//System.out.println("Value " + $2);
- «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
+ «QName.name» _resultName = «QName.name».create(QNAME,QNAME.getLocalName());
java.util.List _childNodes = new java.util.ArrayList();
«type.resolvedName» value = («type.resolvedName») $2;
«FOR child : node.childNodes»
//staticField(Map,"AUGMENTATION_SERIALIZERS");
//staticQNameField(inputType);
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
staticField(it, CLASS_TO_CASE_MAP, Map)
staticField(it, COMPOSITE_TO_CASE, Map)
//staticField(it,QNAME_TO_CASE_MAP,BindingCodec)
if (hasYangBinding) {
implementsType(BINDING_CODEC)
staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
+ staticField(it, IDENTITYREF_CODEC, BindingCodec)
implementsType(BindingDeserializer.asCtClass)
}
method(Object, "toDomValue", Object) [
private def dispatch String deserializeValue(Type type, String domParameter) {
if (INSTANCE_IDENTIFIER.equals(type)) {
-
return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)'''
+ } else if (CLASS_TYPE.equals(type)) {
+ return '''(«Class.name») «IDENTITYREF_CODEC».deserialize(«domParameter»)'''
}
-
return '''(«type.resolvedName») «domParameter»'''
}
private def dispatch serializeValue(Type signature, String property) {
if (INSTANCE_IDENTIFIER == signature) {
return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)'''
+ }else if (CLASS_TYPE.equals(signature)) {
+ return '''(«QName.resolvedName») «IDENTITYREF_CODEC».serialize(«property»)'''
}
return '''«property»''';
}
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError;
public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
try {
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path);
+
+
CompositeNode result = biDataService.readOperationalData(biPath);
+ Class<? extends DataObject> targetType = path.getTargetType();
+
+ if(Augmentation.class.isAssignableFrom(targetType)) {
+ path = mappingService.fromDataDom(biPath);
+ Class<? extends Augmentation<?>> augmentType = (Class<? extends Augmentation<?>>) targetType;
+ DataObject parentTo = mappingService.dataObjectFromDataDom(path, result);
+ if(parentTo instanceof Augmentable<?>) {
+ return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType);
+ }
+
+ }
return mappingService.dataObjectFromDataDom(path, result);
+
} catch (DeserializationException e) {
throw new IllegalStateException(e);
}
DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
target.putConfigurationData(baKey, baData);
} catch (DeserializationException e) {
- LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry.getKey(), e);
+ LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
}
}
for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
DataObject baData = mappingService.dataObjectFromDataDom(baKey, entry.getValue());
target.putOperationalData(baKey, baData);
} catch (DeserializationException e) {
- LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry.getKey(), e);
+ LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
}
}
for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
target.removeConfigurationData(baEntry);
} catch (DeserializationException e) {
- LOG.error("Ommiting from BA transaction: {}. Reason {}.", entry, e);
+ LOG.error("Ommiting from BA transaction: {}.", entry, e);
}
}
for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
target.removeOperationalData(baEntry);
} catch (DeserializationException e) {
- LOG.error("Ommiting from BA transaction: {}. Reason{}.", entry, e);
+ LOG.error("Ommiting from BA transaction: {}.", entry, e);
}
}
return target;
</build>
<dependencies>
- <dependency>
+ <dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
<version>1.0-SNAPSHOT</version>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ <version>1.7.2</version>
+ </dependency>
</dependencies>
</project>
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.bugfix;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+import static org.junit.Assert.*;
+
+public class PutAugmentationTest extends AbstractDataServiceTest implements DataChangeListener {
+
+ private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+ private static final String NODE_ID = "openflow:1";
+
+ private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+
+ private static final Map<QName, Object> NODE_KEY_BI = Collections.<QName, Object> singletonMap(NODE_ID_QNAME,
+ NODE_ID);
+
+ private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+ .toInstance();
+
+
+ private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier//
+ .builder(NODES_INSTANCE_ID_BA) //
+ .child(Node.class, NODE_KEY).toInstance();
+
+
+ private static final InstanceIdentifier<SupportedActions> SUPPORTED_ACTIONS_INSTANCE_ID_BA = InstanceIdentifier//
+ .builder(NODES_INSTANCE_ID_BA) //
+ .child(Node.class, NODE_KEY) //
+ .augmentation(FlowCapableNode.class) //
+ .child(SupportedActions.class)
+ .toInstance();
+
+
+ private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+ .node(Nodes.QNAME) //
+ .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+ .toInstance();
+ private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, SupportedActions.QNAME.getLocalName());
+
+
+ private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BI = //
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+ .node(Nodes.QNAME) //
+ .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+ .node(SUPPORTED_ACTIONS_QNAME) //
+ .toInstance();
+
+ private DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedChangeEvent;
+
+
+
+ /**
+ * Test for Bug 148
+ *
+ * @throws Exception
+ */
+ @Test
+ public void putNodeAndAugmentation() throws Exception {
+
+ baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
+
+ NodeBuilder nodeBuilder = new NodeBuilder();
+ nodeBuilder.setId(new NodeId(NODE_ID));
+ nodeBuilder.setKey(NODE_KEY);
+ DataModificationTransaction baseTransaction = baDataService.beginTransaction();
+ baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build());
+ RpcResult<TransactionStatus> result = baseTransaction.commit().get();
+ assertEquals(TransactionStatus.COMMITED, result.getResult());
+ assertNotNull(receivedChangeEvent);
+ Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+ assertNotNull(node);
+ assertEquals(NODE_KEY, node.getKey());
+
+ FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
+ fnub.setHardware("Hardware Foo");
+ fnub.setManufacturer("Manufacturer Foo");
+ fnub.setSerialNumber("Serial Foo");
+ fnub.setDescription("Description Foo");
+ fnub.setSoftware("JUnit emulated");
+ FlowCapableNode fnu = fnub.build();
+ InstanceIdentifier<FlowCapableNode> augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance();
+ DataModificationTransaction augmentedTransaction = baDataService.beginTransaction();
+ augmentedTransaction.putOperationalData(augmentIdentifier, fnu);
+
+ result = augmentedTransaction.commit().get();
+ assertEquals(TransactionStatus.COMMITED, result.getResult());
+
+
+ Node augmentedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+ assertNotNull(node);
+ assertEquals(NODE_KEY, augmentedNode.getKey());
+ System.out.println("Before assertion");
+ assertNotNull(augmentedNode.getAugmentation(FlowCapableNode.class));
+ FlowCapableNode readedAugmentation = augmentedNode.getAugmentation(FlowCapableNode.class);
+ assertEquals(fnu.getDescription(), readedAugmentation.getDescription());
+ assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
+ testNodeRemove();
+ }
+
+
+ private void testNodeRemove() throws Exception {
+ DataModificationTransaction transaction = baDataService.beginTransaction();
+ transaction.removeOperationalData(NODE_INSTANCE_ID_BA);
+ RpcResult<TransactionStatus> result = transaction.commit().get();
+ assertEquals(TransactionStatus.COMMITED, result.getResult());
+
+ Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
+ assertNull(node);
+ }
+
+ private void verifyNodes(Nodes nodes,Node original) {
+ assertNotNull(nodes);
+ assertNotNull(nodes.getNode());
+ assertEquals(1, nodes.getNode().size());
+ Node readedNode = nodes.getNode().get(0);
+ assertEquals(original.getId(), readedNode.getId());
+ assertEquals(original.getKey(), readedNode.getKey());
+
+ FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class);
+ FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class);
+ assertNotNull(fnu);
+ assertEquals(fnu.getDescription(), readedAugment.getDescription());
+ assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber());
+
+ }
+
+ private void assertBindingIndependentVersion(
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) {
+ CompositeNode node = biDataService.readOperationalData(nodeId);
+ assertNotNull(node);
+ }
+
+ private Nodes checkForNodes() {
+ return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
+ }
+
+ @Override
+ public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ receivedChangeEvent = change;
+ }
+
+}
@Test
public void simpleModifyOperation() throws Exception {
+ assertNull(biDataService.readConfigurationData(FLOW_INSTANCE_ID_BI));
registerCommitHandler();
DataModificationTransaction biTransaction = biDataService.beginTransaction();
biTransaction.putConfigurationData(FLOW_INSTANCE_ID_BI, domflow);
RpcResult<TransactionStatus> biResult = biTransaction.commit().get();
-
+ assertEquals(TransactionStatus.COMMITED, biResult.getResult());
assertNotNull(modificationCapture);
Flow flow = (Flow) modificationCapture.getCreatedConfigurationData().get(FLOW_INSTANCE_ID_BA);
assertNotNull(flow);
import org.opendaylight.yangtools.yang.common.RpcResult
import org.opendaylight.yangtools.yang.data.api.CompositeNode
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.slf4j.LoggerFactory
class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
+
+ val static LOG = LoggerFactory.getLogger(BrokerFacade)
val static BrokerFacade INSTANCE = new BrokerFacade
@Property
override readConfigurationData(InstanceIdentifier path) {
checkPreconditions
+ LOG.info("Read Configuration via Restconf: {}",path)
return dataService.readConfigurationData(path);
}
override readOperationalData(InstanceIdentifier path) {
checkPreconditions
+ LOG.info("Read Operational via Restconf: {}",path)
return dataService.readOperationalData(path);
}
import static com.google.common.base.Preconditions.*
import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
class ControllerContext implements SchemaServiceListener {
checkArgument(node instanceof LeafSchemaNode);
val urlDecoded = URLDecoder.decode(uriValue);
val typedef = (node as LeafSchemaNode).type;
- val decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
+ var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
+ if(decoded == null) {
+ var baseType = typedef
+ while (baseType.baseType != null) {
+ baseType = baseType.baseType;
+ }
+ if(baseType instanceof IdentityrefTypeDefinition) {
+ decoded = toQName(urlDecoded)
+ }
+ }
map.put(node.QName, decoded);
}