Added initial version of documentation generator.
authorMartin Vitez <mvitez@cisco.com>
Thu, 14 Nov 2013 16:40:15 +0000 (17:40 +0100)
committerMartin Vitez <mvitez@cisco.com>
Thu, 14 Nov 2013 16:40:15 +0000 (17:40 +0100)
Fixed bug in code generator imports.

Signed-off-by: Martin Vitez <mvitez@cisco.com>
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/ClassTemplate.xtend
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/GeneratorUtil.java
code-generator/maven-sal-api-gen-plugin/pom.xml
code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend [new file with mode: 0644]
code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/DocumentationGeneratorImpl.java [new file with mode: 0644]
code-generator/maven-sal-api-gen-plugin/src/test/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/DocGenTest.java [new file with mode: 0644]
code-generator/maven-sal-api-gen-plugin/src/test/resources/doc-gen/network-topology@2013-07-12.yang [new file with mode: 0644]
model/ietf/ietf-topology/pom.xml

index 458b8114e0cba8a59eb790fd8129f1a2147a21a8..d02d34a3ee733d6e52fc73c8a256c30fcde4694f 100644 (file)
@@ -11,6 +11,7 @@ import java.util.ArrayList
 import java.util.Collections\rimport java.util.Arrays
 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
 import com.google.common.collect.Range
