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 com.google.common.annotations.VisibleForTesting;
11 import com.google.common.base.Optional;
12 import com.google.common.collect.Sets;
13 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
14 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
15 import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
16 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
17 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
18 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
19 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
20 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
21 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
22 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
25 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
26 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
28 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.Module;
34 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
35 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
36 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
37 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
39 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.UsesNode;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
44 import java.util.Arrays;
45 import java.util.Collection;
46 import java.util.Collections;
47 import java.util.HashMap;
49 import java.util.Map.Entry;
51 import java.util.regex.Matcher;
52 import java.util.regex.Pattern;
54 import static com.google.common.base.Preconditions.checkNotNull;
55 import static com.google.common.base.Preconditions.checkState;
56 import static java.lang.String.format;
57 import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants.createConfigQName;
60 * Represents part of yang model that describes a module.
67 * identity threadpool-dynamic {
68 * base config:module-type;
69 * description "threadpool-dynamic description";
70 * config:provided-service "th2:threadpool";
71 * config:provided-service "th2:scheduled-threadpool";
72 * config:java-name-prefix DynamicThreadPool
74 * augment "/config:modules/config:module/config:module-type" {
75 * case threadpool-dynamic {
76 * when "/config:modules/config:module/config:module-type = 'threadpool-dynamic'";
78 * container "configuration" {
79 * // regular java attribute
86 * container threadfactory {
87 * uses config:service-ref {
89 * config:required-identity th:threadfactory;
100 public class ModuleMXBeanEntry extends AbstractEntry {
101 private static final Logger logger = LoggerFactory
102 .getLogger(ModuleMXBeanEntry.class);
104 // TODO: the XPath should be parsed by code generator IMO
105 private static final String MAGIC_STRING = "MAGIC_STRING";
106 private static final String MODULE_CONDITION_XPATH_TEMPLATE = "^/MAGIC_STRING:modules/MAGIC_STRING:module/MAGIC_STRING:type\\s*=\\s*['\"](.+)['\"]$";
107 private static final SchemaPath expectedConfigurationAugmentationSchemaPath = new SchemaPath(
108 Arrays.asList(createConfigQName("modules"),
109 createConfigQName("module"),
110 createConfigQName("configuration")), true);
111 private static final SchemaPath expectedStateAugmentationSchemaPath = new SchemaPath(
112 Arrays.asList(createConfigQName("modules"),
113 createConfigQName("module"), createConfigQName("state")),
116 private static final Pattern PREFIX_COLON_LOCAL_NAME = Pattern
117 .compile("^(.+):(.+)$");
119 private static final String MODULE_SUFFIX = "Module";
120 private static final String FACTORY_SUFFIX = MODULE_SUFFIX + "Factory";
121 private static final String CLASS_NAME_SUFFIX = MODULE_SUFFIX + "MXBean";
122 private static final String ABSTRACT_PREFIX = "Abstract";
125 * threadpool-dynamic from the example above, taken from when condition, not
128 private final String globallyUniqueName;
130 private Map<String, AttributeIfc> yangToAttributes;
132 private final String nullableDescription, packageName, javaNamePrefix,
135 private final Map<String, QName> providedServices;
137 private Collection<RuntimeBeanEntry> runtimeBeans;
139 public ModuleMXBeanEntry(IdentitySchemaNode id,
140 Map<String, AttributeIfc> yangToAttributes, String packageName,
141 Map<String, QName> providedServices2, String javaNamePrefix,
142 String namespace, Collection<RuntimeBeanEntry> runtimeBeans) {
143 this.globallyUniqueName = id.getQName().getLocalName();
144 this.yangToAttributes = yangToAttributes;
145 this.nullableDescription = id.getDescription();
146 this.packageName = packageName;
147 this.javaNamePrefix = checkNotNull(javaNamePrefix);
148 this.namespace = checkNotNull(namespace);
149 this.providedServices = Collections.unmodifiableMap(providedServices2);
150 this.runtimeBeans = runtimeBeans;
153 public String getMXBeanInterfaceName() {
154 return javaNamePrefix + CLASS_NAME_SUFFIX;
157 public String getStubFactoryName() {
158 return javaNamePrefix + FACTORY_SUFFIX;
161 public String getAbstractFactoryName() {
162 return ABSTRACT_PREFIX + getStubFactoryName();
165 public String getStubModuleName() {
166 return javaNamePrefix + MODULE_SUFFIX;
169 public String getAbstractModuleName() {
170 return ABSTRACT_PREFIX + getStubModuleName();
173 public String getFullyQualifiedName(String typeName) {
174 return FullyQualifiedNameHelper.getFullyQualifiedName(packageName,
178 public String getGloballyUniqueName() {
179 return globallyUniqueName;
182 public String getPackageName() {
187 * @return services implemented by this module. Keys are fully qualified java names of generated
188 * ServiceInterface classes, values are identity local names.
190 public Map<String, QName> getProvidedServices() {
191 return providedServices;
194 public void setRuntimeBeans(Collection<RuntimeBeanEntry> newRuntimeBeans) {
195 runtimeBeans = newRuntimeBeans;
198 public Collection<RuntimeBeanEntry> getRuntimeBeans() {
202 public String getJavaNamePrefix() {
203 return javaNamePrefix;
206 public String getNamespace() {
211 static Matcher getWhenConditionMatcher(String prefix,
212 RevisionAwareXPath whenConstraint) {
213 String xpathRegex = MODULE_CONDITION_XPATH_TEMPLATE.replace(
214 MAGIC_STRING, prefix);
215 Pattern pattern = Pattern.compile(xpathRegex);
216 return pattern.matcher(whenConstraint.toString());
219 static String getConfigModulePrefixFromImport(Module currentModule) {
220 for (ModuleImport currentImport : currentModule.getImports()) {
221 if (currentImport.getModuleName().equals(
222 ConfigConstants.CONFIG_MODULE)) {
223 return currentImport.getPrefix();
226 throw new IllegalArgumentException("Cannot find import "
227 + ConfigConstants.CONFIG_MODULE + " in " + currentModule);
231 * Transform module to zero or more ModuleMXBeanEntry instances. Each
232 * instance must have a globally unique local name.
234 * @return Map of identity local names as keys, and ModuleMXBeanEntry
235 * instances as values
237 public static Map<String/* identity local name */, ModuleMXBeanEntry> create(
238 Module currentModule,
239 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
240 SchemaContext schemaContext,
241 TypeProviderWrapper typeProviderWrapper, String packageName) {
242 Map<String, QName> uniqueGeneratedClassesNames = new HashMap<>();
243 logger.debug("Generating ModuleMXBeans of {} to package {}",
244 currentModule.getNamespace(), packageName);
245 String configModulePrefix;
247 configModulePrefix = getConfigModulePrefixFromImport(currentModule);
248 } catch (IllegalArgumentException e) {
249 // this module does not import config module
250 return Collections.emptyMap();
253 // get identities of base config:module-type
254 Map<String, IdentitySchemaNode> moduleIdentities = new HashMap<>();
256 for (IdentitySchemaNode id : currentModule.getIdentities()) {
257 if (id.getBaseIdentity() != null
258 && ConfigConstants.MODULE_TYPE_Q_NAME.equals(id
259 .getBaseIdentity().getQName())) {
260 String identityLocalName = id.getQName().getLocalName();
261 if (moduleIdentities.containsKey(identityLocalName)) {
262 throw new IllegalStateException(
263 "Module name already defined in this module: "
264 + identityLocalName);
266 moduleIdentities.put(identityLocalName, id);
267 logger.debug("Found identity {}", identityLocalName);
269 // validation check on unknown schema nodes
270 boolean providedServiceWasSet = false;
271 for (UnknownSchemaNode unknownNode : id.getUnknownSchemaNodes()) {
273 if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME
274 .equals(unknownNode.getNodeType())) {
275 // no op: 0 or more provided identities are allowed
276 } else if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME
277 .equals(unknownNode.getNodeType())) {
280 providedServiceWasSet == false,
281 format("More than one language extension %s is not allowed here: %s",
282 ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME,
284 providedServiceWasSet = true;
286 throw new IllegalStateException(
287 "Unexpected language extension "
288 + unknownNode.getNodeType());
293 Map<String, ModuleMXBeanEntry> result = new HashMap<>();
294 // each module name should have an augmentation defined
295 Map<String, IdentitySchemaNode> unaugmentedModuleIdentities = new HashMap<>(
297 for (AugmentationSchema augmentation : currentModule.getAugmentations()) {
298 Set<DataSchemaNode> childNodes = augmentation.getChildNodes();
299 if (childNodes.size() == 1) {
300 DataSchemaNode when = childNodes.iterator().next();
301 if (when instanceof ChoiceCaseNode) {
302 ChoiceCaseNode choiceCaseNode = (ChoiceCaseNode) when;
303 if (choiceCaseNode.getConstraints() == null
304 || choiceCaseNode.getConstraints()
305 .getWhenCondition() == null) {
308 RevisionAwareXPath xPath = choiceCaseNode.getConstraints()
310 Matcher matcher = getWhenConditionMatcher(
311 configModulePrefix, xPath);
312 if (matcher.matches() == false) {
315 String moduleLocalNameFromXPath = matcher.group(1);
316 IdentitySchemaNode moduleIdentity = moduleIdentities
317 .get(moduleLocalNameFromXPath);
318 unaugmentedModuleIdentities
319 .remove(moduleLocalNameFromXPath);
320 checkState(moduleIdentity != null, "Cannot find identity "
321 + moduleLocalNameFromXPath
322 + " matching augmentation " + augmentation);
323 Map<String, QName> providedServices = findProvidedServices(
324 moduleIdentity, currentModule, qNamesToSIEs,
327 if (moduleIdentity == null) {
328 throw new IllegalStateException(
329 "Cannot find identity specified by augmentation xpath constraint: "
330 + moduleLocalNameFromXPath + " of "
333 String javaNamePrefix = findJavaNamePrefix(moduleIdentity);
335 Map<String, AttributeIfc> yangToAttributes = null;
337 Collection<RuntimeBeanEntry> runtimeBeans = null;
339 if (expectedConfigurationAugmentationSchemaPath
340 .equals(augmentation.getTargetPath())) {
341 logger.debug("Parsing configuration of {}",
342 moduleLocalNameFromXPath);
343 yangToAttributes = fillConfiguration(choiceCaseNode,
344 currentModule, typeProviderWrapper,
345 qNamesToSIEs, schemaContext, packageName);
346 checkUniqueAttributesWithGeneratedClass(
347 uniqueGeneratedClassesNames, when.getQName(),
349 } else if (expectedStateAugmentationSchemaPath
350 .equals(augmentation.getTargetPath())) {
351 logger.debug("Parsing state of {}",
352 moduleLocalNameFromXPath);
354 runtimeBeans = fillRuntimeBeans(choiceCaseNode,
355 currentModule, typeProviderWrapper,
356 packageName, moduleLocalNameFromXPath,
358 } catch (NameConflictException e) {
359 throw new NameConflictException(
360 e.getConflictingName(), when.getQName(),
364 checkUniqueRuntimeBeansGeneratedClasses(
365 uniqueGeneratedClassesNames, when, runtimeBeans);
366 Set<RuntimeBeanEntry> runtimeBeanEntryValues = Sets
367 .newHashSet(runtimeBeans);
368 for (RuntimeBeanEntry entry : runtimeBeanEntryValues) {
369 checkUniqueAttributesWithGeneratedClass(
370 uniqueGeneratedClassesNames,
372 entry.getYangPropertiesToTypesMap());
376 throw new IllegalArgumentException(
377 "Cannot parse augmentation " + augmentation);
379 if (result.containsKey(moduleLocalNameFromXPath)) {
380 // either fill runtimeBeans or yangToAttributes
381 ModuleMXBeanEntry moduleMXBeanEntry = result
382 .get(moduleLocalNameFromXPath);
383 if (yangToAttributes != null
384 && moduleMXBeanEntry.getAttributes() == null) {
386 .setYangToAttributes(yangToAttributes);
387 } else if (runtimeBeans != null
388 && moduleMXBeanEntry.getRuntimeBeans() == null) {
389 moduleMXBeanEntry.setRuntimeBeans(runtimeBeans);
392 // construct ModuleMXBeanEntry
393 ModuleMXBeanEntry moduleMXBeanEntry = new ModuleMXBeanEntry(
394 moduleIdentity, yangToAttributes, packageName,
395 providedServices, javaNamePrefix, currentModule
396 .getNamespace().toString(),
398 moduleMXBeanEntry.setYangModuleName(currentModule
401 .setYangModuleLocalname(moduleLocalNameFromXPath);
402 result.put(moduleLocalNameFromXPath, moduleMXBeanEntry);
404 } // skip if child node is not ChoiceCaseNode
405 } // skip if childNodes != 1
408 for (Entry<String, ModuleMXBeanEntry> entry : result.entrySet()) {
409 ModuleMXBeanEntry module = entry.getValue();
410 if (module.getAttributes() == null) {
411 module.setYangToAttributes(Collections
412 .<String, AttributeIfc> emptyMap());
413 } else if (module.getRuntimeBeans() == null) {
414 module.setRuntimeBeans(Collections
415 .<RuntimeBeanEntry> emptyList());
418 if (unaugmentedModuleIdentities.size() > 0) {
419 logger.warn("Augmentation not found for all module identities: {}",
420 unaugmentedModuleIdentities.keySet());
423 logger.debug("Number of ModuleMXBeans to be generated: {}",
428 private static void checkUniqueRuntimeBeansGeneratedClasses(
429 Map<String, QName> uniqueGeneratedClassesNames,
430 DataSchemaNode when, Collection<RuntimeBeanEntry> runtimeBeans) {
431 for (RuntimeBeanEntry runtimeBean : runtimeBeans) {
432 final String javaNameOfRuntimeMXBean = runtimeBean
433 .getJavaNameOfRuntimeMXBean();
434 if (uniqueGeneratedClassesNames
435 .containsKey(javaNameOfRuntimeMXBean)) {
436 QName firstDefinedQName = uniqueGeneratedClassesNames
437 .get(javaNameOfRuntimeMXBean);
438 throw new NameConflictException(javaNameOfRuntimeMXBean,
439 firstDefinedQName, when.getQName());
441 uniqueGeneratedClassesNames.put(javaNameOfRuntimeMXBean,
446 private static void checkUniqueAttributesWithGeneratedClass(
447 Map<String, QName> uniqueGeneratedClassNames, QName parentQName,
448 Map<String, AttributeIfc> yangToAttributes) {
449 for (Entry<String, AttributeIfc> attr : yangToAttributes.entrySet()) {
450 if (attr.getValue() instanceof TOAttribute) {
451 checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName,
452 (TOAttribute) attr.getValue());
453 } else if (attr.getValue() instanceof ListAttribute
454 && ((ListAttribute) attr.getValue()).getInnerAttribute() instanceof TOAttribute) {
455 checkUniqueTOAttr(uniqueGeneratedClassNames, parentQName,
456 (TOAttribute) ((ListAttribute) attr.getValue())
457 .getInnerAttribute());
462 private static void checkUniqueTOAttr(
463 Map<String, QName> uniqueGeneratedClassNames, QName parentQName,
465 final String upperCaseCammelCase = attr.getUpperCaseCammelCase();
466 if (uniqueGeneratedClassNames.containsKey(upperCaseCammelCase)) {
467 QName firstDefinedQName = uniqueGeneratedClassNames
468 .get(upperCaseCammelCase);
469 throw new NameConflictException(upperCaseCammelCase,
470 firstDefinedQName, parentQName);
472 uniqueGeneratedClassNames.put(upperCaseCammelCase, parentQName);
476 private static Collection<RuntimeBeanEntry> fillRuntimeBeans(
477 ChoiceCaseNode choiceCaseNode, Module currentModule,
478 TypeProviderWrapper typeProviderWrapper, String packageName,
479 String moduleLocalNameFromXPath, String javaNamePrefix) {
481 return RuntimeBeanEntry.extractClassNameToRuntimeBeanMap(packageName,
482 choiceCaseNode, moduleLocalNameFromXPath, typeProviderWrapper,
483 javaNamePrefix, currentModule).values();
487 private static Map<String, AttributeIfc> fillConfiguration(
488 ChoiceCaseNode choiceCaseNode, Module currentModule,
489 TypeProviderWrapper typeProviderWrapper,
490 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
491 SchemaContext schemaContext, String packageName) {
492 Map<String, AttributeIfc> yangToAttributes = new HashMap<>();
493 for (DataSchemaNode attrNode : choiceCaseNode.getChildNodes()) {
494 AttributeIfc attributeValue = getAttributeValue(attrNode,
495 currentModule, qNamesToSIEs, typeProviderWrapper,
496 schemaContext, packageName);
497 yangToAttributes.put(attributeValue.getAttributeYangName(),
500 return yangToAttributes;
503 private static Map<String, QName> findProvidedServices(
504 IdentitySchemaNode moduleIdentity, Module currentModule,
505 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
506 SchemaContext schemaContext) {
507 Map<String, QName> result = new HashMap<>();
508 for (UnknownSchemaNode unknownNode : moduleIdentity
509 .getUnknownSchemaNodes()) {
510 if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME
511 .equals(unknownNode.getNodeType())) {
512 String prefixAndIdentityLocalName = unknownNode
514 ServiceInterfaceEntry sie = findSIE(prefixAndIdentityLocalName,
515 currentModule, qNamesToSIEs, schemaContext);
516 result.put(sie.getFullyQualifiedName(), sie.getQName());
523 * For input node, find if it contains config:java-name-prefix extension. If
524 * not found, convert local name of node converted to cammel case.
526 public static String findJavaNamePrefix(SchemaNode schemaNode) {
527 return convertToJavaName(schemaNode, true);
530 public static String findJavaParameter(SchemaNode schemaNode) {
531 return convertToJavaName(schemaNode, false);
534 public static String convertToJavaName(SchemaNode schemaNode,
535 boolean capitalizeFirstLetter) {
536 for (UnknownSchemaNode unknownNode : schemaNode.getUnknownSchemaNodes()) {
537 if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME
538 .equals(unknownNode.getNodeType())) {
539 String value = unknownNode.getNodeParameter();
540 return convertToJavaName(value, capitalizeFirstLetter);
543 return convertToJavaName(schemaNode.getQName().getLocalName(),
544 capitalizeFirstLetter);
547 public static String convertToJavaName(String localName,
548 boolean capitalizeFirstLetter) {
549 if (capitalizeFirstLetter) {
550 return BindingGeneratorUtil.parseToClassName(localName);
552 return BindingGeneratorUtil.parseToValidParamName(localName);
556 private static int getChildNodeSizeWithoutUses(DataNodeContainer csn) {
558 for (DataSchemaNode dsn : csn.getChildNodes()) {
559 if (dsn.isAddedByUses() == false) {
566 private static AttributeIfc getAttributeValue(DataSchemaNode attrNode,
567 Module currentModule,
568 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
569 TypeProviderWrapper typeProviderWrapper, SchemaContext schemaContext, String packageName) {
571 if (attrNode instanceof LeafSchemaNode) {
573 LeafSchemaNode leaf = (LeafSchemaNode) attrNode;
574 return new JavaAttribute(leaf, typeProviderWrapper);
575 } else if (attrNode instanceof ContainerSchemaNode) {
577 ContainerSchemaNode containerSchemaNode = (ContainerSchemaNode) attrNode;
578 Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(containerSchemaNode,
579 attrNode, currentModule, qNamesToSIEs, schemaContext);
580 if (dependencyAttributeOptional.isPresent()) {
581 return dependencyAttributeOptional.get();
583 return TOAttribute.create(containerSchemaNode, typeProviderWrapper, packageName);
586 } else if (attrNode instanceof LeafListSchemaNode) {
587 return ListAttribute.create((LeafListSchemaNode) attrNode,
588 typeProviderWrapper);
589 } else if (attrNode instanceof ListSchemaNode) {
590 ListSchemaNode listSchemaNode = (ListSchemaNode) attrNode;
591 Optional<? extends AbstractDependencyAttribute> dependencyAttributeOptional = extractDependency(listSchemaNode,
592 attrNode, currentModule, qNamesToSIEs, schemaContext);
593 if (dependencyAttributeOptional.isPresent()) {
594 return dependencyAttributeOptional.get();
596 return ListAttribute.create(listSchemaNode, typeProviderWrapper, packageName);
599 throw new UnsupportedOperationException(
600 "Unknown configuration node " + attrNode.toString());
604 private static Optional<? extends AbstractDependencyAttribute> extractDependency(DataNodeContainer dataNodeContainer,
605 DataSchemaNode attrNode,
606 Module currentModule,
607 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
608 SchemaContext schemaContext) {
609 if (dataNodeContainer.getUses().size() == 1
610 && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) {
612 UsesNode usesNode = dataNodeContainer.getUses().iterator()
614 checkState(usesNode.getRefines().size() == 1,
615 "Unexpected 'refine' child node size of "
616 + dataNodeContainer);
617 LeafSchemaNode refine = (LeafSchemaNode) usesNode.getRefines()
618 .values().iterator().next();
619 checkState(refine.getUnknownSchemaNodes().size() == 1,
620 "Unexpected unknown schema node size of " + refine);
621 UnknownSchemaNode requiredIdentity = refine
622 .getUnknownSchemaNodes().iterator().next();
624 ConfigConstants.REQUIRED_IDENTITY_EXTENSION_QNAME.equals(requiredIdentity
626 "Unexpected language extension " + requiredIdentity);
627 String prefixAndIdentityLocalName = requiredIdentity
629 // import should point to a module
630 ServiceInterfaceEntry serviceInterfaceEntry = findSIE(
631 prefixAndIdentityLocalName, currentModule,
632 qNamesToSIEs, schemaContext);
633 boolean mandatory = refine.getConstraints().isMandatory();
634 AbstractDependencyAttribute reference;
635 if (dataNodeContainer instanceof ContainerSchemaNode ){
636 reference = new DependencyAttribute(attrNode, serviceInterfaceEntry,
637 mandatory, attrNode.getDescription());
639 reference = new ListDependenciesAttribute(attrNode, serviceInterfaceEntry,
640 mandatory, attrNode.getDescription());
642 return Optional.of(reference);
644 return Optional.absent();
647 private static ServiceInterfaceEntry findSIE(
648 String prefixAndIdentityLocalName, Module currentModule,
649 Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
650 SchemaContext schemaContext) {
652 Matcher m = PREFIX_COLON_LOCAL_NAME.matcher(prefixAndIdentityLocalName);
656 // if there is a prefix, look for ModuleImport with this prefix. Get
657 // Module from SchemaContext
658 String prefix = m.group(1);
659 ModuleImport moduleImport = findModuleImport(currentModule, prefix);
660 foundModule = schemaContext.findModuleByName(
661 moduleImport.getModuleName(), moduleImport.getRevision());
664 format("Module not found in SchemaContext by %s",
666 localSIName = m.group(2);
668 foundModule = currentModule; // no prefix => SIE is in currentModule
669 localSIName = prefixAndIdentityLocalName;
671 QName siQName = new QName(foundModule.getNamespace(),
672 foundModule.getRevision(), localSIName);
673 ServiceInterfaceEntry sie = qNamesToSIEs.get(siQName);
674 checkState(sie != null, "Cannot find referenced Service Interface by "
675 + prefixAndIdentityLocalName);
679 private static ModuleImport findModuleImport(Module module, String prefix) {
680 for (ModuleImport moduleImport : module.getImports()) {
681 if (moduleImport.getPrefix().equals(prefix)) {
685 throw new IllegalStateException(format(
686 "Import not found with prefix %s in %s", prefix, module));
689 public Map<String, AttributeIfc> getAttributes() {
690 return yangToAttributes;
693 private void setYangToAttributes(Map<String, AttributeIfc> newAttributes) {
694 this.yangToAttributes = newAttributes;
698 public String getNullableDescription() {
699 return nullableDescription;
703 public String toString() {
704 return "ModuleMXBeanEntry{" + "globallyUniqueName='"
705 + globallyUniqueName + '\'' + ", packageName='" + packageName