Netconf endpoint for config subsystem did not (de)serialize enum values properly
It assumed the enum constants are identical in yang and in generated binding
Change-Id: If46c770a49653348201cd5d5c9303b5207048252
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
import org.opendaylight.yangtools.concepts.ObjectRegistration;
import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
import org.opendaylight.yangtools.sal.binding.generator.api.ModuleInfoRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
import org.osgi.framework.BundleContext;
private void updateService() {
bindingContextProvider.update(classLoadingStrat, schemaContextProvider);
- osgiReg.setProperties(null); // send modifiedService event
+ osgiReg.setProperties(new Hashtable<String, Object>() {{
+ put(BindingRuntimeContext.class.getName(), bindingContextProvider.getBindingContext());
+ }
+ }); // send modifiedService event
}
@Override
package org.opendaylight.controller.config.manager.impl.osgi;
+import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import org.opendaylight.yangtools.concepts.ObjectRegistration;
import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
import org.opendaylight.yangtools.sal.binding.generator.api.ModuleInfoRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
import org.osgi.framework.BundleContext;
doReturn("string").when(prov).toString();
BundleContext ctxt = mock(BundleContext.class);
ServiceRegistration<?> servReg = mock(ServiceRegistration.class);
- doReturn(servReg).when(ctxt).registerService(Mockito.any(Class.class), Mockito.any(SchemaContextProvider.class), Mockito.any(Dictionary.class));
- doReturn(servReg).when(ctxt).registerService(Mockito.anyString(), Mockito.any(Object.class), Mockito.any(Dictionary.class));
+ doReturn(servReg).when(ctxt).registerService(any(Class.class), any(SchemaContextProvider.class), any(Dictionary.class));
+ doReturn(servReg).when(ctxt).registerService(Mockito.anyString(), any(Object.class), any(Dictionary.class));
+ doNothing().when(servReg).setProperties(any(Dictionary.class));
final ClassLoadingStrategy classLoadingStrat = mock(ClassLoadingStrategy.class);
final BindingContextProvider codecRegistryProvider = mock(BindingContextProvider.class);
doNothing().when(codecRegistryProvider).update(classLoadingStrat, prov);
+ final BindingRuntimeContext bindingRuntimeContext = mock(BindingRuntimeContext.class);
+ doReturn("B-runtime-context").when(bindingRuntimeContext).toString();
+ doReturn(bindingRuntimeContext).when(codecRegistryProvider).getBindingContext();
RefreshingSCPModuleInfoRegistry scpreg = new RefreshingSCPModuleInfoRegistry(reg, prov, classLoadingStrat, codecRegistryProvider, ctxt);
- doNothing().when(servReg).setProperties(null);
doNothing().when(servReg).unregister();
YangModuleInfo modInfo = mock(YangModuleInfo.class);
scpreg.close();
- Mockito.verify(servReg, Mockito.times(1)).setProperties(null);
+ Mockito.verify(servReg, Mockito.times(1)).setProperties(any(Dictionary.class));
Mockito.verify(servReg, Mockito.times(1)).unregister();
}
}
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
return base instanceof UnionTypeDefinition;
}
+ public boolean isEnum() {
+ TypeDefinition<?> base = getBaseType(typeProviderWrapper, typeDefinition);
+ return base instanceof EnumTypeDefinition;
+ }
+
public TypeDefinition<?> getTypeDefinition() {
return typeDefinition;
}
if (isArray()) {
return getArrayType();
- } else if (isEnum(baseType)) {
- return getSimpleType(baseType);
+ } else if (isEnum()) {
+ return getEnumType(baseTypeDefinition);
} else if (isUnion()) {
return getCompositeTypeForUnion(baseTypeDefinition);
} else if (isDerivedType(baseType, getType())) {
return getSimpleType(getType());
}
+ private OpenType<?> getEnumType(final TypeDefinition<?> baseType) {
+ final String fullyQualifiedName = typeProviderWrapper.getType(node, getTypeDefinition()).getFullyQualifiedName();
+ final String[] items = {"instance"};
+ String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription();
+
+ try {
+ return new CompositeType(fullyQualifiedName, description, items, items, new OpenType[]{SimpleType.STRING});
+ } catch (OpenDataException e) {
+ throw new RuntimeException("Unable to create enum type" + fullyQualifiedName + " as open type", e);
+ }
+ }
+
public boolean isIdentityRef() {
return typeDefinition instanceof IdentityrefTypeDefinition;
}
itemTypes[0] = artificialPropertyType;
}
- private boolean isEnum(Type baseType) {
- return baseType.getFullyQualifiedName().equals(Enum.class.getName());
- }
-
private OpenType<?> getSimpleType(Type type) {
SimpleType<?> simpleType = SimpleTypeResolver.getSimpleType(type);
return simpleType;
JAVA_TYPE_TO_SIMPLE_TYPE.put(Long.class.getName(), SimpleType.LONG);
JAVA_TYPE_TO_SIMPLE_TYPE.put(long.class.getName(), SimpleType.LONG);
JAVA_TYPE_TO_SIMPLE_TYPE.put(String.class.getName(), SimpleType.STRING);
- JAVA_TYPE_TO_SIMPLE_TYPE.put(Enum.class.getName(), SimpleType.STRING);
JAVA_TYPE_TO_SIMPLE_TYPE.put(Boolean.class.getName(), SimpleType.BOOLEAN);
JAVA_TYPE_TO_SIMPLE_TYPE.put(boolean.class.getName(), SimpleType.BOOLEAN);
JAVA_TYPE_TO_SIMPLE_TYPE.put(BigInteger.class.getName(), SimpleType.BIGINTEGER);
JAVA_TYPE_TO_SIMPLE_TYPE.put(Date.class.getName(), SimpleType.DATE);
JAVA_TYPE_TO_SIMPLE_TYPE.put(Double.class.getName(), SimpleType.DOUBLE);
JAVA_TYPE_TO_SIMPLE_TYPE.put(double.class.getName(), SimpleType.DOUBLE);
-
JAVA_TYPE_TO_SIMPLE_TYPE.put(char.class.getName(), SimpleType.CHARACTER);
}
leaf extended-enum {
type tt:extend-enum;
- default ONE;
+ default one;
}
leaf ip {
typedef extend-enum {
type enumeration {
- enum "ONE";
- enum "TWO";
+ enum "one";
+ enum "two";
}
}
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>mockito-configuration</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>binding-generator-impl</artifactId>
+ </dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
return caseJavaUnionAttribute(openType);
} else if(((JavaAttribute)attributeIfc).isIdentityRef()) {
return caseJavaIdentityRefAttribute(openType);
+ } else if(((JavaAttribute)attributeIfc).isEnum()) {
+ return caseJavaEnumAttribute(openType);
} else {
return caseJavaAttribute(openType);
}
return caseJavaAttribute(openType);
}
+ protected T caseJavaEnumAttribute(OpenType<?> openType) {
+ return caseJavaAttribute(openType);
+ }
+
protected T caseJavaBinaryAttribute(OpenType<?> openType) {
return caseJavaAttribute(openType);
}
--- /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.controller.netconf.confignetconfconnector.mapping.attributes.mapping;
+
+import com.google.common.base.Optional;
+import javax.management.openmbean.CompositeType;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
+
+public class EnumAttributeMappingStrategy extends AbstractAttributeMappingStrategy<String, CompositeType> {
+
+ private final EnumResolver enumResolver;
+
+ public EnumAttributeMappingStrategy(CompositeType openType, final EnumResolver enumResolver) {
+ super(openType);
+ this.enumResolver = enumResolver;
+ }
+
+ @Override
+ public Optional<String> mapAttribute(Object value) {
+ if (value == null){
+ return Optional.absent();
+ }
+
+ String expectedClass = getOpenType().getTypeName();
+ return Optional.of(enumResolver.toYang(expectedClass, value.toString()));
+ }
+
+}
import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
public class ObjectMapper extends AttributeIfcSwitchStatement<AttributeMappingStrategy<?, ? extends OpenType<?>>> {
+ private EnumResolver enumResolver;
public Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> prepareMapping(
- Map<String, AttributeIfc> configDefinition) {
+ Map<String, AttributeIfc> configDefinition, EnumResolver enumResolver) {
+ this.enumResolver = Preconditions.checkNotNull(enumResolver);
Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> strategies = Maps.newHashMap();
for (Entry<String, AttributeIfc> attrEntry : configDefinition.entrySet()) {
return new SimpleAttributeMappingStrategy(openType);
}
+ @Override
+ protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaEnumAttribute(final OpenType<?> openType) {
+ return new EnumAttributeMappingStrategy(((CompositeType) openType), enumResolver);
+ }
+
@Override
protected AttributeMappingStrategy<?, ? extends OpenType<?>> caseJavaArrayAttribute(ArrayType<?> openType) {
--- /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.controller.netconf.confignetconfconnector.mapping.attributes.resolving;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import java.util.Map;
+import javax.management.openmbean.CompositeType;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
+import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class EnumAttributeResolvingStrategy extends AbstractAttributeResolvingStrategy<Object, CompositeType> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(EnumAttributeResolvingStrategy.class);
+ private final EnumResolver enumResolver;
+
+ EnumAttributeResolvingStrategy(CompositeType simpleType, final EnumResolver enumResolver) {
+ super(simpleType);
+ this.enumResolver = enumResolver;
+ }
+
+ @Override
+ public String toString() {
+ return "ResolvedEnumAttribute [" + getOpenType().getClassName() + "]";
+ }
+
+ @Override
+ public Optional<Object> parseAttribute(String attrName, Object value) throws NetconfDocumentedException {
+ if (value == null) {
+ return Optional.absent();
+ }
+
+ Util.checkType(value, Map.class);
+ Map<?, ?> valueMap = (Map<?, ?>) value;
+ Preconditions.checkArgument(valueMap.size() == 1, "Unexpected value size " + value + " should be just 1 foe enum");
+ final Object innerValue = valueMap.values().iterator().next();
+ Util.checkType(innerValue, String.class);
+
+ final String className = getOpenType().getTypeName();
+ final Object parsedValue = enumResolver.fromYang(className, ((String) innerValue));
+
+ LOG.debug("Attribute {} : {} parsed to enum type {} with value {}", attrName, innerValue, getOpenType(), parsedValue);
+ return Optional.of(parsedValue);
+ }
+
+}
import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.AttributeIfcSwitchStatement;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
public class ObjectResolver extends AttributeIfcSwitchStatement<AttributeResolvingStrategy<?, ? extends OpenType<?>>> {
private final ServiceRegistryWrapper serviceTracker;
+ private EnumResolver enumResolver;
public ObjectResolver(ServiceRegistryWrapper serviceTracker) {
this.serviceTracker = serviceTracker;
}
public Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> prepareResolving(
- Map<String, AttributeIfc> configDefinition) {
+ Map<String, AttributeIfc> configDefinition, final EnumResolver enumResolver) {
+ this.enumResolver = enumResolver;
+
Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> strategies = Maps.newHashMap();
for (Entry<String, AttributeIfc> attrEntry : configDefinition.entrySet()) {
}
private AttributeResolvingStrategy<?, ? extends OpenType<?>> prepareStrategy(AttributeIfc attributeIfc) {
-
return switchAttribute(attributeIfc);
}
return retVal;
}
+ @Override
+ protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaEnumAttribute(final OpenType<?> openType) {
+ return new EnumAttributeResolvingStrategy((CompositeType) openType, enumResolver);
+ }
+
@Override
protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaSimpleAttribute(SimpleType<?> openType) {
return new SimpleAttributeResolvingStrategy(openType);
@Override
protected AttributeResolvingStrategy<?, ? extends OpenType<?>> caseJavaArrayAttribute(ArrayType<?> openType) {
+
SimpleType<?> innerType = (SimpleType<?>) openType.getElementOpenType();
AttributeResolvingStrategy<?, ? extends OpenType<?>> strat = new SimpleAttributeResolvingStrategy(innerType);
return new ArrayAttributeResolvingStrategy(strat, openType);
return new SimpleBinaryAttributeWritingStrategy(document, key);
}
+ @Override
+ protected AttributeWritingStrategy caseJavaEnumAttribute(final OpenType<?> openType) {
+ return new SimpleAttributeWritingStrategy(document, key);
+ }
+
@Override
protected AttributeWritingStrategy caseJavaSimpleAttribute(SimpleType<?> openType) {
return new SimpleAttributeWritingStrategy(document, key);
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
private final Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap;
- public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs) {
- this(moduleConfigs, Collections.<String, Map<Date, EditConfig.IdentityMapping>>emptyMap());
+ private final EnumResolver enumResolver;
+
+ public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, final EnumResolver enumResolver) {
+ this(moduleConfigs, Collections.<String, Map<Date, EditConfig.IdentityMapping>>emptyMap(), enumResolver);
}
- public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) {
+ public Config(Map<String, Map<String, ModuleConfig>> moduleConfigs, Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap, final EnumResolver enumResolver) {
this.moduleConfigs = moduleConfigs;
this.identityMap = identityMap;
+ this.enumResolver = enumResolver;
}
public static Map<String, Map<String, Collection<ObjectName>>> getMappedInstances(Set<ObjectName> instancesToMap,
}
for (ObjectName objectName : moduleMappingEntry.getValue()) {
- modulesElement.appendChild(mapping.toXml(objectName, document, moduleToInstanceEntry.getKey()));
+ modulesElement.appendChild(mapping.toXml(objectName, document, moduleToInstanceEntry.getKey(), enumResolver));
}
}
@Override
public ModuleElementResolved resolveElement(ModuleConfig moduleMapping, XmlElement moduleElement, ServiceRegistryWrapper serviceTracker, String instanceName, String moduleNamespace, EditStrategyType defaultStrategy) throws NetconfDocumentedException {
return moduleMapping.fromXml(moduleElement, serviceTracker,
- instanceName, moduleNamespace, defaultStrategy, identityMap);
+ instanceName, moduleNamespace, defaultStrategy, identityMap, enumResolver);
}
};
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml.ObjectXmlWriter;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
this.configRegistryClient = configRegistryClient;
}
- private Map<String, Object> getMappedConfiguration(ObjectName on) {
+ private Map<String, Object> getMappedConfiguration(ObjectName on, final EnumResolver enumResolver) {
// TODO make field, mappingStrategies can be instantiated only once
Map<String, AttributeMappingStrategy<?, ? extends OpenType<?>>> mappingStrategies = new ObjectMapper()
- .prepareMapping(jmxToAttrConfig);
+ .prepareMapping(jmxToAttrConfig, enumResolver);
Map<String, Object> toXml = Maps.newHashMap();
return toXml;
}
- public Element toXml(ObjectName on, String namespace, Document document, Element rootElement) {
+ public Element toXml(ObjectName on, String namespace, Document document, Element rootElement, final EnumResolver enumResolver) {
Map<String, AttributeWritingStrategy> strats = new ObjectXmlWriter().prepareWriting(yangToAttrConfig, document);
- Map<String, Object> mappedConfig = getMappedConfiguration(on);
+ Map<String, Object> mappedConfig = getMappedConfiguration(on, enumResolver);
Element parentElement;
if (nullableDummyContainerName != null) {
Element dummyElement = XmlUtil.createElement(document, nullableDummyContainerName, Optional.of(namespace));
return rootElement;
}
- private void resolveConfiguration(InstanceConfigElementResolved mappedConfig, ServiceRegistryWrapper depTracker) {
+ private void resolveConfiguration(InstanceConfigElementResolved mappedConfig, ServiceRegistryWrapper depTracker, final EnumResolver enumResolver) {
// TODO make field, resolvingStrategies can be instantiated only once
Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> resolvingStrategies = new ObjectResolver(
- depTracker).prepareResolving(yangToAttrConfig);
+ depTracker).prepareResolving(yangToAttrConfig, enumResolver);
for (Entry<String, AttributeConfigElement> configDefEntry : mappedConfig.getConfiguration().entrySet()) {
AttributeConfigElement value = configDefEntry.getValue();
public InstanceConfigElementResolved fromXml(XmlElement moduleElement, ServiceRegistryWrapper services, String moduleNamespace,
EditStrategyType defaultStrategy,
- Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) throws NetconfDocumentedException {
+ Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap, final EnumResolver enumResolver) throws NetconfDocumentedException {
Map<String, AttributeConfigElement> retVal = Maps.newHashMap();
Map<String, AttributeReadingStrategy> strats = new ObjectXmlReader().prepareReading(yangToAttrConfig, identityMap);
InstanceConfigElementResolved instanceConfigElementResolved = perInstanceEditStrategy.equals("") ? new InstanceConfigElementResolved(
retVal, defaultStrategy) : new InstanceConfigElementResolved(perInstanceEditStrategy, retVal, defaultStrategy);
- resolveConfiguration(instanceConfigElementResolved, services);
+ resolveConfiguration(instanceConfigElementResolved, services, enumResolver);
return instanceConfigElementResolved;
}
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
this.instanceConfig = mbeanMapping;
}
- public Element toXml(ObjectName instanceON, Document document, String namespace) {
+ public Element toXml(ObjectName instanceON, Document document, String namespace, final EnumResolver enumResolver) {
Element root = XmlUtil.createElement(document, XmlNetconfConstants.MODULE_KEY, Optional.<String>absent());
// type belongs to config.yang namespace, but needs to be <type prefix:moduleNS>prefix:moduleName</type>
root.appendChild(nameElement);
- root = instanceConfig.toXml(instanceON, namespace, document, root);
+ root = instanceConfig.toXml(instanceON, namespace, document, root, enumResolver);
return root;
}
public ModuleElementResolved fromXml(XmlElement moduleElement, ServiceRegistryWrapper depTracker, String instanceName,
- String moduleNamespace, EditStrategyType defaultStrategy, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) throws NetconfDocumentedException {
+ String moduleNamespace, EditStrategyType defaultStrategy, Map<String, Map<Date, EditConfig.IdentityMapping>> identityMap, final EnumResolver enumResolver) throws NetconfDocumentedException {
- InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy, identityMap);
+ InstanceConfigElementResolved ice = instanceConfig.fromXml(moduleElement, depTracker, moduleNamespace, defaultStrategy, identityMap, enumResolver);
return new ModuleElementResolved(instanceName, ice);
}
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.AttributeResolvingStrategy;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.resolving.ObjectResolver;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
public final class InstanceRuntimeRpc {
private final Map<String, AttributeIfc> yangToAttrConfig;
private final Rpc rpc;
+ private final EnumResolver enumResolver;
- public InstanceRuntimeRpc(Rpc rpc) {
+ public InstanceRuntimeRpc(Rpc rpc, final EnumResolver enumResolver) {
+ this.enumResolver = enumResolver;
this.yangToAttrConfig = map(rpc.getParameters());
this.rpc = rpc;
}
// TODO make field, resolvingStrategies can be instantiated only once
Map<String, AttributeResolvingStrategy<?, ? extends OpenType<?>>> resolvingStrategies = new ObjectResolver(null)
- .prepareResolving(yangToAttrConfig);
+ .prepareResolving(yangToAttrConfig, enumResolver);
// TODO make constructor for object resolver without service tracker
for (Entry<String, AttributeConfigElement> configDefEntry : mappedConfig.entrySet()) {
try {
import java.util.Map;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
public final class ModuleRpcs {
private final Map<String, String> yangToJavaNames = Maps.newHashMap();
private final Map<String, Map<String, InstanceRuntimeRpc>> rpcMapping = Maps.newHashMap();
+ private final EnumResolver enumResolver;
+
+ public ModuleRpcs(final EnumResolver enumResolver) {
+ this.enumResolver = enumResolver;
+ }
public void addNameMapping(RuntimeBeanEntry runtimeEntry) {
String yangName = runtimeEntry.getYangName();
Preconditions.checkState(!map.containsKey(rpc.getYangName()), "Rpc %s for runtime bean %s added twice",
rpc.getYangName(), yangName);
- map.put(rpc.getYangName(), new InstanceRuntimeRpc(rpc));
+ map.put(rpc.getYangName(), new InstanceRuntimeRpc(rpc, enumResolver));
}
public String getRbeJavaName(String yangName) {
import java.util.Set;
import javax.management.ObjectName;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
}));
}
- public Element toXml(ObjectName rootOn, Set<ObjectName> childRbeOns, Document document, Element parentElement, String namespace) {
- return toXml(rootOn, childRbeOns, document, null, parentElement, namespace);
+ public Element toXml(ObjectName rootOn, Set<ObjectName> childRbeOns, Document document, Element parentElement, String namespace, final EnumResolver enumResolver) {
+ return toXml(rootOn, childRbeOns, document, null, parentElement, namespace, enumResolver);
}
public Element toXml(ObjectName rootOn, Set<ObjectName> childRbeOns, Document document, String instanceIndex,
- Element parentElement, String namespace) {
- Element xml = instanceMapping.toXml(rootOn, namespace, document, parentElement);
+ Element parentElement, String namespace, final EnumResolver enumResolver) {
+ Element xml = instanceMapping.toXml(rootOn, namespace, document, parentElement, enumResolver);
if (instanceIndex != null) {
xml.setAttribute(KEY_ATTRIBUTE_KEY, instanceIndex);
Element innerXml = XmlUtil.createElement(document, elementName, Optional.of(namespace));
childMappingEntry.getValue().toXml(objectName, innerChildRbeOns, document,
- runtimeInstanceIndex, innerXml, namespace);
+ runtimeInstanceIndex, innerXml, namespace, enumResolver);
xml.appendChild(innerXml);
}
}
import java.util.Set;
import javax.management.ObjectName;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
}
public Element toXml(String namespace, Collection<ObjectName> runtimeBeanOns,
- Document document, ModuleConfig moduleConfig, ObjectName configBeanON) {
+ Document document, ModuleConfig moduleConfig, ObjectName configBeanON, final EnumResolver enumResolver) {
- Element moduleElement = moduleConfig.toXml(configBeanON, document, namespace);
+ Element moduleElement = moduleConfig.toXml(configBeanON, document, namespace, enumResolver);
ObjectName rootName = findRoot(runtimeBeanOns);
childrenRuntimeBeans.remove(rootName);
// FIXME: why is this called and not used?
- instanceRuntime.toXml(rootName, childrenRuntimeBeans, document, moduleElement, namespace);
+ instanceRuntime.toXml(rootName, childrenRuntimeBeans, document, moduleElement, namespace, enumResolver);
return moduleElement;
}
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
return retVal;
}
- public Element toXml(Set<ObjectName> instancesToMap, Set<ObjectName> configBeans, Document document) {
+ public Element toXml(Set<ObjectName> instancesToMap, Set<ObjectName> configBeans, Document document, final EnumResolver enumResolver) {
Element root = XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.<String>absent());
Element modulesElement = XmlUtil.createElement(document, XmlNetconfConstants.MODULES_KEY, Optional.of(XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG));
Element runtimeXml;
ModuleConfig moduleConfig = moduleConfigs.get(localNamespace).get(moduleName);
if(instanceToRbe==null || !instanceToRbe.containsKey(instanceName)) {
- runtimeXml = moduleConfig.toXml(instanceON, document, localNamespace);
+ runtimeXml = moduleConfig.toXml(instanceON, document, localNamespace, enumResolver);
} else {
ModuleRuntime moduleRuntime = moduleRuntimes.get(localNamespace).get(moduleName);
runtimeXml = moduleRuntime.toXml(localNamespace, instanceToRbe.get(instanceName), document,
- moduleConfig, instanceON);
+ moduleConfig, instanceON, enumResolver);
}
modulesElement.appendChild(runtimeXml);
}
Map<String, Map<String, ModuleConfig>> factories = transformMbeToModuleConfigs(configRegistryClient,
yangStoreSnapshot.getModuleMXBeanEntryMap());
Map<String, Map<Date, IdentityMapping>> identitiesMap = transformIdentities(yangStoreSnapshot.getModules());
- return new Config(factories, identitiesMap);
+ return new Config(factories, identitiesMap, yangStoreSnapshot.getEnumResolver());
}
final Runtime runtime = new Runtime(moduleRuntimes, moduleConfigs);
- final Element element = runtime.toXml(runtimeBeans, configBeans, document);
+ final Element element = runtime.toXml(runtimeBeans, configBeans, document, yangStoreSnapshot.getEnumResolver());
LOG.trace("{} operation successful", XmlNetconfConstants.GET);
.queryInstances(configRegistryClient);
final Config configMapping = new Config(EditConfig.transformMbeToModuleConfigs(registryClient,
- yangStoreSnapshot.getModuleMXBeanEntryMap()));
+ yangStoreSnapshot.getModuleMXBeanEntryMap()), yangStoreSnapshot.getEnumResolver());
ServiceRegistryWrapper serviceTracker = new ServiceRegistryWrapper(registryClient);
dataElement = configMapping.toXml(instances, this.maybeNamespace, document, dataElement, serviceTracker);
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.ModuleRpcs;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.Rpcs;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
final RuntimeRpcElementResolved id = RuntimeRpcElementResolved.fromXpath(
contextInstanceElement.getTextContent(), operationName, namespace);
- final Rpcs rpcs = mapRpcs(yangStoreSnapshot.getModuleMXBeanEntryMap());
+ final Rpcs rpcs = mapRpcs(yangStoreSnapshot.getModuleMXBeanEntryMap(), yangStoreSnapshot.getEnumResolver());
final ModuleRpcs rpcMapping = rpcs.getRpcMapping(id);
final InstanceRuntimeRpc instanceRuntimeRpc = rpcMapping.getRpc(id.getRuntimeBeanName(), operationName);
.getTextContent(), netconfOperationName, netconfOperationNamespace);
// TODO reuse rpcs instance in fromXml method
- final Rpcs rpcs = mapRpcs(yangStoreSnapshot.getModuleMXBeanEntryMap());
+ final Rpcs rpcs = mapRpcs(yangStoreSnapshot.getModuleMXBeanEntryMap(), yangStoreSnapshot.getEnumResolver());
try {
return sorted;
}
- private static Rpcs mapRpcs(final Map<String, Map<String, ModuleMXBeanEntry>> mBeanEntries) {
+ private static Rpcs mapRpcs(final Map<String, Map<String, ModuleMXBeanEntry>> mBeanEntries, final EnumResolver enumResolver) {
final Map<String, Map<String, ModuleRpcs>> map = Maps.newHashMap();
ModuleRpcs rpcMapping = namespaceToModules.get(moduleEntry.getKey());
if (rpcMapping == null) {
- rpcMapping = new ModuleRpcs();
+ rpcMapping = new ModuleRpcs(enumResolver);
namespaceToModules.put(moduleEntry.getKey(), rpcMapping);
}
import java.util.Hashtable;
import org.opendaylight.controller.netconf.api.util.NetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
@Override
public void modifiedService(ServiceReference<SchemaContextProvider> reference, ConfigRegistryLookupThread configRegistryLookup) {
LOG.debug("Got modifiedService(SchemaContextProvider) event");
- configRegistryLookup.yangStoreService.refresh();
+ final BindingRuntimeContext runtimeContext = (BindingRuntimeContext) reference.getProperty(BindingRuntimeContext.class.getName());
+ LOG.debug("BindingRuntimeContext retrieved as {}", runtimeContext);
+ configRegistryLookup.yangStoreService.refresh(runtimeContext);
}
--- /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.controller.netconf.confignetconfconnector.osgi;
+
+public interface EnumResolver {
+
+ String fromYang(String enumType, String enumYangValue);
+
+ String toYang(String enumType, String enumJavaValue);
+}
String getModuleSource(ModuleIdentifier moduleIdentifier);
+ EnumResolver getEnumResolver();
+
}
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChangeBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.changed.by.parms.ChangedByBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.changed.by.parms.changed.by.server.or.user.ServerBuilder;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
*
* We synchronize with GC as usual, using a SoftReference.
*
- * The atomic reference is used to synchronize with {@link #refresh()}, e.g. when
+ * The atomic reference is used to synchronize with {@link #refresh(org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext)}, e.g. when
* refresh happens, it will push a SoftReference(null), e.g. simulate the GC. Now
* that may happen while the getter is already busy acting on the old schema context,
* so it needs to understand that a refresh has happened and retry. To do that, it
private final AtomicReference<SoftReference<YangStoreSnapshot>> ref =
new AtomicReference<>(new SoftReference<YangStoreSnapshot>(null));
+ private final AtomicReference<SoftReference<BindingRuntimeContext>> refBindingContext =
+ new AtomicReference<>(new SoftReference<BindingRuntimeContext>(null));
+
private final SchemaContextProvider schemaContextProvider;
private final BaseNetconfNotificationListener notificationPublisher;
while (ret == null) {
// We need to be compute a new value
- ret = new YangStoreSnapshot(schemaContextProvider.getSchemaContext());
+ ret = new YangStoreSnapshot(schemaContextProvider.getSchemaContext(), refBindingContext.get().get());
if (!ref.compareAndSet(r, new SoftReference<>(ret))) {
LOG.debug("Concurrent refresh detected, recomputing snapshot");
return getYangStoreSnapshot().getModuleSource(moduleIdentifier);
}
- public void refresh() {
+ @Override
+ public EnumResolver getEnumResolver() {
+ return getYangStoreSnapshot().getEnumResolver();
+ }
+
+ public void refresh(final BindingRuntimeContext runtimeContext) {
final YangStoreSnapshot previous = ref.get().get();
ref.set(new SoftReference<YangStoreSnapshot>(null));
+ refBindingContext.set(new SoftReference<>(runtimeContext));
notificationExecutor.submit(new CapabilityChangeNotifier(previous));
}
package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
+import com.google.common.collect.BiMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.opendaylight.controller.config.yangjmxgenerator.PackageTranslator;
import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
import org.opendaylight.yangtools.sal.binding.yang.types.TypeProviderImpl;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-final class YangStoreSnapshot implements YangStoreContext {
+final class YangStoreSnapshot implements YangStoreContext, EnumResolver {
private static final Logger LOG = LoggerFactory.getLogger(YangStoreSnapshot.class);
private final Map<QName, Map<String, ModuleMXBeanEntry>> qNamesToIdentitiesToModuleMXBeanEntries;
private final SchemaContext schemaContext;
+ private final BindingRuntimeContext bindingContextProvider;
- public YangStoreSnapshot(final SchemaContext resolveSchemaContext) {
+ public YangStoreSnapshot(final SchemaContext resolveSchemaContext, final BindingRuntimeContext bindingContextProvider) {
+ this.bindingContextProvider = bindingContextProvider;
LOG.trace("Resolved modules:{}", resolveSchemaContext.getModules());
this.schemaContext = resolveSchemaContext;
// JMX generator
}
}
+ @Override
+ public EnumResolver getEnumResolver() {
+ return this;
+ }
+
@Override
public boolean equals(final Object o) {
if (this == o) return true;
public int hashCode() {
return schemaContext != null ? schemaContext.hashCode() : 0;
}
+
+ @Override
+ public String fromYang(final String enumClass, final String enumYangValue) {
+ Preconditions.checkState(bindingContextProvider != null, "Binding context provider was not set yet");
+ final BiMap<String, String> enumMapping = bindingContextProvider.getEnumMapping(enumClass);
+ final String javaName = enumMapping.get(enumYangValue);
+ return Preconditions.checkNotNull(javaName, "Unable to resolve enum value %s for enum class %s with assumed enum mapping: %s", enumYangValue, enumClass, enumMapping);
+ }
+
+ @Override
+ public String toYang(final String enumClass, final String enumJavaValue) {
+ Preconditions.checkState(bindingContextProvider != null, "Binding context provider was not set yet");
+ final BiMap<String, String> enumMapping = bindingContextProvider.getEnumMapping(enumClass);
+ final String javaName = enumMapping.inverse().get(enumJavaValue);
+ return Preconditions.checkNotNull(javaName, "Unable to map enumcd .." +
+ "cd value %s for enum class %s with assumed enum mapping: %s", enumJavaValue, enumClass, enumMapping.inverse());
+ }
}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.get.Get;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc.RuntimeRpc;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
doReturn(getMbes()).when(this.yangStoreSnapshot).getModuleMXBeanEntryMap();
doReturn(getModules()).when(this.yangStoreSnapshot).getModules();
+ doReturn(new EnumResolver() {
+ @Override
+ public String fromYang(final String enumType, final String enumYangValue) {
+ return Preconditions.checkNotNull(getEnumMapping().get(enumYangValue),
+ "Unable to resolve enum value %s, for enum %s with mappings %s", enumYangValue, enumType, getEnumMapping());
+ }
+
+ @Override
+ public String toYang(final String enumType, final String enumYangValue) {
+ return Preconditions.checkNotNull(getEnumMapping().inverse().get(enumYangValue),
+ "Unable to resolve enum value %s, for enum %s with mappings %s", enumYangValue, enumType, getEnumMapping().inverse());
+ }
+ }).when(this.yangStoreSnapshot).getEnumResolver();
this.factory = new NetconfTestImplModuleFactory();
this.factory2 = new DepTestImplModuleFactory();
// Default
assertContainsElement(response, readXmlToElement("<extended-twice xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">2</extended-twice>"));
- assertContainsElement(response, readXmlToElement("<extended-enum xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">TWO</extended-enum>"));
+ assertContainsElement(response, readXmlToElement("<extended-enum xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">two</extended-enum>"));
// Default
- assertContainsElement(response, readXmlToElement("<extended-enum xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">ONE</extended-enum>"));
+ assertContainsElement(response, readXmlToElement("<extended-enum xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">one</extended-enum>"));
}
private void assertContainsString(String string, String substring) {
private void checkEnum(final Document response) throws Exception {
- String expectedEnumContent = "TWO";
+ String expectedEnumContent = "two";
XMLAssert.assertXpathEvaluatesTo(expectedEnumContent,
getXpathForNetconfImplSubnode(INSTANCE_NAME,"extended-enum"),
return schemaContext ;
}
}, mockedContext);
+ final BindingRuntimeContext bindingRuntimeContext = mock(BindingRuntimeContext.class);
+ doReturn(getEnumMapping()).when(bindingRuntimeContext).getEnumMapping(any(Class.class));
+ yangStoreService.refresh(bindingRuntimeContext);
mBeanEntries.putAll(yangStoreService.getModuleMXBeanEntryMap());
return mBeanEntries;
}
+ private BiMap<String, String> getEnumMapping() {
+ final HashBiMap<String, String> enumBiMap = HashBiMap.create();
+ // Enum constants mapping from yang -> Java and back
+ enumBiMap.put("one", "One");
+ enumBiMap.put("two", "Two");
+ return enumBiMap;
+ }
+
private Set<org.opendaylight.yangtools.yang.model.api.Module> getModules() throws Exception {
SchemaContext resolveSchemaContext = getSchemaContext();
return resolveSchemaContext.getModules();
import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.EnumResolver;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.opendaylight.protocol.framework.NeverReconnectStrategy;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
final YangParserImpl yangParser = new YangParserImpl();
return yangParser.resolveSchemaContext(new HashSet<>(yangParser.parseYangModelsFromStreamsMapped(byteArrayInputStreams).values()));
}
+
+ @Override
+ public EnumResolver getEnumResolver() {
+ return new EnumResolver() {
+ @Override
+ public String fromYang(final String enumType, final String enumYangValue) {
+ return BindingMapping.getClassName(enumYangValue);
+ }
+
+ @Override
+ public String toYang(final String enumType, final String enumJavaValue) {
+ return enumJavaValue.toLowerCase();
+ }
+ };
+ }
}
}
</extended-twice>
<extended-enum>
- TWO
+ two
</extended-enum>
<simple-long-2>44</simple-long-2>