Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
bartoszm committed Mar 27, 2018
0 parents commit d513c25
Show file tree
Hide file tree
Showing 4 changed files with 340 additions and 0 deletions.
75 changes: 75 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<modelVersion>4.0.0</modelVersion>

<groupId>com.amartus.y2s</groupId>
<artifactId>yang2swagger-tapi-cli</artifactId>
<version>1.0</version>
<properties>
<y2s.version>1.1.7</y2s.version>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<configuration></configuration>
<executions>
<execution>
<goals>
<goal>shade</goal>
</goals>
<phase>package</phase>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.amartus.y2s.Generator</mainClass>
</transformer>
</transformers>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>cli</shadedClassifierName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>com.mrv.yangtools</groupId>
<artifactId>swagger-generator</artifactId>
<version>${y2s.version}</version>
</dependency>

<dependency>
<groupId>com.mrv.yangtools</groupId>
<artifactId>common</artifactId>
<version>${y2s.version}</version>
</dependency>

<dependency>
<groupId>args4j</groupId>
<artifactId>args4j</artifactId>
<version>2.33</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-parser</artifactId>
<version>1.0.22</version>
</dependency>
</dependencies>
</project>
88 changes: 88 additions & 0 deletions src/main/java/com/amartus/y2s/Converter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2018 Amartus. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bartosz Michalik <bartosz.michalik@amartus.com>
*/
package com.amartus.y2s;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.mrv.yangtools.codegen.SwaggerGenerator;
import com.mrv.yangtools.codegen.impl.postprocessor.RemoveUnusedDefinitions;
import com.mrv.yangtools.codegen.impl.postprocessor.SingleParentInheritenceModel;
import com.mrv.yangtools.codegen.impl.postprocessor.SortComplexModels;
import com.mrv.yangtools.common.SwaggerUtils;
import io.swagger.models.Swagger;
import io.swagger.parser.Swagger20Parser;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;

import java.io.*;

/**
* @author bartosz.michalik@amartus.com
*/
public class Converter {
@Option(name = "-output", usage = "File to generate, containing the output - defaults to stdout", metaVar = "file")
public String output = "";

@Option(name = "-input", usage = "File with original swagger, containing the input - defaults to stdin", metaVar = "file")
public String input = "";

@Option(name="-format", usage = "Define format for swagger input/output")
public SwaggerGenerator.Format format = SwaggerGenerator.Format.YAML;
private ObjectMapper mapper;


public static void main(String[] args) throws IOException {
Converter cli = new Converter();
CmdLineParser parser = new CmdLineParser(cli);
try {
parser.parseArgument(args);
cli.convert();
} catch (CmdLineException e) {
System.err.println(e.getMessage());
parser.printUsage(System.err);
}


}

private void convert() throws IOException {
mapper = format == SwaggerGenerator.Format.JSON ? new ObjectMapper(new JsonFactory())
: new ObjectMapper(new YAMLFactory());

try(
Reader in = "".equals(input) ? new InputStreamReader(System.in) : new FileReader(input);
Writer out = "".equals(output) ? new OutputStreamWriter(System.out) : new FileWriter(output)
) {
JsonNode jsonNode = mapper.reader().readTree(in);

Swagger swagger = new Swagger20Parser().read(jsonNode);
new SingleParentInheritenceModel().andThen(new RemoveUnusedDefinitions()).accept(swagger);

new SortComplexModels().accept(swagger);

swagger.setDefinitions(SwaggerUtils.sortMap(swagger.getDefinitions()));
swagger.setPaths(SwaggerUtils.sortMap(swagger.getPaths()));

write(out, swagger);

}
}

private void write(Writer target, Swagger swagger) throws IOException {

mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.writeValue(target, swagger);
}

}
154 changes: 154 additions & 0 deletions src/main/java/com/amartus/y2s/Generator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* Copyright (c) 2018 Amartus. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bartosz Michalik <bartosz.michalik@amartus.com>
*/
package com.amartus.y2s;

