-/*
- * 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.yang.model.parser.impl;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-import org.antlr.v4.runtime.ANTLRInputStream;
-import org.antlr.v4.runtime.CommonTokenStream;
-import org.antlr.v4.runtime.tree.ParseTree;
-import org.antlr.v4.runtime.tree.ParseTreeWalker;
-import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
-import org.opendaylight.controller.antlrv4.code.gen.YangParser;
-import org.opendaylight.controller.yang.common.QName;
-import org.opendaylight.controller.yang.model.api.AugmentationSchema;
-import org.opendaylight.controller.yang.model.api.DataSchemaNode;
-import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
-import org.opendaylight.controller.yang.model.api.Module;
-import org.opendaylight.controller.yang.model.api.ModuleImport;
-import org.opendaylight.controller.yang.model.api.NotificationDefinition;
-import org.opendaylight.controller.yang.model.api.RpcDefinition;
-import org.opendaylight.controller.yang.model.api.SchemaContext;
-import org.opendaylight.controller.yang.model.api.SchemaPath;
-import org.opendaylight.controller.yang.model.api.TypeDefinition;
-import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
-import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;
-import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
-import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
-import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
-import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
-import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
-import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
-import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
-import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
-import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;
-import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder;
-import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder;
-import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;
-import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;
-import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;
-import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;
-import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
-import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder;
-import org.opendaylight.controller.yang.model.parser.util.TypeConstraints;
-import org.opendaylight.controller.yang.model.parser.util.YangParseException;
-import org.opendaylight.controller.yang.model.util.BinaryType;
-import org.opendaylight.controller.yang.model.util.BitsType;
-import org.opendaylight.controller.yang.model.util.StringType;
-import org.opendaylight.controller.yang.model.util.UnknownType;
-import org.opendaylight.controller.yang.model.util.YangTypesConverter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class YangModelParserImpl implements YangModelParser {
-
- private static final Logger logger = LoggerFactory
- .getLogger(YangModelParserImpl.class);
-
- @Override
- public Module parseYangModel(String yangFile) {
- final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFile);
- Set<Module> result = build(modules);
- return result.iterator().next();
- }
-
- @Override
- public Set<Module> parseYangModels(String... yangFiles) {
- final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFiles);
- Set<Module> result = build(modules);
- return result;
- }
-
- @Override
- public Set<Module> parseYangModelsFromStreams(
- InputStream... yangModelStreams) {
- final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangModelStreams);
- Set<Module> result = build(modules);
- return result;
- }
-
- @Override
- public SchemaContext resolveSchemaContext(Set<Module> modules) {
- return new SchemaContextImpl(modules);
- }
-
- private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(
- String... yangFiles) {
- InputStream[] streams = new InputStream[yangFiles.length];
- for (int i = 0; i < yangFiles.length; i++) {
- final String yangFileName = yangFiles[i];
- final File yangFile = new File(yangFileName);
- FileInputStream inStream = null;
- try {
- inStream = new FileInputStream(yangFile);
- } catch (FileNotFoundException e) {
- logger.warn("Exception while reading yang stream: " + inStream,
- e);
- }
- streams[i] = inStream;
- }
- return resolveModuleBuildersFromStreams(streams);
- }
-
- private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(
- InputStream... yangFiles) {
- final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
- final ParseTreeWalker walker = new ParseTreeWalker();
- final List<ParseTree> trees = parseStreams(yangFiles);
- final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
-
- for (int i = 0; i < trees.size(); i++) {
- final YangModelParserListenerImpl yangModelParser = new YangModelParserListenerImpl();
- walker.walk(yangModelParser, trees.get(i));
- builders[i] = yangModelParser.getModuleBuilder();
- }
-
- for (ModuleBuilder builder : builders) {
- final String builderName = builder.getName();
- Date builderRevision = builder.getRevision();
- if (builderRevision == null) {
- builderRevision = createEpochTime();
- }
- TreeMap<Date, ModuleBuilder> builderByRevision = modules
- .get(builderName);
- if (builderByRevision == null) {
- builderByRevision = new TreeMap<Date, ModuleBuilder>();
- }
- builderByRevision.put(builderRevision, builder);
- modules.put(builderName, builderByRevision);
- }
- return modules;
- }
-
- private List<ParseTree> parseStreams(InputStream... yangStreams) {
- List<ParseTree> trees = new ArrayList<ParseTree>();
- for (InputStream yangStream : yangStreams) {
- trees.add(parseStream(yangStream));
- }
- return trees;
- }
-
- private ParseTree parseStream(InputStream yangStream) {
- ParseTree result = null;
- try {
- final ANTLRInputStream input = new ANTLRInputStream(yangStream);
- final YangLexer lexer = new YangLexer(input);
- final CommonTokenStream tokens = new CommonTokenStream(lexer);
- final YangParser parser = new YangParser(tokens);
- result = parser.yang();
- } catch (IOException e) {
- logger.warn("Exception while reading yang file: " + yangStream, e);
- }
- return result;
- }
-
- private Set<Module> build(Map<String, TreeMap<Date, ModuleBuilder>> modules) {
- // validate
- for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
- .entrySet()) {
- for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
- .entrySet()) {
- ModuleBuilder moduleBuilder = childEntry.getValue();
- validateBuilder(modules, moduleBuilder);
- }
- }
- // build
- final Set<Module> result = new HashSet<Module>();
- for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
- .entrySet()) {
- final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
- for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
- .entrySet()) {
- ModuleBuilder moduleBuilder = childEntry.getValue();
- modulesByRevision.put(childEntry.getKey(),
- moduleBuilder.build());
- result.add(moduleBuilder.build());
- }
- }
-
- return result;
- }
-
- private void validateBuilder(
- Map<String, TreeMap<Date, ModuleBuilder>> modules,
- ModuleBuilder builder) {
- resolveTypedefs(modules, builder);
- resolveAugments(modules, builder);
- resolveIdentities(modules, builder);
- }
-
- /**
- * Search for dirty nodes (node which contains UnknownType) and resolve
- * unknown types.
- *
- * @param modules
- * all available modules
- * @param module
- * current module
- */
- private void resolveTypedefs(
- Map<String, TreeMap<Date, ModuleBuilder>> modules,
- ModuleBuilder module) {
- Map<List<String>, TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
- if (dirtyNodes.size() == 0) {
- return;
- } else {
- for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
- .entrySet()) {
- TypeAwareBuilder typeToResolve = entry.getValue();
-
- if (typeToResolve instanceof UnionTypeBuilder) {
- resolveUnionTypeBuilder(modules, module,
- (UnionTypeBuilder) typeToResolve);
- } else {
- UnknownType ut = (UnknownType) typeToResolve.getType();
- TypeDefinition<?> resolvedType = findTargetType(ut,
- modules, module);
- typeToResolve.setType(resolvedType);
- }
- }
- }
- }
-
- private UnionTypeBuilder resolveUnionTypeBuilder(
- Map<String, TreeMap<Date, ModuleBuilder>> modules,
- ModuleBuilder builder, UnionTypeBuilder unionTypeBuilderToResolve) {
- List<TypeDefinition<?>> resolvedTypes = new ArrayList<TypeDefinition<?>>();
- List<TypeDefinition<?>> typesToRemove = new ArrayList<TypeDefinition<?>>();
-
- for (TypeDefinition<?> td : unionTypeBuilderToResolve.getTypes()) {
- if (td instanceof UnknownType) {
- TypeDefinition<?> resolvedType = findTargetType(
- (UnknownType) td, modules, builder);
- resolvedTypes.add(resolvedType);
- typesToRemove.add(td);
- }
- }
-
- List<TypeDefinition<?>> unionTypeBuilderTypes = unionTypeBuilderToResolve
- .getTypes();
- unionTypeBuilderTypes.addAll(resolvedTypes);
- unionTypeBuilderTypes.removeAll(typesToRemove);
-
- return unionTypeBuilderToResolve;
- }
-
- private TypeDefinition<?> findTargetType(UnknownType ut,
- Map<String, TreeMap<Date, ModuleBuilder>> modules,
- ModuleBuilder builder) {
-
- TypeConstraints constraints = new TypeConstraints();
- // RANGE
- List<RangeConstraint> ranges = ut.getRangeStatements();
- constraints.addRanges(ranges);
- // LENGTH
- List<LengthConstraint> lengths = ut.getLengthStatements();
- constraints.addLengths(lengths);
- // PATTERN
- List<PatternConstraint> patterns = ut.getPatterns();
- constraints.addPatterns(patterns);
- // Fraction Digits
- Integer fractionDigits = ut.getFractionDigits();
-
- Map<TypeDefinitionBuilder, TypeConstraints> foundedTypeDefinitionBuilder = findTypeDefinitionBuilderWithConstraints(
- constraints, modules, ut, builder);
- TypeDefinitionBuilder targetType = foundedTypeDefinitionBuilder
- .entrySet().iterator().next().getKey();
-
- TypeDefinition<?> targetTypeBaseType = targetType.getBaseType();
- targetTypeBaseType = mergeConstraints(targetTypeBaseType, constraints,
- fractionDigits);
-
- return targetTypeBaseType;
- }
-
- /**
- * Traverse through all referenced types chain until base YANG type is
- * founded.
- *
- * @param constraints
- * current type constraints
- * @param modules
- * all available modules
- * @param unknownType
- * unknown type
- * @param builder
- * current module
- * @return map, where key is type referenced and value is its constraints
- */
- private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(
- TypeConstraints constraints,
- Map<String, TreeMap<Date, ModuleBuilder>> modules,
- UnknownType unknownType, ModuleBuilder builder) {
- Map<TypeDefinitionBuilder, TypeConstraints> result = new HashMap<TypeDefinitionBuilder, TypeConstraints>();
- QName unknownTypeQName = unknownType.getQName();
- String unknownTypeName = unknownTypeQName.getLocalName();
- String unknownTypePrefix = unknownTypeQName.getPrefix();
-
- // search for module which contains referenced typedef
- ModuleBuilder dependentModuleBuilder = findDependentModule(modules,
- builder, unknownTypePrefix);
-
- TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilder(
- dependentModuleBuilder.getModuleTypedefs(), unknownTypeName);
-
- // if referenced type is UnknownType again, search recursively with
- // current constraints
- TypeDefinition<?> referencedType = lookedUpBuilder.getBaseType();
- if (referencedType instanceof UnknownType) {
- UnknownType unknown = (UnknownType) referencedType;
-
- final List<RangeConstraint> ranges = unknown.getRangeStatements();
- constraints.addRanges(ranges);
- final List<LengthConstraint> lengths = unknown
- .getLengthStatements();
- constraints.addLengths(lengths);
- final List<PatternConstraint> patterns = unknown.getPatterns();
- constraints.addPatterns(patterns);
- return findTypeDefinitionBuilderWithConstraints(constraints,
- modules, unknown, dependentModuleBuilder);
- } else {
- mergeConstraints(referencedType, constraints);
- result.put(lookedUpBuilder, constraints);
- return result;
- }
- }
-
- /**
- * Go through all typedef statements from given module and search for one
- * with given name
- *
- * @param typedefs
- * typedef statements to search
- * @param name
- * name of searched typedef
- * @return typedef with name equals to given name
- */
- private TypeDefinitionBuilder findTypedefBuilder(
- Set<TypeDefinitionBuilder> typedefs, String name) {
- TypeDefinitionBuilder result = null;
- for (TypeDefinitionBuilder td : typedefs) {
- if (td.getQName().getLocalName().equals(name)) {
- result = td;
- break;
- }
- }
- if (result == null) {
- throw new YangParseException(
- "Target module does not contain typedef '" + name + "'.");
- }
- return result;
- }
-
- /**
- * Merge curent constraints with founded type constraints
- *
- * @param targetTypeBaseType
- * @param constraints
- * @param fractionDigits
- * @return
- */
- private TypeDefinition<?> mergeConstraints(
- TypeDefinition<?> targetTypeBaseType, TypeConstraints constraints,
- Integer fractionDigits) {
- String targetTypeBaseTypeName = targetTypeBaseType.getQName()
- .getLocalName();
- // enumeration, leafref and identityref omitted because they have no
- // restrictions
- if (targetTypeBaseType instanceof DecimalTypeDefinition) {
- List<RangeConstraint> ranges = constraints.getRange();
- Integer fd = fractionDigits == null ? constraints
- .getFractionDigits() : fractionDigits;
- targetTypeBaseType = YangTypesConverter
- .javaTypeForBaseYangDecimal64Type(ranges, fd);
- } else if (targetTypeBaseType instanceof IntegerTypeDefinition) {
- List<RangeConstraint> ranges = constraints.getRange();
- if (targetTypeBaseTypeName.startsWith("int")) {
- targetTypeBaseType = YangTypesConverter
- .javaTypeForBaseYangSignedIntegerType(
- targetTypeBaseTypeName, ranges);
- } else {
- targetTypeBaseType = YangTypesConverter
- .javaTypeForBaseYangUnsignedIntegerType(
- targetTypeBaseTypeName, ranges);
- }
- } else if (targetTypeBaseType instanceof StringTypeDefinition) {
- List<LengthConstraint> lengths = constraints.getLength();
- List<PatternConstraint> patterns = constraints.getPatterns();
- targetTypeBaseType = new StringType(lengths, patterns);
- } else if (targetTypeBaseType instanceof BitsTypeDefinition) {
- BitsTypeDefinition bitsType = (BitsTypeDefinition) targetTypeBaseType;
- List<Bit> bits = bitsType.getBits();
- targetTypeBaseType = new BitsType(bits);
- } else if (targetTypeBaseType instanceof BinaryTypeDefinition) {
- List<LengthConstraint> lengths = constraints.getLength();
- List<Byte> bytes = Collections.emptyList();
- targetTypeBaseType = new BinaryType(bytes, lengths, null);
- }
- return targetTypeBaseType;
- }
-
- /**
- * Pull restriction from base type and add them to given constraints
- *
- * @param referencedType
- * @param constraints
- */
- private void mergeConstraints(TypeDefinition<?> referencedType,
- TypeConstraints constraints) {
-
- if (referencedType instanceof DecimalTypeDefinition) {
- constraints.addRanges(((DecimalTypeDefinition) referencedType)
- .getRangeStatements());
- constraints
- .setFractionDigits(((DecimalTypeDefinition) referencedType)
- .getFractionDigits());
- } else if (referencedType instanceof IntegerTypeDefinition) {
- constraints.addRanges(((IntegerTypeDefinition) referencedType)
- .getRangeStatements());
- } else if (referencedType instanceof StringTypeDefinition) {
- constraints.addPatterns(((StringTypeDefinition) referencedType)
- .getPatterns());
- constraints.addLengths(((StringTypeDefinition) referencedType)
- .getLengthStatements());
- } else if (referencedType instanceof BinaryTypeDefinition) {
- constraints.addLengths(((BinaryTypeDefinition) referencedType)
- .getLengthConstraints());
- }
- }
-
- /**
- * Go through all augmentation definitions and resolve them. This means find
- * referenced node and add child nodes to it.
- *
- * @param modules
- * all available modules
- * @param module
- * current module
- */
- private void resolveAugments(
- Map<String, TreeMap<Date, ModuleBuilder>> modules,
- ModuleBuilder module) {
- Set<AugmentationSchemaBuilder> augmentBuilders = module
- .getAddedAugments();
-
- Set<AugmentationSchema> augments = new HashSet<AugmentationSchema>();
- for (AugmentationSchemaBuilder augmentBuilder : augmentBuilders) {
- SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
- String prefix = null;
- List<String> augmentTargetPath = new ArrayList<String>();
-
- for (QName pathPart : augmentTargetSchemaPath.getPath()) {
- prefix = pathPart.getPrefix();
- augmentTargetPath.add(pathPart.getLocalName());
- }
- ModuleBuilder dependentModule = findDependentModule(modules,
- module, prefix);
- augmentTargetPath.add(0, dependentModule.getName());
-
- AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule
- .getNode(augmentTargetPath);
- AugmentationSchema result = augmentBuilder.build();
- augmentTarget.addAugmentation(result);
- fillAugmentTarget(augmentBuilder, (ChildNodeBuilder) augmentTarget);
- augments.add(result);
- }
- module.setAugmentations(augments);
- }
-
- /**
- * Add all augment's child nodes to given target.
- *
- * @param augment
- * @param target
- */
- private void fillAugmentTarget(AugmentationSchemaBuilder augment,
- ChildNodeBuilder target) {
- for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
- builder.setAugmenting(true);
- target.addChildNode(builder);
- }
- }
-
- /**
- * Go through identity statements defined in current module and resolve
- * their 'base' statement if present.
- *
- * @param modules
- * all modules
- * @param module
- * module being resolved
- */
- private void resolveIdentities(
- Map<String, TreeMap<Date, ModuleBuilder>> modules,
- ModuleBuilder module) {
- Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();
- for (IdentitySchemaNodeBuilder identity : identities) {
- String baseIdentityName = identity.getBaseIdentityName();
- if (baseIdentityName != null) {
- String baseIdentityPrefix = null;
- String baseIdentityLocalName = null;
- if (baseIdentityName.contains(":")) {
- String[] splitted = baseIdentityName.split(":");
- baseIdentityPrefix = splitted[0];
- baseIdentityLocalName = splitted[1];
- } else {
- baseIdentityPrefix = module.getPrefix();
- baseIdentityLocalName = baseIdentityName;
- }
- ModuleBuilder dependentModule = findDependentModule(modules,
- module, baseIdentityPrefix);
-
- Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
- .getAddedIdentities();
- for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
- if (idBuilder.getQName().getLocalName()
- .equals(baseIdentityLocalName)) {
- identity.setBaseIdentity(idBuilder);
- }
- }
- }
- }
- }
-
- /**
- * Find dependent module based on given prefix
- *
- * @param modules
- * all available modules
- * @param module
- * current module
- * @param prefix
- * target module prefix
- * @return
- */
- private ModuleBuilder findDependentModule(
- Map<String, TreeMap<Date, ModuleBuilder>> modules,
- ModuleBuilder module, String prefix) {
- ModuleBuilder dependentModule = null;
- Date dependentModuleRevision = null;
-
- if (prefix.equals(module.getPrefix())) {
- dependentModule = module;
- } else {
- ModuleImport dependentModuleImport = getModuleImport(module, prefix);
- if (dependentModuleImport == null) {
- throw new YangParseException("No import found with prefix '"
- + prefix + "' in module " + module.getName() + "'.");
- }
- String dependentModuleName = dependentModuleImport.getModuleName();
- dependentModuleRevision = dependentModuleImport.getRevision();
-
- TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
- .get(dependentModuleName);
- if (dependentModuleRevision == null) {
- dependentModule = moduleBuildersByRevision.lastEntry()
- .getValue();
- } else {
- dependentModule = moduleBuildersByRevision
- .get(dependentModuleRevision);
- }
- }
-
- if (dependentModule == null) {
- throw new YangParseException(
- "Failed to find dependent module with prefix '" + prefix
- + "' and revision '" + dependentModuleRevision
- + "'.");
- }
- return dependentModule;
- }
-
- /**
- * Get module import referenced by given prefix.
- *
- * @param builder
- * module to search
- * @param prefix
- * prefix associated with import
- * @return ModuleImport based on given prefix
- */
- private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {
- ModuleImport moduleImport = null;
- for (ModuleImport mi : builder.getModuleImports()) {
- if (mi.getPrefix().equals(prefix)) {
- moduleImport = mi;
- break;
- }
- }
- return moduleImport;
- }
-
- private Date createEpochTime() {
- Calendar c = Calendar.getInstance();
- c.setTimeInMillis(0);
- return c.getTime();
- }
-
- private static class SchemaContextImpl implements SchemaContext {
- private final Set<Module> modules;
-
- private SchemaContextImpl(Set<Module> modules) {
- this.modules = modules;
- }
-
- @Override
- public Set<DataSchemaNode> getDataDefinitions() {
- final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
- for (Module m : modules) {
- dataDefs.addAll(m.getChildNodes());
- }
- return dataDefs;
- }
-
- @Override
- public Set<Module> getModules() {
- return modules;
- }
-
- @Override
- public Set<NotificationDefinition> getNotifications() {
- final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
- for (Module m : modules) {
- notifications.addAll(m.getNotifications());
- }
- return notifications;
- }
-
- @Override
- public Set<RpcDefinition> getOperations() {
- final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
- for (Module m : modules) {
- rpcs.addAll(m.getRpcs());
- }
- return rpcs;
- }
-
- @Override
- public Set<ExtensionDefinition> getExtensions() {
- final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
- for (Module m : modules) {
- extensions.addAll(m.getExtensionSchemaNodes());
- }
- return extensions;
- }
- }
-
-}
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.model.parser.impl;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.util.ArrayList;\r
+import java.util.Calendar;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.TreeMap;\r
+\r
+import org.antlr.v4.runtime.ANTLRInputStream;\r
+import org.antlr.v4.runtime.CommonTokenStream;\r
+import org.antlr.v4.runtime.tree.ParseTree;\r
+import org.antlr.v4.runtime.tree.ParseTreeWalker;\r
+import org.opendaylight.controller.antlrv4.code.gen.YangLexer;\r
+import org.opendaylight.controller.antlrv4.code.gen.YangParser;\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;\r
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;\r
+import org.opendaylight.controller.yang.model.api.ExtensionDefinition;\r
+import org.opendaylight.controller.yang.model.api.Module;\r
+import org.opendaylight.controller.yang.model.api.ModuleImport;\r
+import org.opendaylight.controller.yang.model.api.NotificationDefinition;\r
+import org.opendaylight.controller.yang.model.api.RpcDefinition;\r
+import org.opendaylight.controller.yang.model.api.SchemaContext;\r
+import org.opendaylight.controller.yang.model.api.SchemaPath;\r
+import org.opendaylight.controller.yang.model.api.TypeDefinition;\r
+import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;\r
+import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;\r
+import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;\r
+import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;\r
+import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;\r
+import org.opendaylight.controller.yang.model.api.type.LengthConstraint;\r
+import org.opendaylight.controller.yang.model.api.type.PatternConstraint;\r
+import org.opendaylight.controller.yang.model.api.type.RangeConstraint;\r
+import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;\r
+import org.opendaylight.controller.yang.model.parser.api.YangModelParser;\r
+import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;\r
+import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder;\r
+import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder;\r
+import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;\r
+import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;\r
+import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;\r
+import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;\r
+import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;\r
+import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder;\r
+import org.opendaylight.controller.yang.model.util.BaseConstraints;\r
+import org.opendaylight.controller.yang.model.util.BinaryType;\r
+import org.opendaylight.controller.yang.model.util.BitsType;\r
+import org.opendaylight.controller.yang.model.util.StringType;\r
+import org.opendaylight.controller.yang.model.util.UnknownType;\r
+import org.opendaylight.controller.yang.model.util.YangTypesConverter;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+public class YangModelParserImpl implements YangModelParser {\r
+\r
+ private static final Logger logger = LoggerFactory\r
+ .getLogger(YangModelParserImpl.class);\r
+\r
+ @Override\r
+ public Module parseYangModel(String yangFile) {\r
+ final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFile);\r
+ Set<Module> result = build(modules);\r
+ return result.iterator().next();\r
+ }\r
+\r
+ @Override\r
+ public Set<Module> parseYangModels(String... yangFiles) {\r
+ final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFiles);\r
+ Set<Module> result = build(modules);\r
+ return result;\r
+ }\r
+\r
+ @Override\r
+ public Set<Module> parseYangModelsFromStreams(\r
+ InputStream... yangModelStreams) {\r
+ final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangModelStreams);\r
+ Set<Module> result = build(modules);\r
+ return result;\r
+ }\r
+\r
+ @Override\r
+ public SchemaContext resolveSchemaContext(Set<Module> modules) {\r
+ return new SchemaContextImpl(modules);\r
+ }\r
+\r
+ private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(\r
+ String... yangFiles) {\r
+ InputStream[] streams = new InputStream[yangFiles.length];\r
+ for (int i = 0; i < yangFiles.length; i++) {\r
+ final String yangFileName = yangFiles[i];\r
+ final File yangFile = new File(yangFileName);\r
+ FileInputStream inStream = null;\r
+ try {\r
+ inStream = new FileInputStream(yangFile);\r
+ } catch (FileNotFoundException e) {\r
+ logger.warn("Exception while reading yang stream: " + inStream,\r
+ e);\r
+ }\r
+ streams[i] = inStream;\r
+ }\r
+ return resolveModuleBuildersFromStreams(streams);\r
+ }\r
+\r
+ private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(\r
+ InputStream... yangFiles) {\r
+ final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();\r
+ final ParseTreeWalker walker = new ParseTreeWalker();\r
+ final List<ParseTree> trees = parseStreams(yangFiles);\r
+ final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];\r
+\r
+ for (int i = 0; i < trees.size(); i++) {\r
+ final YangModelParserListenerImpl yangModelParser = new YangModelParserListenerImpl();\r
+ walker.walk(yangModelParser, trees.get(i));\r
+ builders[i] = yangModelParser.getModuleBuilder();\r
+ }\r
+\r
+ for (ModuleBuilder builder : builders) {\r
+ final String builderName = builder.getName();\r
+ Date builderRevision = builder.getRevision();\r
+ if (builderRevision == null) {\r
+ builderRevision = createEpochTime();\r
+ }\r
+ TreeMap<Date, ModuleBuilder> builderByRevision = modules\r
+ .get(builderName);\r
+ if (builderByRevision == null) {\r
+ builderByRevision = new TreeMap<Date, ModuleBuilder>();\r
+ }\r
+ builderByRevision.put(builderRevision, builder);\r
+ modules.put(builderName, builderByRevision);\r
+ }\r
+ return modules;\r
+ }\r
+\r
+ private List<ParseTree> parseStreams(InputStream... yangStreams) {\r
+ List<ParseTree> trees = new ArrayList<ParseTree>();\r
+ for (InputStream yangStream : yangStreams) {\r
+ trees.add(parseStream(yangStream));\r
+ }\r
+ return trees;\r
+ }\r
+\r
+ private ParseTree parseStream(InputStream yangStream) {\r
+ ParseTree result = null;\r
+ try {\r
+ final ANTLRInputStream input = new ANTLRInputStream(yangStream);\r
+ final YangLexer lexer = new YangLexer(input);\r
+ final CommonTokenStream tokens = new CommonTokenStream(lexer);\r
+ final YangParser parser = new YangParser(tokens);\r
+ result = parser.yang();\r
+ } catch (IOException e) {\r
+ logger.warn("Exception while reading yang file: " + yangStream, e);\r
+ }\r
+ return result;\r
+ }\r
+\r
+ private Set<Module> build(Map<String, TreeMap<Date, ModuleBuilder>> modules) {\r
+ // first validate\r
+ for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules\r
+ .entrySet()) {\r
+ for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()\r
+ .entrySet()) {\r
+ ModuleBuilder moduleBuilder = childEntry.getValue();\r
+ validateBuilder(modules, moduleBuilder);\r
+ }\r
+ }\r
+ // then build\r
+ final Set<Module> result = new HashSet<Module>();\r
+ for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules\r
+ .entrySet()) {\r
+ final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();\r
+ for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()\r
+ .entrySet()) {\r
+ ModuleBuilder moduleBuilder = childEntry.getValue();\r
+ modulesByRevision.put(childEntry.getKey(),\r
+ moduleBuilder.build());\r
+ result.add(moduleBuilder.build());\r
+ }\r
+ }\r
+\r
+ return result;\r
+ }\r
+\r
+ private void validateBuilder(\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ ModuleBuilder builder) {\r
+ resolveTypedefs(modules, builder);\r
+ resolveAugments(modules, builder);\r
+ resolveIdentities(modules, builder);\r
+ }\r
+\r
+ /**\r
+ * Search for dirty nodes (node which contains UnknownType) and resolve\r
+ * unknown types.\r
+ *\r
+ * @param modules\r
+ * all available modules\r
+ * @param module\r
+ * current module\r
+ */\r
+ private void resolveTypedefs(\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ ModuleBuilder module) {\r
+ Map<List<String>, TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();\r
+ if (dirtyNodes.size() == 0) {\r
+ return;\r
+ } else {\r
+ for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes\r
+ .entrySet()) {\r
+ TypeAwareBuilder typeToResolve = entry.getValue();\r
+\r
+ if (typeToResolve instanceof UnionTypeBuilder) {\r
+ resolveUnionTypeBuilder(modules, module,\r
+ (UnionTypeBuilder) typeToResolve);\r
+ } else {\r
+ UnknownType ut = (UnknownType) typeToResolve.getType();\r
+ TypeDefinition<?> resolvedType = findTargetType(ut,\r
+ modules, module);\r
+ typeToResolve.setType(resolvedType);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ private UnionTypeBuilder resolveUnionTypeBuilder(\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ ModuleBuilder builder, UnionTypeBuilder unionTypeBuilderToResolve) {\r
+ List<TypeDefinition<?>> resolvedTypes = new ArrayList<TypeDefinition<?>>();\r
+ List<TypeDefinition<?>> typesToRemove = new ArrayList<TypeDefinition<?>>();\r
+\r
+ for (TypeDefinition<?> td : unionTypeBuilderToResolve.getTypes()) {\r
+ if (td instanceof UnknownType) {\r
+ TypeDefinition<?> resolvedType = findTargetType(\r
+ (UnknownType) td, modules, builder);\r
+ resolvedTypes.add(resolvedType);\r
+ typesToRemove.add(td);\r
+ }\r
+ }\r
+\r
+ List<TypeDefinition<?>> unionTypeBuilderTypes = unionTypeBuilderToResolve\r
+ .getTypes();\r
+ unionTypeBuilderTypes.addAll(resolvedTypes);\r
+ unionTypeBuilderTypes.removeAll(typesToRemove);\r
+\r
+ return unionTypeBuilderToResolve;\r
+ }\r
+\r
+ private TypeDefinition<?> findTargetType(UnknownType ut,\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ ModuleBuilder builder) {\r
+\r
+ Map<TypeDefinitionBuilder, TypeConstraints> foundedTypeDefinitionBuilder = findTypeDefinitionBuilderWithConstraints(\r
+ modules, ut, builder);\r
+ TypeDefinitionBuilder targetType = foundedTypeDefinitionBuilder\r
+ .entrySet().iterator().next().getKey();\r
+ TypeConstraints constraints = foundedTypeDefinitionBuilder.entrySet()\r
+ .iterator().next().getValue();\r
+\r
+ TypeDefinition<?> targetTypeBaseType = targetType.getBaseType();\r
+\r
+ // RANGE\r
+ List<RangeConstraint> ranges = ut.getRangeStatements();\r
+ resolveRanges(ranges, targetType, modules, builder);\r
+ // LENGTH\r
+ List<LengthConstraint> lengths = ut.getLengthStatements();\r
+ resolveLengths(lengths, targetType, modules, builder);\r
+ // PATTERN\r
+ List<PatternConstraint> patterns = ut.getPatterns();\r
+ // Fraction Digits\r
+ Integer fractionDigits = ut.getFractionDigits();\r
+\r
+ targetTypeBaseType = mergeConstraints(targetTypeBaseType, constraints, ranges, lengths,\r
+ patterns, fractionDigits);\r
+\r
+ return targetTypeBaseType;\r
+ }\r
+\r
+ /**\r
+ * Merge curent constraints with founded type constraints\r
+ *\r
+ * @param targetTypeBaseType\r
+ * @param constraints\r
+ * @param ranges\r
+ * @param lengths\r
+ * @param patterns\r
+ * @param fractionDigits\r
+ */\r
+ private TypeDefinition<?> mergeConstraints(TypeDefinition<?> targetTypeBaseType,\r
+ TypeConstraints constraints, List<RangeConstraint> ranges,\r
+ List<LengthConstraint> lengths, List<PatternConstraint> patterns,\r
+ Integer fractionDigits) {\r
+ String targetTypeBaseTypeName = targetTypeBaseType.getQName()\r
+ .getLocalName();\r
+ // enumeration, leafref and identityref omitted because they have no\r
+ // restrictions\r
+ if (targetTypeBaseType instanceof DecimalTypeDefinition) {\r
+ List<RangeConstraint> fullRanges = new ArrayList<RangeConstraint>();\r
+ fullRanges.addAll(constraints.getRanges());\r
+ fullRanges.addAll(ranges);\r
+ Integer fd = fractionDigits == null ? constraints\r
+ .getFractionDigits() : fractionDigits;\r
+ targetTypeBaseType = YangTypesConverter\r
+ .javaTypeForBaseYangDecimal64Type(fullRanges, fd);\r
+ } else if (targetTypeBaseType instanceof IntegerTypeDefinition) {\r
+ List<RangeConstraint> fullRanges = new ArrayList<RangeConstraint>();\r
+ fullRanges.addAll(constraints.getRanges());\r
+ fullRanges.addAll(ranges);\r
+ if (targetTypeBaseTypeName.startsWith("int")) {\r
+ targetTypeBaseType = YangTypesConverter\r
+ .javaTypeForBaseYangSignedIntegerType(\r
+ targetTypeBaseTypeName, fullRanges);\r
+ } else {\r
+ targetTypeBaseType = YangTypesConverter\r
+ .javaTypeForBaseYangUnsignedIntegerType(\r
+ targetTypeBaseTypeName, fullRanges);\r
+ }\r
+ } else if (targetTypeBaseType instanceof StringTypeDefinition) {\r
+ List<LengthConstraint> fullLengths = new ArrayList<LengthConstraint>();\r
+ fullLengths.addAll(constraints.getLengths());\r
+ fullLengths.addAll(lengths);\r
+ List<PatternConstraint> fullPatterns = new ArrayList<PatternConstraint>();\r
+ fullPatterns.addAll(constraints.getPatterns());\r
+ fullPatterns.addAll(patterns);\r
+ targetTypeBaseType = new StringType(fullLengths, fullPatterns);\r
+ } else if (targetTypeBaseType instanceof BitsTypeDefinition) {\r
+ BitsTypeDefinition bitsType = (BitsTypeDefinition) targetTypeBaseType;\r
+ List<Bit> bits = bitsType.getBits();\r
+ targetTypeBaseType = new BitsType(bits);\r
+ } else if (targetTypeBaseType instanceof BinaryTypeDefinition) {\r
+ targetTypeBaseType = new BinaryType(null, lengths, null);\r
+ }\r
+ return targetTypeBaseType;\r
+ }\r
+\r
+ private TypeDefinitionBuilder findTypeDefinitionBuilder(\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ UnknownType unknownType, ModuleBuilder builder) {\r
+ Map<TypeDefinitionBuilder, TypeConstraints> result = findTypeDefinitionBuilderWithConstraints(\r
+ modules, unknownType, builder);\r
+ return result.entrySet().iterator().next().getKey();\r
+ }\r
+\r
+ private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ UnknownType unknownType, ModuleBuilder builder) {\r
+ return findTypeDefinitionBuilderWithConstraints(new TypeConstraints(),\r
+ modules, unknownType, builder);\r
+ }\r
+\r
+ /**\r
+ * Traverse through all referenced types chain until base YANG type is\r
+ * founded.\r
+ *\r
+ * @param constraints\r
+ * current type constraints\r
+ * @param modules\r
+ * all available modules\r
+ * @param unknownType\r
+ * unknown type\r
+ * @param builder\r
+ * current module\r
+ * @return map, where key is type referenced and value is its constraints\r
+ */\r
+ private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(\r
+ TypeConstraints constraints,\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ UnknownType unknownType, ModuleBuilder builder) {\r
+ Map<TypeDefinitionBuilder, TypeConstraints> result = new HashMap<TypeDefinitionBuilder, TypeConstraints>();\r
+ QName unknownTypeQName = unknownType.getQName();\r
+ String unknownTypeName = unknownTypeQName.getLocalName();\r
+ String unknownTypePrefix = unknownTypeQName.getPrefix();\r
+\r
+ // search for module which contains referenced typedef\r
+ ModuleBuilder dependentModuleBuilder;\r
+ if (unknownTypePrefix.equals(builder.getPrefix())) {\r
+ dependentModuleBuilder = builder;\r
+ } else {\r
+ dependentModuleBuilder = findDependentModule(modules, builder,\r
+ unknownTypePrefix);\r
+ }\r
+\r
+ // pull all typedef statements from dependent module...\r
+ final Set<TypeDefinitionBuilder> typedefs = dependentModuleBuilder\r
+ .getModuleTypedefs();\r
+ // and search for referenced typedef\r
+ TypeDefinitionBuilder lookedUpBuilder = null;\r
+ for (TypeDefinitionBuilder tdb : typedefs) {\r
+ QName qname = tdb.getQName();\r
+ if (qname.getLocalName().equals(unknownTypeName)) {\r
+ lookedUpBuilder = tdb;\r
+ break;\r
+ }\r
+ }\r
+\r
+ // if referenced type is UnknownType again, search recursively with\r
+ // current constraints\r
+ TypeDefinition<?> referencedType = lookedUpBuilder.getBaseType();\r
+ if (referencedType instanceof UnknownType) {\r
+ UnknownType unknown = (UnknownType) lookedUpBuilder.getBaseType();\r
+\r
+ final List<RangeConstraint> ranges = unknown.getRangeStatements();\r
+ constraints.addRanges(ranges);\r
+ final List<LengthConstraint> lengths = unknown\r
+ .getLengthStatements();\r
+ constraints.addLengths(lengths);\r
+ final List<PatternConstraint> patterns = unknown.getPatterns();\r
+ constraints.addPatterns(patterns);\r
+ return findTypeDefinitionBuilderWithConstraints(constraints,\r
+ modules, unknown, dependentModuleBuilder);\r
+ } else {\r
+ // pull restriction from this base type and add them to\r
+ // 'constraints'\r
+ if (referencedType instanceof DecimalTypeDefinition) {\r
+ constraints.addRanges(((DecimalTypeDefinition) referencedType)\r
+ .getRangeStatements());\r
+ constraints\r
+ .setFractionDigits(((DecimalTypeDefinition) referencedType)\r
+ .getFractionDigits());\r
+ } else if (referencedType instanceof IntegerTypeDefinition) {\r
+ constraints.addRanges(((IntegerTypeDefinition) referencedType)\r
+ .getRangeStatements());\r
+ } else if (referencedType instanceof StringTypeDefinition) {\r
+ constraints.addPatterns(((StringTypeDefinition) referencedType)\r
+ .getPatterns());\r
+ } else if (referencedType instanceof BinaryTypeDefinition) {\r
+ constraints.addLengths(((BinaryTypeDefinition) referencedType)\r
+ .getLengthConstraints());\r
+ }\r
+ result.put(lookedUpBuilder, constraints);\r
+ return result;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Go through all augmentation definitions and resolve them. This means find\r
+ * referenced node and add child nodes to it.\r
+ *\r
+ * @param modules\r
+ * all available modules\r
+ * @param module\r
+ * current module\r
+ */\r
+ private void resolveAugments(\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ ModuleBuilder module) {\r
+ Set<AugmentationSchemaBuilder> augmentBuilders = module\r
+ .getAddedAugments();\r
+\r
+ Set<AugmentationSchema> augments = new HashSet<AugmentationSchema>();\r
+ for (AugmentationSchemaBuilder augmentBuilder : augmentBuilders) {\r
+ SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();\r
+ String prefix = null;\r
+ List<String> augmentTargetPath = new ArrayList<String>();\r
+\r
+ for (QName pathPart : augmentTargetSchemaPath.getPath()) {\r
+ prefix = pathPart.getPrefix();\r
+ augmentTargetPath.add(pathPart.getLocalName());\r
+ }\r
+ ModuleBuilder dependentModule = findDependentModule(modules,\r
+ module, prefix);\r
+ //\r
+ augmentTargetPath.add(0, dependentModule.getName());\r
+ //\r
+\r
+\r
+ AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule\r
+ .getNode(augmentTargetPath);\r
+ AugmentationSchema result = augmentBuilder.build();\r
+ augmentTarget.addAugmentation(result);\r
+ fillAugmentTarget(augmentBuilder, (ChildNodeBuilder) augmentTarget);\r
+ augments.add(result);\r
+ }\r
+ module.setAugmentations(augments);\r
+ }\r
+\r
+ /**\r
+ * Add all augment's child nodes to given target.\r
+ *\r
+ * @param augment\r
+ * @param target\r
+ */\r
+ private void fillAugmentTarget(AugmentationSchemaBuilder augment,\r
+ ChildNodeBuilder target) {\r
+ for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {\r
+ builder.setAugmenting(true);\r
+ target.addChildNode(builder);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Go through identity statements defined in current module and resolve\r
+ * their 'base' statement if present.\r
+ *\r
+ * @param modules\r
+ * all modules\r
+ * @param module\r
+ * module being resolved\r
+ */\r
+ private void resolveIdentities(\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ ModuleBuilder module) {\r
+ Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();\r
+ for (IdentitySchemaNodeBuilder identity : identities) {\r
+ String baseIdentityName = identity.getBaseIdentityName();\r
+ if (baseIdentityName != null) {\r
+ String baseIdentityPrefix = null;\r
+ String baseIdentityLocalName = null;\r
+ if (baseIdentityName.contains(":")) {\r
+ String[] splitted = baseIdentityName.split(":");\r
+ baseIdentityPrefix = splitted[0];\r
+ baseIdentityLocalName = splitted[1];\r
+ } else {\r
+ baseIdentityPrefix = module.getPrefix();\r
+ baseIdentityLocalName = baseIdentityName;\r
+ }\r
+ ModuleBuilder dependentModule;\r
+ if (baseIdentityPrefix.equals(module.getPrefix())) {\r
+ dependentModule = module;\r
+ } else {\r
+ dependentModule = findDependentModule(modules, module,\r
+ baseIdentityPrefix);\r
+ }\r
+\r
+ Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule\r
+ .getAddedIdentities();\r
+ for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {\r
+ if (idBuilder.getQName().getLocalName()\r
+ .equals(baseIdentityLocalName)) {\r
+ identity.setBaseIdentity(idBuilder);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Find dependent module based on given prefix\r
+ *\r
+ * @param modules\r
+ * all available modules\r
+ * @param module\r
+ * current module\r
+ * @param prefix\r
+ * target module prefix\r
+ * @return dependent module builder\r
+ */\r
+ private ModuleBuilder findDependentModule(\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ ModuleBuilder module, String prefix) {\r
+ ModuleImport dependentModuleImport = getModuleImport(module, prefix);\r
+ String dependentModuleName = dependentModuleImport.getModuleName();\r
+ Date dependentModuleRevision = dependentModuleImport.getRevision();\r
+\r
+ TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules\r
+ .get(dependentModuleName);\r
+ ModuleBuilder dependentModule;\r
+ if (dependentModuleRevision == null) {\r
+ dependentModule = moduleBuildersByRevision.lastEntry().getValue();\r
+ } else {\r
+ dependentModule = moduleBuildersByRevision\r
+ .get(dependentModuleRevision);\r
+ }\r
+ return dependentModule;\r
+ }\r
+\r
+ /**\r
+ * Get module import referenced by given prefix.\r
+ *\r
+ * @param builder\r
+ * module to search\r
+ * @param prefix\r
+ * prefix associated with import\r
+ * @return ModuleImport based on given prefix\r
+ */\r
+ private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {\r
+ ModuleImport moduleImport = null;\r
+ for (ModuleImport mi : builder.getModuleImports()) {\r
+ if (mi.getPrefix().equals(prefix)) {\r
+ moduleImport = mi;\r
+ break;\r
+ }\r
+ }\r
+ return moduleImport;\r
+ }\r
+\r
+ /**\r
+ * Helper method for resolving special 'min' or 'max' values in range\r
+ * constraint\r
+ *\r
+ * @param ranges\r
+ * ranges to resolve\r
+ * @param targetType\r
+ * target type\r
+ * @param modules\r
+ * all available modules\r
+ * @param builder\r
+ * current module\r
+ */\r
+ private void resolveRanges(List<RangeConstraint> ranges,\r
+ TypeDefinitionBuilder targetType,\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ ModuleBuilder builder) {\r
+ if (ranges != null && ranges.size() > 0) {\r
+ Long min = (Long) ranges.get(0).getMin();\r
+ Long max = (Long) ranges.get(ranges.size() - 1).getMax();\r
+ // if range contains one of the special values 'min' or 'max'\r
+ if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) {\r
+ Long[] values = parseRangeConstraint(targetType, modules,\r
+ builder);\r
+ if (min.equals(Long.MIN_VALUE)) {\r
+ min = values[0];\r
+ RangeConstraint oldFirst = ranges.get(0);\r
+ RangeConstraint newFirst = BaseConstraints.rangeConstraint(\r
+ min, oldFirst.getMax(), oldFirst.getDescription(),\r
+ oldFirst.getReference());\r
+ ranges.set(0, newFirst);\r
+ }\r
+ if (max.equals(Long.MAX_VALUE)) {\r
+ max = values[1];\r
+ RangeConstraint oldLast = ranges.get(ranges.size() - 1);\r
+ RangeConstraint newLast = BaseConstraints.rangeConstraint(\r
+ oldLast.getMin(), max, oldLast.getDescription(),\r
+ oldLast.getReference());\r
+ ranges.set(ranges.size() - 1, newLast);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Helper method for resolving special 'min' or 'max' values in length\r
+ * constraint\r
+ *\r
+ * @param lengths\r
+ * lengths to resolve\r
+ * @param targetType\r
+ * target type\r
+ * @param modules\r
+ * all available modules\r
+ * @param builder\r
+ * current module\r
+ */\r
+ private void resolveLengths(List<LengthConstraint> lengths,\r
+ TypeDefinitionBuilder targetType,\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ ModuleBuilder builder) {\r
+ if (lengths != null && lengths.size() > 0) {\r
+ Long min = lengths.get(0).getMin().longValue();\r
+ Long max = lengths.get(lengths.size() - 1).getMax().longValue();\r
+ // if length contains one of the special values 'min' or 'max'\r
+ if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) {\r
+ Long[] values = parseRangeConstraint(targetType, modules,\r
+ builder);\r
+ if (min.equals(Long.MIN_VALUE)) {\r
+ min = values[0];\r
+ LengthConstraint oldFirst = lengths.get(0);\r
+ LengthConstraint newFirst = BaseConstraints\r
+ .lengthConstraint(min, oldFirst.getMax(),\r
+ oldFirst.getDescription(),\r
+ oldFirst.getReference());\r
+ lengths.set(0, newFirst);\r
+ }\r
+ if (max.equals(Long.MAX_VALUE)) {\r
+ max = values[1];\r
+ LengthConstraint oldLast = lengths.get(lengths.size() - 1);\r
+ LengthConstraint newLast = BaseConstraints\r
+ .lengthConstraint(oldLast.getMin(), max,\r
+ oldLast.getDescription(),\r
+ oldLast.getReference());\r
+ lengths.set(lengths.size() - 1, newLast);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ private Long[] parseRangeConstraint(TypeDefinitionBuilder targetType,\r
+ Map<String, TreeMap<Date, ModuleBuilder>> modules,\r
+ ModuleBuilder builder) {\r
+ TypeDefinition<?> targetBaseType = targetType.getBaseType();\r
+\r
+ if (targetBaseType instanceof IntegerTypeDefinition) {\r
+ IntegerTypeDefinition itd = (IntegerTypeDefinition) targetBaseType;\r
+ List<RangeConstraint> ranges = itd.getRangeStatements();\r
+ Long min = (Long) ranges.get(0).getMin();\r
+ Long max = (Long) ranges.get(ranges.size() - 1).getMax();\r
+ return new Long[] { min, max };\r
+ } else if (targetBaseType instanceof DecimalTypeDefinition) {\r
+ DecimalTypeDefinition dtd = (DecimalTypeDefinition) targetBaseType;\r
+ List<RangeConstraint> ranges = dtd.getRangeStatements();\r
+ Long min = (Long) ranges.get(0).getMin();\r
+ Long max = (Long) ranges.get(ranges.size() - 1).getMax();\r
+ return new Long[] { min, max };\r
+ } else {\r
+ return parseRangeConstraint(\r
+ findTypeDefinitionBuilder(modules,\r
+ (UnknownType) targetBaseType, builder), modules,\r
+ builder);\r
+ }\r
+ }\r
+\r
+ private Date createEpochTime() {\r
+ Calendar c = Calendar.getInstance();\r
+ c.setTimeInMillis(0);\r
+ return c.getTime();\r
+ }\r
+\r
+ private static class SchemaContextImpl implements SchemaContext {\r
+ private final Set<Module> modules;\r
+\r
+ private SchemaContextImpl(Set<Module> modules) {\r
+ this.modules = modules;\r
+ }\r
+\r
+ @Override\r
+ public Set<DataSchemaNode> getDataDefinitions() {\r
+ final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();\r
+ for (Module m : modules) {\r
+ dataDefs.addAll(m.getChildNodes());\r
+ }\r
+ return dataDefs;\r
+ }\r
+\r
+ @Override\r
+ public Set<Module> getModules() {\r
+ return modules;\r
+ }\r
+\r
+ @Override\r
+ public Set<NotificationDefinition> getNotifications() {\r
+ final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();\r
+ for (Module m : modules) {\r
+ notifications.addAll(m.getNotifications());\r
+ }\r
+ return notifications;\r
+ }\r
+\r
+ @Override\r
+ public Set<RpcDefinition> getOperations() {\r
+ final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();\r
+ for (Module m : modules) {\r
+ rpcs.addAll(m.getRpcs());\r
+ }\r
+ return rpcs;\r
+ }\r
+\r
+ @Override\r
+ public Set<ExtensionDefinition> getExtensions() {\r
+ final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();\r
+ for (Module m : modules) {\r
+ extensions.addAll(m.getExtensionSchemaNodes());\r
+ }\r
+ return extensions;\r
+ }\r
+ }\r
+\r
+ private static class TypeConstraints {\r
+ private final List<RangeConstraint> ranges = new ArrayList<RangeConstraint>();\r
+ private final List<LengthConstraint> lengths = new ArrayList<LengthConstraint>();\r
+ private final List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();\r
+ private Integer fractionDigits;\r
+\r
+ public List<RangeConstraint> getRanges() {\r
+ return ranges;\r
+ }\r
+\r
+ public void addRanges(List<RangeConstraint> ranges) {\r
+ this.ranges.addAll(0, ranges);\r
+ }\r
+\r
+ public List<LengthConstraint> getLengths() {\r
+ return lengths;\r
+ }\r
+\r
+ public void addLengths(List<LengthConstraint> lengths) {\r
+ this.lengths.addAll(0, lengths);\r
+ }\r
+\r
+ public List<PatternConstraint> getPatterns() {\r
+ return patterns;\r
+ }\r
+\r
+ public void addPatterns(List<PatternConstraint> patterns) {\r
+ this.patterns.addAll(0, patterns);\r
+ }\r
+\r
+ public Integer getFractionDigits() {\r
+ return fractionDigits;\r
+ }\r
+\r
+ public void setFractionDigits(Integer fractionDigits) {\r
+ if (fractionDigits != null) {\r
+ this.fractionDigits = fractionDigits;\r
+ }\r
+ }\r
+ }\r
+\r
+}\r