2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.config.yangjmxgenerator;
10 import static com.google.common.base.Preconditions.checkNotNull;
11 import static com.google.common.base.Preconditions.checkState;
12 import static java.lang.String.format;
13 import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
15 import java.util.Arrays;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.HashMap;
20 import java.util.Map.Entry;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
25 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
26 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
27 import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
28 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
29 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
30 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
31 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
32 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
33 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
34 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
35 import org.opendaylight.yangtools.yang.common.QName;
36 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
37 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
38 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
40 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
45 import org.opendaylight.yangtools.yang.model.api.Module;
46 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
47 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
48 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
49 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
51 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
52 import org.opendaylight.yangtools.yang.model.api.UsesNode;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 import com.google.common.annotations.VisibleForTesting;
57 import com.google.common.base.Optional;
58 import com.google.common.collect.Sets;
61 * Represents part of yang model that describes a module.
68 * identity threadpool-dynamic {
69 * base config:module-type;
70 * description "threadpool-dynamic description";
71 * config:provided-service "th2:threadpool";
72 * config:provided-service "th2:scheduled-threadpool";
73 * config:java-name-prefix DynamicThreadPool
75 * augment "/config:modules/config:module/config:module-type" {
76 * case threadpool-dynamic {
77 * when "/config:modules/config:module/config:module-type = 'threadpool-dynamic'";
79 * container "configuration" {
80 * // regular java attribute
87 * container threadfactory {
88 * uses config:service-ref {
90 * config:required-identity th:threadfactory;
101 public class ModuleMXBeanEntry extends AbstractEntry {
102 private static final Logger logger = LoggerFactory
103 .getLogger(ModuleMXBeanEntry.class);
105 // TODO: the XPath should be parsed by code generator IMO
106 private static final String MAGIC_STRING = "MAGIC_STRING";
107 private static final String MODULE_CONDITION_XPATH_TEMPLATE = "^/MAGIC_STRING:modules/MAGIC_STRING:module/MAGIC_STRING:type\\s*=\\s*['\"](.+)['\"]$";
108 private static final SchemaPath expectedConfigurationAugmentationSchemaPath = new SchemaPath(
109 Arrays.asList(createConfigQName("modules"),
110 createConfigQName("module"),
111 createConfigQName("configuration")), true);
112 private static final SchemaPath expectedStateAugmentationSchemaPath = new SchemaPath(
113 Arrays.asList(createConfigQName("modules"),
114 createConfigQName("module"), createConfigQName("state")),
117 private static final Pattern PREFIX_COLON_LOCAL_NAME = Pattern
118 .compile("^(.+):(.+)$");
120 private static final String MODULE_SUFFIX = "Module";
121 private static final String FACTORY_SUFFIX = MODULE_SUFFIX + "Factory";
122 private static final String CLASS_NAME_SUFFIX = MODULE_SUFFIX + "MXBean";
123 private static final String ABSTRACT_PREFIX = "Abstract";
126 * threadpool-dynamic from the example above, taken from when condition, not
129 private final String globallyUniqueName;
131 private Map<String, AttributeIfc> yangToAttributes;
133 private final String nullableDescription, packageName, javaNamePrefix,
136 private final Map<String, QName> providedServices;
138 private Collection<RuntimeBeanEntry> runtimeBeans;
139 private final QName yangModuleQName;
141 public ModuleMXBeanEntry(IdentitySchemaNode id,
142 Map<String, AttributeIfc> yangToAttributes, String packageName,
143 Map<String, QName> providedServices2, String javaNamePrefix,
144 String namespace, Collection<RuntimeBeanEntry> runtimeBeans,
145 QName yangModuleQName) {
146 this.globallyUniqueName = id.getQName().getLocalName();
147 this.yangToAttributes = yangToAttributes;
148 this.nullableDescription = id.getDescription();
149 this.packageName = packageName;
150 this.javaNamePrefix = checkNotNull(javaNamePrefix);
151 this.namespace = checkNotNull(namespace);
152 this.providedServices = Collections.unmodifiableMap(providedServices2);
153 this.runtimeBeans = runtimeBeans;
154 this.yangModuleQName = yangModuleQName;
157 public String getMXBeanInterfaceName() {
158 return javaNamePrefix + CLASS_NAME_SUFFIX;
161 public String getStubFactoryName() {
162 return javaNamePrefix + FACTORY_SUFFIX;
165 public String getAbstractFactoryName() {
166 return ABSTRACT_PREFIX + getStubFactoryName();
169 public String getStubModuleName() {
170 return javaNamePrefix + MODULE_SUFFIX;
173 public String getAbstractModuleName() {
174 return ABSTRACT_PREFIX + getStubModuleName();
177 public String getFullyQualifiedName(String typeName) {
178 return FullyQualifiedNameHelper.getFullyQualifiedName(packageName,
182 public String getGloballyUniqueName() {
183 return globallyUniqueName;
186 public String getPackageName() {
191 * @return services implemented by this module. Keys are fully qualified
192 * java names of generated ServiceInterface classes, values are
193 * identity local names.
195 public Map<String, QName> getProvidedServices() {
196 return providedServices;
199 public void setRuntimeBeans(Collection<RuntimeBeanEntry> newRuntimeBeans) {
200 runtimeBeans = newRuntimeBeans;
203 public Collection<RuntimeBeanEntry> getRuntimeBeans() {
207 public String getJavaNamePrefix() {
208 return javaNamePrefix;
211 public String getNamespace() {
216 static Matcher getWhenConditionMatcher(String prefix,
217 RevisionAwareXPath whenConstraint) {
218 String xpathRegex = MODULE_CONDITION_XPATH_TEMPLATE.replace(
219 MAGIC_STRING, prefix);
220 Pattern pattern = Pattern.compile(xpathRegex);
221 return pattern.matcher(whenConstraint.toString());
224 static String getConfigModulePrefixFromImport(Module currentModule) {
225 for (ModuleImport currentImport : currentModule.getImports()) {
226 if (currentImport.getModuleName().equals(
227 ConfigConstants.CONFIG_MODULE)) {
228 return currentImport.getPrefix();
231 throw new IllegalArgumentException("Cannot find import "
232 + ConfigConstants.CONFIG_MODULE + " in " + currentModule);
236 * Transform module to zero or more ModuleMXBeanEntry instances. Each
237 * instance must have a globally unique local name.
239 * @return Map of identity local names as keys, and ModuleMXBeanEntry
240 * instances as values
242 public static Map<String/* identity local name */, ModuleMXBeanEntry> create(
243 Module currentModule,
244 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
245 SchemaContext schemaContext,
246 TypeProviderWrapper typeProviderWrapper, String packageName) {
247 Map<String, QName> uniqueGeneratedClassesNames = new HashMap<>();
248 logger.debug("Generating ModuleMXBeans of {} to package {}",
249 currentModule.getNamespace(), packageName);
250 String configModulePrefix;
252 configModulePrefix = getConfigModulePrefixFromImport(currentModule);
253 } catch (IllegalArgumentException e) {
254 // this module does not import config module
255 return Collections.emptyMap();
258 // get identities of base config:module-type
259 Map<String, IdentitySchemaNode> moduleIdentities = new HashMap<>();
261 for (IdentitySchemaNode id : currentModule.getIdentities()) {
262 if (id.getBaseIdentity() != null
263 && ConfigConstants.MODULE_TYPE_Q_NAME.equals(id
264 .getBaseIdentity().getQName())) {
265 String identityLocalName = id.getQName().getLocalName();
266 if (moduleIdentities.containsKey(identityLocalName)) {
267 throw new IllegalStateException(
268 "Module name already defined in this module: "
269 + identityLocalName);
271 moduleIdentities.put(identityLocalName, id);
272 logger.debug("Found identity {}", identityLocalName);
274 // validation check on unknown schema nodes
275 boolean providedServiceWasSet = false;
276 for (UnknownSchemaNode unknownNode : id.getUnknownSchemaNodes()) {
278 if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME
279 .equals(unknownNode.getNodeType())) {
280 // no op: 0 or more provided identities are allowed
281 } else if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME
282 .equals(unknownNode.getNodeType())) {
285 providedServiceWasSet == false,
286 format("More than one language extension %s is not allowed here: %s",
287 ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME,
289 providedServiceWasSet = true;
291 throw new IllegalStateException(
292 "Unexpected language extension "
293 + unknownNode.getNodeType());
298 Map<String, ModuleMXBeanEntry> result = new HashMap<>();
299 // each module name should have an augmentation defined
300 Map<String, IdentitySchemaNode> unaugmentedModuleIdentities = new HashMap<>(
302 for (AugmentationSchema augmentation : currentModule.getAugmentations()) {
303 Set<DataSchemaNode> childNodes = augmentation.getChildNodes();
304 if (childNodes.size() == 1) {
305 DataSchemaNode when = childNodes.iterator().next();
306 if (when instanceof ChoiceCaseNode) {
307 ChoiceCaseNode choiceCaseNode = (ChoiceCaseNode) when;
308 if (choiceCaseNode.getConstraints() == null
309 || choiceCaseNode.getConstraints()
310 .getWhenCondition() == null) {
313 RevisionAwareXPath xPath = choiceCaseNode.getConstraints()
315 Matcher matcher = getWhenConditionMatcher(
316 configModulePrefix, xPath);
317 if (matcher.matches() == false) {
320 String moduleLocalNameFromXPath = matcher.group(1);
321 IdentitySchemaNode moduleIdentity = moduleIdentities
322 .get(moduleLocalNameFromXPath);
323 unaugmentedModuleIdentities
324 .remove(moduleLocalNameFromXPath);
325 checkState(moduleIdentity != null, "Cannot find identity "
326 + moduleLocalNameFromXPath
327 + " matching augmentation " + augmentation);
328 Map<String, QName> providedServices = findProvidedServices(
329 moduleIdentity, currentModule, qNamesToSIEs,
332 if (moduleIdentity == null) {
333 throw new IllegalStateException(
334 "Cannot find identity specified by augmentation xpath constraint: "
335 + moduleLocalNameFromXPath + " of "
338 String javaNamePrefix = findJavaNamePrefix(moduleIdentity);
340 Map<String, AttributeIfc> yangToAttributes = null;
342 Collection<RuntimeBeanEntry> runtimeBeans = null;
344 if (expectedConfigurationAugmentationSchemaPath
345 .equals(augmentation.getTargetPath())) {
346 logger.debug("Parsing configuration of {}",
347 moduleLocalNameFromXPath);
348 yangToAttributes = fillConfiguration(choiceCaseNode,
349 currentModule, typeProviderWrapper,
350 qNamesToSIEs, schemaContext, packageName);
351 checkUniqueAttributesWithGeneratedClass(
352 uniqueGeneratedClassesNames, when.getQName(),
354 } else if (expectedStateAugmentationSchemaPath
355 .equals(augmentation.getTargetPath())) {
356 logger.debug("Parsing state of {}",
357 moduleLocalNameFromXPath);
359 runtimeBeans = fillRuntimeBeans(choiceCaseNode,
360 currentModule, typeProviderWrapper,
361 packageName, moduleLocalNameFromXPath,
363 } catch (NameConflictException e) {
364 throw new NameConflictException(
365 e.getConflictingName(), when.getQName(),
368 checkUniqueRuntimeBeansGeneratedClasses(
369 uniqueGeneratedClassesNames, when, runtimeBeans);
370 Set<RuntimeBeanEntry> runtimeBeanEntryValues = Sets
371 .newHashSet(runtimeBeans);
372 for (RuntimeBeanEntry entry : runtimeBeanEntryValues) {
373 checkUniqueAttributesWithGeneratedClass(
374 uniqueGeneratedClassesNames,
376 entry.getYangPropertiesToTypesMap());
380 throw new IllegalArgumentException(
381 "Cannot parse augmentation " + augmentation);
383 if (result.containsKey(moduleLocalNameFromXPath)) {
384 // either fill runtimeBeans or yangToAttributes
385 ModuleMXBeanEntry moduleMXBeanEntry = result
386 .get(moduleLocalNameFromXPath);
387 if (yangToAttributes != null
388 && moduleMXBeanEntry.getAttributes() == null) {
390 .setYangToAttributes(yangToAttributes);
391 } else if (runtimeBeans != null
392 && moduleMXBeanEntry.getRuntimeBeans() == null) {
393 moduleMXBeanEntry.setRuntimeBeans(runtimeBeans);
396 // construct ModuleMXBeanEntry
397 ModuleMXBeanEntry moduleMXBeanEntry = new ModuleMXBeanEntry(
398 moduleIdentity, yangToAttributes, packageName,
399 providedServices, javaNamePrefix, currentModule
400 .getNamespace().toString(),
402 ModuleUtil.getQName(currentModule));
403 moduleMXBeanEntry.setYangModuleName(currentModule
406 .setYangModuleLocalname(moduleLocalNameFromXPath);
407 result.put(moduleLocalNameFromXPath, moduleMXBeanEntry);
409 } // skip if child node is not ChoiceCaseNode
410 } // skip if childNodes != 1
413 for (Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
414 ModuleMXBeanEntry module = entry.getValue();
415 if (module.getAttributes() == null) {
416 module.setYangToAttributes(Collections
417 .<String, AttributeIfc> emptyMap());
418 } else if (module.getRuntimeBeans() == null) {
419 module.setRuntimeBeans(Collections
420 .<RuntimeBeanEntry> emptyList());
423 // check attributes name uniqueness
424 for (Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
425 checkUniqueRuntimeBeanAttributesName(entry.getValue(),
426 uniqueGeneratedClassesNames);
428 if (unaugmentedModuleIdentities.size() > 0) {
429 logger.warn("Augmentation not found for all module identities: {}",
430 unaugmentedModuleIdentities.keySet());
433 logger.debug("Number of ModuleMXBeans to be generated: {}",
438 private static void checkUniqueRuntimeBeansGeneratedClasses(
439 Map<String, QName> uniqueGeneratedClassesNames,
440 DataSchemaNode when, Collection<RuntimeBeanEntry> runtimeBeans) {
441 for (RuntimeBeanEntry runtimeBean : runtimeBeans) {
442 final String javaNameOfRuntimeMXBean = runtimeBean
443 .getJavaNameOfRuntimeMXBean();
444 if (uniqueGeneratedClassesNames
445 .containsKey(javaNameOfRuntimeMXBean)) {
446 QName firstDefinedQName = uniqueGeneratedClassesNames
447 .get(javaNameOfRuntimeMXBean);
448 throw new NameConflictException(javaNameOfRuntimeMXBean,
449 firstDefinedQName, when.getQName());
451 uniqueGeneratedClassesNames.put(javaNameOfRuntimeMXBean,
456 private static void checkUniqueRuntimeBeanAttributesName(
457 ModuleMXBeanEntry mxBeanEntry,
458 Map<String, QName> uniqueGeneratedClassesNames) {
459 for (RuntimeBeanEntry runtimeBeanEntry : mxBeanEntry.getRuntimeBeans()) {
460 for (String runtimeAttName : runtimeBeanEntry
461 .getYangPropertiesToTypesMap().keySet()) {
462 if (mxBeanEntry.getAttributes().keySet()
463 .contains(runtimeAttName)) {
464 QName qName1 = uniqueGeneratedClassesNames
465 .get(runtimeBeanEntry.getJavaNameOfRuntimeMXBean());
466 QName qName2 = uniqueGeneratedClassesNames.get(mxBeanEntry
467 .getGloballyUniqueName());
468 throw new NameConflictException(runtimeAttName, qName1,
475 private static void checkUniqueAttributesWithGeneratedClass(
476 Map<String, QName> uniqueGeneratedClassNames, QName parentQName,
477 Map<String, AttributeIfc> yangToAttributes) {
478 for (Entry<String, AttributeIfc> attr : yangToAttributes.entrySet()) {
479 if (attr.getValue() instanceof TOAttribute) {
480 checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName,
481 (TOAttribute) attr.getValue());
482 } else if (attr.getValue() instanceof ListAttribute
483 && ((ListAttribute) attr.getValue()).getInnerAttribute() instanceof TOAttribute) {
484 checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName,
485 (TOAttribute) ((ListAttribute) attr.getValue())
486 .getInnerAttribute());
491 private static void checkUniqueTOAttr(
492 Map<String, QName> uniqueGeneratedClassNames, QName parentQName,
494 final String upperCaseCammelCase = attr.getUpperCaseCammelCase();
495 if (uniqueGeneratedClassNames.containsKey(upperCaseCammelCase)) {
496 QName firstDefinedQName = uniqueGeneratedClassNames
497 .get(upperCaseCammelCase);
498 throw new NameConflictException(upperCaseCammelCase,
499 firstDefinedQName, parentQName);
501 uniqueGeneratedClassNames.put(upperCaseCammelCase, parentQName);
505 private static Collection<RuntimeBeanEntry> fillRuntimeBeans(
506 ChoiceCaseNode choiceCaseNode, Module currentModule,
507 TypeProviderWrapper typeProviderWrapper, String packageName,
508 String moduleLocalNameFromXPath, String javaNamePrefix) {
510 return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName,
511 choiceCaseNode, moduleLocalNameFromXPath, typeProviderWrapper,
512 javaNamePrefix, currentModule).values();
516 private static Map<String, AttributeIfc> fillConfiguration(
517 ChoiceCaseNode choiceCaseNode, Module currentModule,
518 TypeProviderWrapper typeProviderWrapper,
519 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
520 SchemaContext schemaContext, String packageName) {
521 Map<String, AttributeIfc> yangToAttributes = new HashMap<>();
522 for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) {
523 AttributeIfc attributeValue = getAttributeValue(attrNode,
524 currentModule, qNamesToSIEs, typeProviderWrapper,
525 schemaContext, packageName);
526 yangToAttributes.put(attributeValue.getAttributeYangName(),
529 return yangToAttributes;
532 private static Map<String, QName> findProvidedServices(
533 IdentitySchemaNode moduleIdentity, Module currentModule,
534 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
535 SchemaContext schemaContext) {
536 Map<String, QName> result = new HashMap<>();
537 for (UnknownSchemaNode unknownNode : moduleIdentity
538 .getUnknownSchemaNodes()) {
539 if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME
540 .equals(unknownNode.getNodeType())) {
541 String prefixAndIdentityLocalName = unknownNode
543 ServiceInterfaceEntry sie = findSIE(prefixAndIdentityLocalName,
544 currentModule, qNamesToSIEs, schemaContext);
545 result.put(sie.getFullyQualifiedName(), sie.getQName());
552 * For input node, find if it contains config:java-name-prefix extension. If
553 * not found, convert local name of node converted to cammel case.
555 public static String findJavaNamePrefix(SchemaNode schemaNode) {
556 return convertToJavaName(schemaNode, true);
559 public static String findJavaParameter(SchemaNode schemaNode) {
560 return convertToJavaName(schemaNode, false);
563 public static String convertToJavaName(SchemaNode schemaNode,
564 boolean capitalizeFirstLetter) {
565 for (UnknownSchemaNode unknownNode : schemaNode.getUnknownSchemaNodes()) {
566 if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME
567 .equals(unknownNode.getNodeType())) {
568 String value = unknownNode.getNodeParameter();
569 return convertToJavaName(value, capitalizeFirstLetter);
572 return convertToJavaName(schemaNode.getQName().getLocalName(),
573 capitalizeFirstLetter);
576 public static String convertToJavaName(String localName,
577 boolean capitalizeFirstLetter) {
578 if (capitalizeFirstLetter) {
579 return BindingGeneratorUtil.parseToClassName(localName);
581 return BindingGeneratorUtil.parseToValidParamName(localName);
585 private static int getChildNodeSizeWithoutUses(DataNodeContainer csn) {
587 for (DataSchemaNode dsn : csn.getChildNodes()) {
588 if (dsn.isAddedByUses() == false) {
595 private static AttributeIfc getAttributeValue(DataSchemaNode attrNode,
596 Module currentModule,
597 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
598 TypeProviderWrapper typeProviderWrapper,
599 SchemaContext schemaContext, String packageName) {
601 if (attrNode instanceof LeafSchemaNode) {
603 LeafSchemaNode leaf = (LeafSchemaNode) attrNode;
604 return new JavaAttribute(leaf, typeProviderWrapper);
605 } else if (attrNode instanceof ContainerSchemaNode) {
607 ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) attrNode;
608 Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
609 containerSchemaNode, attrNode, currentModule, qNamesToSIEs,
611 if (dependencyAttributeOptional.isPresent()) {
612 return dependencyAttributeOptional.get();
614 return TOAttribute.create(containerSchemaNode,
615 typeProviderWrapper, packageName);
618 } else if (attrNode instanceof LeafListSchemaNode) {
619 return ListAttribute.create((LeafListSchemaNode) attrNode,
620 typeProviderWrapper);
621 } else if (attrNode instanceof ListSchemaNode) {
622 ListSchemaNode listSchemaNode = (ListSchemaNode) attrNode;
623 Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(
624 listSchemaNode, attrNode, currentModule, qNamesToSIEs,
626 if (dependencyAttributeOptional.isPresent()) {
627 return dependencyAttributeOptional.get();
629 return ListAttribute.create(listSchemaNode,
630 typeProviderWrapper, packageName);
633 throw new UnsupportedOperationException(
634 "Unknown configuration node " + attrNode.toString());
638 private static Optional<? extends AbstractDependencyAttribute> extractDependency(
639 DataNodeContainer dataNodeContainer, DataSchemaNode attrNode,
640 Module currentModule,
641 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
642 SchemaContext schemaContext) {
643 if (dataNodeContainer.getUses().size() == 1
644 && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) {
646 UsesNode usesNode = dataNodeContainer.getUses().iterator().next();
647 checkState(usesNode.getRefines().size() == 1,
648 "Unexpected 'refine' child node size of "
649 + dataNodeContainer);
650 LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines()
651 .values().iterator().next();
652 checkState(refine.getUnknownSchemaNodes().size() == 1,
653 "Unexpected unknown schema node size of " + refine);
654 UnknownSchemaNode requiredIdentity = refine.getUnknownSchemaNodes()
657 ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity
658 .getNodeType()), "Unexpected language extension "
660 String prefixAndIdentityLocalName = requiredIdentity
662 // import should point to a module
663 ServiceInterfaceEntry serviceInterfaceEntry = findSIE(
664 prefixAndIdentityLocalName, currentModule, qNamesToSIEs,
666 boolean mandatory = refine.getConstraints().isMandatory();
667 AbstractDependencyAttribute reference;
668 if (dataNodeContainer instanceof ContainerSchemaNode) {
669 reference = new DependencyAttribute(attrNode,
670 serviceInterfaceEntry, mandatory,
671 attrNode.getDescription());
673 reference = new ListDependenciesAttribute(attrNode,
674 serviceInterfaceEntry, mandatory,
675 attrNode.getDescription());
677 return Optional.of(reference);
679 return Optional.absent();
682 private static ServiceInterfaceEntry findSIE(
683 String prefixAndIdentityLocalName, Module currentModule,
684 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
685 SchemaContext schemaContext) {
687 Matcher m = PREFIX_COLON_LOCAL_NAME.matcher(prefixAndIdentityLocalName);
691 // if there is a prefix, look for ModuleImport with this prefix. Get
692 // Module from SchemaContext
693 String prefix = m.group(1);
694 ModuleImport moduleImport = findModuleImport(currentModule, prefix);
695 foundModule = schemaContext.findModuleByName(
696 moduleImport.getModuleName(), moduleImport.getRevision());
699 format("Module not found in SchemaContext by %s",
701 localSIName = m.group(2);
703 foundModule = currentModule; // no prefix => SIE is in currentModule
704 localSIName = prefixAndIdentityLocalName;
706 QName siQName = new QName(foundModule.getNamespace(),
707 foundModule.getRevision(), localSIName);
708 ServiceInterfaceEntry sie = qNamesToSIEs.get(siQName);
709 checkState(sie != null, "Cannot find referenced Service Interface by "
710 + prefixAndIdentityLocalName);
714 private static ModuleImport findModuleImport(Module module, String prefix) {
715 for (ModuleImport moduleImport : module.getImports()) {
716 if (moduleImport.getPrefix().equals(prefix)) {
720 throw new IllegalStateException(format(
721 "Import not found with prefix %s in %s", prefix, module));
724 public Map<String, AttributeIfc> getAttributes() {
725 return yangToAttributes;
728 private void setYangToAttributes(Map<String, AttributeIfc> newAttributes) {
729 this.yangToAttributes = newAttributes;
733 public String getNullableDescription() {
734 return nullableDescription;
737 public QName getYangModuleQName() {
738 return yangModuleQName;
742 public String toString() {
743 return "ModuleMXBeanEntry{" + "globallyUniqueName='"
744 + globallyUniqueName + '\'' + ", packageName='" + packageName