import com.mrv.yangtools.codegen.SwaggerGenerator;
import com.mrv.yangtools.codegen.impl.path.rfc8040.PathHandlerBuilder;
import com.mrv.yangtools.codegen.impl.postprocessor.PathPrunner;
import com.mrv.yangtools.codegen.impl.postprocessor.RemoveUnusedDefinitions;
import com.mrv.yangtools.codegen.impl.postprocessor.SingleParentInheritenceModel;
import com.mrv.yangtools.common.ContextHelper;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* @author bartosz.michalik@amartus.com
*/
public class Generator {
private static final Logger log = LoggerFactory.getLogger(Generator.class);

@Option(name = "-yang-dir", usage = "Directory to search for YANG modules - defaults to current directory. " +
"Multiple dirs might be separated by system path separator", metaVar = "path")
public String yangDir = "";

@Option(name = "-output", usage = "File to generate, containing the output - defaults to stdout", metaVar = "file")
public String output = "";

@Argument(multiValued = true, usage = "List of YANG module names to generate in swagger output", metaVar = "module ...")
List<String> modules;

@Option(name = "-format", usage = "Output format of generated file - defaults to yaml with options of json or yaml", metaVar = "enum")
public SwaggerGenerator.Format outputFormat = SwaggerGenerator.Format.YAML;

@Option(name = "-api-version", usage = "Version of api generated - default 1.0", metaVar = "version")
public String apiVersion = "1.0";

// RESTCONF uses yang-data+json or yang-data+xml as the content type.
@Option(name= "-content-type", usage = "Content type the API generates / consumes - default application/yang-data+json")
public String contentType = "application/yang-data+json";

@Option(name = "-simplify-hierarchy", usage = "Use it to generate Swagger which with simplified inheritence model which can be used with standard code generators. Default false")
public boolean simplified = false;

@Option(name = "-use-namespaces", usage="Use namespaces in resource URI")
public boolean useNamespaces = false;

OutputStream out = System.out;


public enum ElementType {
DATA, RPC, DATA_AND_RPC;
}

@Option(name="-elements", usage="Define YANG elements to focus on. Defaul DATA + RPC")
public ElementType elementType = ElementType.DATA_AND_RPC;

public static void main(String[] args) {
Generator cli = new Generator();
CmdLineParser parser = new CmdLineParser(cli);

try {
parser.parseArgument(args);
cli.init();
cli.generate();
} catch (CmdLineException e) {
System.err.println(e.getMessage());
parser.printUsage(System.err);
} catch (Throwable t) {
log.error("Error while generating Swagger", t);
}
}

protected void init() throws FileNotFoundException {
if (output != null && output.trim().length() > 0) {
out = new FileOutputStream(output);
}
}

protected void generate() throws IOException, ReactorException {
final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:*.yang");

final SchemaContext context = buildSchemaContext(yangDir, p -> matcher.matches(p.getFileName()));
final Set<Module> toGenerate = context.getModules().stream().filter(m -> modules == null || modules.contains(m.getName()))
.collect(Collectors.toSet());


PathHandlerBuilder pathHandler = new PathHandlerBuilder().withoutFullCrud();
if(useNamespaces)
pathHandler = pathHandler.useModuleName();


final SwaggerGenerator generator = new SwaggerGenerator(context, toGenerate)
.version(apiVersion)
.format(outputFormat).consumes(contentType).produces(contentType)
.host("localhost:1234").elements(map(elementType))
.pathHandler(pathHandler)
.appendPostProcessor(new PathPrunner("/operations").withType("tapi.common.GlobalClass"));

if(simplified) {
generator.appendPostProcessor(new SingleParentInheritenceModel());
}


generator.appendPostProcessor(new RemoveUnusedDefinitions());

generator.generate(new OutputStreamWriter(out));
}

private SwaggerGenerator.Elements[] map(ElementType elementType) {
switch(elementType) {
case DATA:
return new SwaggerGenerator.Elements[]{SwaggerGenerator.Elements.DATA};
case RPC:
return new SwaggerGenerator.Elements[]{SwaggerGenerator.Elements.RCP};
case DATA_AND_RPC:
default:
return new SwaggerGenerator.Elements[]{SwaggerGenerator.Elements.DATA, SwaggerGenerator.Elements.RCP};
}

}

protected SchemaContext buildSchemaContext(String dir, Predicate<Path> accept)
throws ReactorException {
if(dir.contains(File.pathSeparator)) {
return ContextHelper.getFromDir(Arrays.stream(dir.split(File.pathSeparator)).map(s -> FileSystems.getDefault().getPath(s)), accept);
} else {
return ContextHelper.getFromDir(Stream.of(FileSystems.getDefault().getPath(dir)), accept);
}
}
}
23 changes: 23 additions & 0 deletions src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!--
~ Copyright (c) 2016 MRV Communications, Inc. All rights reserved.
~ This program and the accompanying materials are made available under the
~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
~ and is available at http://www.eclipse.org/legal/epl-v10.html
~
~ Contributors:
~ Christopher Murch <cmurch@mrv.com>
~ Bartosz Michalik <bartosz.michalik@amartus.com>
-->

<configuration>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%date [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<logger name="root" level="INFO">
<appender-ref ref="STDERR" />
</logger>
</configuration>

0 comments on commit d513c25

Please sign in to comment.