2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
\r
4 * This program and the accompanying materials are made available under the
\r
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
\r
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
\r
8 package org.opendaylight.controller.yang.model.parser.impl;
\r
10 import java.io.File;
\r
11 import java.io.FileInputStream;
\r
12 import java.io.FileNotFoundException;
\r
13 import java.io.IOException;
\r
14 import java.io.InputStream;
\r
15 import java.util.ArrayList;
\r
16 import java.util.Calendar;
\r
17 import java.util.Date;
\r
18 import java.util.HashMap;
\r
19 import java.util.HashSet;
\r
20 import java.util.List;
\r
21 import java.util.Map;
\r
22 import java.util.Set;
\r
23 import java.util.TreeMap;
\r
25 import org.antlr.v4.runtime.ANTLRInputStream;
\r
26 import org.antlr.v4.runtime.CommonTokenStream;
\r
27 import org.antlr.v4.runtime.tree.ParseTree;
\r
28 import org.antlr.v4.runtime.tree.ParseTreeWalker;
\r
29 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
\r
30 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
\r
31 import org.opendaylight.controller.yang.common.QName;
\r
32 import org.opendaylight.controller.yang.model.api.AugmentationSchema;
\r
33 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
\r
34 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
\r
35 import org.opendaylight.controller.yang.model.api.Module;
\r
36 import org.opendaylight.controller.yang.model.api.ModuleImport;
\r
37 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
\r
38 import org.opendaylight.controller.yang.model.api.RpcDefinition;
\r
39 import org.opendaylight.controller.yang.model.api.SchemaContext;
\r
40 import org.opendaylight.controller.yang.model.api.SchemaPath;
\r
41 import org.opendaylight.controller.yang.model.api.TypeDefinition;
\r
42 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
\r
43 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;
\r
44 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
\r
45 import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
\r
46 import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
\r
47 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
\r
48 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
\r
49 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
\r
50 import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
\r
51 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
\r
52 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;
\r
53 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder;
\r
54 import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder;
\r
55 import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;
\r
56 import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;
\r
57 import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;
\r
58 import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;
\r
59 import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
\r
60 import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder;
\r
61 import org.opendaylight.controller.yang.model.util.BaseConstraints;
\r
62 import org.opendaylight.controller.yang.model.util.BinaryType;
\r
63 import org.opendaylight.controller.yang.model.util.BitsType;
\r
64 import org.opendaylight.controller.yang.model.util.StringType;
\r
65 import org.opendaylight.controller.yang.model.util.UnknownType;
\r
66 import org.opendaylight.controller.yang.model.util.YangTypesConverter;
\r
67 import org.slf4j.Logger;
\r
68 import org.slf4j.LoggerFactory;
\r
70 public class YangModelParserImpl implements YangModelParser {
\r
72 private static final Logger logger = LoggerFactory
\r
73 .getLogger(YangModelParserImpl.class);
\r
76 public Module parseYangModel(String yangFile) {
\r
77 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFile);
\r
78 Set<Module> result = build(modules);
\r
79 return result.iterator().next();
\r
83 public Set<Module> parseYangModels(String... yangFiles) {
\r
84 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFiles);
\r
85 Set<Module> result = build(modules);
\r
90 public Set<Module> parseYangModelsFromStreams(
\r
91 InputStream... yangModelStreams) {
\r
92 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangModelStreams);
\r
93 Set<Module> result = build(modules);
\r
98 public SchemaContext resolveSchemaContext(Set<Module> modules) {
\r
99 return new SchemaContextImpl(modules);
\r
102 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(
\r
103 String... yangFiles) {
\r
104 InputStream[] streams = new InputStream[yangFiles.length];
\r
105 for (int i = 0; i < yangFiles.length; i++) {
\r
106 final String yangFileName = yangFiles[i];
\r
107 final File yangFile = new File(yangFileName);
\r
108 FileInputStream inStream = null;
\r
110 inStream = new FileInputStream(yangFile);
\r
111 } catch (FileNotFoundException e) {
\r
112 logger.warn("Exception while reading yang stream: " + inStream,
\r
115 streams[i] = inStream;
\r
117 return resolveModuleBuildersFromStreams(streams);
\r
120 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(
\r
121 InputStream... yangFiles) {
\r
122 final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
\r
123 final ParseTreeWalker walker = new ParseTreeWalker();
\r
124 final List<ParseTree> trees = parseStreams(yangFiles);
\r
125 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
\r
127 for (int i = 0; i < trees.size(); i++) {
\r
128 final YangModelParserListenerImpl yangModelParser = new YangModelParserListenerImpl();
\r
129 walker.walk(yangModelParser, trees.get(i));
\r
130 builders[i] = yangModelParser.getModuleBuilder();
\r
133 for (ModuleBuilder builder : builders) {
\r
134 final String builderName = builder.getName();
\r
135 Date builderRevision = builder.getRevision();
\r
136 if (builderRevision == null) {
\r
137 builderRevision = createEpochTime();
\r
139 TreeMap<Date, ModuleBuilder> builderByRevision = modules
\r
141 if (builderByRevision == null) {
\r
142 builderByRevision = new TreeMap<Date, ModuleBuilder>();
\r
144 builderByRevision.put(builderRevision, builder);
\r
145 modules.put(builderName, builderByRevision);
\r
150 private List<ParseTree> parseStreams(InputStream... yangStreams) {
\r
151 List<ParseTree> trees = new ArrayList<ParseTree>();
\r
152 for (InputStream yangStream : yangStreams) {
\r
153 trees.add(parseStream(yangStream));
\r
158 private ParseTree parseStream(InputStream yangStream) {
\r
159 ParseTree result = null;
\r
161 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
\r
162 final YangLexer lexer = new YangLexer(input);
\r
163 final CommonTokenStream tokens = new CommonTokenStream(lexer);
\r
164 final YangParser parser = new YangParser(tokens);
\r
165 result = parser.yang();
\r
166 } catch (IOException e) {
\r
167 logger.warn("Exception while reading yang file: " + yangStream, e);
\r
172 private Set<Module> build(Map<String, TreeMap<Date, ModuleBuilder>> modules) {
\r
174 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
\r
176 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
\r
178 ModuleBuilder moduleBuilder = childEntry.getValue();
\r
179 validateBuilder(modules, moduleBuilder);
\r
183 final Set<Module> result = new HashSet<Module>();
\r
184 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
\r
186 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
\r
187 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
\r
189 ModuleBuilder moduleBuilder = childEntry.getValue();
\r
190 modulesByRevision.put(childEntry.getKey(),
\r
191 moduleBuilder.build());
\r
192 result.add(moduleBuilder.build());
\r
199 private void validateBuilder(
\r
200 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
201 ModuleBuilder builder) {
\r
202 resolveTypedefs(modules, builder);
\r
203 resolveAugments(modules, builder);
\r
204 resolveIdentities(modules, builder);
\r
208 * Search for dirty nodes (node which contains UnknownType) and resolve
\r
212 * all available modules
\r
216 private void resolveTypedefs(
\r
217 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
218 ModuleBuilder module) {
\r
219 Map<List<String>, TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
\r
220 if (dirtyNodes.size() == 0) {
\r
223 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
\r
225 TypeAwareBuilder typeToResolve = entry.getValue();
\r
227 if (typeToResolve instanceof UnionTypeBuilder) {
\r
228 resolveUnionTypeBuilder(modules, module,
\r
229 (UnionTypeBuilder) typeToResolve);
\r
231 UnknownType ut = (UnknownType) typeToResolve.getType();
\r
232 TypeDefinition<?> resolvedType = findTargetType(ut,
\r
234 typeToResolve.setType(resolvedType);
\r
240 private UnionTypeBuilder resolveUnionTypeBuilder(
\r
241 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
242 ModuleBuilder builder, UnionTypeBuilder unionTypeBuilderToResolve) {
\r
243 List<TypeDefinition<?>> resolvedTypes = new ArrayList<TypeDefinition<?>>();
\r
244 List<TypeDefinition<?>> typesToRemove = new ArrayList<TypeDefinition<?>>();
\r
246 for (TypeDefinition<?> td : unionTypeBuilderToResolve.getTypes()) {
\r
247 if (td instanceof UnknownType) {
\r
248 TypeDefinition<?> resolvedType = findTargetType(
\r
249 (UnknownType) td, modules, builder);
\r
250 resolvedTypes.add(resolvedType);
\r
251 typesToRemove.add(td);
\r
255 List<TypeDefinition<?>> unionTypeBuilderTypes = unionTypeBuilderToResolve
\r
257 unionTypeBuilderTypes.addAll(resolvedTypes);
\r
258 unionTypeBuilderTypes.removeAll(typesToRemove);
\r
260 return unionTypeBuilderToResolve;
\r
263 private TypeDefinition<?> findTargetType(UnknownType ut,
\r
264 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
265 ModuleBuilder builder) {
\r
267 Map<TypeDefinitionBuilder, TypeConstraints> foundedTypeDefinitionBuilder = findTypeDefinitionBuilderWithConstraints(
\r
268 modules, ut, builder);
\r
269 TypeDefinitionBuilder targetType = foundedTypeDefinitionBuilder
\r
270 .entrySet().iterator().next().getKey();
\r
271 TypeConstraints constraints = foundedTypeDefinitionBuilder.entrySet()
\r
272 .iterator().next().getValue();
\r
274 TypeDefinition<?> targetTypeBaseType = targetType.getBaseType();
\r
277 List<RangeConstraint> ranges = ut.getRangeStatements();
\r
278 resolveRanges(ranges, targetType, modules, builder);
\r
280 List<LengthConstraint> lengths = ut.getLengthStatements();
\r
281 resolveLengths(lengths, targetType, modules, builder);
\r
283 List<PatternConstraint> patterns = ut.getPatterns();
\r
285 Integer fractionDigits = ut.getFractionDigits();
\r
287 targetTypeBaseType = mergeConstraints(targetTypeBaseType, constraints, ranges, lengths,
\r
288 patterns, fractionDigits);
\r
290 return targetTypeBaseType;
\r
294 * Merge curent constraints with founded type constraints
\r
296 * @param targetTypeBaseType
\r
297 * @param constraints
\r
301 * @param fractionDigits
\r
303 private TypeDefinition<?> mergeConstraints(TypeDefinition<?> targetTypeBaseType,
\r
304 TypeConstraints constraints, List<RangeConstraint> ranges,
\r
305 List<LengthConstraint> lengths, List<PatternConstraint> patterns,
\r
306 Integer fractionDigits) {
\r
307 String targetTypeBaseTypeName = targetTypeBaseType.getQName()
\r
309 // enumeration, leafref and identityref omitted because they have no
\r
311 if (targetTypeBaseType instanceof DecimalTypeDefinition) {
\r
312 List<RangeConstraint> fullRanges = new ArrayList<RangeConstraint>();
\r
313 fullRanges.addAll(constraints.getRanges());
\r
314 fullRanges.addAll(ranges);
\r
315 Integer fd = fractionDigits == null ? constraints
\r
316 .getFractionDigits() : fractionDigits;
\r
317 targetTypeBaseType = YangTypesConverter
\r
318 .javaTypeForBaseYangDecimal64Type(fullRanges, fd);
\r
319 } else if (targetTypeBaseType instanceof IntegerTypeDefinition) {
\r
320 List<RangeConstraint> fullRanges = new ArrayList<RangeConstraint>();
\r
321 fullRanges.addAll(constraints.getRanges());
\r
322 fullRanges.addAll(ranges);
\r
323 if (targetTypeBaseTypeName.startsWith("int")) {
\r
324 targetTypeBaseType = YangTypesConverter
\r
325 .javaTypeForBaseYangSignedIntegerType(
\r
326 targetTypeBaseTypeName, fullRanges);
\r
328 targetTypeBaseType = YangTypesConverter
\r
329 .javaTypeForBaseYangUnsignedIntegerType(
\r
330 targetTypeBaseTypeName, fullRanges);
\r
332 } else if (targetTypeBaseType instanceof StringTypeDefinition) {
\r
333 List<LengthConstraint> fullLengths = new ArrayList<LengthConstraint>();
\r
334 fullLengths.addAll(constraints.getLengths());
\r
335 fullLengths.addAll(lengths);
\r
336 List<PatternConstraint> fullPatterns = new ArrayList<PatternConstraint>();
\r
337 fullPatterns.addAll(constraints.getPatterns());
\r
338 fullPatterns.addAll(patterns);
\r
339 targetTypeBaseType = new StringType(fullLengths, fullPatterns);
\r
340 } else if (targetTypeBaseType instanceof BitsTypeDefinition) {
\r
341 BitsTypeDefinition bitsType = (BitsTypeDefinition) targetTypeBaseType;
\r
342 List<Bit> bits = bitsType.getBits();
\r
343 targetTypeBaseType = new BitsType(bits);
\r
344 } else if (targetTypeBaseType instanceof BinaryTypeDefinition) {
\r
345 targetTypeBaseType = new BinaryType(null, lengths, null);
\r
347 return targetTypeBaseType;
\r
350 private TypeDefinitionBuilder findTypeDefinitionBuilder(
\r
351 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
352 UnknownType unknownType, ModuleBuilder builder) {
\r
353 Map<TypeDefinitionBuilder, TypeConstraints> result = findTypeDefinitionBuilderWithConstraints(
\r
354 modules, unknownType, builder);
\r
355 return result.entrySet().iterator().next().getKey();
\r
358 private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(
\r
359 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
360 UnknownType unknownType, ModuleBuilder builder) {
\r
361 return findTypeDefinitionBuilderWithConstraints(new TypeConstraints(),
\r
362 modules, unknownType, builder);
\r
366 * Traverse through all referenced types chain until base YANG type is
\r
369 * @param constraints
\r
370 * current type constraints
\r
372 * all available modules
\r
373 * @param unknownType
\r
377 * @return map, where key is type referenced and value is its constraints
\r
379 private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(
\r
380 TypeConstraints constraints,
\r
381 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
382 UnknownType unknownType, ModuleBuilder builder) {
\r
383 Map<TypeDefinitionBuilder, TypeConstraints> result = new HashMap<TypeDefinitionBuilder, TypeConstraints>();
\r
384 QName unknownTypeQName = unknownType.getQName();
\r
385 String unknownTypeName = unknownTypeQName.getLocalName();
\r
386 String unknownTypePrefix = unknownTypeQName.getPrefix();
\r
388 // search for module which contains referenced typedef
\r
389 ModuleBuilder dependentModuleBuilder;
\r
390 if (unknownTypePrefix.equals(builder.getPrefix())) {
\r
391 dependentModuleBuilder = builder;
\r
393 dependentModuleBuilder = findDependentModule(modules, builder,
\r
394 unknownTypePrefix);
\r
397 // pull all typedef statements from dependent module...
\r
398 final Set<TypeDefinitionBuilder> typedefs = dependentModuleBuilder
\r
399 .getModuleTypedefs();
\r
400 // and search for referenced typedef
\r
401 TypeDefinitionBuilder lookedUpBuilder = null;
\r
402 for (TypeDefinitionBuilder tdb : typedefs) {
\r
403 QName qname = tdb.getQName();
\r
404 if (qname.getLocalName().equals(unknownTypeName)) {
\r
405 lookedUpBuilder = tdb;
\r
410 // if referenced type is UnknownType again, search recursively with
\r
411 // current constraints
\r
412 TypeDefinition<?> referencedType = lookedUpBuilder.getBaseType();
\r
413 if (referencedType instanceof UnknownType) {
\r
414 UnknownType unknown = (UnknownType) lookedUpBuilder.getBaseType();
\r
416 final List<RangeConstraint> ranges = unknown.getRangeStatements();
\r
417 constraints.addRanges(ranges);
\r
418 final List<LengthConstraint> lengths = unknown
\r
419 .getLengthStatements();
\r
420 constraints.addLengths(lengths);
\r
421 final List<PatternConstraint> patterns = unknown.getPatterns();
\r
422 constraints.addPatterns(patterns);
\r
423 return findTypeDefinitionBuilderWithConstraints(constraints,
\r
424 modules, unknown, dependentModuleBuilder);
\r
426 // pull restriction from this base type and add them to
\r
428 if (referencedType instanceof DecimalTypeDefinition) {
\r
429 constraints.addRanges(((DecimalTypeDefinition) referencedType)
\r
430 .getRangeStatements());
\r
432 .setFractionDigits(((DecimalTypeDefinition) referencedType)
\r
433 .getFractionDigits());
\r
434 } else if (referencedType instanceof IntegerTypeDefinition) {
\r
435 constraints.addRanges(((IntegerTypeDefinition) referencedType)
\r
436 .getRangeStatements());
\r
437 } else if (referencedType instanceof StringTypeDefinition) {
\r
438 constraints.addPatterns(((StringTypeDefinition) referencedType)
\r
440 } else if (referencedType instanceof BinaryTypeDefinition) {
\r
441 constraints.addLengths(((BinaryTypeDefinition) referencedType)
\r
442 .getLengthConstraints());
\r
444 result.put(lookedUpBuilder, constraints);
\r
450 * Go through all augmentation definitions and resolve them. This means find
\r
451 * referenced node and add child nodes to it.
\r
454 * all available modules
\r
458 private void resolveAugments(
\r
459 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
460 ModuleBuilder module) {
\r
461 Set<AugmentationSchemaBuilder> augmentBuilders = module
\r
462 .getAddedAugments();
\r
464 Set<AugmentationSchema> augments = new HashSet<AugmentationSchema>();
\r
465 for (AugmentationSchemaBuilder augmentBuilder : augmentBuilders) {
\r
466 SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
\r
467 String prefix = null;
\r
468 List<String> augmentTargetPath = new ArrayList<String>();
\r
470 for (QName pathPart : augmentTargetSchemaPath.getPath()) {
\r
471 prefix = pathPart.getPrefix();
\r
472 augmentTargetPath.add(pathPart.getLocalName());
\r
474 ModuleBuilder dependentModule = findDependentModule(modules,
\r
477 augmentTargetPath.add(0, dependentModule.getName());
\r
481 AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule
\r
482 .getNode(augmentTargetPath);
\r
483 AugmentationSchema result = augmentBuilder.build();
\r
484 augmentTarget.addAugmentation(result);
\r
485 fillAugmentTarget(augmentBuilder, (ChildNodeBuilder) augmentTarget);
\r
486 augments.add(result);
\r
488 module.setAugmentations(augments);
\r
492 * Add all augment's child nodes to given target.
\r
497 private void fillAugmentTarget(AugmentationSchemaBuilder augment,
\r
498 ChildNodeBuilder target) {
\r
499 for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
\r
500 builder.setAugmenting(true);
\r
501 target.addChildNode(builder);
\r
506 * Go through identity statements defined in current module and resolve
\r
507 * their 'base' statement if present.
\r
512 * module being resolved
\r
514 private void resolveIdentities(
\r
515 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
516 ModuleBuilder module) {
\r
517 Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();
\r
518 for (IdentitySchemaNodeBuilder identity : identities) {
\r
519 String baseIdentityName = identity.getBaseIdentityName();
\r
520 if (baseIdentityName != null) {
\r
521 String baseIdentityPrefix = null;
\r
522 String baseIdentityLocalName = null;
\r
523 if (baseIdentityName.contains(":")) {
\r
524 String[] splitted = baseIdentityName.split(":");
\r
525 baseIdentityPrefix = splitted[0];
\r
526 baseIdentityLocalName = splitted[1];
\r
528 baseIdentityPrefix = module.getPrefix();
\r
529 baseIdentityLocalName = baseIdentityName;
\r
531 ModuleBuilder dependentModule;
\r
532 if (baseIdentityPrefix.equals(module.getPrefix())) {
\r
533 dependentModule = module;
\r
535 dependentModule = findDependentModule(modules, module,
\r
536 baseIdentityPrefix);
\r
539 Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
\r
540 .getAddedIdentities();
\r
541 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
\r
542 if (idBuilder.getQName().getLocalName()
\r
543 .equals(baseIdentityLocalName)) {
\r
544 identity.setBaseIdentity(idBuilder);
\r
552 * Find dependent module based on given prefix
\r
555 * all available modules
\r
559 * target module prefix
\r
560 * @return dependent module builder
\r
562 private ModuleBuilder findDependentModule(
\r
563 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
564 ModuleBuilder module, String prefix) {
\r
565 ModuleImport dependentModuleImport = getModuleImport(module, prefix);
\r
566 String dependentModuleName = dependentModuleImport.getModuleName();
\r
567 Date dependentModuleRevision = dependentModuleImport.getRevision();
\r
569 TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
\r
570 .get(dependentModuleName);
\r
571 ModuleBuilder dependentModule;
\r
572 if (dependentModuleRevision == null) {
\r
573 dependentModule = moduleBuildersByRevision.lastEntry().getValue();
\r
575 dependentModule = moduleBuildersByRevision
\r
576 .get(dependentModuleRevision);
\r
578 return dependentModule;
\r
582 * Get module import referenced by given prefix.
\r
587 * prefix associated with import
\r
588 * @return ModuleImport based on given prefix
\r
590 private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {
\r
591 ModuleImport moduleImport = null;
\r
592 for (ModuleImport mi : builder.getModuleImports()) {
\r
593 if (mi.getPrefix().equals(prefix)) {
\r
598 return moduleImport;
\r
602 * Helper method for resolving special 'min' or 'max' values in range
\r
606 * ranges to resolve
\r
607 * @param targetType
\r
610 * all available modules
\r
614 private void resolveRanges(List<RangeConstraint> ranges,
\r
615 TypeDefinitionBuilder targetType,
\r
616 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
617 ModuleBuilder builder) {
\r
618 if (ranges != null && ranges.size() > 0) {
\r
619 Long min = (Long) ranges.get(0).getMin();
\r
620 Long max = (Long) ranges.get(ranges.size() - 1).getMax();
\r
621 // if range contains one of the special values 'min' or 'max'
\r
622 if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) {
\r
623 Long[] values = parseRangeConstraint(targetType, modules,
\r
625 if (min.equals(Long.MIN_VALUE)) {
\r
627 RangeConstraint oldFirst = ranges.get(0);
\r
628 RangeConstraint newFirst = BaseConstraints.rangeConstraint(
\r
629 min, oldFirst.getMax(), oldFirst.getDescription(),
\r
630 oldFirst.getReference());
\r
631 ranges.set(0, newFirst);
\r
633 if (max.equals(Long.MAX_VALUE)) {
\r
635 RangeConstraint oldLast = ranges.get(ranges.size() - 1);
\r
636 RangeConstraint newLast = BaseConstraints.rangeConstraint(
\r
637 oldLast.getMin(), max, oldLast.getDescription(),
\r
638 oldLast.getReference());
\r
639 ranges.set(ranges.size() - 1, newLast);
\r
646 * Helper method for resolving special 'min' or 'max' values in length
\r
650 * lengths to resolve
\r
651 * @param targetType
\r
654 * all available modules
\r
658 private void resolveLengths(List<LengthConstraint> lengths,
\r
659 TypeDefinitionBuilder targetType,
\r
660 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
661 ModuleBuilder builder) {
\r
662 if (lengths != null && lengths.size() > 0) {
\r
663 Long min = lengths.get(0).getMin().longValue();
\r
664 Long max = lengths.get(lengths.size() - 1).getMax().longValue();
\r
665 // if length contains one of the special values 'min' or 'max'
\r
666 if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) {
\r
667 Long[] values = parseRangeConstraint(targetType, modules,
\r
669 if (min.equals(Long.MIN_VALUE)) {
\r
671 LengthConstraint oldFirst = lengths.get(0);
\r
672 LengthConstraint newFirst = BaseConstraints
\r
673 .lengthConstraint(min, oldFirst.getMax(),
\r
674 oldFirst.getDescription(),
\r
675 oldFirst.getReference());
\r
676 lengths.set(0, newFirst);
\r
678 if (max.equals(Long.MAX_VALUE)) {
\r
680 LengthConstraint oldLast = lengths.get(lengths.size() - 1);
\r
681 LengthConstraint newLast = BaseConstraints
\r
682 .lengthConstraint(oldLast.getMin(), max,
\r
683 oldLast.getDescription(),
\r
684 oldLast.getReference());
\r
685 lengths.set(lengths.size() - 1, newLast);
\r
691 private Long[] parseRangeConstraint(TypeDefinitionBuilder targetType,
\r
692 Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
693 ModuleBuilder builder) {
\r
694 TypeDefinition<?> targetBaseType = targetType.getBaseType();
\r
696 if (targetBaseType instanceof IntegerTypeDefinition) {
\r
697 IntegerTypeDefinition itd = (IntegerTypeDefinition) targetBaseType;
\r
698 List<RangeConstraint> ranges = itd.getRangeStatements();
\r
699 Long min = (Long) ranges.get(0).getMin();
\r
700 Long max = (Long) ranges.get(ranges.size() - 1).getMax();
\r
701 return new Long[] { min, max };
\r
702 } else if (targetBaseType instanceof DecimalTypeDefinition) {
\r
703 DecimalTypeDefinition dtd = (DecimalTypeDefinition) targetBaseType;
\r
704 List<RangeConstraint> ranges = dtd.getRangeStatements();
\r
705 Long min = (Long) ranges.get(0).getMin();
\r
706 Long max = (Long) ranges.get(ranges.size() - 1).getMax();
\r
707 return new Long[] { min, max };
\r
709 return parseRangeConstraint(
\r
710 findTypeDefinitionBuilder(modules,
\r
711 (UnknownType) targetBaseType, builder), modules,
\r
716 private Date createEpochTime() {
\r
717 Calendar c = Calendar.getInstance();
\r
718 c.setTimeInMillis(0);
\r
719 return c.getTime();
\r
722 private static class SchemaContextImpl implements SchemaContext {
\r
723 private final Set<Module> modules;
\r
725 private SchemaContextImpl(Set<Module> modules) {
\r
726 this.modules = modules;
\r
730 public Set<DataSchemaNode> getDataDefinitions() {
\r
731 final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
\r
732 for (Module m : modules) {
\r
733 dataDefs.addAll(m.getChildNodes());
\r
739 public Set<Module> getModules() {
\r
744 public Set<NotificationDefinition> getNotifications() {
\r
745 final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
\r
746 for (Module m : modules) {
\r
747 notifications.addAll(m.getNotifications());
\r
749 return notifications;
\r
753 public Set<RpcDefinition> getOperations() {
\r
754 final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
\r
755 for (Module m : modules) {
\r
756 rpcs.addAll(m.getRpcs());
\r
762 public Set<ExtensionDefinition> getExtensions() {
\r
763 final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
\r
764 for (Module m : modules) {
\r
765 extensions.addAll(m.getExtensionSchemaNodes());
\r
771 private static class TypeConstraints {
\r
772 private final List<RangeConstraint> ranges = new ArrayList<RangeConstraint>();
\r
773 private final List<LengthConstraint> lengths = new ArrayList<LengthConstraint>();
\r
774 private final List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();
\r
775 private Integer fractionDigits;
\r
777 public List<RangeConstraint> getRanges() {
\r
781 public void addRanges(List<RangeConstraint> ranges) {
\r
782 this.ranges.addAll(0, ranges);
\r
785 public List<LengthConstraint> getLengths() {
\r
789 public void addLengths(List<LengthConstraint> lengths) {
\r
790 this.lengths.addAll(0, lengths);
\r
793 public List<PatternConstraint> getPatterns() {
\r
797 public void addPatterns(List<PatternConstraint> patterns) {
\r
798 this.patterns.addAll(0, patterns);
\r
801 public Integer getFractionDigits() {
\r
802 return fractionDigits;
\r
805 public void setFractionDigits(Integer fractionDigits) {
\r
806 if (fractionDigits != null) {
\r
807 this.fractionDigits = fractionDigits;
\r