+import java.util.regex.Pattern
 
 /**\r
  * Template for generating JAVA class. \r
@@ -269,8 +270,8 @@ class ClassTemplate extends BaseTemplate {
                     «val cValue = c.value»\r
                     «IF cValue instanceof List<?>»\r
                         «val cValues = cValue as List<?>»\r
-                        private static final List<Pattern> «Constants.MEMBER_PATTERN_LIST» = new ArrayList<Pattern>();\r
-                        public static final List<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «Arrays.importedName».asList(«\r
+                        private static final «List.importedName»<«Pattern.importedName»> «Constants.MEMBER_PATTERN_LIST» = new «ArrayList.importedName»<«Pattern.importedName»>();\r
+                        public static final «List.importedName»<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «Arrays.importedName».asList(«\r
                         FOR v : cValues SEPARATOR ", "»«\r
                             IF v instanceof String»"«\r
                                 v as String»"«\r
index 9db1ce8540293d662798ab4517ab94b11ab2f7e1..da285e37bec39d80c12000d68d4821e367198ee2 100644 (file)
@@ -60,17 +60,6 @@ public final class GeneratorUtil {
             }
         }
 
-        final List<Constant> constants = genType.getConstantDefinitions();
-        final List<MethodSignature> methods = genType.getMethodDefinitions();
-
-        // CONSTANTS
-        if (constants != null) {
-            for (final Constant constant : constants) {
-                final Type constantType = constant.getType();
-                putTypeIntoImports(genType, constantType, imports);
-            }
-        }
-
         // REGULAR EXPRESSION
         if (genType instanceof GeneratedTransferObject
                 && isConstantInTO(TypeConstants.PATTERN_CONSTANT_NAME, (GeneratedTransferObject) genType)) {
@@ -79,6 +68,7 @@ public final class GeneratorUtil {
             putTypeIntoImports(genType, Types.typeForClass(java.util.ArrayList.class), imports);
         }
 
+        final List<MethodSignature> methods = genType.getMethodDefinitions();
         // METHODS
         if (methods != null) {
             for (final MethodSignature method : methods) {
index 0fa60578607a3b086cc5dfeac658d87aca57dacc..97fe5d27347e6cbf8a9c0152a8d2c33d20b33298 100644 (file)
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>binding-java-api-generator</artifactId>
         </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
                     </instructions>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.eclipse.xtend</groupId>
+                <artifactId>xtend-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <artifactId>maven-clean-plugin</artifactId>
+            </plugin>
         </plugins>
     </build>
 
diff --git a/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend b/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend
new file mode 100644 (file)
index 0000000..965fd75
--- /dev/null
@@ -0,0 +1,507 @@
+package org.opendaylight.yangtools.yang.unified.doc.generator
+
+import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import java.io.File
+import java.util.Set
+import org.opendaylight.yangtools.yang.model.api.Module
+import java.io.IOException
+import java.util.HashSet
+import java.io.FileWriter
+import java.io.BufferedWriter
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition
+import org.opendaylight.yangtools.yang.model.api.SchemaNode
+import org.opendaylight.yangtools.yang.model.util.ExtendedType
+import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition
+import java.text.SimpleDateFormat
+import java.util.Collection
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint
+import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint
+import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition
+import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
+import org.slf4j.LoggerFactory
+import org.slf4j.Logger
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
+import java.util.List
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
+
+class GeneratorImpl {
+
+    File path
+    static val REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")
+    static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl)
+
+
+    def generate(SchemaContext context, File targetPath, Set<Module> modulesToGen) throws IOException {
+        path = targetPath;
+        path.mkdirs();
+        val it = new HashSet;
+        for (module : modulesToGen) {
+            add(module.generateDocumentation());
+        }
+        return it;
+    }
+
+    def generateDocumentation(Module module) {
+        val destination = new File(path, '''«module.name».html''')
+        try {
+            val fw = new FileWriter(destination)
+            destination.createNewFile();
+            val bw = new BufferedWriter(fw)
+
+            bw.append(module.generate);
+            bw.close();
+            fw.close();
+        } catch (IOException e) {
+            LOG.error(e.getMessage());
+        }
+        return destination;
+    }
+
+    def generate(Module module) '''
+        <!DOCTYPE html>
+        <html lang="en">
+          <head>
+            <title>«module.name»</title>
+          </head>
+          <body>
+            «module.body»
+          </body>
+        </html>
+    '''
+
+    def body(Module module) '''
+        «header(module)»
+
+        «typeDefinitions(module)»
+
+        «groupings(module)»
+
+        «dataStore(module)»
+
+        «notifications(module)»
+
+        «augmentations(module)»
+
+        «rpcs(module)»
+
+        «extensions(module)»
+
+    '''
+
+
+    def typeDefinitions(Module module) {
+        val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
+        if (typedefs.empty) {
+            return '';
+        }
+        return '''
+            <h2>Type Definitions</h2>
+            «list(typedefs)»
+
+            «FOR typedef : typedefs»
+            «typeDefinition(typedef)»
+            «ENDFOR»
+        '''
+    }
+
+    private def CharSequence typeDefinition(TypeDefinition<?> type) '''
+        «header(type)»
+        «body(type)»
+        «restrictions(type)»
+    '''
+
+    def groupings(Module module) {
+        if (module.groupings.empty) {
+            return '';
+        }
+        return '''
+            <h2>Groupings</h2>
+            «list(module.groupings)»
+
+            «FOR grouping : module.groupings»
+            «headerAndBody(grouping)»
+            «ENDFOR»
+        '''
+    }
+
+    def dataStore(Module module) {
+        if (module.childNodes.empty) {
+            return '';
+        }
+        return '''
+            <h2>Datastore Structure</h2>
+            «tree(module)»
+        '''
+    }
+
+    def augmentations(Module module) {
+        if (module.augmentations.empty) {
+            return '';
+        }
+        return '''
+            <h2>Augmentations</h2>
+
+            <ul>
+            «FOR augment : module.augmentations»
+                <li>
+                    augment
+                    «augment.tree»
+                </li>
+            «ENDFOR»
+            </ul>
+        '''
+    }
+
+    def notifications(Module module) {
+        val Set<NotificationDefinition> notificationdefs = module.notifications
+        if (notificationdefs.empty) {
+            return '';
+        }
+        return '''
+            <h2>Notifications</h2>
+
+            <ul>
+            «FOR notificationdef : notificationdefs»
+                <li>
+                    «notificationdef.nodeName»
+                    «notificationdef.tree»
+                </li>
+            «ENDFOR»
+            </ul>
+        '''
+    }
+
+    def rpcs(Module module) {
+        if (module.rpcs.empty) {
+            return '';
+        }
+        return '''
+            <h2>RPC Definitions</h2>
+
+            <ul>
+            «FOR rpc : module.rpcs»
+                <li>
+                    «rpc.nodeName»
+                    «rpc.tree»
+                </li>
+            «ENDFOR»
+            </ul>
+        '''
+    }
+
+    def extensions(Module module) {
+        if (module.extensionSchemaNodes.empty) {
+            return '';
+        }
+        return '''
+            <h2>Extensions</h2>
+
+            <ul>
+            «FOR ext : module.extensionSchemaNodes»
+                <li>
+                    «ext.nodeName»
+                    «ext.tree»
+                </li>
+            «ENDFOR»
+            </ul>
+        '''
+    }
+
+    def CharSequence headerAndBody(SchemaNode node) '''
+        «header(node)»
+        «body(node)»
+    '''
+
+    def header(SchemaNode type) '''
+        <h3>«type.QName.localName»</h3>
+    '''
+
+    def body(SchemaNode definition) '''
+
+        «paragraphs(definition.description)»
+
+        «definition.reference»
+    '''
+
+
+    def list(Set<? extends SchemaNode> definitions) '''
+        <ul>
+        «FOR nodeDef : definitions» 
+            <li>«nodeDef.QName.localName»</li>
+        «ENDFOR»
+        </ul>
+    '''
+
+    def header(Module module) '''
+        <h1>«module.name»</h1>
+        
+        <h2>Base Information</h2>
+        <dl>
+            <dt>Prefix</dt>
+            <dd><pre>«module.prefix»</pre></dd>
+            <dt>Namespace</dt>
+            <dd><pre>«module.namespace»</pre></dd>
+            <dt>Revision</dt>
+            <dd>«REVISION_FORMAT.format(module.revision)»</dd>
+            
+            «FOR imp : module.imports BEFORE "<dt>Imports</dt>" »
+                <dd>«pre(imp.prefix)» = «pre(imp.moduleName)»</dd>
+            «ENDFOR»
+        </dl>
+    '''
+
+
+    def process(Module module) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+
+
+
+    /* #################### TREE STRUCTURE #################### */
+    def dispatch CharSequence tree(Module module) '''
+        «strong("module " + module.name)»
+        «module.childNodes.childrenToTree»
+    '''
+
+    def dispatch CharSequence tree(DataNodeContainer node) '''
+        «IF node instanceof SchemaNode»
+            «(node as SchemaNode).nodeName»
+        «ENDIF»
+        «node.childNodes.childrenToTree»
+    '''
+
+    def dispatch CharSequence tree(DataSchemaNode node) '''
+        «node.nodeName»
+    '''
+
+    def dispatch CharSequence tree(ListSchemaNode node) '''
+        «node.nodeName»
+        «node.childNodes.childrenToTree»
+    '''
+
+    private def CharSequence childrenToTree(Collection<DataSchemaNode> childNodes) '''
+        «IF childNodes !== null && !childNodes.empty»
+            <ul>
+            «FOR child : childNodes»
+                <li>
+                    «child.tree»
+                </li>
+            «ENDFOR»
+            </ul>
+        «ENDIF»
+    '''
+
+    def listKeys(ListSchemaNode node) '''
+        [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]
+    '''
+
+    def dispatch CharSequence tree(AugmentationSchema augment) '''
+        <ul>
+            «listItem("Description", augment.description)»
+            «listItem("Reference", augment.reference)»
+            «IF augment.whenCondition !== null»
+                «listItem("When", augment.whenCondition.toString)»
+            «ENDIF»
+            <li>
+                Path «augment.targetPath.path.pathToTree»
+            </li>
+            <li>
+                Child nodes
+                «augment.childNodes.childrenToTree»
+            </li>
+        </ul>
+    '''
+
+    private def CharSequence pathToTree(List<QName> path) '''
+        «IF path !== null && !path.empty»
+            <ul>
+            «FOR pathElement : path»
+                <li>
+                    «pathElement.namespace» «pathElement.localName»
+                </li>
+            «ENDFOR»
+            </ul>
+        «ENDIF»
+    '''
+
+    def dispatch CharSequence tree(NotificationDefinition notification) '''
+        <ul>
+            «listItem("Description", notification.description)»
+            «listItem("Reference", notification.reference)»
+            <li>
+                Child nodes
+                «notification.childNodes.childrenToTree»
+            </li>
+        </ul>
+    '''
+
+    def dispatch CharSequence tree(RpcDefinition rpc) '''
+        <ul>
+            «listItem("Description", rpc.description)»
+            «listItem("Reference", rpc.reference)»
+            <li>
+                «rpc.input.tree»
+            </li>
+            <li>
+                «rpc.output.tree»
+            </li>
+        </ul>
+    '''
+
+    def dispatch CharSequence tree(ExtensionDefinition ext) '''
+        <ul>
+            «listItem("Description", ext.description)»
+            «listItem("Reference", ext.reference)»
+            «listItem("Argument", ext.argument)»
+        </ul>
+    '''
+
+
+    /* #################### RESTRICTIONS #################### */
+    private def restrictions(TypeDefinition<?> type) '''
+        «type.toLength»
+        «type.toRange»
+    '''
+
+    def dispatch toLength(TypeDefinition<?> type) {
+    }
+
+    def dispatch toLength(BinaryTypeDefinition type) '''
+        «type.lengthConstraints.toLengthStmt»
+    '''
+
+    def dispatch toLength(StringTypeDefinition type) '''
+        «type.lengthConstraints.toLengthStmt»
+    '''
+
+    def dispatch toLength(ExtendedType type) '''
+        «type.lengthConstraints.toLengthStmt»
+    '''
+
+    def dispatch toRange(TypeDefinition<?> type) {
+    }
+
+    def dispatch toRange(DecimalTypeDefinition type) '''
+        «type.rangeConstraints.toRangeStmt»
+    '''
+
+    def dispatch toRange(IntegerTypeDefinition type) '''
+        «type.rangeConstraints.toRangeStmt»
+    '''
+
+    def dispatch toRange(UnsignedIntegerTypeDefinition type) '''
+        «type.rangeConstraints.toRangeStmt»
+    '''
+
+    def dispatch toRange(ExtendedType type) '''
+        «type.rangeConstraints.toRangeStmt»
+    '''
+
+    def toLengthStmt(Collection<LengthConstraint> lengths) '''
+        «IF lengths != null && !lengths.empty»
+            «strong("Length restrictions")»
+            <ul>
+            «FOR length : lengths»
+                <li>
+                «IF length.min == length.max»
+                    «length.min»
+                «ELSE»
+                    &lt;«length.min», «length.max»&gt;
+                «ENDIF»
+                </li>
+            «ENDFOR»
+            </ul>
+        «ENDIF»
+    '''
+
+    def toRangeStmt(Collection<RangeConstraint> ranges) '''
+        «IF ranges != null && !ranges.empty»
+            «strong("Range restrictions")»
+            <ul>
+            «FOR range : ranges»
+                <li>
+                «IF range.min == range.max»
+                    «range.min»
+                «ELSE»
+                    &lt;«range.min», «range.max»&gt;
+                «ENDIF»
+                </li>
+            «ENDFOR»
+            </ul>
+        «ENDIF»
+    '''
+
+
+
+    /* #################### UTILITY #################### */
+    def strong(String str) '''
+        <strong>«str»</strong>
+    '''
+
+    def italic(String str) '''
+        <i>«str»</i>
+    '''
+
+    def pre(String string) '''<pre>«string»</pre>'''
+
+    def paragraphs(String body) '''
+        <p>«body»</p>
+    '''
+
+    def listItem(String name, String value) '''
+        «IF value !== null && !value.empty»
+            <li>
+                «name»
+                <ul>
+                    <li>
+                        «value»
+                    </li>
+                </ul>
+            </li>
+        «ENDIF»
+    '''
+
+    def dispatch addedByInfo(SchemaNode node) '''
+    '''
+
+    def dispatch addedByInfo(DataSchemaNode node) '''
+        «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»
+    '''
+
+    def dispatch isAddedBy(SchemaNode node) {
+        return false;
+    }
+
+    def dispatch isAddedBy(DataSchemaNode node) {
+        if (node.augmenting || node.addedByUses) {
+            return true
+        } else {
+            return false;
+        }
+    }
+
+    def nodeName(SchemaNode node) '''
+        «IF node.isAddedBy»
+            «italic(node.QName.localName)»«node.addedByInfo»
+        «ELSE»
+            «strong(node.QName.localName)»«node.addedByInfo»
+        «ENDIF»
+    '''
+
+    def nodeName(ListSchemaNode node) '''
+        «IF node.isAddedBy»
+            «italic(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»
+        «ELSE»
+            «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»
+        «ENDIF»
+    '''
+
+}
diff --git a/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/DocumentationGeneratorImpl.java b/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/DocumentationGeneratorImpl.java
new file mode 100644 (file)
index 0000000..39a1d0b
--- /dev/null
@@ -0,0 +1,46 @@
+package org.opendaylight.yangtools.yang.unified.doc.generator.maven;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.unified.doc.generator.GeneratorImpl;
+import org.opendaylight.yangtools.yang2sources.spi.CodeGenerator;
+
+public class DocumentationGeneratorImpl extends GeneratorImpl implements CodeGenerator {
+
+    @Override
+    public Collection<File> generateSources(SchemaContext arg0, File arg1, Set<Module> arg2) throws IOException {
+        // TODO Auto-generated method stub
+         generate(arg0, arg1, arg2);
+         return Collections.emptySet();
+    }
+
+    @Override
+    public void setLog(Log log) {
+        // use maven logging if necessary
+
+    }
+
+    @Override
+    public void setAdditionalConfig(Map<String, String> additionalConfiguration) {
+        // no additional config utilized
+    }
+
+    @Override
+    public void setResourceBaseDir(File resourceBaseDir) {
+        // no resource processing necessary
+    }
+
+    @Override
+    public void setMavenProject(MavenProject project) {
+        // no additional information needed
+    }
+}
diff --git a/code-generator/maven-sal-api-gen-plugin/src/test/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/DocGenTest.java b/code-generator/maven-sal-api-gen-plugin/src/test/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/DocGenTest.java
new file mode 100644 (file)
index 0000000..59290bf
--- /dev/null
@@ -0,0 +1,94 @@
+package org.opendaylight.yangtools.yang.unified.doc.generator.maven;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.sal.binding.generator.api.BindingGenerator;
+import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.opendaylight.yangtools.yang2sources.spi.CodeGenerator;
+
+public class DocGenTest {
+
+    public static final String FS = File.separator;
+    static final String BASE_PKG = "org.opendaylight.yang.gen.v1";
+
+    static final String TEST_PATH = "target" + FS + "test";
+    static final File TEST_DIR = new File(TEST_PATH);
+
+    static final File GENERATOR_OUTPUT_DIR = new File(TEST_PATH);
+    static final String COMPILER_OUTPUT_PATH = TEST_PATH + FS + "bin";
+    static final File COMPILER_OUTPUT_DIR = new File(COMPILER_OUTPUT_PATH);
+
+
+    protected YangParserImpl parser;
+    protected BindingGenerator bindingGenerator;
+
+    @BeforeClass
+    public static void createTestDirs() {
+        if (TEST_DIR.exists()) {
+            deleteTestDir(TEST_DIR);
+        }
+        assertTrue(GENERATOR_OUTPUT_DIR.mkdirs());
+        assertTrue(COMPILER_OUTPUT_DIR.mkdirs());
+    }
+
+    @Before
+    public void init() {
+        parser = new YangParserImpl();
+        bindingGenerator = new BindingGeneratorImpl();
+    }
+
+    @Test
+    public void testListGeneration() throws Exception {
+        final List<File> sourceFiles = getSourceFiles("/doc-gen");
+        final Set<Module> modulesToBuild = parser.parseYangModels(sourceFiles);
+        final SchemaContext context = parser.resolveSchemaContext(modulesToBuild);
+        final CodeGenerator generator = new DocumentationGeneratorImpl();
+        generator.generateSources(context, GENERATOR_OUTPUT_DIR, modulesToBuild);
+
+
+    }
+
+    static List<File> getSourceFiles(String path) throws FileNotFoundException {
+        final String resPath = DocGenTest.class.getResource(path).getPath();
+        final File sourcesDir = new File(resPath);
+        if (sourcesDir.exists()) {
+            final List<File> sourceFiles = new ArrayList<>();
+            final File[] fileArray = sourcesDir.listFiles();
+            if (fileArray == null) {
+                throw new IllegalArgumentException("Unable to locate files in " + sourcesDir);
+            }
+            sourceFiles.addAll(Arrays.asList(fileArray));
+            return sourceFiles;
+        } else {
+            throw new FileNotFoundException("Testing files were not found(" + sourcesDir.getName() + ")");
+        }
+    }
+
+
+    static void deleteTestDir(File file) {
+        if (file.isDirectory()) {
+            File[] filesToDelete = file.listFiles();
+            if (filesToDelete != null) {
+                for (File f : filesToDelete) {
+                    deleteTestDir(f);
+                }
+            }
+        }
+        if (!file.delete()) {
+            throw new RuntimeException("Failed to clean up after test");
+        }
+    }
+}
diff --git a/code-generator/maven-sal-api-gen-plugin/src/test/resources/doc-gen/network-topology@2013-07-12.yang b/code-generator/maven-sal-api-gen-plugin/src/test/resources/doc-gen/network-topology@2013-07-12.yang
new file mode 100644 (file)
index 0000000..835288c
--- /dev/null
@@ -0,0 +1,397 @@
+module network-topology  {
+    yang-version 1;
+    namespace "urn:TBD:params:xml:ns:yang:network-topology";
+    // replace with IANA namespace when assigned
+    prefix "nt";
+
+    organization "TBD";
+
+    contact "WILL-BE-DEFINED-LATER";
+/*
+    description 
+        "This module defines a model for the topology of a network.
+        Key design decisions are as follows:
+        A topology consists of a set of nodes and links.  
+        Links are point-to-point and unidirectional.  
+        Bidirectional connections need to be represented through
+        two separate links.  
+        Multipoint connections, broadcast domains etc can be represented 
+        through a hierarchy of nodes, then connecting nodes at 
+        upper layers of the hierarchy.";  
+*/
+    revision 2013-07-12 {
+        description
+            "Initial revision.";
+    }
+        
+    typedef topology-id {
+        type string;
+        description 
+            "An identifier for a topology.";
+    }
+
+    typedef node-id {
+        type string;
+        description
+            "An identifier for a node in a topology.  
+            The identifier may be opaque.  
+            The identifier SHOULD be chosen such that the same node in a 
+            real network topology will always be identified through the 
+            same identifier, even if the model is instantiated in separate 
+            datastores. An implementation MAY choose to capture semantics 
+            in the identifier, for example to indicate the type of node 
+            and/or the type of topology that the node is a part of.";  
+    }
+
+    typedef link-id {
+        type string;
+        description
+            "An identifier for a link in a topology.  
+            The identifier may be opaque.  
+            The identifier SHOULD be chosen such that the same link in a 
+            real network topology will always be identified through the 
+            same identifier, even if the model is instantiated in separate 
+            datastores. An implementation MAY choose to capture semantics 
+            in the identifier, for example to indicate the type of link 
+            and/or the type of topology that the link is a part of.";  
+    }
+
+    typedef tp-id {
+        type string;
+        description 
+            "An identifier for termination points on a node. 
+            The identifier may be opaque.  
+            The identifier SHOULD be chosen such that the same TP in a 
+            real network topology will always be identified through the 
+            same identifier, even if the model is instantiated in separate 
+            datastores. An implementation MAY choose to capture semantics 
+            in the identifier, for example to indicate the type of TP 
+            and/or the type of node and topology that the TP is a part of.";  
+    }
+
+    typedef tp-ref {
+        type leafref {
+            path "/network-topology/topology/node/termination-point/tp-id";
+        }
+        description 
+            "A type for an absolute reference to a termination point.
+            (This type should not be used for relative references.
+            In such a case, a relative path should be used instead.)";
+    }
+    typedef topology-ref {
+        type leafref {
+            path "/network-topology/topology/topology-id";
+        }
+        description 
+            "A type for an absolute reference a topology instance.";
+    }
+    
+    typedef node-ref {
+        type leafref {
+            path "/network-topology/topology/node/node-id";
+        }
+        description 
+            "A type for an absolute reference to a node instance.
+            (This type should not be used for relative references.
+            In such a case, a relative path should be used instead.)";
+    }
+
+    typedef link-ref {
+        type leafref {
+            path "/network-topology/topology/link/link-id";
+        }
+        description 
+            "A type for an absolute reference a link instance.
+            (This type should not be used for relative references.
+            In such a case, a relative path should be used instead.)";
+    }
+
+    typedef x {
+        type binary {
+            length 5..10;
+        }
+    }
+
+    typedef y {
+        type int32 {
+            range 5..555;
+        }
+    }
+
+    grouping tp-attributes {
+        description 
+            "The data objects needed to define a termination point.
+            (This only includes a single leaf at this point, used
+            to identify the termination point.)  
+            Provided in a grouping so that in addition to the datastore,
+            the data can also be included in notifications.";
+        leaf tp-id {
+            type tp-id;
+        }
+        leaf-list tp-ref {
+            type tp-ref;
+            config false;
+            description 
+                "The leaf list identifies any termination points that the 
+                termination point is dependent on, or maps onto.  
+                Those termination points will themselves be contained 
+                in a supporting node.  
+                This dependency information can be inferred from 
+                the dependencies between links.  For this reason, 
+                this item is not separately configurable.  Hence no
+                corresponding constraint needs to be articulated.  
+                The corresponding information is simply provided by the
+                implementing system.";
+        }
+    } 
+    
+    grouping node-attributes {
+        description
+            "The data objects needed to define a node.
+            The objects are provided in a grouping so that in addition to
+            the datastore, the data can also be included in notifications
+            as needed.";
+        leaf node-id {
+            type node-id;
+            description 
+                "The identifier of a node in the topology.  
+                A node is specific to a topology to which it belongs.";   
+        }
+        list supporting-node {
+            description 
+                "This list defines vertical layering information for nodes. 
+                It allows to capture for any given node, which node (or nodes)
+                in the corresponding underlay topology it maps onto.  
+                A node can map to zero, one, or more nodes below it;
+                accordingly there can be zero, one, or more elements in the list.
+                If there are specific layering requirements, for example
+                specific to a particular type of topology that only allows
+                for certain layering relationships, the choice
+                below can be augmented with additional cases.
+                A list has been chosen rather than a leaf-list in order 
+                to provide room for augmentations, e.g. for 
+                statistics or priorization information associated with 
+                supporting nodes.";
+            key "node-ref";
+            leaf node-ref {
+                type node-ref;
+            }
+        }
+    }
+            
+    grouping link-attributes {
+        // This is a grouping, not defined inline with the link definition itself,
+        // so it can be included in a notification, if needed
+        leaf link-id {
+            type link-id;
+            description
+                "The identifier of a link in the topology.  
+                A link is specific to a topology to which it belongs.";   
+        }
+        container source { 
+            description "XYZ";
+            leaf source-node {
+                mandatory true;
+                type node-ref; 
+                description 
+                    "Source node identifier, must be in same topology.";
+            }
+            leaf source-tp {
+                type tp-ref; 
+                description 
+                    "Termination point within source node that terminates the link.";           
+            }
+        }
+        container destination { 
+            leaf dest-node {
+                mandatory true;
+                type node-ref; 
+                description 
+                    "Destination node identifier, must be in same topology.";
+            }
+            leaf dest-tp {
+                type tp-ref;
+                description 
+                    "Termination point within destination node that terminates the link.";
+            }
+        }
+        list supporting-link {
+            key "link-ref";
+            leaf link-ref {
+                type link-ref;
+            }
+        }
+    }
+    
+
+    container network-topology {
+        list topology {
+            description "
+                This is the model of an abstract topology.
+                A topology contins nodes and links.  
+                Each topology MUST be identified by
+                unique topology-id for reason that a network could contain many
+                topologies.
+            ";
+            key "topology-id";
+            leaf topology-id {
+                type topology-id; 
+                description "
+                    It is presumed that a datastore will contain many topologies. To
+                    distinguish between topologies it is vital to have UNIQUE
+                    topology identifiers.
+                ";
+            }
+            container topology-types {
+                description 
+                    "This container is used to identify the type, or types 
+                    (as a topology can support several types simultaneously), 
+                    of the topology.  
+                    Topology types are the subject of several integrity constraints 
+                    that an implementing server can validate in order to 
+                    maintain integrity of the datastore.  
+                    Topology types are indicated through separate data nodes; 
+                    the set of topology types is expected to increase over time.
+                    To add support for a new topology, an augmenting module
+                    needs to augment this container with a new empty optional 
+                    container to indicate the new topology type.  
+                    The use of a container allows to indicate a subcategorization
+                    of topology types.  
+                    The container SHALL NOT be augmented with any data nodes 
+                    that serve a purpose other than identifying a particular 
+                    topology type.  
+                ";
+            }   
+            list underlay-topology {
+                key "topology-ref";
+                leaf topology-ref {
+                    type topology-ref;
+                }  
+                // a list, not a leaf-list, to allow for potential augmentation 
+                // with properties specific to the underlay topology, 
+                // such as statistics, preferences, or cost.  
+                description 
+                    "Identifies the topology, or topologies, that this topology
+                    is dependent on.";
+            }
+            
+            list node {
+                description "The list of network nodes defined for the topology.";
+                key "node-id";
+                uses node-attributes;
+                must "boolean(../underlay-topology[*]/node[./supporting-nodes/node-ref])";
+                    // This constraint is meant to ensure that a referenced node is in fact 
+                    // a node in an underlay topology.  
+                list termination-point {
+                    description
+                        "A termination point can terminate a link.  
+                        Depending on the type of topology, a termination point could, 
+                        for example, refer to a port or an interface."; 
+                    key "tp-id";
+                    uses tp-attributes;
+                }
+            }
+            
+            list link {
+                description "
+                    A Network Link connects a by Local (Source) node and
+                    a Remote (Destination) Network Nodes via a set of the 
+                    nodes' termination points. 
+                    As it is possible to have several links between the same
+                    source and destination nodes, and as a link could potentially
+                    be re-homed between termination points, to ensure that we 
+                    would always know to distinguish between links, every link 
+                    is identified by a dedicated link identifier.  
+                    Note that a link models a point-to-point link, not a multipoint
+                    link.  
+                    Layering dependencies on links in underlay topologies are
+                    not represented as the layering information of nodes and of 
+                    termination points is sufficient.  
+                ";
+                key "link-id";
+                uses link-attributes;
+                must "boolean(../underlay-topology/link[./supporting-link]";
+                    // Constraint: any supporting link must be part of an underlay topology
+                must "boolean(../node[./source/source-node])";
+                    // Constraint: A link must have as source a node of the same topology
+                must "boolean(../node[./destination/dest-node])";
+                    // Constraint: A link must have as source a destination of the same topology
+                must "boolean(../node/termination-point[./source/source-tp])";
+                    // Constraint: The source termination point must be contained in the source node
+                must "boolean(../node/termination-point[./destination/dest-tp])";
+                    // Constraint: The destination termination point must be contained 
+                    // in the destination node
+            }
+        }
+    }
+
+    notification n1 {
+        description "This example defines a notification 1.";
+        leaf event-class {
+            type string;
+        }
+        anyxml reporting-entity;
+        container severity {
+            leaf id {
+                type string;
+            }
+        }
+    }
+
+    notification n2 {
+        description "This example defines a notification 2.";
+        leaf event-class {
+            type string;
+        }
+        anyxml reporting-entity;
+        leaf severity {
+            type string;
+        }
+    }
+
+    augment "/network-topology" {
+        anyxml any-a;
+        anyxml any-b;
+    }
+
+    augment "/network-topology/topology" {
+        description "description of augment 2";
+        reference "reference of augment 2";
+        list list-a {}
+        list list-b {
+            leaf leaf-c {
+                type string;
+            }
+        }
+    }
+
+    augment "/network-topology/topology/topology-types" {
+        container container-c {
+            leaf id {
+                type binary;
+            }
+        }
+    }
+
+    rpc rock-the-house {
+        input {
+            leaf zip-code {
+                type string;
+            }
+        }
+        output {
+            leaf number {
+                type int32;
+            }
+        }
+    }
+
+    extension c-define {
+        description
+            "Takes as argument a name string.
+            Makes the code generator use the given name in the
+            #define.";
+        argument "name";
+    }
+
+}
index 27b0559f4be2265e8708028c5b61082d4199801f..828aa89c8250bd7af041810878ae82f1255460a8 100644 (file)
@@ -1,4 +1,5 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
     <parent>
         <artifactId>model-ietf</artifactId>
 
     <build>
         <plugins>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.9-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                                    <outputBaseDir>target/generated-sources/sal</outputBaseDir>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>
+                                    <outputBaseDir>target/generated-sources/site</outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.yangtools</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>0.6.0-SNAPSHOT</version>
+                        <type>jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
             <plugin>
                 <artifactId>maven-jar-plugin</artifactId>
             </plugin>