d7c6711affb740de272f754e76e331561782f8ba
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / yang / model / parser / impl / YangModelParserImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.yang.model.parser.impl;
9
10 import java.io.File;
11 import java.io.FileInputStream;
12 import java.io.IOException;
13 import java.util.ArrayList;
14 import java.util.Calendar;
15 import java.util.Date;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.TreeMap;
22
23 import org.antlr.v4.runtime.ANTLRInputStream;
24 import org.antlr.v4.runtime.CommonTokenStream;
25 import org.antlr.v4.runtime.tree.ParseTree;
26 import org.antlr.v4.runtime.tree.ParseTreeWalker;
27 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
28 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
29 import org.opendaylight.controller.model.api.type.BinaryTypeDefinition;
30 import org.opendaylight.controller.model.api.type.BitsTypeDefinition;
31 import org.opendaylight.controller.model.api.type.BitsTypeDefinition.Bit;
32 import org.opendaylight.controller.model.api.type.DecimalTypeDefinition;
33 import org.opendaylight.controller.model.api.type.InstanceIdentifierTypeDefinition;
34 import org.opendaylight.controller.model.api.type.IntegerTypeDefinition;
35 import org.opendaylight.controller.model.api.type.LengthConstraint;
36 import org.opendaylight.controller.model.api.type.PatternConstraint;
37 import org.opendaylight.controller.model.api.type.RangeConstraint;
38 import org.opendaylight.controller.model.api.type.StringTypeDefinition;
39 import org.opendaylight.controller.model.util.BaseConstraints;
40 import org.opendaylight.controller.model.util.BinaryType;
41 import org.opendaylight.controller.model.util.BitsType;
42 import org.opendaylight.controller.model.util.StringType;
43 import org.opendaylight.controller.model.util.UnknownType;
44 import org.opendaylight.controller.model.util.YangTypesConverter;
45 import org.opendaylight.controller.yang.common.QName;
46 import org.opendaylight.controller.yang.model.api.AugmentationSchema;
47 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
48 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
49 import org.opendaylight.controller.yang.model.api.Module;
50 import org.opendaylight.controller.yang.model.api.ModuleImport;
51 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
52 import org.opendaylight.controller.yang.model.api.RpcDefinition;
53 import org.opendaylight.controller.yang.model.api.SchemaContext;
54 import org.opendaylight.controller.yang.model.api.SchemaPath;
55 import org.opendaylight.controller.yang.model.api.TypeDefinition;
56 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
57 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;
58 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder;
59 import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder;
60 import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;
61 import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;
62 import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;
63 import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 public class YangModelParserImpl implements YangModelParser {
68
69     private static final Logger logger = LoggerFactory
70             .getLogger(YangModelParserImpl.class);
71
72     @Override
73     public Module parseYangModel(String yangFile) {
74         final Map<String, TreeMap<Date, ModuleBuilder>> modules = loadFiles(yangFile);
75         Set<Module> result = build(modules);
76         return result.iterator().next();
77     }
78
79     @Override
80     public Set<Module> parseYangModels(String... yangFiles) {
81         final Map<String, TreeMap<Date, ModuleBuilder>> modules = loadFiles(yangFiles);
82         Set<Module> result = build(modules);
83         return result;
84     }
85
86     @Override
87     public SchemaContext resolveSchemaContext(Set<Module> modules) {
88         return new SchemaContextImpl(modules);
89     }
90
91     private Map<String, TreeMap<Date, ModuleBuilder>> loadFiles(
92             String... yangFiles) {
93         final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
94
95         final YangModelParserListenerImpl yangModelParser = new YangModelParserListenerImpl();
96         final ParseTreeWalker walker = new ParseTreeWalker();
97
98         List<ParseTree> trees = parseFiles(yangFiles);
99
100         ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
101
102         for (int i = 0; i < trees.size(); i++) {
103             walker.walk(yangModelParser, trees.get(i));
104             builders[i] = yangModelParser.getModuleBuilder();
105         }
106
107         for (ModuleBuilder builder : builders) {
108             final String builderName = builder.getName();
109             Date builderRevision = builder.getRevision();
110             if (builderRevision == null) {
111                 builderRevision = createEpochTime();
112             }
113
114             TreeMap<Date, ModuleBuilder> builderByRevision = modules
115                     .get(builderName);
116             if (builderByRevision == null) {
117                 builderByRevision = new TreeMap<Date, ModuleBuilder>();
118             }
119             builderByRevision.put(builderRevision, builder);
120
121             modules.put(builderName, builderByRevision);
122         }
123         return modules;
124     }
125
126     private List<ParseTree> parseFiles(String... yangFileNames) {
127         List<ParseTree> trees = new ArrayList<ParseTree>();
128         for (String fileName : yangFileNames) {
129             trees.add(parseFile(fileName));
130         }
131         return trees;
132     }
133
134     private ParseTree parseFile(String yangFileName) {
135         ParseTree result = null;
136         try {
137             final File yangFile = new File(yangFileName);
138             final FileInputStream inStream = new FileInputStream(yangFile);
139             final ANTLRInputStream input = new ANTLRInputStream(inStream);
140             final YangLexer lexer = new YangLexer(input);
141             final CommonTokenStream tokens = new CommonTokenStream(lexer);
142             final YangParser parser = new YangParser(tokens);
143             result = parser.yang();
144         } catch (IOException e) {
145             logger.warn("Exception while reading yang file: " + yangFileName, e);
146         }
147         return result;
148     }
149
150     private Set<Module> build(Map<String, TreeMap<Date, ModuleBuilder>> modules) {
151         // first validate
152         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
153                 .entrySet()) {
154             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
155                     .entrySet()) {
156                 ModuleBuilder moduleBuilder = childEntry.getValue();
157                 validateBuilder(modules, moduleBuilder);
158             }
159         }
160         // then build
161         final Set<Module> result = new HashSet<Module>();
162         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
163                 .entrySet()) {
164             final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
165             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
166                     .entrySet()) {
167                 ModuleBuilder moduleBuilder = childEntry.getValue();
168                 modulesByRevision.put(childEntry.getKey(),
169                         moduleBuilder.build());
170                 result.add(moduleBuilder.build());
171             }
172         }
173
174         return result;
175     }
176
177     private void validateBuilder(
178             Map<String, TreeMap<Date, ModuleBuilder>> modules,
179             ModuleBuilder builder) {
180         resolveTypedefs(modules, builder);
181         resolveAugments(modules, builder);
182     }
183
184     /**
185      * Search for dirty nodes (node which contains UnknownType) and resolve
186      * unknown types.
187      *
188      * @param modules
189      *            all available modules
190      * @param builder
191      *            current module
192      */
193     private void resolveTypedefs(
194             Map<String, TreeMap<Date, ModuleBuilder>> modules,
195             ModuleBuilder builder) {
196         Map<List<String>, TypeAwareBuilder> dirtyNodes = builder
197                 .getDirtyNodes();
198         if (dirtyNodes.size() == 0) {
199             return;
200         } else {
201             for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
202                     .entrySet()) {
203                 TypeAwareBuilder typeToResolve = entry.getValue();
204                 Map<TypeDefinitionBuilder, TypeConstraints> foundedTypeDefinitionBuilder = findTypeDefinitionBuilderWithConstraints(
205                         modules, entry.getValue(), builder);
206                 TypeDefinitionBuilder targetType = foundedTypeDefinitionBuilder
207                         .entrySet().iterator().next().getKey();
208                 TypeConstraints constraints = foundedTypeDefinitionBuilder
209                         .entrySet().iterator().next().getValue();
210
211                 UnknownType ut = (UnknownType) typeToResolve.getType();
212
213                 // RANGE
214                 List<RangeConstraint> ranges = ut.getRangeStatements();
215                 resolveRanges(ranges, typeToResolve, targetType, modules,
216                         builder);
217
218                 // LENGTH
219                 List<LengthConstraint> lengths = ut.getLengthStatements();
220                 resolveLengths(lengths, typeToResolve, targetType, modules,
221                         builder);
222
223                 // PATTERN
224                 List<PatternConstraint> patterns = ut.getPatterns();
225
226                 // Fraction Digits
227                 Integer fractionDigits = ut.getFractionDigits();
228
229                 TypeDefinition<?> type = targetType.getBaseType();
230                 String typeName = type.getQName().getLocalName();
231
232                 // MERGE CONSTRAINTS (enumeration and leafref omitted because
233                 // they have no restrictions)
234                 if (type instanceof DecimalTypeDefinition) {
235                     List<RangeConstraint> fullRanges = new ArrayList<RangeConstraint>();
236                     fullRanges.addAll(constraints.getRanges());
237                     fullRanges.addAll(ranges);
238                     Integer fd = fractionDigits == null ? constraints
239                             .getFractionDigits() : fractionDigits;
240                     type = YangTypesConverter.javaTypeForBaseYangDecimal64Type(
241                             fullRanges, fd);
242                 } else if (type instanceof IntegerTypeDefinition) {
243                     List<RangeConstraint> fullRanges = new ArrayList<RangeConstraint>();
244                     fullRanges.addAll(constraints.getRanges());
245                     fullRanges.addAll(ranges);
246                     if (typeName.startsWith("int")) {
247                         type = YangTypesConverter
248                                 .javaTypeForBaseYangSignedIntegerType(typeName,
249                                         fullRanges);
250                     } else {
251                         type = YangTypesConverter
252                                 .javaTypeForBaseYangUnsignedIntegerType(
253                                         typeName, fullRanges);
254                     }
255                 } else if (type instanceof StringTypeDefinition) {
256                     List<LengthConstraint> fullLengths = new ArrayList<LengthConstraint>();
257                     fullLengths.addAll(constraints.getLengths());
258                     fullLengths.addAll(lengths);
259                     List<PatternConstraint> fullPatterns = new ArrayList<PatternConstraint>();
260                     fullPatterns.addAll(constraints.getPatterns());
261                     fullPatterns.addAll(patterns);
262                     type = new StringType(fullLengths, fullPatterns);
263                 } else if (type instanceof BitsTypeDefinition) {
264                     // TODO: add 'length' restriction to BitsType
265                     BitsTypeDefinition bitsType = (BitsTypeDefinition) type;
266                     List<Bit> bits = bitsType.getBits();
267                     type = new BitsType(bits);
268                 } else if (type instanceof BinaryTypeDefinition) {
269                     type = new BinaryType(null, lengths, null);
270                 } else if (typeName.equals("instance-identifier")) {
271                     // TODO: instance-identifier
272                     /*
273                      * boolean requireInstance = isRequireInstance(typeBody);
274                      * type = new InstanceIdentifier(null, requireInstance);
275                      */
276                 }
277                 typeToResolve.setType(type);
278             }
279         }
280     }
281
282     private TypeDefinitionBuilder findTypeDefinitionBuilder(
283             Map<String, TreeMap<Date, ModuleBuilder>> modules,
284             TypeAwareBuilder typeBuilder, ModuleBuilder builder) {
285         Map<TypeDefinitionBuilder, TypeConstraints> result = findTypeDefinitionBuilderWithConstraints(
286                 modules, typeBuilder, builder);
287         return result.entrySet().iterator().next().getKey();
288     }
289
290     private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(
291             Map<String, TreeMap<Date, ModuleBuilder>> modules,
292             TypeAwareBuilder typeBuilder, ModuleBuilder builder) {
293         return findTypeDefinitionBuilderWithConstraints(new TypeConstraints(),
294                 modules, typeBuilder, builder);
295     }
296
297     /**
298      * Traverse through all referenced types chain until base YANG type is
299      * founded.
300      *
301      * @param constraints
302      *            current type constraints
303      * @param modules
304      *            all available modules
305      * @param typeBuilder
306      *            type builder which contains type
307      * @param builder
308      *            current module
309      * @return map, where key is type referenced and value is its constraints
310      */
311     private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(
312             TypeConstraints constraints,
313             Map<String, TreeMap<Date, ModuleBuilder>> modules,
314             TypeAwareBuilder typeBuilder, ModuleBuilder builder) {
315         Map<TypeDefinitionBuilder, TypeConstraints> result = new HashMap<TypeDefinitionBuilder, TypeConstraints>();
316
317         UnknownType type = (UnknownType) typeBuilder.getType();
318         QName typeQName = type.getQName();
319         String typeName = type.getQName().getLocalName();
320         String prefix = typeQName.getPrefix();
321
322         // search for module which contains referenced typedef
323         ModuleBuilder dependentModuleBuilder;
324         if (prefix.equals(builder.getPrefix())) {
325             dependentModuleBuilder = builder;
326         } else {
327             ModuleImport dependentModuleImport = getModuleImport(builder,
328                     prefix);
329             String dependentModuleName = dependentModuleImport.getModuleName();
330             Date dependentModuleRevision = dependentModuleImport.getRevision();
331             TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
332                     .get(dependentModuleName);
333             if (dependentModuleRevision == null) {
334                 dependentModuleBuilder = moduleBuildersByRevision.lastEntry()
335                         .getValue();
336             } else {
337                 dependentModuleBuilder = moduleBuildersByRevision
338                         .get(dependentModuleRevision);
339             }
340         }
341
342         // pull all typedef statements from dependent module...
343         final Set<TypeDefinitionBuilder> typedefs = dependentModuleBuilder
344                 .getModuleTypedefs();
345         // and search for referenced typedef
346         TypeDefinitionBuilder lookedUpBuilder = null;
347         for (TypeDefinitionBuilder tdb : typedefs) {
348             QName qname = tdb.getQName();
349             if (qname.getLocalName().equals(typeName)) {
350                 lookedUpBuilder = tdb;
351                 break;
352             }
353         }
354
355         // if referenced type is UnknownType again, search recursively with
356         // current constraints
357         TypeDefinition<?> referencedType = lookedUpBuilder.getBaseType();
358         if (referencedType instanceof UnknownType) {
359             UnknownType unknown = (UnknownType) lookedUpBuilder.getBaseType();
360
361             final List<RangeConstraint> ranges = unknown.getRangeStatements();
362             constraints.addRanges(ranges);
363             final List<LengthConstraint> lengths = unknown
364                     .getLengthStatements();
365             constraints.addLengths(lengths);
366             final List<PatternConstraint> patterns = unknown.getPatterns();
367             constraints.addPatterns(patterns);
368             return findTypeDefinitionBuilderWithConstraints(constraints,
369                     modules, (TypeAwareBuilder) lookedUpBuilder,
370                     dependentModuleBuilder);
371         } else {
372             // pull restriction from this base type and add them to
373             // 'constraints'
374             if (referencedType instanceof DecimalTypeDefinition) {
375                 constraints.addRanges(((DecimalTypeDefinition) referencedType)
376                         .getRangeStatements());
377                 constraints
378                         .setFractionDigits(((DecimalTypeDefinition) referencedType)
379                                 .getFractionDigits());
380             } else if (referencedType instanceof IntegerTypeDefinition) {
381                 constraints.addRanges(((IntegerTypeDefinition) referencedType)
382                         .getRangeStatements());
383             } else if (referencedType instanceof StringTypeDefinition) {
384                 constraints.addPatterns(((StringTypeDefinition) referencedType)
385                         .getPatterns());
386             } else if (referencedType instanceof BitsTypeDefinition) {
387                 // TODO: add 'length' restriction to BitsType
388             } else if (referencedType instanceof BinaryTypeDefinition) {
389                 // TODO
390             } else if (referencedType instanceof InstanceIdentifierTypeDefinition) {
391                 // TODO: instance-identifier
392             }
393
394             result.put(lookedUpBuilder, constraints);
395             // return lookedUpBuilder;
396             return result;
397         }
398     }
399
400     /**
401      * Go through all augmentation definitions and resolve them. This means find
402      * referenced node and add child nodes to it.
403      *
404      * @param modules
405      *            all available modules
406      * @param builder
407      *            current module
408      */
409     private void resolveAugments(
410             Map<String, TreeMap<Date, ModuleBuilder>> modules,
411             ModuleBuilder builder) {
412         Set<AugmentationSchemaBuilder> augmentBuilders = builder
413                 .getAddedAugments();
414
415         Set<AugmentationSchema> augments = new HashSet<AugmentationSchema>();
416         for (AugmentationSchemaBuilder augmentBuilder : augmentBuilders) {
417             SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
418             String prefix = null;
419             List<String> augmentTargetPath = new ArrayList<String>();
420             for (QName pathPart : augmentTargetSchemaPath.getPath()) {
421                 prefix = pathPart.getPrefix();
422                 augmentTargetPath.add(pathPart.getLocalName());
423             }
424             ModuleImport dependentModuleImport = getModuleImport(builder,
425                     prefix);
426             String dependentModuleName = dependentModuleImport.getModuleName();
427             augmentTargetPath.add(0, dependentModuleName);
428
429             Date dependentModuleRevision = dependentModuleImport.getRevision();
430
431             TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
432                     .get(dependentModuleName);
433             ModuleBuilder dependentModule;
434             if (dependentModuleRevision == null) {
435                 dependentModule = moduleBuildersByRevision.lastEntry()
436                         .getValue();
437             } else {
438                 dependentModule = moduleBuildersByRevision
439                         .get(dependentModuleRevision);
440             }
441
442             AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule
443                     .getNode(augmentTargetPath);
444             AugmentationSchema result = augmentBuilder.build();
445             augmentTarget.addAugmentation(result);
446             fillAugmentTarget(augmentBuilder, (ChildNodeBuilder) augmentTarget);
447             augments.add(result);
448         }
449         builder.setAugmentations(augments);
450     }
451
452     /**
453      * Add all augment's child nodes to given target.
454      *
455      * @param augment
456      * @param target
457      */
458     private void fillAugmentTarget(AugmentationSchemaBuilder augment,
459             ChildNodeBuilder target) {
460         for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
461             builder.setAugmenting(true);
462             target.addChildNode(builder);
463         }
464     }
465
466     /**
467      * Get module import referenced by given prefix.
468      *
469      * @param builder
470      *            module to search
471      * @param prefix
472      *            prefix associated with import
473      * @return ModuleImport based on given prefix
474      */
475     private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {
476         ModuleImport moduleImport = null;
477         for (ModuleImport mi : builder.getModuleImports()) {
478             if (mi.getPrefix().equals(prefix)) {
479                 moduleImport = mi;
480                 break;
481             }
482         }
483         return moduleImport;
484     }
485
486     /**
487      * Helper method for resolving special 'min' or 'max' values in range
488      * constraint
489      *
490      * @param ranges
491      *            ranges to resolve
492      * @param typeToResolve
493      *            type to resolve
494      * @param targetType
495      *            target type
496      * @param modules
497      *            all available modules
498      * @param builder
499      *            current module
500      */
501     private void resolveRanges(List<RangeConstraint> ranges,
502             TypeAwareBuilder typeToResolve, TypeDefinitionBuilder targetType,
503             Map<String, TreeMap<Date, ModuleBuilder>> modules,
504             ModuleBuilder builder) {
505         if (ranges != null && ranges.size() > 0) {
506             Long min = (Long) ranges.get(0).getMin();
507             Long max = (Long) ranges.get(ranges.size() - 1).getMax();
508             // if range contains one of the special values 'min' or 'max'
509             if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) {
510                 Long[] values = parseRangeConstraint(typeToResolve, targetType,
511                         modules, builder);
512                 if (min.equals(Long.MIN_VALUE)) {
513                     min = values[0];
514                     RangeConstraint oldFirst = ranges.get(0);
515                     RangeConstraint newFirst = BaseConstraints.rangeConstraint(
516                             min, oldFirst.getMax(), oldFirst.getDescription(),
517                             oldFirst.getReference());
518                     ranges.set(0, newFirst);
519                 }
520                 if (max.equals(Long.MAX_VALUE)) {
521                     max = values[1];
522                     RangeConstraint oldLast = ranges.get(ranges.size() - 1);
523                     RangeConstraint newLast = BaseConstraints.rangeConstraint(
524                             oldLast.getMin(), max, oldLast.getDescription(),
525                             oldLast.getReference());
526                     ranges.set(ranges.size() - 1, newLast);
527                 }
528             }
529         }
530     }
531
532     /**
533      * Helper method for resolving special 'min' or 'max' values in length
534      * constraint
535      *
536      * @param ranges
537      *            ranges to resolve
538      * @param typeToResolve
539      *            type to resolve
540      * @param targetType
541      *            target type
542      * @param modules
543      *            all available modules
544      * @param builder
545      *            current module
546      */
547     private void resolveLengths(List<LengthConstraint> lengths,
548             TypeAwareBuilder typeToResolve, TypeDefinitionBuilder targetType,
549             Map<String, TreeMap<Date, ModuleBuilder>> modules,
550             ModuleBuilder builder) {
551         if (lengths != null && lengths.size() > 0) {
552             Long min = lengths.get(0).getMin();
553             Long max = lengths.get(lengths.size() - 1).getMax();
554             // if length contains one of the special values 'min' or 'max'
555             if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) {
556                 Long[] values = parseRangeConstraint(typeToResolve, targetType,
557                         modules, builder);
558                 if (min.equals(Long.MIN_VALUE)) {
559                     min = values[0];
560                     LengthConstraint oldFirst = lengths.get(0);
561                     LengthConstraint newFirst = BaseConstraints
562                             .lengthConstraint(min, oldFirst.getMax(),
563                                     oldFirst.getDescription(),
564                                     oldFirst.getReference());
565                     lengths.set(0, newFirst);
566                 }
567                 if (max.equals(Long.MAX_VALUE)) {
568                     max = values[1];
569                     LengthConstraint oldLast = lengths.get(lengths.size() - 1);
570                     LengthConstraint newLast = BaseConstraints
571                             .lengthConstraint(oldLast.getMin(), max,
572                                     oldLast.getDescription(),
573                                     oldLast.getReference());
574                     lengths.set(lengths.size() - 1, newLast);
575                 }
576             }
577         }
578     }
579
580     private Long[] parseRangeConstraint(TypeAwareBuilder typeToResolve,
581             TypeDefinitionBuilder targetType,
582             Map<String, TreeMap<Date, ModuleBuilder>> modules,
583             ModuleBuilder builder) {
584         TypeDefinition<?> targetBaseType = targetType.getBaseType();
585
586         if (targetBaseType instanceof IntegerTypeDefinition) {
587             IntegerTypeDefinition itd = (IntegerTypeDefinition) targetBaseType;
588             List<RangeConstraint> ranges = itd.getRangeStatements();
589             Long min = (Long) ranges.get(0).getMin();
590             Long max = (Long) ranges.get(ranges.size() - 1).getMax();
591             return new Long[] { min, max };
592         } else if (targetBaseType instanceof DecimalTypeDefinition) {
593             DecimalTypeDefinition dtd = (DecimalTypeDefinition) targetBaseType;
594             List<RangeConstraint> ranges = dtd.getRangeStatements();
595             Long min = (Long) ranges.get(0).getMin();
596             Long max = (Long) ranges.get(ranges.size() - 1).getMax();
597             return new Long[] { min, max };
598         } else {
599             return parseRangeConstraint(typeToResolve,
600                     findTypeDefinitionBuilder(modules, typeToResolve, builder),
601                     modules, builder);
602         }
603     }
604
605     private Date createEpochTime() {
606         Calendar c = Calendar.getInstance();
607         c.setTimeInMillis(0);
608         return c.getTime();
609     }
610
611     private static class SchemaContextImpl implements SchemaContext {
612         private final Set<Module> modules;
613
614         private SchemaContextImpl(Set<Module> modules) {
615             this.modules = modules;
616         }
617
618         @Override
619         public Set<DataSchemaNode> getDataDefinitions() {
620             final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
621             for (Module m : modules) {
622                 dataDefs.addAll(m.getChildNodes());
623             }
624             return dataDefs;
625         }
626
627         @Override
628         public Set<Module> getModules() {
629             return modules;
630         }
631
632         @Override
633         public Set<NotificationDefinition> getNotifications() {
634             final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
635             for (Module m : modules) {
636                 notifications.addAll(m.getNotifications());
637             }
638             return notifications;
639         }
640
641         @Override
642         public Set<RpcDefinition> getOperations() {
643             final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
644             for (Module m : modules) {
645                 rpcs.addAll(m.getRpcs());
646             }
647             return rpcs;
648         }
649
650         @Override
651         public Set<ExtensionDefinition> getExtensions() {
652             final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
653             for (Module m : modules) {
654                 extensions.addAll(m.getExtensionSchemaNodes());
655             }
656             return extensions;
657         }
658     }
659
660     private static class TypeConstraints {
661         private final List<RangeConstraint> ranges = new ArrayList<RangeConstraint>();
662         private final List<LengthConstraint> lengths = new ArrayList<LengthConstraint>();
663         private final List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();
664         private Integer fractionDigits;
665
666         public List<RangeConstraint> getRanges() {
667             return ranges;
668         }
669
670         public void addRanges(List<RangeConstraint> ranges) {
671             this.ranges.addAll(0, ranges);
672         }
673
674         public List<LengthConstraint> getLengths() {
675             return lengths;
676         }
677
678         public void addLengths(List<LengthConstraint> lengths) {
679             this.lengths.addAll(0, lengths);
680         }
681
682         public List<PatternConstraint> getPatterns() {
683             return patterns;
684         }
685
686         public void addPatterns(List<PatternConstraint> patterns) {
687             this.patterns.addAll(0, patterns);
688         }
689
690         public Integer getFractionDigits() {
691             return fractionDigits;
692         }
693
694         public void setFractionDigits(Integer fractionDigits) {
695             if (fractionDigits != null) {
696                 this.fractionDigits = fractionDigits;
697             }
698         }
699     }
700
701 }