Add support for multiple choice case statements within one augument in config yang... 15/5115/1
authorMaros Marsalek <mmarsale@cisco.com>
Tue, 4 Feb 2014 09:54:04 +0000 (10:54 +0100)
committerMaros Marsalek <mmarsale@cisco.com>
Tue, 4 Feb 2014 12:39:15 +0000 (13:39 +0100)
Change-Id: Ic2111f4f3b1a63160279c1bd36b9c4799dccf159
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntry.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java [new file with mode: 0644]
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java
opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryTest.java
opendaylight/config/yang-jmx-generator/src/test/resources/config-jmx-it-impl.yang

index 5bcc540..0cc950a 100644 (file)
@@ -7,52 +7,16 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
+
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
-import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
-import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
-import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.ModuleImport;
-import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.UsesNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static java.lang.String.format;
-import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
 
 /**
  * Represents part of yang model that describes a module.
@@ -96,67 +60,34 @@ import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstant
  * </p>
  */
 public class ModuleMXBeanEntry extends AbstractEntry {
-    private static final Logger logger = LoggerFactory
-            .getLogger(ModuleMXBeanEntry.class);
-
-    // TODO: the XPath should be parsed by code generator IMO
-    private static final String MAGIC_STRING = "MAGIC_STRING";
-    private static final String MODULE_CONDITION_XPATH_TEMPLATE = "^/MAGIC_STRING:modules/MAGIC_STRING:module/MAGIC_STRING:type\\s*=\\s*['\"](.+)['\"]$";
-    private static final SchemaPath expectedConfigurationAugmentationSchemaPath = new SchemaPath(
-            Arrays.asList(createConfigQName("modules"),
-                    createConfigQName("module"),
-                    createConfigQName("configuration")), true);
-    private static final SchemaPath expectedStateAugmentationSchemaPath = new SchemaPath(
-            Arrays.asList(createConfigQName("modules"),
-                    createConfigQName("module"), createConfigQName("state")),
-            true);
-
-    private static final Pattern PREFIX_COLON_LOCAL_NAME = Pattern
-            .compile("^(.+):(.+)$");
 
     private static final String MODULE_SUFFIX = "Module";
     private static final String FACTORY_SUFFIX = MODULE_SUFFIX + "Factory";
     private static final String CLASS_NAME_SUFFIX = MODULE_SUFFIX + "MXBean";
     private static final String ABSTRACT_PREFIX = "Abstract";
 
-    /*
-     * threadpool-dynamic from the example above, taken from when condition, not
-     * the case name
-     */
-    private final String globallyUniqueName;
+    private final ModuleMXBeanEntryInitial initial;
 
     private Map<String, AttributeIfc> yangToAttributes;
 
-    private final String nullableDescription, packageName, javaNamePrefix,
-            namespace;
-
     private final Map<String, QName> providedServices;
 
     private Collection<RuntimeBeanEntry> runtimeBeans;
-    private final QName yangModuleQName;
-
-    public ModuleMXBeanEntry(IdentitySchemaNode id,
-            Map<String, AttributeIfc> yangToAttributes, String packageName,
-            Map<String, QName> providedServices2, String javaNamePrefix,
-            String namespace, Collection<RuntimeBeanEntry> runtimeBeans,
-            QName yangModuleQName) {
-        this.globallyUniqueName = id.getQName().getLocalName();
+
+    ModuleMXBeanEntry(ModuleMXBeanEntryInitial initials, Map<String, AttributeIfc> yangToAttributes,
+            Map<String, QName> providedServices2, Collection<RuntimeBeanEntry> runtimeBeans) {
         this.yangToAttributes = yangToAttributes;
-        this.nullableDescription = id.getDescription();
-        this.packageName = packageName;
-        this.javaNamePrefix = checkNotNull(javaNamePrefix);
-        this.namespace = checkNotNull(namespace);
         this.providedServices = Collections.unmodifiableMap(providedServices2);
         this.runtimeBeans = runtimeBeans;
-        this.yangModuleQName = yangModuleQName;
+        this.initial = initials;
     }
 
     public String getMXBeanInterfaceName() {
-        return javaNamePrefix + CLASS_NAME_SUFFIX;
+        return initial.javaNamePrefix + CLASS_NAME_SUFFIX;
     }
 
     public String getStubFactoryName() {
-        return javaNamePrefix + FACTORY_SUFFIX;
+        return initial.javaNamePrefix + FACTORY_SUFFIX;
     }
 
     public String getAbstractFactoryName() {
@@ -164,7 +95,7 @@ public class ModuleMXBeanEntry extends AbstractEntry {
     }
 
     public String getStubModuleName() {
-        return javaNamePrefix + MODULE_SUFFIX;
+        return initial.javaNamePrefix + MODULE_SUFFIX;
     }
 
     public String getAbstractModuleName() {
@@ -172,16 +103,16 @@ public class ModuleMXBeanEntry extends AbstractEntry {
     }
 
     public String getFullyQualifiedName(String typeName) {
-        return FullyQualifiedNameHelper.getFullyQualifiedName(packageName,
+        return FullyQualifiedNameHelper.getFullyQualifiedName(initial.packageName,
                 typeName);
     }
 
     public String getGloballyUniqueName() {
-        return globallyUniqueName;
+        return initial.localName;
     }
 
     public String getPackageName() {
-        return packageName;
+        return initial.packageName;
     }
 
     /**
@@ -202,31 +133,11 @@ public class ModuleMXBeanEntry extends AbstractEntry {
     }
 
     public String getJavaNamePrefix() {
-        return javaNamePrefix;
+        return initial.javaNamePrefix;
     }
 
     public String getNamespace() {
-        return namespace;
-    }
-
-    @VisibleForTesting
-    static Matcher getWhenConditionMatcher(String prefix,
-            RevisionAwareXPath whenConstraint) {
-        String xpathRegex = MODULE_CONDITION_XPATH_TEMPLATE.replace(
-                MAGIC_STRING, prefix);
-        Pattern pattern = Pattern.compile(xpathRegex);
-        return pattern.matcher(whenConstraint.toString());
-    }
-
-    static String getConfigModulePrefixFromImport(Module currentModule) {
-        for (ModuleImport currentImport : currentModule.getImports()) {
-            if (currentImport.getModuleName().equals(
-                    ConfigConstants.CONFIG_MODULE)) {
-                return currentImport.getPrefix();
-            }
-        }
-        throw new IllegalArgumentException("Cannot find import "
-                + ConfigConstants.CONFIG_MODULE + " in " + currentModule);
+        return initial.namespace;
     }
 
     /**
@@ -241,504 +152,93 @@ public class ModuleMXBeanEntry extends AbstractEntry {
             Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
             SchemaContext schemaContext,
             TypeProviderWrapper typeProviderWrapper, String packageName) {
-        Map<String, QName> uniqueGeneratedClassesNames = new HashMap<>();
-        logger.debug("Generating ModuleMXBeans of {} to package {}",
-                currentModule.getNamespace(), packageName);
-        String configModulePrefix;
-        try {
-            configModulePrefix = getConfigModulePrefixFromImport(currentModule);
-        } catch (IllegalArgumentException e) {
-            // this module does not import config module
-            return Collections.emptyMap();
-        }
 
-        // get identities of base config:module-type
-        Map<String, IdentitySchemaNode> moduleIdentities = new HashMap<>();
-
-        for (IdentitySchemaNode id : currentModule.getIdentities()) {
-            if (id.getBaseIdentity() != null
-                    && ConfigConstants.MODULE_TYPE_Q_NAME.equals(id
-                            .getBaseIdentity().getQName())) {
-                String identityLocalName = id.getQName().getLocalName();
-                if (moduleIdentities.containsKey(identityLocalName)) {
-                    throw new IllegalStateException(
-                            "Module name already defined in this module: "
-                                    + identityLocalName);
-                } else {
-                    moduleIdentities.put(identityLocalName, id);
-                    logger.debug("Found identity {}", identityLocalName);
-                }
-                // validation check on unknown schema nodes
-                boolean providedServiceWasSet = false;
-                for (UnknownSchemaNode unknownNode : id.getUnknownSchemaNodes()) {
-                    // TODO: test this
-                    if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME
-                            .equals(unknownNode.getNodeType())) {
-                        // no op: 0 or more provided identities are allowed
-                    } else if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME
-                            .equals(unknownNode.getNodeType())) {
-                        // 0..1 allowed
-                        checkState(
-                                providedServiceWasSet == false,
-                                format("More than one language extension %s is not allowed here: %s",
-                                        ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME,
-                                        id));
-                        providedServiceWasSet = true;
-                    } else {
-                        throw new IllegalStateException(
-                                "Unexpected language extension "
-                                        + unknownNode.getNodeType());
-                    }
-                }
-            }
-        }
-        Map<String, ModuleMXBeanEntry> result = new HashMap<>();
-        // each module name should have an augmentation defined
-        Map<String, IdentitySchemaNode> unaugmentedModuleIdentities = new HashMap<>(
-                moduleIdentities);
-        for (AugmentationSchema augmentation : currentModule.getAugmentations()) {
-            Set<DataSchemaNode> childNodes = augmentation.getChildNodes();
-            if (childNodes.size() == 1) {
-                DataSchemaNode when = childNodes.iterator().next();
-                if (when instanceof ChoiceCaseNode) {
-                    ChoiceCaseNode choiceCaseNode = (ChoiceCaseNode) when;
-                    if (choiceCaseNode.getConstraints() == null
-                            || choiceCaseNode.getConstraints()
-                                    .getWhenCondition() == null) {
-                        continue;
-                    }
-                    RevisionAwareXPath xPath = choiceCaseNode.getConstraints()
-                            .getWhenCondition();
-                    Matcher matcher = getWhenConditionMatcher(
-                            configModulePrefix, xPath);
-                    if (matcher.matches() == false) {
-                        continue;
-                    }
-                    String moduleLocalNameFromXPath = matcher.group(1);
-                    IdentitySchemaNode moduleIdentity = moduleIdentities
-                            .get(moduleLocalNameFromXPath);
-                    unaugmentedModuleIdentities
-                            .remove(moduleLocalNameFromXPath);
-                    checkState(moduleIdentity != null, "Cannot find identity "
-                            + moduleLocalNameFromXPath
-                            + " matching augmentation " + augmentation);
-                    Map<String, QName> providedServices = findProvidedServices(
-                            moduleIdentity, currentModule, qNamesToSIEs,
-                            schemaContext);
-
-                    if (moduleIdentity == null) {
-                        throw new IllegalStateException(
-                                "Cannot find identity specified by augmentation xpath constraint: "
-                                        + moduleLocalNameFromXPath + " of "
-                                        + augmentation);
-                    }
-                    String javaNamePrefix = findJavaNamePrefix(moduleIdentity);
-
-                    Map<String, AttributeIfc> yangToAttributes = null;
-                    // runtime-data
-                    Collection<RuntimeBeanEntry> runtimeBeans = null;
-
-                    if (expectedConfigurationAugmentationSchemaPath
-                            .equals(augmentation.getTargetPath())) {
-                        logger.debug("Parsing configuration of {}",
-                                moduleLocalNameFromXPath);
-                        yangToAttributes = fillConfiguration(choiceCaseNode,
-                                currentModule, typeProviderWrapper,
-                                qNamesToSIEs, schemaContext, packageName);
-                        checkUniqueAttributesWithGeneratedClass(
-                                uniqueGeneratedClassesNames, when.getQName(),
-                                yangToAttributes);
-                    } else if (expectedStateAugmentationSchemaPath
-                            .equals(augmentation.getTargetPath())) {
-                        logger.debug("Parsing state of {}",
-                                moduleLocalNameFromXPath);
-                        try {
-                            runtimeBeans = fillRuntimeBeans(choiceCaseNode,
-                                    currentModule, typeProviderWrapper,
-                                    packageName, moduleLocalNameFromXPath,
-                                    javaNamePrefix);
-                        } catch (NameConflictException e) {
-                            throw new NameConflictException(
-                                    e.getConflictingName(), when.getQName(),
-                                    when.getQName());
-                        }
-                        checkUniqueRuntimeBeansGeneratedClasses(
-                                uniqueGeneratedClassesNames, when, runtimeBeans);
-                        Set<RuntimeBeanEntry> runtimeBeanEntryValues = Sets
-                                .newHashSet(runtimeBeans);
-                        for (RuntimeBeanEntry entry : runtimeBeanEntryValues) {
-                            checkUniqueAttributesWithGeneratedClass(
-                                    uniqueGeneratedClassesNames,
-                                    when.getQName(),
-                                    entry.getYangPropertiesToTypesMap());
-                        }
-
-                    } else {
-                        throw new IllegalArgumentException(
-                                "Cannot parse augmentation " + augmentation);
-                    }
-                    if (result.containsKey(moduleLocalNameFromXPath)) {
-                        // either fill runtimeBeans or yangToAttributes
-                        ModuleMXBeanEntry moduleMXBeanEntry = result
-                                .get(moduleLocalNameFromXPath);
-                        if (yangToAttributes != null
-                                && moduleMXBeanEntry.getAttributes() == null) {
-                            moduleMXBeanEntry
-                                    .setYangToAttributes(yangToAttributes);
-                        } else if (runtimeBeans != null
-                                && moduleMXBeanEntry.getRuntimeBeans() == null) {
-                            moduleMXBeanEntry.setRuntimeBeans(runtimeBeans);
-                        }
-                    } else {
-                        // construct ModuleMXBeanEntry
-                        ModuleMXBeanEntry moduleMXBeanEntry = new ModuleMXBeanEntry(
-                                moduleIdentity, yangToAttributes, packageName,
-                                providedServices, javaNamePrefix, currentModule
-                                        .getNamespace().toString(),
-                                runtimeBeans,
-                                ModuleUtil.getQName(currentModule));
-                        moduleMXBeanEntry.setYangModuleName(currentModule
-                                .getName());
-                        moduleMXBeanEntry
-                                .setYangModuleLocalname(moduleLocalNameFromXPath);
-                        result.put(moduleLocalNameFromXPath, moduleMXBeanEntry);
-                    }
-                } // skip if child node is not ChoiceCaseNode
-            } // skip if childNodes != 1
-        }
-        // clean up nulls
-        for (Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
-            ModuleMXBeanEntry module = entry.getValue();
-            if (module.getAttributes() == null) {
-                module.setYangToAttributes(Collections
-                        .<String, AttributeIfc> emptyMap());
-            } else if (module.getRuntimeBeans() == null) {
-                module.setRuntimeBeans(Collections
-                        .<RuntimeBeanEntry> emptyList());
-            }
-        }
-        // check attributes name uniqueness
-        for (Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
-            checkUniqueRuntimeBeanAttributesName(entry.getValue(),
-                    uniqueGeneratedClassesNames);
-        }
-        if (unaugmentedModuleIdentities.size() > 0) {
-            logger.warn("Augmentation not found for all module identities: {}",
-                    unaugmentedModuleIdentities.keySet());
-        }
+        ModuleMXBeanEntryBuilder builder = new ModuleMXBeanEntryBuilder().setModule(currentModule).setqNamesToSIEs(qNamesToSIEs)
+                .setSchemaContext(schemaContext).setTypeProviderWrapper(typeProviderWrapper)
+                .setPackageName(packageName);
 
-        logger.debug("Number of ModuleMXBeans to be generated: {}",
-                result.size());
-        return result;
+        return builder.build();
     }
 
-    private static void checkUniqueRuntimeBeansGeneratedClasses(
-            Map<String, QName> uniqueGeneratedClassesNames,
-            DataSchemaNode when, Collection<RuntimeBeanEntry> runtimeBeans) {
-        for (RuntimeBeanEntry runtimeBean : runtimeBeans) {
-            final String javaNameOfRuntimeMXBean = runtimeBean
-                    .getJavaNameOfRuntimeMXBean();
-            if (uniqueGeneratedClassesNames
-                    .containsKey(javaNameOfRuntimeMXBean)) {
-                QName firstDefinedQName = uniqueGeneratedClassesNames
-                        .get(javaNameOfRuntimeMXBean);
-                throw new NameConflictException(javaNameOfRuntimeMXBean,
-                        firstDefinedQName, when.getQName());
-            }
-            uniqueGeneratedClassesNames.put(javaNameOfRuntimeMXBean,
-                    when.getQName());
-        }
-    }
-
-    private static void checkUniqueRuntimeBeanAttributesName(
-            ModuleMXBeanEntry mxBeanEntry,
-            Map<String, QName> uniqueGeneratedClassesNames) {
-        for (RuntimeBeanEntry runtimeBeanEntry : mxBeanEntry.getRuntimeBeans()) {
-            for (String runtimeAttName : runtimeBeanEntry
-                    .getYangPropertiesToTypesMap().keySet()) {
-                if (mxBeanEntry.getAttributes().keySet()
-                        .contains(runtimeAttName)) {
-                    QName qName1 = uniqueGeneratedClassesNames
-                            .get(runtimeBeanEntry.getJavaNameOfRuntimeMXBean());
-                    QName qName2 = uniqueGeneratedClassesNames.get(mxBeanEntry
-                            .getGloballyUniqueName());
-                    throw new NameConflictException(runtimeAttName, qName1,
-                            qName2);
-                }
-            }
-        }
-    }
-
-    private static void checkUniqueAttributesWithGeneratedClass(
-            Map<String, QName> uniqueGeneratedClassNames, QName parentQName,
-            Map<String, AttributeIfc> yangToAttributes) {
-        for (Entry<String, AttributeIfc> attr : yangToAttributes.entrySet()) {
-            if (attr.getValue() instanceof TOAttribute) {
-                checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName,
-                        (TOAttribute) attr.getValue());
-            } else if (attr.getValue() instanceof ListAttribute
-                    && ((ListAttribute) attr.getValue()).getInnerAttribute() instanceof TOAttribute) {
-                checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName,
-                        (TOAttribute) ((ListAttribute) attr.getValue())
-                                .getInnerAttribute());
-            }
-        }
+    public Map<String, AttributeIfc> getAttributes() {
+        return yangToAttributes;
     }
 
-    private static void checkUniqueTOAttr(
-            Map<String, QName> uniqueGeneratedClassNames, QName parentQName,
-            TOAttribute attr) {
-        final String upperCaseCammelCase = attr.getUpperCaseCammelCase();
-        if (uniqueGeneratedClassNames.containsKey(upperCaseCammelCase)) {
-            QName firstDefinedQName = uniqueGeneratedClassNames
-                    .get(upperCaseCammelCase);
-            throw new NameConflictException(upperCaseCammelCase,
-                    firstDefinedQName, parentQName);
-        } else {
-            uniqueGeneratedClassNames.put(upperCaseCammelCase, parentQName);
-        }
+    void setYangToAttributes(Map<String, AttributeIfc> newAttributes) {
+        this.yangToAttributes = newAttributes;
     }
 
-    private static Collection<RuntimeBeanEntry> fillRuntimeBeans(
-            ChoiceCaseNode choiceCaseNode, Module currentModule,
-            TypeProviderWrapper typeProviderWrapper, String packageName,
-            String moduleLocalNameFromXPath, String javaNamePrefix) {
-
-        return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName,
-                choiceCaseNode, moduleLocalNameFromXPath, typeProviderWrapper,
-                javaNamePrefix, currentModule).values();
-
+    public String getNullableDescription() {
+        return initial.description;
     }
 
-    private static Map<String, AttributeIfc> fillConfiguration(
-            ChoiceCaseNode choiceCaseNode, Module currentModule,
-            TypeProviderWrapper typeProviderWrapper,
-            Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
-            SchemaContext schemaContext, String packageName) {
-        Map<String, AttributeIfc> yangToAttributes = new HashMap<>();
-        for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) {
-            AttributeIfc attributeValue = getAttributeValue(attrNode,
-                    currentModule, qNamesToSIEs, typeProviderWrapper,
-                    schemaContext, packageName);
-            yangToAttributes.put(attributeValue.getAttributeYangName(),
-                    attributeValue);
-        }
-        return yangToAttributes;
+    public QName getYangModuleQName() {
+        return initial.qName;
     }
 
-    private static Map<String, QName> findProvidedServices(
-            IdentitySchemaNode moduleIdentity, Module currentModule,
-            Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
-            SchemaContext schemaContext) {
-        Map<String, QName> result = new HashMap<>();
-        for (UnknownSchemaNode unknownNode : moduleIdentity
-                .getUnknownSchemaNodes()) {
-            if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME
-                    .equals(unknownNode.getNodeType())) {
-                String prefixAndIdentityLocalName = unknownNode
-                        .getNodeParameter();
-                ServiceInterfaceEntry sie = findSIE(prefixAndIdentityLocalName,
-                        currentModule, qNamesToSIEs, schemaContext);
-                result.put(sie.getFullyQualifiedName(), sie.getQName());
-            }
-        }
-        return result;
+    @Override
+    public String toString() {
+        return "ModuleMXBeanEntry{" + "globallyUniqueName='"
+                + initial.localName + '\'' + ", packageName='" + initial.packageName
+                + '\'' + '}';
     }
 
-    /**
-     * For input node, find if it contains config:java-name-prefix extension. If
-     * not found, convert local name of node converted to cammel case.
-     */
-    public static String findJavaNamePrefix(SchemaNode schemaNode) {
-        return convertToJavaName(schemaNode, true);
-    }
+    static final class ModuleMXBeanEntryInitial {
 
-    public static String findJavaParameter(SchemaNode schemaNode) {
-        return convertToJavaName(schemaNode, false);
-    }
+        private String localName;
+        private String description;
+        private String packageName;
+        private String javaNamePrefix;
+        private String namespace;
+        private QName qName;
 
-    public static String convertToJavaName(SchemaNode schemaNode,
-            boolean capitalizeFirstLetter) {
-        for (UnknownSchemaNode unknownNode : schemaNode.getUnknownSchemaNodes()) {
-            if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME
-                    .equals(unknownNode.getNodeType())) {
-                String value = unknownNode.getNodeParameter();
-                return convertToJavaName(value, capitalizeFirstLetter);
-            }
+        ModuleMXBeanEntryInitial(String localName, String description, String packageName, String javaNamePrefix, String namespace, QName qName) {
+            this.localName = localName;
+            this.description = description;
+            this.packageName = packageName;
+            this.javaNamePrefix = javaNamePrefix;
+            this.namespace = namespace;
+            this.qName = qName;
         }
-        return convertToJavaName(schemaNode.getQName().getLocalName(),
-                capitalizeFirstLetter);
     }
 
-    public static String convertToJavaName(String localName,
-            boolean capitalizeFirstLetter) {
-        if (capitalizeFirstLetter) {
-            return BindingGeneratorUtil.parseToClassName(localName);
-        } else {
-            return BindingGeneratorUtil.parseToValidParamName(localName);
-        }
-    }
+    static final class ModuleMXBeanEntryInitialBuilder {
+        private String localName;
+        private String description;
+        private String packageName;
+        private String javaNamePrefix;
+        private String namespace;
+        private QName qName;
 
-    private static int getChildNodeSizeWithoutUses(DataNodeContainer csn) {
-        int result = 0;
-        for (DataSchemaNode dsn : csn.getChildNodes()) {
-            if (dsn.isAddedByUses() == false) {
-                result++;
-            }
+        public ModuleMXBeanEntryInitialBuilder setPackageName(String packageName) {
+            this.packageName = packageName;
+            return this;
         }
-        return result;
-    }
 
-    private static AttributeIfc getAttributeValue(DataSchemaNode attrNode,
-            Module currentModule,
-            Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
-            TypeProviderWrapper typeProviderWrapper,
-            SchemaContext schemaContext, String packageName) {
-
-        if (attrNode instanceof LeafSchemaNode) {
-            // simple type
-            LeafSchemaNode leaf = (LeafSchemaNode) attrNode;
-            return new JavaAttribute(leaf, typeProviderWrapper);
-        } else if (attrNode instanceof ContainerSchemaNode) {
-            // reference or TO
-            ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) attrNode;
-            Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
-                    containerSchemaNode, attrNode, currentModule, qNamesToSIEs,
-                    schemaContext);
-            if (dependencyAttributeOptional.isPresent()) {
-                return dependencyAttributeOptional.get();
-            } else {
-                return TOAttribute.create(containerSchemaNode,
-                        typeProviderWrapper, packageName);
-            }
-
-        } else if (attrNode instanceof LeafListSchemaNode) {
-            return ListAttribute.create((LeafListSchemaNode) attrNode,
-                    typeProviderWrapper);
-        } else if (attrNode instanceof ListSchemaNode) {
-            ListSchemaNode listSchemaNode = (ListSchemaNode) attrNode;
-            Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
-                    listSchemaNode, attrNode, currentModule, qNamesToSIEs,
-                    schemaContext);
-            if (dependencyAttributeOptional.isPresent()) {
-                return dependencyAttributeOptional.get();
-            } else {
-                return ListAttribute.create(listSchemaNode,
-                        typeProviderWrapper, packageName);
-            }
-        } else {
-            throw new UnsupportedOperationException(
-                    "Unknown configuration node " + attrNode.toString());
+        public ModuleMXBeanEntryInitialBuilder setJavaNamePrefix(String javaNamePrefix) {
+            this.javaNamePrefix = javaNamePrefix;
+            return this;
         }
-    }
 
-    private static Optional<? extends AbstractDependencyAttribute> extractDependency(
-            DataNodeContainer dataNodeContainer, DataSchemaNode attrNode,
-            Module currentModule,
-            Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
-            SchemaContext schemaContext) {
-        if (dataNodeContainer.getUses().size() == 1
-                && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) {
-            // reference
-            UsesNode usesNode = dataNodeContainer.getUses().iterator().next();
-            checkState(usesNode.getRefines().size() == 1,
-                    "Unexpected 'refine' child node size of "
-                            + dataNodeContainer);
-            LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines()
-                    .values().iterator().next();
-            checkState(refine.getUnknownSchemaNodes().size() == 1,
-                    "Unexpected unknown schema node size of " + refine);
-            UnknownSchemaNode requiredIdentity = refine.getUnknownSchemaNodes()
-                    .iterator().next();
-            checkState(
-                    ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity
-                            .getNodeType()), "Unexpected language extension "
-                            + requiredIdentity);
-            String prefixAndIdentityLocalName = requiredIdentity
-                    .getNodeParameter();
-            // import should point to a module
-            ServiceInterfaceEntry serviceInterfaceEntry = findSIE(
-                    prefixAndIdentityLocalName, currentModule, qNamesToSIEs,
-                    schemaContext);
-            boolean mandatory = refine.getConstraints().isMandatory();
-            AbstractDependencyAttribute reference;
-            if (dataNodeContainer instanceof ContainerSchemaNode) {
-                reference = new DependencyAttribute(attrNode,
-                        serviceInterfaceEntry, mandatory,
-                        attrNode.getDescription());
-            } else {
-                reference = new ListDependenciesAttribute(attrNode,
-                        serviceInterfaceEntry, mandatory,
-                        attrNode.getDescription());
-            }
-            return Optional.of(reference);
+        public ModuleMXBeanEntryInitialBuilder setNamespace(String namespace) {
+            this.namespace = namespace;
+            return this;
         }
-        return Optional.absent();
-    }
 
-    private static ServiceInterfaceEntry findSIE(
-            String prefixAndIdentityLocalName, Module currentModule,
-            Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
-            SchemaContext schemaContext) {
-
-        Matcher m = PREFIX_COLON_LOCAL_NAME.matcher(prefixAndIdentityLocalName);
-        Module foundModule;
-        String localSIName;
-        if (m.matches()) {
-            // if there is a prefix, look for ModuleImport with this prefix. Get
-            // Module from SchemaContext
-            String prefix = m.group(1);
-            ModuleImport moduleImport = findModuleImport(currentModule, prefix);
-            foundModule = schemaContext.findModuleByName(
-                    moduleImport.getModuleName(), moduleImport.getRevision());
-            checkState(
-                    foundModule != null,
-                    format("Module not found in SchemaContext by %s",
-                            moduleImport));
-            localSIName = m.group(2);
-        } else {
-            foundModule = currentModule; // no prefix => SIE is in currentModule
-            localSIName = prefixAndIdentityLocalName;
+        public ModuleMXBeanEntryInitialBuilder setqName(QName qName) {
+            this.qName = qName;
+            return this;
         }
-        QName siQName = new QName(foundModule.getNamespace(),
-                foundModule.getRevision(), localSIName);
-        ServiceInterfaceEntry sie = qNamesToSIEs.get(siQName);
-        checkState(sie != null, "Cannot find referenced Service Interface by "
-                + prefixAndIdentityLocalName);
-        return sie;
-    }
 
-    private static ModuleImport findModuleImport(Module module, String prefix) {
-        for (ModuleImport moduleImport : module.getImports()) {
-            if (moduleImport.getPrefix().equals(prefix)) {
-                return moduleImport;
-            }
+        public ModuleMXBeanEntry.ModuleMXBeanEntryInitial build() {
+            return new ModuleMXBeanEntry.ModuleMXBeanEntryInitial(localName, description, packageName, javaNamePrefix, namespace, qName);
         }
-        throw new IllegalStateException(format(
-                "Import not found with prefix %s in %s", prefix, module));
-    }
 
-    public Map<String, AttributeIfc> getAttributes() {
-        return yangToAttributes;
-    }
-
-    private void setYangToAttributes(Map<String, AttributeIfc> newAttributes) {
-        this.yangToAttributes = newAttributes;
-
-    }
-
-    public String getNullableDescription() {
-        return nullableDescription;
-    }
-
-    public QName getYangModuleQName() {
-        return yangModuleQName;
-    }
+        public ModuleMXBeanEntryInitialBuilder setIdSchemaNode(IdentitySchemaNode idSchemaNode) {
+            this.localName = idSchemaNode.getQName().getLocalName();
+            this.description = idSchemaNode.getDescription();
+            return this;
+        }
 
-    @Override
-    public String toString() {
-        return "ModuleMXBeanEntry{" + "globallyUniqueName='"
-                + globallyUniqueName + '\'' + ", packageName='" + packageName
-                + '\'' + '}';
     }
 }
diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java
new file mode 100644 (file)
index 0000000..4a9d551
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2013 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.config.yangjmxgenerator;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.lang.String.format;
+import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
+
+final class ModuleMXBeanEntryBuilder {
+
+    private Module currentModule;
+    private Map<QName, ServiceInterfaceEntry> qNamesToSIEs;
+    private SchemaContext schemaContext;
+    private TypeProviderWrapper typeProviderWrapper;
+    private String packageName;
+
+    public ModuleMXBeanEntryBuilder setModule(Module module) {
+        this.currentModule = module;
+        return this;
+    }
+
+    public ModuleMXBeanEntryBuilder setqNamesToSIEs(Map<QName, ServiceInterfaceEntry> qNamesToSIEs) {
+        this.qNamesToSIEs = qNamesToSIEs;
+        return this;
+    }
+
+    public ModuleMXBeanEntryBuilder setSchemaContext(SchemaContext schemaContext) {
+        this.schemaContext = schemaContext;
+        return this;
+    }
+
+    public ModuleMXBeanEntryBuilder setTypeProviderWrapper(TypeProviderWrapper typeProviderWrapper) {
+        this.typeProviderWrapper = typeProviderWrapper;
+        return this;
+    }
+
+    public ModuleMXBeanEntryBuilder setPackageName(String packageName) {
+        this.packageName = packageName;
+        return this;
+    }
+
+    private static final Logger logger = LoggerFactory
+            .getLogger(ModuleMXBeanEntryBuilder.class);
+
+    // TODO: the XPath should be parsed by code generator IMO
+    private static final String MAGIC_STRING = "MAGIC_STRING";
+    private static final String MODULE_CONDITION_XPATH_TEMPLATE = "^/MAGIC_STRING:modules/MAGIC_STRING:module/MAGIC_STRING:type\\s*=\\s*['\"](.+)['\"]$";
+    private static final SchemaPath expectedConfigurationAugmentationSchemaPath = new SchemaPath(
+            Arrays.asList(createConfigQName("modules"),
+                    createConfigQName("module"),
+                    createConfigQName("configuration")), true);
+    private static final SchemaPath expectedStateAugmentationSchemaPath = new SchemaPath(
+            Arrays.asList(createConfigQName("modules"),
+                    createConfigQName("module"), createConfigQName("state")),
+            true);
+    private static final Pattern PREFIX_COLON_LOCAL_NAME = Pattern
+            .compile("^(.+):(.+)$");
+
+
+    public Map<String, ModuleMXBeanEntry> build() {
+        logger.debug("Generating ModuleMXBeans of {} to package {}",
+                currentModule.getNamespace(), packageName);
+
+        String configModulePrefix;
+        try {
+            configModulePrefix = getConfigModulePrefixFromImport(currentModule);
+        } catch (IllegalArgumentException e) {
+            // this currentModule does not import config currentModule
+            return Collections.emptyMap();
+        }
+
+        // get identities of base config:currentModule-type
+        Map<String, IdentitySchemaNode> moduleIdentities =  getIdentityMap();
+
+        Map<String, QName> uniqueGeneratedClassesNames = new HashMap<>();
+
+        // each currentModule name should have an augmentation defined
+        Map<String, IdentitySchemaNode> unaugmentedModuleIdentities = new HashMap<>(
+                moduleIdentities);
+
+        Map<String, ModuleMXBeanEntry> result = new HashMap<>();
+
+        for (AugmentationSchema augmentation : currentModule.getAugmentations()) {
+            Set<DataSchemaNode> childNodes = augmentation.getChildNodes();
+            if (areAllChildrenChoiceCaseNodes(childNodes)) {
+                for (ChoiceCaseNode childCase : castChildNodesToChoiceCases(childNodes)) {
+                    // TODO refactor, extract to standalone builder class
+                    processChoiceCaseNode(result, uniqueGeneratedClassesNames, configModulePrefix, moduleIdentities,
+                            unaugmentedModuleIdentities, augmentation, childCase);
+                }
+            } // skip if child nodes are not all cases
+        }
+        // clean up nulls
+        cleanUpNulls(result);
+        // check attributes name uniqueness
+        checkAttributeNamesUniqueness(uniqueGeneratedClassesNames, result);
+        checkUnaugumentedIdentities(unaugmentedModuleIdentities);
+
+        logger.debug("Number of ModuleMXBeans to be generated: {}", result.size());
+
+        return result;
+    }
+
+    private static void cleanUpNulls(Map<String, ModuleMXBeanEntry> result) {
+        for (Map.Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
+            ModuleMXBeanEntry module = entry.getValue();
+            if (module.getAttributes() == null) {
+                module.setYangToAttributes(Collections
+                        .<String, AttributeIfc> emptyMap());
+            } else if (module.getRuntimeBeans() == null) {
+                module.setRuntimeBeans(Collections
+                        .<RuntimeBeanEntry> emptyList());
+            }
+        }
+    }
+
+    private static void checkUnaugumentedIdentities(Map<String, IdentitySchemaNode> unaugmentedModuleIdentities) {
+        if (unaugmentedModuleIdentities.size() > 0) {
+            logger.warn("Augmentation not found for all currentModule identities: {}",
+                    unaugmentedModuleIdentities.keySet());
+        }
+    }
+
+    private static void checkAttributeNamesUniqueness(Map<String, QName> uniqueGeneratedClassesNames, Map<String, ModuleMXBeanEntry> result) {
+        for (Map.Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
+            checkUniqueRuntimeBeanAttributesName(entry.getValue(),
+                    uniqueGeneratedClassesNames);
+        }
+    }
+
+    private Map<String, IdentitySchemaNode> getIdentityMap() {
+        Map<String, IdentitySchemaNode> moduleIdentities = Maps.newHashMap();
+
+        for (IdentitySchemaNode id : currentModule.getIdentities()) {
+            if (id.getBaseIdentity() != null
+                    && ConfigConstants.MODULE_TYPE_Q_NAME.equals(id.getBaseIdentity().getQName())) {
+                String identityLocalName = id.getQName().getLocalName();
+                if (moduleIdentities.containsKey(identityLocalName)) {
+                    throw new IllegalStateException("Module name already defined in this currentModule: "
+                            + identityLocalName);
+                } else {
+                    moduleIdentities.put(identityLocalName, id);
+                    logger.debug("Found identity {}", identityLocalName);
+                }
+                // validation check on unknown schema nodes
+                boolean providedServiceWasSet = false;
+                for (UnknownSchemaNode unknownNode : id.getUnknownSchemaNodes()) {
+                    // TODO: test this
+                    if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
+                        // no op: 0 or more provided identities are allowed
+                    } else if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
+                        // 0..1 allowed
+                        checkState(
+                                providedServiceWasSet == false,
+                                format("More than one language extension %s is not allowed here: %s",
+                                        ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME, id));
+                        providedServiceWasSet = true;
+                    } else {
+                        throw new IllegalStateException("Unexpected language extension " + unknownNode.getNodeType());
+                    }
+                }
+            }
+        }
+
+        return moduleIdentities;
+    }
+
+    private Collection<ChoiceCaseNode> castChildNodesToChoiceCases(Set<DataSchemaNode> childNodes) {
+        return Collections2.transform(childNodes, new Function<DataSchemaNode, ChoiceCaseNode>() {
+            @Nullable
+            @Override
+            public ChoiceCaseNode apply(@Nullable DataSchemaNode input) {
+                return (ChoiceCaseNode) input;
+            }
+        });
+    }
+
+    private boolean areAllChildrenChoiceCaseNodes(Set<DataSchemaNode> childNodes) {
+        for (DataSchemaNode childNode : childNodes) {
+            if (childNode instanceof ChoiceCaseNode == false)
+                return false;
+        }
+        return true;
+    }
+
+    private void processChoiceCaseNode(Map<String, ModuleMXBeanEntry> result,
+            Map<String, QName> uniqueGeneratedClassesNames, String configModulePrefix,
+            Map<String, IdentitySchemaNode> moduleIdentities,
+            Map<String, IdentitySchemaNode> unaugmentedModuleIdentities, AugmentationSchema augmentation,
+            DataSchemaNode when) {
+
+        ChoiceCaseNode choiceCaseNode = (ChoiceCaseNode) when;
+        if (choiceCaseNode.getConstraints() == null || choiceCaseNode.getConstraints().getWhenCondition() == null) {
+            return;
+        }
+        RevisionAwareXPath xPath = choiceCaseNode.getConstraints().getWhenCondition();
+        Matcher matcher = getWhenConditionMatcher(configModulePrefix, xPath);
+        if (matcher.matches() == false) {
+            return;
+        }
+        String moduleLocalNameFromXPath = matcher.group(1);
+        IdentitySchemaNode moduleIdentity = moduleIdentities.get(moduleLocalNameFromXPath);
+        unaugmentedModuleIdentities.remove(moduleLocalNameFromXPath);
+        checkState(moduleIdentity != null, "Cannot find identity " + moduleLocalNameFromXPath
+                + " matching augmentation " + augmentation);
+        Map<String, QName> providedServices = findProvidedServices(moduleIdentity, currentModule, qNamesToSIEs,
+                schemaContext);
+
+        if (moduleIdentity == null) {
+            throw new IllegalStateException("Cannot find identity specified by augmentation xpath constraint: "
+                    + moduleLocalNameFromXPath + " of " + augmentation);
+        }
+        String javaNamePrefix = TypeProviderWrapper.findJavaNamePrefix(moduleIdentity);
+
+        Map<String, AttributeIfc> yangToAttributes = null;
+        // runtime-data
+        Collection<RuntimeBeanEntry> runtimeBeans = null;
+
+        if (expectedConfigurationAugmentationSchemaPath.equals(augmentation.getTargetPath())) {
+            logger.debug("Parsing configuration of {}", moduleLocalNameFromXPath);
+            yangToAttributes = fillConfiguration(choiceCaseNode, currentModule, typeProviderWrapper, qNamesToSIEs,
+                    schemaContext, packageName);
+            checkUniqueAttributesWithGeneratedClass(uniqueGeneratedClassesNames, when.getQName(), yangToAttributes);
+        } else if (expectedStateAugmentationSchemaPath.equals(augmentation.getTargetPath())) {
+            logger.debug("Parsing state of {}", moduleLocalNameFromXPath);
+            try {
+                runtimeBeans = fillRuntimeBeans(choiceCaseNode, currentModule, typeProviderWrapper, packageName,
+                        moduleLocalNameFromXPath, javaNamePrefix);
+            } catch (NameConflictException e) {
+                throw new NameConflictException(e.getConflictingName(), when.getQName(), when.getQName());
+            }
+            checkUniqueRuntimeBeansGeneratedClasses(uniqueGeneratedClassesNames, when, runtimeBeans);
+            Set<RuntimeBeanEntry> runtimeBeanEntryValues = Sets.newHashSet(runtimeBeans);
+            for (RuntimeBeanEntry entry : runtimeBeanEntryValues) {
+                checkUniqueAttributesWithGeneratedClass(uniqueGeneratedClassesNames, when.getQName(),
+                        entry.getYangPropertiesToTypesMap());
+            }
+
+        } else {
+            throw new IllegalArgumentException("Cannot parse augmentation " + augmentation);
+        }
+        if (result.containsKey(moduleLocalNameFromXPath)) {
+            // either fill runtimeBeans or yangToAttributes
+            ModuleMXBeanEntry moduleMXBeanEntry = result.get(moduleLocalNameFromXPath);
+            if (yangToAttributes != null && moduleMXBeanEntry.getAttributes() == null) {
+                moduleMXBeanEntry.setYangToAttributes(yangToAttributes);
+            } else if (runtimeBeans != null && moduleMXBeanEntry.getRuntimeBeans() == null) {
+                moduleMXBeanEntry.setRuntimeBeans(runtimeBeans);
+            }
+        } else {
+            ModuleMXBeanEntry.ModuleMXBeanEntryInitial initial = new ModuleMXBeanEntry.ModuleMXBeanEntryInitialBuilder()
+                    .setIdSchemaNode(moduleIdentity).setPackageName(packageName).setJavaNamePrefix(javaNamePrefix)
+                    .setNamespace(currentModule.getNamespace().toString()).setqName(ModuleUtil.getQName(currentModule))
+                    .build();
+
+            // construct ModuleMXBeanEntry
+            ModuleMXBeanEntry moduleMXBeanEntry = new ModuleMXBeanEntry(initial, yangToAttributes, providedServices,
+                    runtimeBeans);
+
+            moduleMXBeanEntry.setYangModuleName(currentModule.getName());
+            moduleMXBeanEntry.setYangModuleLocalname(moduleLocalNameFromXPath);
+            result.put(moduleLocalNameFromXPath, moduleMXBeanEntry);
+        }
+    }
+
+    private void checkUniqueRuntimeBeansGeneratedClasses(Map<String, QName> uniqueGeneratedClassesNames,
+            DataSchemaNode when, Collection<RuntimeBeanEntry> runtimeBeans) {
+        for (RuntimeBeanEntry runtimeBean : runtimeBeans) {
+            final String javaNameOfRuntimeMXBean = runtimeBean.getJavaNameOfRuntimeMXBean();
+            if (uniqueGeneratedClassesNames.containsKey(javaNameOfRuntimeMXBean)) {
+                QName firstDefinedQName = uniqueGeneratedClassesNames.get(javaNameOfRuntimeMXBean);
+                throw new NameConflictException(javaNameOfRuntimeMXBean, firstDefinedQName, when.getQName());
+            }
+            uniqueGeneratedClassesNames.put(javaNameOfRuntimeMXBean, when.getQName());
+        }
+    }
+
+    private static void checkUniqueRuntimeBeanAttributesName(ModuleMXBeanEntry mxBeanEntry,
+            Map<String, QName> uniqueGeneratedClassesNames) {
+        for (RuntimeBeanEntry runtimeBeanEntry : mxBeanEntry.getRuntimeBeans()) {
+            for (String runtimeAttName : runtimeBeanEntry.getYangPropertiesToTypesMap().keySet()) {
+                if (mxBeanEntry.getAttributes().keySet().contains(runtimeAttName)) {
+                    QName qName1 = uniqueGeneratedClassesNames.get(runtimeBeanEntry.getJavaNameOfRuntimeMXBean());
+                    QName qName2 = uniqueGeneratedClassesNames.get(mxBeanEntry.getGloballyUniqueName());
+                    throw new NameConflictException(runtimeAttName, qName1, qName2);
+                }
+            }
+        }
+    }
+
+    private void checkUniqueAttributesWithGeneratedClass(Map<String, QName> uniqueGeneratedClassNames,
+            QName parentQName, Map<String, AttributeIfc> yangToAttributes) {
+        for (Map.Entry<String, AttributeIfc> attr : yangToAttributes.entrySet()) {
+            if (attr.getValue() instanceof TOAttribute) {
+                checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName, (TOAttribute) attr.getValue());
+            } else if (attr.getValue() instanceof ListAttribute
+                    && ((ListAttribute) attr.getValue()).getInnerAttribute() instanceof TOAttribute) {
+                checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName,
+                        (TOAttribute) ((ListAttribute) attr.getValue()).getInnerAttribute());
+            }
+        }
+    }
+
+    private void checkUniqueTOAttr(Map<String, QName> uniqueGeneratedClassNames, QName parentQName, TOAttribute attr) {
+        final String upperCaseCammelCase = attr.getUpperCaseCammelCase();
+        if (uniqueGeneratedClassNames.containsKey(upperCaseCammelCase)) {
+            QName firstDefinedQName = uniqueGeneratedClassNames.get(upperCaseCammelCase);
+            throw new NameConflictException(upperCaseCammelCase, firstDefinedQName, parentQName);
+        } else {
+            uniqueGeneratedClassNames.put(upperCaseCammelCase, parentQName);
+        }
+    }
+
+    private Collection<RuntimeBeanEntry> fillRuntimeBeans(ChoiceCaseNode choiceCaseNode, Module currentModule,
+            TypeProviderWrapper typeProviderWrapper, String packageName, String moduleLocalNameFromXPath,
+            String javaNamePrefix) {
+
+        return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName, choiceCaseNode, moduleLocalNameFromXPath,
+                typeProviderWrapper, javaNamePrefix, currentModule).values();
+
+    }
+
+    private Map<String, AttributeIfc> fillConfiguration(ChoiceCaseNode choiceCaseNode, Module currentModule,
+            TypeProviderWrapper typeProviderWrapper, Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
+            SchemaContext schemaContext, String packageName) {
+        Map<String, AttributeIfc> yangToAttributes = new HashMap<>();
+        for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) {
+            AttributeIfc attributeValue = getAttributeValue(attrNode, currentModule, qNamesToSIEs, typeProviderWrapper,
+                    schemaContext, packageName);
+            yangToAttributes.put(attributeValue.getAttributeYangName(), attributeValue);
+        }
+        return yangToAttributes;
+    }
+
+    private Map<String, QName> findProvidedServices(IdentitySchemaNode moduleIdentity, Module currentModule,
+            Map<QName, ServiceInterfaceEntry> qNamesToSIEs, SchemaContext schemaContext) {
+        Map<String, QName> result = new HashMap<>();
+        for (UnknownSchemaNode unknownNode : moduleIdentity.getUnknownSchemaNodes()) {
+            if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
+                String prefixAndIdentityLocalName = unknownNode.getNodeParameter();
+                ServiceInterfaceEntry sie = findSIE(prefixAndIdentityLocalName, currentModule, qNamesToSIEs,
+                        schemaContext);
+                result.put(sie.getFullyQualifiedName(), sie.getQName());
+            }
+        }
+        return result;
+    }
+
+    private AttributeIfc getAttributeValue(DataSchemaNode attrNode, Module currentModule,
+            Map<QName, ServiceInterfaceEntry> qNamesToSIEs, TypeProviderWrapper typeProviderWrapper,
+            SchemaContext schemaContext, String packageName) {
+
+        if (attrNode instanceof LeafSchemaNode) {
+            // simple type
+            LeafSchemaNode leaf = (LeafSchemaNode) attrNode;
+            return new JavaAttribute(leaf, typeProviderWrapper);
+        } else if (attrNode instanceof ContainerSchemaNode) {
+            // reference or TO
+            ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) attrNode;
+            Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
+                    containerSchemaNode, attrNode, currentModule, qNamesToSIEs, schemaContext);
+            if (dependencyAttributeOptional.isPresent()) {
+                return dependencyAttributeOptional.get();
+            } else {
+                return TOAttribute.create(containerSchemaNode, typeProviderWrapper, packageName);
+            }
+
+        } else if (attrNode instanceof LeafListSchemaNode) {
+            return ListAttribute.create((LeafListSchemaNode) attrNode, typeProviderWrapper);
+        } else if (attrNode instanceof ListSchemaNode) {
+            ListSchemaNode listSchemaNode = (ListSchemaNode) attrNode;
+            Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
+                    listSchemaNode, attrNode, currentModule, qNamesToSIEs, schemaContext);
+            if (dependencyAttributeOptional.isPresent()) {
+                return dependencyAttributeOptional.get();
+            } else {
+                return ListAttribute.create(listSchemaNode, typeProviderWrapper, packageName);
+            }
+        } else {
+            throw new UnsupportedOperationException("Unknown configuration node " + attrNode.toString());
+        }
+    }
+
+    private Optional<? extends AbstractDependencyAttribute> extractDependency(DataNodeContainer dataNodeContainer,
+            DataSchemaNode attrNode, Module currentModule, Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
+            SchemaContext schemaContext) {
+        if (dataNodeContainer.getUses().size() == 1 && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) {
+            // reference
+            UsesNode usesNode = dataNodeContainer.getUses().iterator().next();
+            checkState(usesNode.getRefines().size() == 1, "Unexpected 'refine' child node size of " + dataNodeContainer);
+            LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines().values().iterator().next();
+            checkState(refine.getUnknownSchemaNodes().size() == 1, "Unexpected unknown schema node size of " + refine);
+            UnknownSchemaNode requiredIdentity = refine.getUnknownSchemaNodes().iterator().next();
+            checkState(ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity.getNodeType()),
+                    "Unexpected language extension " + requiredIdentity);
+            String prefixAndIdentityLocalName = requiredIdentity.getNodeParameter();
+            // import should point to a module
+            ServiceInterfaceEntry serviceInterfaceEntry = findSIE(prefixAndIdentityLocalName, currentModule,
+                    qNamesToSIEs, schemaContext);
+            boolean mandatory = refine.getConstraints().isMandatory();
+            AbstractDependencyAttribute reference;
+            if (dataNodeContainer instanceof ContainerSchemaNode) {
+                reference = new DependencyAttribute(attrNode, serviceInterfaceEntry, mandatory,
+                        attrNode.getDescription());
+            } else {
+                reference = new ListDependenciesAttribute(attrNode, serviceInterfaceEntry, mandatory,
+                        attrNode.getDescription());
+            }
+            return Optional.of(reference);
+        }
+        return Optional.absent();
+    }
+
+    private int getChildNodeSizeWithoutUses(DataNodeContainer csn) {
+        int result = 0;
+        for (DataSchemaNode dsn : csn.getChildNodes()) {
+            if (dsn.isAddedByUses() == false) {
+                result++;
+            }
+        }
+        return result;
+    }
+
+    private ServiceInterfaceEntry findSIE(String prefixAndIdentityLocalName, Module currentModule,
+            Map<QName, ServiceInterfaceEntry> qNamesToSIEs, SchemaContext schemaContext) {
+
+        Matcher m = PREFIX_COLON_LOCAL_NAME.matcher(prefixAndIdentityLocalName);
+        Module foundModule;
+        String localSIName;
+        if (m.matches()) {
+            // if there is a prefix, look for ModuleImport with this prefix. Get
+            // Module from SchemaContext
+            String prefix = m.group(1);
+            ModuleImport moduleImport = findModuleImport(currentModule, prefix);
+            foundModule = schemaContext.findModuleByName(moduleImport.getModuleName(), moduleImport.getRevision());
+            checkState(foundModule != null, format("Module not found in SchemaContext by %s", moduleImport));
+            localSIName = m.group(2);
+        } else {
+            foundModule = currentModule; // no prefix => SIE is in currentModule
+            localSIName = prefixAndIdentityLocalName;
+        }
+        QName siQName = new QName(foundModule.getNamespace(), foundModule.getRevision(), localSIName);
+        ServiceInterfaceEntry sie = qNamesToSIEs.get(siQName);
+        checkState(sie != null, "Cannot find referenced Service Interface by " + prefixAndIdentityLocalName);
+        return sie;
+    }
+
+    private ModuleImport findModuleImport(Module module, String prefix) {
+        for (ModuleImport moduleImport : module.getImports()) {
+            if (moduleImport.getPrefix().equals(prefix)) {
+                return moduleImport;
+            }
+        }
+        throw new IllegalStateException(format("Import not found with prefix %s in %s", prefix, module));
+    }
+
+    @VisibleForTesting
+    static Matcher getWhenConditionMatcher(String prefix, RevisionAwareXPath whenConstraint) {
+        String xpathRegex = MODULE_CONDITION_XPATH_TEMPLATE.replace(MAGIC_STRING, prefix);
+        Pattern pattern = Pattern.compile(xpathRegex);
+        return pattern.matcher(whenConstraint.toString());
+    }
+
+    String getConfigModulePrefixFromImport(Module currentModule) {
+        for (ModuleImport currentImport : currentModule.getImports()) {
+            if (currentImport.getModuleName().equals(ConfigConstants.CONFIG_MODULE)) {
+                return currentImport.getPrefix();
+            }
+        }
+        throw new IllegalArgumentException("Cannot find import " + ConfigConstants.CONFIG_MODULE + " in "
+                + currentModule);
+    }
+
+}
index 4831545..cd14458 100644 (file)
@@ -272,7 +272,7 @@ public class RuntimeBeanEntry {
                 }
                 // convert RpcDefinition to Rpc
                 for (RpcDefinition rpcDefinition : rpcDefinitions) {
-                    String name = ModuleMXBeanEntry
+                    String name = TypeProviderWrapper
                             .findJavaParameter(rpcDefinition);
                     AttributeIfc returnType;
                     if (rpcDefinition.getOutput() == null
@@ -376,7 +376,7 @@ public class RuntimeBeanEntry {
                     "More than one key is not supported in " + listSchemaNode);
         }
 
-        String javaNamePrefix = ModuleMXBeanEntry
+        String javaNamePrefix = TypeProviderWrapper
                 .findJavaNamePrefix(listSchemaNode);
 
         RuntimeBeanEntry rbFromAttributes = new RuntimeBeanEntry(packageName,
index c43fead..3c8c8aa 100644 (file)
@@ -7,12 +7,14 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator;
 
+import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.sal.binding.generator.spi.TypeProvider;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 
 public class TypeProviderWrapper {
     private final TypeProvider typeProvider;
@@ -21,6 +23,40 @@ public class TypeProviderWrapper {
         this.typeProvider = typeProvider;
     }
 
+    /**
+     * For input node, find if it contains config:java-name-prefix extension. If
+     * not found, convert local name of node converted to cammel case.
+     */
+    public static String findJavaNamePrefix(SchemaNode schemaNode) {
+        return convertToJavaName(schemaNode, true);
+    }
+
+    public static String findJavaParameter(SchemaNode schemaNode) {
+        return convertToJavaName(schemaNode, false);
+    }
+
+    public static String convertToJavaName(SchemaNode schemaNode,
+                                           boolean capitalizeFirstLetter) {
+        for (UnknownSchemaNode unknownNode : schemaNode.getUnknownSchemaNodes()) {
+            if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME
+                    .equals(unknownNode.getNodeType())) {
+                String value = unknownNode.getNodeParameter();
+                return convertToJavaName(value, capitalizeFirstLetter);
+            }
+        }
+        return convertToJavaName(schemaNode.getQName().getLocalName(),
+                capitalizeFirstLetter);
+    }
+
+    public static String convertToJavaName(String localName,
+                                           boolean capitalizeFirstLetter) {
+        if (capitalizeFirstLetter) {
+            return BindingGeneratorUtil.parseToClassName(localName);
+        } else {
+            return BindingGeneratorUtil.parseToValidParamName(localName);
+        }
+    }
+
     public Type getType(LeafSchemaNode leaf) {
         TypeDefinition<?> type = leaf.getType();
         return getType(leaf, type);
index ba2edc4..edfb4c5 100644 (file)
@@ -7,7 +7,7 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.attribute;
 
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
+import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 
 public abstract class AbstractAttribute implements AttributeIfc {
@@ -22,8 +22,8 @@ public abstract class AbstractAttribute implements AttributeIfc {
     AbstractAttribute(DataSchemaNode attrNode) {
         this.attributeYangName = getLocalName(attrNode);
         this.node = attrNode;
-        this.upperCaseCammelCase = ModuleMXBeanEntry.findJavaNamePrefix(node);
-        this.lowerCaseCammelCase = ModuleMXBeanEntry.findJavaParameter(node);
+        this.upperCaseCammelCase = TypeProviderWrapper.findJavaNamePrefix(node);
+        this.lowerCaseCammelCase = TypeProviderWrapper.findJavaParameter(node);
     }
 
     @Override
index 6a540b5..84300cb 100644 (file)
@@ -11,7 +11,6 @@ import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
-import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
 import org.opendaylight.controller.config.yangjmxgenerator.TypeProviderWrapper;
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
@@ -121,7 +120,7 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute {
                 .entrySet()) {
 
             capitalizedPropertiesToTypesMap.put(
-                    ModuleMXBeanEntry.convertToJavaName(entry.getKey(), true),
+                    TypeProviderWrapper.convertToJavaName(entry.getKey(), true),
                     entry.getValue());
         }
         return capitalizedPropertiesToTypesMap;
@@ -133,7 +132,7 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute {
                 .entrySet()) {
 
             jmxPropertiesToTypesMap.put(
-                    ModuleMXBeanEntry.convertToJavaName(entry.getKey(), false),
+                    TypeProviderWrapper.convertToJavaName(entry.getKey(), false),
                     entry.getValue());
         }
         return jmxPropertiesToTypesMap;
index 9ea34ca..8ca2bb5 100644 (file)
@@ -113,6 +113,9 @@ public class ModuleMXBeanEntryTest extends AbstractYangTest {
                         , PACKAGE_NAME);
         Map<String, AttributeIfc> attributes = namesToMBEs.get("impl-netconf")
                 .getAttributes();
+
+        assertCorrectAttributesSize(namesToMBEs, attributes);
+
         //
         DependencyAttribute threadFactoryAttribute = (DependencyAttribute) attributes
                 .get("thread-factory");
@@ -132,6 +135,16 @@ public class ModuleMXBeanEntryTest extends AbstractYangTest {
         assertThat(threadFactoryAttribute.getType().getName(), is("ObjectName"));
     }
 
+    private void assertCorrectAttributesSize(Map<String, ModuleMXBeanEntry> namesToMBEs, Map<String, AttributeIfc> attributes) {
+        assertEquals(14, attributes.size());
+        assertEquals(1, namesToMBEs.get("impl-netconf").getRuntimeBeans().size());
+        assertEquals(2, namesToMBEs.get("impl-netconf").getRuntimeBeans().iterator().next().getAttributes().size());
+
+        assertEquals(4, namesToMBEs.get("impl").getAttributes().size());
+        assertEquals(1, namesToMBEs.get("impl").getRuntimeBeans().size());
+        assertEquals(1, namesToMBEs.get("impl").getRuntimeBeans().iterator().next().getAttributes().size());
+    }
+
     protected RuntimeBeanEntry findFirstByYangName(
             Collection<RuntimeBeanEntry> runtimeBeans, String yangName) {
         for (RuntimeBeanEntry rb : runtimeBeans) {
@@ -155,7 +168,7 @@ public class ModuleMXBeanEntryTest extends AbstractYangTest {
     private void assertMatches(String prefix, String input) {
         RevisionAwareXPath whenConstraint = mock(RevisionAwareXPath.class);
         doReturn(input).when(whenConstraint).toString();
-        Matcher output = ModuleMXBeanEntry.getWhenConditionMatcher(prefix,
+        Matcher output = ModuleMXBeanEntryBuilder.getWhenConditionMatcher(prefix,
                 whenConstraint);
         assertTrue(output.matches());
         assertEquals("threadpool-dynamic", output.group(1));
index 97078e0..16085ef 100644 (file)
@@ -8,8 +8,6 @@ module config-jmx-it-impl {
     import ietf-inet-types { prefix inet; revision-date 2010-09-24;}
     import config-threads { prefix th; revision-date 2013-04-09; }
 
-
-
     description
         "Testing IMPL";
 
@@ -67,19 +65,7 @@ module config-jmx-it-impl {
             }
 
         }
-    }
-
-    augment "/config:modules/config:module/config:state" {
-        case impl {
-            when "/config:modules/config:module/config:type = 'impl'";
-            // root runtime bean
-            leaf created-sessions {
-                type uint32;
-            }
-        }
-    }
 
-    augment "/config:modules/config:module/config:configuration" {
         case impl-netconf {
             when "/config:modules/config:module/config:type = 'impl-netconf'";
 
@@ -205,6 +191,14 @@ module config-jmx-it-impl {
     }
 
     augment "/config:modules/config:module/config:state" {
+        case impl {
+            when "/config:modules/config:module/config:type = 'impl'";
+            // root runtime bean
+            leaf created-sessions {
+                type uint32;
+            }
+        }
+
         case impl-netconf {
             when "/config:modules/config:module/config:type = 'impl-netconf'";
             // root runtime bean
@@ -212,6 +206,11 @@ module config-jmx-it-impl {
                 type uint32;
             }
 
+            leaf created-sessions-2 {
+                type uint32;
+            }
+
         }
     }
+
 }

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.