Skip to content

Commit

Permalink
fix for #57
Browse files Browse the repository at this point in the history
  • Loading branch information
bartoszm committed Sep 13, 2022
1 parent a84b51f commit 53df472
Show file tree
Hide file tree
Showing 9 changed files with 320 additions and 54 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
*.yaml
.idea/
**/*.iml
target/
Expand Down
54 changes: 39 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,50 @@ we have prepared our own version of the code generator. You might run it standal

You can easily run ```SwaggerGenerator``` from the command-line:
```
java -jar ~/.m2/repository/com/mrv/yangtools/swagger-generator-cli/1.0-SNAPSHOT/swagger-generator-cli-1.0-SNAPSHOT-executable.jar
java -jar swagger-generator-cli-<<version>>-executable.jar
Argument "module ..." is required
module ... : List of YANG module names to generate in swagger output
-output file : File to generate, containing the output - defaults to stdout
(default: )
-yang-dir path : Directory to search for YANG modules - defaults to current
directory (default: )
-api-version string : The current version of your API (default: 1.0)
-format enum : The output format (options: YAML, JSON) (default: YAML)
-content-type string: Content type the API generates / consumes (default: application/yang-data+json)
-simplify-hierarchy : Use it to generate Swagger which with simplified inheritence model which can be used with standard code generators. (default: false)
-use-namespaces : Use namespaces in resource URI (default: false)
-fullCrud : If the flag is set to false path are generated for GET operations only. (default: true)
-elements : Define YANG elements to focus on. (default: DATA + RPC)
-authentication : Authentication definition (options: BASIC, NONE) (default: NONE)
module ... : List of YANG module names to generate
in swagger output
-api-version file : Version of api generated - default 1.0
(default: 1.0)
-authentication [BASIC | NONE] : Authentication definition (default:
NONE)
-content-type VAL : Content type the API generates /
consumes - default application/yang-dat
a+json (default: application/yang-data+
json)
-elements [DATA | RPC | DATA_AND_RPC] : Define YANG elements to focus on.
Defaul DATA + RPC (default:
DATA_AND_RPC)
-format [YAML | JSON] : Output format of generated file -
defaults to yaml with options of json
or yaml (default: YAML)
-fullCrud : If the flag is set to false path are
generated for GET operations only.
Default true (default: true)
-output file : File to generate, containing the
output - defaults to stdout (default: )
-reuse-groupings : Use it to generate Swagger which
attempts to reuse structurally
identical grouping types. Default
false (default: false)
-simplify-hierarchy : Use it to generate Swagger which with
simplified inheritence model which can
be used with standard code generators.
Default false (default: false)
-use-namespaces : Use namespaces in resource URI
(default: false)
-use-odl-path-format : Select to use bierman-02 RESTCONF path
format. Default false (default: false)
-yang-dir path : Directory to search for YANG modules -
defaults to current directory.
Multiple dirs might be separated by
system path separator (default: )
```

For example:
```
java -jar ~/.m2/repository/com/mrv/yangtools/swagger-generator-cli/1.0-SNAPSHOT/swagger-generator-cli-1.0-SNAPSHOT-executable.jar \
java -jar swagger-generator-cli-<<version>>-executable.jar \
-yang-dir examples/build-standalone/src/main/resources \
-output swagger.yaml \
mef-services
Expand Down
10 changes: 8 additions & 2 deletions cli/src/main/java/com/mrv/yangtools/codegen/main/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ public class Main {
@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 = "-reuse-groupings", usage = "Use it to generate Swagger which attempts to reuse structurally identical grouping types. Default false")
public boolean reuseGroupings = false;

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

Expand Down Expand Up @@ -149,13 +152,16 @@ void generate() throws IOException, ReactorException {
.pathHandler(pathHandler)
.elements(map(elementType));

generator
.appendPostProcessor(new CollapseTypes());


if(AuthenticationMechanism.BASIC.equals(authenticationMechanism)) {
generator.appendPostProcessor(new AddSecurityDefinitions().withSecurityDefinition("api_sec", new BasicAuthDefinition()));
}

if(reuseGroupings) {
generator.appendPostProcessor(new CollapseTypes());
}

if(simplified) {
generator.appendPostProcessor(new SingleParentInheritenceModel());
}
Expand Down
59 changes: 47 additions & 12 deletions cli/src/test/java/com/mrv/yangtools/codegen/main/Issue57.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,76 @@
import org.kohsuke.args4j.CmdLineParser;

import java.io.ByteArrayOutputStream;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Issue57 {
private static String path;

static {
try {
path = Paths.get(Issue57.class.getResource("/bug_57/").toURI()).toAbsolutePath().toString();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}

@Test
public void test() throws Exception {
public void testRegular() {

List<String> args = Stream.of(
"-yang-dir",
path
).collect(Collectors.toList());

Swagger swagger = runParser(args);
assertContainsOnly(swagger, s -> s.endsWith("Input"),
"objects.createobject.Input","objects.updateobject.Input");
}

String path = Paths.get(Issue57.class.getResource("/bug_57/").toURI()).toAbsolutePath().toString();
@Test
public void testOptimized() {

List<String> args = Stream.of(
"-reuse-groupings",
"-yang-dir",
path
).collect(Collectors.toList());

Main main = new Main();
CmdLineParser parser = new CmdLineParser(main);
parser.parseArgument(args);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
main.out = baos;
main.init();
main.generate();
Swagger swagger = runParser(args);

Swagger swagger = new SwaggerParser().parse(new String(baos.toByteArray(), StandardCharsets.UTF_8));
assertContainsOnly(swagger, s -> s.endsWith("Input"), "objects.createobject.Input");
}

private void assertContainsOnly(Swagger swagger, Predicate<String> filterDefs, String... name) {
Set<String> result = swagger.getDefinitions().keySet().stream()
.filter(s -> s.endsWith("Input"))
.filter(filterDefs)
.collect(Collectors.toSet());
Set<String> expected = Stream.of("objects.createobject.Input", "objects.updateobject.Input")
Set<String> expected = Stream.of(name)
.collect(Collectors.toSet());
Assert.assertEquals(expected, result);
}

private Swagger runParser(List<String> args) {
Main main = new Main();
CmdLineParser parser = new CmdLineParser(main);
try {
parser.parseArgument(args);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
main.out = baos;
main.init();
main.generate();

return new SwaggerParser().parse(new String(baos.toByteArray(), StandardCharsets.UTF_8));
} catch (Exception e) {
throw new RuntimeException(e);
}

}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/*
* Copyright (c) 2018 Amartus. All rights reserved.
* Copyright (c) 2018-2022 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:
* Damian Mrozowicz <[email protected]>
* Bartosz Michalik <[email protected]>
*/

package com.mrv.yangtools.codegen;
Expand All @@ -23,6 +24,8 @@
import com.mrv.yangtools.common.SwaggerUtils;
import io.swagger.models.Info;
import io.swagger.models.Swagger;
import io.swagger.util.Json;
import io.swagger.util.Yaml;
import org.opendaylight.yangtools.yang.model.api.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -200,11 +203,11 @@ public SwaggerGenerator elements(Elements... elements) {
public SwaggerGenerator format(Format f) {
switch(f) {
case YAML:
mapper = new ObjectMapper(new YAMLFactory());
mapper = Yaml.mapper();
break;
case JSON:
default:
mapper = new ObjectMapper(new JsonFactory());
mapper = Json.mapper();
}
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import java.util.stream.Collectors;

/**
* Processor that allows replacing one definitions with another in any swagger.
* Processor that allows replacing one definition with another one in any swagger.
* This implementation is simple and limited only to the type definitions that are aggregators of references.
* @author [email protected]
*/
Expand All @@ -51,13 +51,19 @@ public void accept(Swagger target) {

private void fixModel(String name, Model m, Map<String, String> replacements) {
ModelImpl fixProperties = null;

if(m instanceof RefModel) {
fixRefModel((RefModel) m, replacements);
return;
}

if(m instanceof ModelImpl) {
fixProperties = (ModelImpl) m;
}

if(m instanceof ComposedModel) {
ComposedModel cm = (ComposedModel) m;
fixComposedModel(name, cm, replacements);
fixComposedModel(cm, replacements);
fixProperties = cm.getAllOf().stream()
.filter(c -> c instanceof ModelImpl).map(c -> (ModelImpl)c)
.findFirst().orElse(null);
Expand Down Expand Up @@ -88,13 +94,13 @@ private void fixModel(String name, Model m, Map<String, String> replacements) {
}
private boolean fixProperty(RefProperty p, Map<String, String> replacements) {
if(replacements.containsKey(p.getSimpleRef())) {
p.set$ref(replacements.get(p.getSimpleRef()));
p.set$ref("#/definitions/" + replacements.get(p.getSimpleRef()));
return true;
}
return false;
}

private void fixComposedModel(String name, ComposedModel m, Map<String, String> replacements) {
private void fixComposedModel(ComposedModel m, Map<String, String> replacements) {
Set<RefModel> toReplace = m.getAllOf().stream().filter(c -> c instanceof RefModel).map(cm -> (RefModel) cm)
.filter(rm -> replacements.containsKey(rm.getSimpleRef())).collect(Collectors.toSet());
toReplace.forEach(r -> {
Expand All @@ -107,6 +113,11 @@ private void fixComposedModel(String name, ComposedModel m, Map<String, String>
});
}

private void fixRefModel(RefModel model, Map<String, String> replacements) {
if(replacements.containsKey(model.getSimpleRef())) {
model.set$ref("#/definitions/" + replacements.get(model.getSimpleRef()));
}
}

private void fixOperation(Operation operation, Map<String, String> replacements) {
operation.getResponses().values()
Expand All @@ -126,26 +137,14 @@ private void fixOperation(Operation operation, Map<String, String> replacements)
private void fixParameter(Parameter p, Map<String, String> replacements) {
if(!(p instanceof BodyParameter)) return;
BodyParameter bp = (BodyParameter) p;
if(!(bp.getSchema() instanceof RefModel)) return;
RefModel ref = (RefModel) bp.getSchema();
if(replacements.containsKey(ref.getSimpleRef())) {
String replacement = replacements.get(ref.getSimpleRef());
bp.setDescription(bp.getDescription().replace(ref.getSimpleRef(), replacement));
bp.setSchema(new RefModel(replacement));
}

fixModel(null, bp.getSchema(), replacements);
}

private void fixResponse(Response r, Map<String, String> replacements) {
if(! (r.getSchema() instanceof RefProperty)) return;
RefProperty schema = (RefProperty) r.getSchema();
if(replacements.containsKey(schema.getSimpleRef())) {
String replacement = replacements.get(schema.getSimpleRef());
if(r.getDescription() != null)
r.setDescription(r.getDescription().replace(schema.getSimpleRef(), replacement));
schema.setDescription(replacement);
r.setSchema(new RefProperty(replacement));
Model model = r.getResponseSchema();
if(model != null) {
fixModel(null, model, replacements);
}

}
}
Loading

0 comments on commit 53df472

Please sign in to comment.