Committed by
Gerrit Code Review
ONOS Swagger Plugin
just does swagger now to build the plugin, you need to download to following: https://github.com/bocon13/buck/releases/download/v2016.07.29.01-wip/buck.jar put the buck.jar in tools/build/buck-plugin/lib Change-Id: Id1b833dd013fbc5581f8e884e755920829c4a17e
Showing
15 changed files
with
1133 additions
and
2 deletions
| ... | @@ -16,4 +16,9 @@ osgi_jar_with_tests ( | ... | @@ -16,4 +16,9 @@ osgi_jar_with_tests ( |
| 16 | deps = COMPILE_DEPS, | 16 | deps = COMPILE_DEPS, |
| 17 | test_deps = TEST_DEPS, | 17 | test_deps = TEST_DEPS, |
| 18 | web_context = '/onos/dhcp', | 18 | web_context = '/onos/dhcp', |
| 19 | + api_title = 'DHCP Server App', | ||
| 20 | + api_version = '1.0', | ||
| 21 | + api_description = 'REST API for DHCP Server App', | ||
| 22 | + api_package = 'org.onosproject.dhcp.rest', | ||
| 23 | + debug = False | ||
| 19 | ) | 24 | ) | ... | ... |
| ... | @@ -107,6 +107,10 @@ def osgi_jar( | ... | @@ -107,6 +107,10 @@ def osgi_jar( |
| 107 | package_name_root = 'org.onosproject', | 107 | package_name_root = 'org.onosproject', |
| 108 | include_resources = NONE, | 108 | include_resources = NONE, |
| 109 | web_context = NONE, | 109 | web_context = NONE, |
| 110 | + api_title = NONE, | ||
| 111 | + api_version = NONE, | ||
| 112 | + api_package = NONE, | ||
| 113 | + api_description = NONE, | ||
| 110 | resources = NONE, | 114 | resources = NONE, |
| 111 | resources_root = None, | 115 | resources_root = None, |
| 112 | **kwargs | 116 | **kwargs |
| ... | @@ -128,18 +132,27 @@ def osgi_jar( | ... | @@ -128,18 +132,27 @@ def osgi_jar( |
| 128 | if resources and not resources_root: | 132 | if resources and not resources_root: |
| 129 | resources_root = RESOURCES_ROOT | 133 | resources_root = RESOURCES_ROOT |
| 130 | 134 | ||
| 135 | + if api_title != NONE: | ||
| 136 | + r = 'WEB-INF/classes/apidoc/swagger.json=bin/swagger.json' | ||
| 137 | + include_resources = include_resources + ',' + r if include_resources != NONE else r | ||
| 138 | + | ||
| 131 | bare_jar_name = name + '-jar' | 139 | bare_jar_name = name + '-jar' |
| 132 | osgi_jar_name = name + '-osgi' | 140 | osgi_jar_name = name + '-osgi' |
| 133 | mvn_coords = group_id + ':' + name + ':' + version | 141 | mvn_coords = group_id + ':' + name + ':' + version |
| 134 | 142 | ||
| 135 | 143 | ||
| 136 | - java_library( | 144 | + onos_jar( |
| 137 | name = bare_jar_name, | 145 | name = bare_jar_name, |
| 138 | srcs = srcs, | 146 | srcs = srcs, |
| 139 | deps = deps, | 147 | deps = deps, |
| 140 | visibility = [], #intentially, not visible | 148 | visibility = [], #intentially, not visible |
| 141 | resources = resources, | 149 | resources = resources, |
| 142 | resources_root = resources_root, | 150 | resources_root = resources_root, |
| 151 | + web_context = web_context, | ||
| 152 | + api_title = api_title, | ||
| 153 | + api_version = api_version, | ||
| 154 | + api_package = api_package, | ||
| 155 | + api_description = api_description, | ||
| 143 | **kwargs | 156 | **kwargs |
| 144 | ) | 157 | ) |
| 145 | 158 | ||
| ... | @@ -167,6 +180,7 @@ def osgi_jar( | ... | @@ -167,6 +180,7 @@ def osgi_jar( |
| 167 | bash = stage_jar + DEBUG_ARG + ' ' + wrap_jar | 180 | bash = stage_jar + DEBUG_ARG + ' ' + wrap_jar |
| 168 | print bash | 181 | print bash |
| 169 | 182 | ||
| 183 | + # FIXME: make sure that /swagger.json gets filtered | ||
| 170 | genrule( | 184 | genrule( |
| 171 | name = osgi_jar_name, | 185 | name = osgi_jar_name, |
| 172 | bash = bash, | 186 | bash = bash, | ... | ... |
tools/build/buck-plugin/BUCK
0 → 100644
| 1 | +remote_jar ( | ||
| 2 | + name = 'buck-api', | ||
| 3 | + out = 'buck.jar', | ||
| 4 | + url = 'https://github.com/bocon13/buck/releases/download/v2016.07.29.01-wip/buck.jar', | ||
| 5 | + sha1 = 'f89324cb869b74fdcd4db9972233065a93d890a2', | ||
| 6 | + visibility = [], | ||
| 7 | +) | ||
| 8 | + | ||
| 9 | +COMPILE = [ | ||
| 10 | + '//lib:qdox', | ||
| 11 | + #'//lib:jackson-core', | ||
| 12 | + #'//lib:jackson-databind', | ||
| 13 | + #'//lib:jackson-annotations', | ||
| 14 | +] | ||
| 15 | + | ||
| 16 | +RUNTIME = [ | ||
| 17 | +] | ||
| 18 | + | ||
| 19 | +java_library( | ||
| 20 | + name = 'lib', | ||
| 21 | + srcs = glob(['src/main/java/**/*.java']), | ||
| 22 | + resources = glob(['src/main/resources/**/*']), | ||
| 23 | + resources_root = 'src/main/resources', | ||
| 24 | + deps = COMPILE, | ||
| 25 | + provided_deps = [':buck-api'], | ||
| 26 | + visibility = [], | ||
| 27 | +) | ||
| 28 | + | ||
| 29 | +java_binary( | ||
| 30 | + name = 'onosjar', | ||
| 31 | + deps = [':lib'], | ||
| 32 | + visibility = ['PUBLIC'], | ||
| 33 | +) | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
tools/build/buck-plugin/buck-plugin-install
0 → 100755
| 1 | +#!/bin/bash | ||
| 2 | + | ||
| 3 | +PLUGINS=$ONOS_ROOT/bucklets/plugins | ||
| 4 | + | ||
| 5 | +# Build it first | ||
| 6 | +pluginJar=$(NO_BUCKD=1 buck build //tools/build/buck-plugin:onosjar --no-cache --show-output | grep onosjar.jar | cut -d\ -f2) | ||
| 7 | + | ||
| 8 | +# Then install it | ||
| 9 | +mkdir -p $PLUGINS | ||
| 10 | +cp $ONOS_ROOT/$pluginJar $PLUGINS | ||
| 11 | + | ||
| 12 | +ls -l $PLUGINS |
tools/build/buck-plugin/buck-plugin-test
0 → 100755
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.onosjar; | ||
| 17 | + | ||
| 18 | +import com.facebook.buck.jvm.java.CompileToJarStepFactory; | ||
| 19 | +import com.facebook.buck.jvm.java.DefaultJavaLibrary; | ||
| 20 | +import com.facebook.buck.model.BuildTarget; | ||
| 21 | +import com.facebook.buck.rules.AddToRuleKey; | ||
| 22 | +import com.facebook.buck.rules.BuildRule; | ||
| 23 | +import com.facebook.buck.rules.BuildRuleParams; | ||
| 24 | +import com.facebook.buck.rules.SourcePath; | ||
| 25 | +import com.facebook.buck.rules.SourcePathResolver; | ||
| 26 | +import com.google.common.base.Optional; | ||
| 27 | +import com.google.common.collect.ImmutableList; | ||
| 28 | +import com.google.common.collect.ImmutableSet; | ||
| 29 | +import com.google.common.collect.ImmutableSortedSet; | ||
| 30 | + | ||
| 31 | +import java.nio.file.Path; | ||
| 32 | +import java.util.Set; | ||
| 33 | +import java.util.regex.Pattern; | ||
| 34 | + | ||
| 35 | +/** | ||
| 36 | + * Implementation of a build rule that generates a onosjar.json file for a set | ||
| 37 | + * of Java sources. | ||
| 38 | + */ | ||
| 39 | +public class OnosJar extends DefaultJavaLibrary { | ||
| 40 | + | ||
| 41 | + @AddToRuleKey | ||
| 42 | + final Optional<String> webContext; | ||
| 43 | + | ||
| 44 | + @AddToRuleKey | ||
| 45 | + final Optional<String> apiTitle; | ||
| 46 | + | ||
| 47 | + @AddToRuleKey | ||
| 48 | + final Optional<String> apiVersion; | ||
| 49 | + | ||
| 50 | + @AddToRuleKey | ||
| 51 | + final Optional<String> apiPackage; | ||
| 52 | + | ||
| 53 | + @AddToRuleKey | ||
| 54 | + final Optional<String> apiDescription; | ||
| 55 | + | ||
| 56 | + public OnosJar(BuildRuleParams params, | ||
| 57 | + SourcePathResolver resolver, | ||
| 58 | + Set<? extends SourcePath> srcs, | ||
| 59 | + Set<? extends SourcePath> resources, | ||
| 60 | + Optional<Path> generatedSourceFolder, | ||
| 61 | + Optional<SourcePath> proguardConfig, | ||
| 62 | + ImmutableList<String> postprocessClassesCommands, | ||
| 63 | + ImmutableSortedSet<BuildRule> exportedDeps, | ||
| 64 | + ImmutableSortedSet<BuildRule> providedDeps, | ||
| 65 | + SourcePath abiJar, boolean trackClassUsage, | ||
| 66 | + ImmutableSet<Path> additionalClasspathEntries, | ||
| 67 | + CompileToJarStepFactory compileStepFactory, | ||
| 68 | + Optional<Path> resourcesRoot, | ||
| 69 | + Optional<String> mavenCoords, | ||
| 70 | + ImmutableSortedSet<BuildTarget> tests, | ||
| 71 | + ImmutableSet<Pattern> classesToRemoveFromJar, | ||
| 72 | + Optional<String> webContext, | ||
| 73 | + Optional<String> apiTitle, | ||
| 74 | + Optional<String> apiVersion, | ||
| 75 | + Optional<String> apiPackage, | ||
| 76 | + Optional<String> apiDescription) { | ||
| 77 | + super(params, resolver, srcs, resources, generatedSourceFolder, | ||
| 78 | + proguardConfig, postprocessClassesCommands, exportedDeps, | ||
| 79 | + providedDeps, abiJar, trackClassUsage, additionalClasspathEntries, | ||
| 80 | + compileStepFactory, resourcesRoot, mavenCoords, tests, | ||
| 81 | + classesToRemoveFromJar); | ||
| 82 | + this.webContext = webContext; | ||
| 83 | + this.apiTitle = apiTitle; | ||
| 84 | + this.apiVersion = apiVersion; | ||
| 85 | + this.apiPackage = apiPackage; | ||
| 86 | + this.apiDescription = apiDescription; | ||
| 87 | + } | ||
| 88 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.onosjar; | ||
| 17 | + | ||
| 18 | +import com.facebook.buck.cli.BuckConfig; | ||
| 19 | +import com.facebook.buck.jvm.java.CalculateAbi; | ||
| 20 | +import com.facebook.buck.jvm.java.DefaultJavaLibrary; | ||
| 21 | +import com.facebook.buck.jvm.java.JavaBuckConfig; | ||
| 22 | +import com.facebook.buck.jvm.java.JavaLibraryDescription; | ||
| 23 | +import com.facebook.buck.jvm.java.JavaOptions; | ||
| 24 | +import com.facebook.buck.jvm.java.JavacOptions; | ||
| 25 | +import com.facebook.buck.jvm.java.JavacOptionsAmender; | ||
| 26 | +import com.facebook.buck.jvm.java.JavacOptionsFactory; | ||
| 27 | +import com.facebook.buck.model.BuildTarget; | ||
| 28 | +import com.facebook.buck.model.Flavor; | ||
| 29 | +import com.facebook.buck.parser.NoSuchBuildTargetException; | ||
| 30 | +import com.facebook.buck.rules.BuildRule; | ||
| 31 | +import com.facebook.buck.rules.BuildRuleParams; | ||
| 32 | +import com.facebook.buck.rules.BuildRuleResolver; | ||
| 33 | +import com.facebook.buck.rules.BuildRuleType; | ||
| 34 | +import com.facebook.buck.rules.BuildRules; | ||
| 35 | +import com.facebook.buck.rules.BuildTargetSourcePath; | ||
| 36 | +import com.facebook.buck.rules.Description; | ||
| 37 | +import com.facebook.buck.rules.SourcePathResolver; | ||
| 38 | +import com.facebook.buck.rules.SourcePaths; | ||
| 39 | +import com.facebook.buck.rules.TargetGraph; | ||
| 40 | +import com.google.common.base.Optional; | ||
| 41 | +import com.google.common.collect.ImmutableSet; | ||
| 42 | +import com.google.common.collect.ImmutableSortedSet; | ||
| 43 | +import com.google.common.collect.Iterables; | ||
| 44 | + | ||
| 45 | +import java.nio.file.Path; | ||
| 46 | + | ||
| 47 | +import static com.facebook.buck.jvm.common.ResourceValidator.validateResources; | ||
| 48 | + | ||
| 49 | +/** | ||
| 50 | + * Description for the onos_jar rules. | ||
| 51 | + * | ||
| 52 | + * Currently, this only does Swagger generation. | ||
| 53 | + */ | ||
| 54 | +public class OnosJarDescription implements Description<OnosJarDescription.Arg> { | ||
| 55 | + public static final BuildRuleType TYPE = BuildRuleType.of("onos_jar"); | ||
| 56 | + private final JavacOptions defaultJavacOptions; | ||
| 57 | + private final JavaOptions defaultJavaOptions; | ||
| 58 | + | ||
| 59 | + public OnosJarDescription(BuckConfig config) { | ||
| 60 | + JavaBuckConfig javaConfig = new JavaBuckConfig(config); | ||
| 61 | + defaultJavacOptions = javaConfig.getDefaultJavacOptions(); | ||
| 62 | + defaultJavaOptions = javaConfig.getDefaultJavaOptions(); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + @Override | ||
| 66 | + public BuildRuleType getBuildRuleType() { | ||
| 67 | + return TYPE; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + @Override | ||
| 71 | + public Arg createUnpopulatedConstructorArg() { | ||
| 72 | + return new Arg(); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + @Override | ||
| 76 | + public <A extends Arg> BuildRule createBuildRule(TargetGraph targetGraph, | ||
| 77 | + BuildRuleParams params, | ||
| 78 | + BuildRuleResolver resolver, | ||
| 79 | + A args) | ||
| 80 | + throws NoSuchBuildTargetException { | ||
| 81 | + | ||
| 82 | + | ||
| 83 | + SourcePathResolver pathResolver = new SourcePathResolver(resolver); | ||
| 84 | + BuildTarget target = params.getBuildTarget(); | ||
| 85 | + | ||
| 86 | + // We know that the flavour we're being asked to create is valid, since the check is done when | ||
| 87 | + // creating the action graph from the target graph. | ||
| 88 | + | ||
| 89 | + ImmutableSortedSet<Flavor> flavors = target.getFlavors(); | ||
| 90 | + BuildRuleParams paramsWithMavenFlavor = null; | ||
| 91 | + | ||
| 92 | + JavacOptions javacOptions = JavacOptionsFactory.create( | ||
| 93 | + defaultJavacOptions, | ||
| 94 | + params, | ||
| 95 | + resolver, | ||
| 96 | + pathResolver, | ||
| 97 | + args | ||
| 98 | + ); | ||
| 99 | + | ||
| 100 | + BuildTarget abiJarTarget = params.getBuildTarget().withAppendedFlavors(CalculateAbi.FLAVOR); | ||
| 101 | + | ||
| 102 | + ImmutableSortedSet<BuildRule> exportedDeps = resolver.getAllRules(args.exportedDeps.get()); | ||
| 103 | + | ||
| 104 | + DefaultJavaLibrary defaultJavaLibrary = | ||
| 105 | + resolver.addToIndex( | ||
| 106 | + new OnosJar( | ||
| 107 | + params.appendExtraDeps( | ||
| 108 | + Iterables.concat( | ||
| 109 | + BuildRules.getExportedRules( | ||
| 110 | + Iterables.concat( | ||
| 111 | + params.getDeclaredDeps().get(), | ||
| 112 | + exportedDeps, | ||
| 113 | + resolver.getAllRules(args.providedDeps.get()))), | ||
| 114 | + pathResolver.filterBuildRuleInputs( | ||
| 115 | + javacOptions.getInputs(pathResolver)))), | ||
| 116 | + pathResolver, | ||
| 117 | + args.srcs.get(), | ||
| 118 | + validateResources( | ||
| 119 | + pathResolver, | ||
| 120 | + params.getProjectFilesystem(), | ||
| 121 | + args.resources.get()), | ||
| 122 | + javacOptions.getGeneratedSourceFolderName(), | ||
| 123 | + args.proguardConfig.transform( | ||
| 124 | + SourcePaths.toSourcePath(params.getProjectFilesystem())), | ||
| 125 | + args.postprocessClassesCommands.get(), // FIXME this should be forbidden | ||
| 126 | + exportedDeps, | ||
| 127 | + resolver.getAllRules(args.providedDeps.get()), | ||
| 128 | + new BuildTargetSourcePath(abiJarTarget), | ||
| 129 | + javacOptions.trackClassUsage(), | ||
| 130 | + /* additionalClasspathEntries */ ImmutableSet.<Path>of(), | ||
| 131 | + new OnosJarStepFactory(javacOptions, JavacOptionsAmender.IDENTITY, | ||
| 132 | + args.webContext, args.apiTitle, args.apiVersion, | ||
| 133 | + args.apiPackage, args.apiDescription, args.resources), | ||
| 134 | + args.resourcesRoot, | ||
| 135 | + args.mavenCoords, | ||
| 136 | + args.tests.get(), | ||
| 137 | + javacOptions.getClassesToRemoveFromJar(), | ||
| 138 | + args.webContext, | ||
| 139 | + args.apiTitle, | ||
| 140 | + args.apiVersion, | ||
| 141 | + args.apiPackage, | ||
| 142 | + args.apiDescription)); | ||
| 143 | + | ||
| 144 | + resolver.addToIndex( | ||
| 145 | + CalculateAbi.of( | ||
| 146 | + abiJarTarget, | ||
| 147 | + pathResolver, | ||
| 148 | + params, | ||
| 149 | + new BuildTargetSourcePath(defaultJavaLibrary.getBuildTarget()))); | ||
| 150 | + | ||
| 151 | + return defaultJavaLibrary; | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + | ||
| 155 | + public static class Arg extends JavaLibraryDescription.Arg { | ||
| 156 | + public Optional<String> webContext; | ||
| 157 | + public Optional<String> apiTitle; | ||
| 158 | + public Optional<String> apiVersion; | ||
| 159 | + public Optional<String> apiPackage; | ||
| 160 | + public Optional<String> apiDescription; | ||
| 161 | + } | ||
| 162 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.onosjar; | ||
| 17 | + | ||
| 18 | +import com.facebook.buck.io.ProjectFilesystem; | ||
| 19 | +import com.facebook.buck.jvm.core.SuggestBuildRules; | ||
| 20 | +import com.facebook.buck.jvm.java.ClassUsageFileWriter; | ||
| 21 | +import com.facebook.buck.jvm.java.JarDirectoryStep; | ||
| 22 | +import com.facebook.buck.jvm.java.JavacOptions; | ||
| 23 | +import com.facebook.buck.jvm.java.JavacOptionsAmender; | ||
| 24 | +import com.facebook.buck.jvm.java.JavacToJarStepFactory; | ||
| 25 | +import com.facebook.buck.model.BuildTarget; | ||
| 26 | +import com.facebook.buck.rules.BuildContext; | ||
| 27 | +import com.facebook.buck.rules.BuildableContext; | ||
| 28 | +import com.facebook.buck.rules.SourcePath; | ||
| 29 | +import com.facebook.buck.rules.SourcePathResolver; | ||
| 30 | +import com.facebook.buck.step.Step; | ||
| 31 | +import com.google.common.base.Optional; | ||
| 32 | +import com.google.common.collect.ImmutableList; | ||
| 33 | +import com.google.common.collect.ImmutableSet; | ||
| 34 | +import com.google.common.collect.ImmutableSortedSet; | ||
| 35 | + | ||
| 36 | +import java.nio.file.Path; | ||
| 37 | +import java.util.regex.Pattern; | ||
| 38 | +import java.util.stream.Collectors; | ||
| 39 | + | ||
| 40 | +/** | ||
| 41 | + * Creates the list of build steps for the onos_jar rules. | ||
| 42 | + */ | ||
| 43 | +public class OnosJarStepFactory extends JavacToJarStepFactory { | ||
| 44 | + | ||
| 45 | + private static final String DEFINITIONS = "/definitions/"; | ||
| 46 | + private final String webContext; | ||
| 47 | + private final String apiTitle; | ||
| 48 | + private final String apiVersion; | ||
| 49 | + private final String apiPackage; | ||
| 50 | + private final String apiDescription; | ||
| 51 | + private final Optional<ImmutableSortedSet<SourcePath>> resources; | ||
| 52 | + | ||
| 53 | + public OnosJarStepFactory(JavacOptions javacOptions, | ||
| 54 | + JavacOptionsAmender amender, | ||
| 55 | + Optional<String> webContext, | ||
| 56 | + Optional<String> apiTitle, | ||
| 57 | + Optional<String> apiVersion, | ||
| 58 | + Optional<String> apiPackage, | ||
| 59 | + Optional<String> apiDescription, | ||
| 60 | + Optional<ImmutableSortedSet<SourcePath>> resources) { | ||
| 61 | + super(javacOptions, amender); | ||
| 62 | + this.webContext = processParameter(webContext); | ||
| 63 | + this.apiTitle = processParameter(apiTitle); | ||
| 64 | + this.apiVersion = processParameter(apiVersion); | ||
| 65 | + this.apiPackage = processParameter(apiPackage); | ||
| 66 | + this.apiDescription = processParameter(apiDescription); | ||
| 67 | + this.resources = resources; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + private String processParameter(Optional<String> p) { | ||
| 71 | + return !p.isPresent() || p.get().equals("NONE") ? null : p.get(); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + @Override | ||
| 75 | + public void createCompileToJarStep(BuildContext context, | ||
| 76 | + ImmutableSortedSet<Path> sourceFilePaths, | ||
| 77 | + BuildTarget invokingRule, | ||
| 78 | + SourcePathResolver resolver, | ||
| 79 | + ProjectFilesystem filesystem, | ||
| 80 | + ImmutableSortedSet<Path> declaredClasspathEntries, | ||
| 81 | + Path outputDirectory, | ||
| 82 | + Optional<Path> workingDirectory, | ||
| 83 | + Path pathToSrcsList, | ||
| 84 | + Optional<SuggestBuildRules> suggestBuildRules, | ||
| 85 | + ImmutableList<String> postprocessClassesCommands, | ||
| 86 | + ImmutableSortedSet<Path> entriesToJar, | ||
| 87 | + Optional<String> mainClass, | ||
| 88 | + Optional<Path> manifestFile, | ||
| 89 | + Path outputJar, | ||
| 90 | + ClassUsageFileWriter usedClassesFileWriter, | ||
| 91 | + ImmutableList.Builder<Step> steps, | ||
| 92 | + BuildableContext buildableContext, | ||
| 93 | + ImmutableSet<Pattern> classesToRemoveFromJar) { | ||
| 94 | + | ||
| 95 | + ImmutableSet.Builder<Path> sourceFilePathBuilder = ImmutableSet.builder(); | ||
| 96 | + sourceFilePathBuilder.addAll(sourceFilePaths); | ||
| 97 | + | ||
| 98 | + ImmutableSet.Builder<Pattern> blacklistBuilder = ImmutableSet.builder(); | ||
| 99 | + blacklistBuilder.addAll(classesToRemoveFromJar); | ||
| 100 | + | ||
| 101 | + // precompilation steps | ||
| 102 | + // - generate sources | ||
| 103 | + // add all generated sources ot pathToSrcsList | ||
| 104 | + if (webContext != null && apiTitle != null && resources.isPresent()) { | ||
| 105 | + ImmutableSortedSet<Path> resourceFilePaths = findSwaggerModelDefs(resolver, resources.get()); | ||
| 106 | + blacklistBuilder.addAll(resourceFilePaths.stream() | ||
| 107 | + .map(rp -> Pattern.compile(rp.getFileName().toString(), Pattern.LITERAL)) | ||
| 108 | + .collect(Collectors.toSet())); | ||
| 109 | + Path genSourcesOutput = workingDirectory.get(); | ||
| 110 | + | ||
| 111 | + SwaggerStep swaggerStep = new SwaggerStep(filesystem, sourceFilePaths, resourceFilePaths, | ||
| 112 | + genSourcesOutput, outputDirectory, | ||
| 113 | + webContext, apiTitle, apiVersion, | ||
| 114 | + apiPackage, apiDescription); | ||
| 115 | + sourceFilePathBuilder.add(swaggerStep.apiRegistratorPath()); | ||
| 116 | + steps.add(swaggerStep); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + createCompileStep(context, | ||
| 120 | + ImmutableSortedSet.copyOf(sourceFilePathBuilder.build()), | ||
| 121 | + invokingRule, | ||
| 122 | + resolver, | ||
| 123 | + filesystem, | ||
| 124 | + declaredClasspathEntries, | ||
| 125 | + outputDirectory, | ||
| 126 | + workingDirectory, | ||
| 127 | + pathToSrcsList, | ||
| 128 | + suggestBuildRules, | ||
| 129 | + usedClassesFileWriter, | ||
| 130 | + steps, | ||
| 131 | + buildableContext); | ||
| 132 | + | ||
| 133 | + // post compilation steps | ||
| 134 | + | ||
| 135 | + // FIXME BOC: add mechanism to inject new Steps | ||
| 136 | + //context.additionalStepFactory(JavaStep.class); | ||
| 137 | + | ||
| 138 | + // build the jar | ||
| 139 | + steps.add(new JarDirectoryStep(filesystem, | ||
| 140 | + outputJar, | ||
| 141 | + ImmutableSortedSet.of(outputDirectory), | ||
| 142 | + mainClass.orNull(), | ||
| 143 | + manifestFile.orNull(), | ||
| 144 | + true, | ||
| 145 | + blacklistBuilder.build())); | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + private ImmutableSortedSet<Path> findSwaggerModelDefs(SourcePathResolver resolver, | ||
| 149 | + ImmutableSortedSet<SourcePath> resourcePaths) { | ||
| 150 | + if (resourcePaths == null) { | ||
| 151 | + return ImmutableSortedSet.of(); | ||
| 152 | + } | ||
| 153 | + return ImmutableSortedSet.copyOf(resourcePaths.stream() | ||
| 154 | + .filter(sp -> sp.toString().contains(DEFINITIONS)) | ||
| 155 | + .map(resolver::getRelativePath) | ||
| 156 | + .collect(Collectors.toList())); | ||
| 157 | + } | ||
| 158 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.onosjar; | ||
| 18 | + | ||
| 19 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 20 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
| 21 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| 22 | +import com.google.common.io.ByteStreams; | ||
| 23 | +import com.google.common.io.Files; | ||
| 24 | +import com.thoughtworks.qdox.JavaProjectBuilder; | ||
| 25 | +import com.thoughtworks.qdox.model.DocletTag; | ||
| 26 | +import com.thoughtworks.qdox.model.JavaAnnotation; | ||
| 27 | +import com.thoughtworks.qdox.model.JavaClass; | ||
| 28 | +import com.thoughtworks.qdox.model.JavaMethod; | ||
| 29 | +import com.thoughtworks.qdox.model.JavaParameter; | ||
| 30 | +import com.thoughtworks.qdox.model.JavaType; | ||
| 31 | + | ||
| 32 | +import java.io.File; | ||
| 33 | +import java.io.FileWriter; | ||
| 34 | +import java.io.IOException; | ||
| 35 | +import java.io.PrintWriter; | ||
| 36 | +import java.util.HashMap; | ||
| 37 | +import java.util.List; | ||
| 38 | +import java.util.Map; | ||
| 39 | +import java.util.Optional; | ||
| 40 | + | ||
| 41 | +import static com.google.common.base.Strings.isNullOrEmpty; | ||
| 42 | + | ||
| 43 | +/** | ||
| 44 | + * Generates Swagger JSON artifacts from the Java source files. | ||
| 45 | + */ | ||
| 46 | +public class SwaggerGenerator { | ||
| 47 | + | ||
| 48 | + private final ObjectMapper mapper = new ObjectMapper(); | ||
| 49 | + | ||
| 50 | + private static final String JSON_FILE = "swagger.json"; | ||
| 51 | + private static final String GEN_SRC = "generated-sources"; | ||
| 52 | + private static final String REG_SRC = "/registrator.javat"; | ||
| 53 | + | ||
| 54 | + private static final String PATH = "javax.ws.rs.Path"; | ||
| 55 | + private static final String PATH_PARAM = "javax.ws.rs.PathParam"; | ||
| 56 | + private static final String QUERY_PARAM = "javax.ws.rs.QueryParam"; | ||
| 57 | + private static final String POST = "javax.ws.rs.POST"; | ||
| 58 | + private static final String GET = "javax.ws.rs.GET"; | ||
| 59 | + private static final String PUT = "javax.ws.rs.PUT"; | ||
| 60 | + private static final String DELETE = "javax.ws.rs.DELETE"; | ||
| 61 | + private static final String PRODUCES = "javax.ws.rs.Produces"; | ||
| 62 | + private static final String CONSUMES = "javax.ws.rs.Consumes"; | ||
| 63 | + private static final String JSON = "MediaType.APPLICATION_JSON"; | ||
| 64 | + private static final String OCTET_STREAM = "MediaType.APPLICATION_OCTET_STREAM"; | ||
| 65 | + | ||
| 66 | + private final List<File> srcs; | ||
| 67 | + private final List<File> resources; | ||
| 68 | + private final File srcDirectory; | ||
| 69 | + private final File resourceDirectory; | ||
| 70 | + private final File genSrcOutputDirectory; | ||
| 71 | + private final File genResourcesOutputDirectory; | ||
| 72 | + private final String webContext; | ||
| 73 | + private final String apiTitle; | ||
| 74 | + private final String apiVersion; | ||
| 75 | + private final String apiPackage; | ||
| 76 | + private final String apiDescription; | ||
| 77 | + | ||
| 78 | + public SwaggerGenerator(List<File> srcs, List<File> resources, | ||
| 79 | + File srcDirectory, File resourceDirectory, | ||
| 80 | + File genSrcOutputDirectory, File genResourcesOutputDirectory, | ||
| 81 | + String webContext, String apiTitle, String apiVersion, | ||
| 82 | + String apiPackage, String apiDescription) { | ||
| 83 | + this.srcs = srcs; | ||
| 84 | + this.resources = resources; | ||
| 85 | + this.srcDirectory = srcDirectory; | ||
| 86 | + this.resourceDirectory = resourceDirectory; | ||
| 87 | + this.genSrcOutputDirectory = genSrcOutputDirectory; | ||
| 88 | + this.genResourcesOutputDirectory = genResourcesOutputDirectory; | ||
| 89 | + this.webContext = webContext; | ||
| 90 | + | ||
| 91 | + this.apiTitle = apiTitle; | ||
| 92 | + this.apiVersion = apiVersion; | ||
| 93 | + this.apiPackage = apiPackage; | ||
| 94 | + this.apiDescription = apiDescription; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + public void execute() { | ||
| 98 | + try { | ||
| 99 | + JavaProjectBuilder builder = new JavaProjectBuilder(); | ||
| 100 | + if (srcDirectory != null) { | ||
| 101 | + builder.addSourceTree(new File(srcDirectory, "src/main/java")); | ||
| 102 | + } | ||
| 103 | + if (srcs != null) { | ||
| 104 | + srcs.forEach(src -> { | ||
| 105 | + try { | ||
| 106 | + builder.addSource(src); | ||
| 107 | + } catch (IOException e) { | ||
| 108 | + throw new RuntimeException(e); | ||
| 109 | + } | ||
| 110 | + }); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + ObjectNode root = initializeRoot(webContext, apiTitle, apiVersion, apiDescription); | ||
| 114 | + ArrayNode tags = mapper.createArrayNode(); | ||
| 115 | + ObjectNode paths = mapper.createObjectNode(); | ||
| 116 | + ObjectNode definitions = mapper.createObjectNode(); | ||
| 117 | + | ||
| 118 | + root.set("tags", tags); | ||
| 119 | + root.set("paths", paths); | ||
| 120 | + root.set("definitions", definitions); | ||
| 121 | + | ||
| 122 | + // TODO: Process resources to allow lookup of files by name | ||
| 123 | + | ||
| 124 | + builder.getClasses().forEach(jc -> processClass(jc, paths, tags, definitions, srcDirectory)); | ||
| 125 | + | ||
| 126 | + if (paths.size() > 0) { | ||
| 127 | + genCatalog(genResourcesOutputDirectory, root); | ||
| 128 | + if (!isNullOrEmpty(apiPackage)) { | ||
| 129 | + genRegistrator(genSrcOutputDirectory, webContext, apiTitle, apiVersion, | ||
| 130 | + apiPackage, apiDescription); | ||
| 131 | + } | ||
| 132 | + } | ||
| 133 | + } catch (Exception e) { | ||
| 134 | + e.printStackTrace(); | ||
| 135 | + throw new RuntimeException("Unable to generate ONOS REST API documentation", e); | ||
| 136 | + } | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + // initializes top level root with Swagger required specifications | ||
| 140 | + private ObjectNode initializeRoot(String webContext, String apiTitle, | ||
| 141 | + String apiVersion, String apiDescription) { | ||
| 142 | + ObjectNode root = mapper.createObjectNode(); | ||
| 143 | + root.put("swagger", "2.0"); | ||
| 144 | + ObjectNode info = mapper.createObjectNode(); | ||
| 145 | + root.set("info", info); | ||
| 146 | + | ||
| 147 | + root.put("basePath", webContext); | ||
| 148 | + info.put("version", apiVersion); | ||
| 149 | + info.put("title", apiTitle); | ||
| 150 | + info.put("description", apiDescription); | ||
| 151 | + | ||
| 152 | + ArrayNode produces = mapper.createArrayNode(); | ||
| 153 | + produces.add("application/json"); | ||
| 154 | + root.set("produces", produces); | ||
| 155 | + | ||
| 156 | + ArrayNode consumes = mapper.createArrayNode(); | ||
| 157 | + consumes.add("application/json"); | ||
| 158 | + root.set("consumes", consumes); | ||
| 159 | + | ||
| 160 | + return root; | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + // Checks whether javaClass has a path tag associated with it and if it does | ||
| 164 | + // processes its methods and creates a tag for the class on the root | ||
| 165 | + void processClass(JavaClass javaClass, ObjectNode paths, ArrayNode tags, | ||
| 166 | + ObjectNode definitions, File srcDirectory) { | ||
| 167 | + // If the class does not have a Path tag then ignore it | ||
| 168 | + JavaAnnotation annotation = getPathAnnotation(javaClass); | ||
| 169 | + if (annotation == null) { | ||
| 170 | + return; | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + String path = getPath(annotation); | ||
| 174 | + if (path == null) { | ||
| 175 | + return; | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + String resourcePath = "/" + path; | ||
| 179 | + String tagPath = path.isEmpty() ? "/" : path; | ||
| 180 | + | ||
| 181 | + // Create tag node for this class. | ||
| 182 | + ObjectNode tagObject = mapper.createObjectNode(); | ||
| 183 | + tagObject.put("name", tagPath); | ||
| 184 | + if (javaClass.getComment() != null) { | ||
| 185 | + tagObject.put("description", shortText(javaClass.getComment())); | ||
| 186 | + } | ||
| 187 | + tags.add(tagObject); | ||
| 188 | + | ||
| 189 | + // Create an array node add to all methods from this class. | ||
| 190 | + ArrayNode tagArray = mapper.createArrayNode(); | ||
| 191 | + tagArray.add(tagPath); | ||
| 192 | + | ||
| 193 | + processAllMethods(javaClass, resourcePath, paths, tagArray, definitions, srcDirectory); | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + private JavaAnnotation getPathAnnotation(JavaClass javaClass) { | ||
| 197 | + Optional<JavaAnnotation> optional = javaClass.getAnnotations() | ||
| 198 | + .stream().filter(a -> a.getType().getName().equals(PATH)).findAny(); | ||
| 199 | + return optional.orElse(null); | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + // Checks whether a class's methods are REST methods and then places all the | ||
| 203 | + // methods under a specific path into the paths node | ||
| 204 | + private void processAllMethods(JavaClass javaClass, String resourcePath, | ||
| 205 | + ObjectNode paths, ArrayNode tagArray, ObjectNode definitions, | ||
| 206 | + File srcDirectory) { | ||
| 207 | + // map of the path to its methods represented by an ObjectNode | ||
| 208 | + Map<String, ObjectNode> pathMap = new HashMap<>(); | ||
| 209 | + | ||
| 210 | + javaClass.getMethods().forEach(javaMethod -> { | ||
| 211 | + javaMethod.getAnnotations().forEach(annotation -> { | ||
| 212 | + String name = annotation.getType().getName(); | ||
| 213 | + if (name.equals(POST) || name.equals(GET) || name.equals(DELETE) || name.equals(PUT)) { | ||
| 214 | + // substring(12) removes "javax.ws.rs." | ||
| 215 | + String method = annotation.getType().toString().substring(12).toLowerCase(); | ||
| 216 | + processRestMethod(javaMethod, method, pathMap, resourcePath, tagArray, definitions, srcDirectory); | ||
| 217 | + } | ||
| 218 | + }); | ||
| 219 | + }); | ||
| 220 | + | ||
| 221 | + // for each path add its methods to the path node | ||
| 222 | + for (Map.Entry<String, ObjectNode> entry : pathMap.entrySet()) { | ||
| 223 | + paths.set(entry.getKey(), entry.getValue()); | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + private void processRestMethod(JavaMethod javaMethod, String method, | ||
| 230 | + Map<String, ObjectNode> pathMap, | ||
| 231 | + String resourcePath, ArrayNode tagArray, | ||
| 232 | + ObjectNode definitions, File srcDirectory) { | ||
| 233 | + String fullPath = resourcePath, consumes = "", produces = "", | ||
| 234 | + comment = javaMethod.getComment(); | ||
| 235 | + DocletTag tag = javaMethod.getTagByName("onos.rsModel"); | ||
| 236 | + for (JavaAnnotation annotation : javaMethod.getAnnotations()) { | ||
| 237 | + String name = annotation.getType().getName(); | ||
| 238 | + if (name.equals(PATH)) { | ||
| 239 | + fullPath = resourcePath + "/" + getPath(annotation); | ||
| 240 | + fullPath = fullPath.replaceFirst("^//", "/"); | ||
| 241 | + } | ||
| 242 | + if (name.equals(CONSUMES)) { | ||
| 243 | + consumes = getIOType(annotation); | ||
| 244 | + } | ||
| 245 | + if (name.equals(PRODUCES)) { | ||
| 246 | + produces = getIOType(annotation); | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | + ObjectNode methodNode = mapper.createObjectNode(); | ||
| 250 | + methodNode.set("tags", tagArray); | ||
| 251 | + | ||
| 252 | + addSummaryDescriptions(methodNode, comment); | ||
| 253 | + addJsonSchemaDefinition(srcDirectory, definitions, tag); | ||
| 254 | + | ||
| 255 | + processParameters(javaMethod, methodNode, method, tag); | ||
| 256 | + | ||
| 257 | + processConsumesProduces(methodNode, "consumes", consumes); | ||
| 258 | + processConsumesProduces(methodNode, "produces", produces); | ||
| 259 | + if (tag == null || ((method.toLowerCase().equals("post") || method.toLowerCase().equals("put")) | ||
| 260 | + && !(tag.getParameters().size() > 1))) { | ||
| 261 | + addResponses(methodNode, tag, false); | ||
| 262 | + } else { | ||
| 263 | + addResponses(methodNode, tag, true); | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + ObjectNode operations = pathMap.get(fullPath); | ||
| 267 | + if (operations == null) { | ||
| 268 | + operations = mapper.createObjectNode(); | ||
| 269 | + operations.set(method, methodNode); | ||
| 270 | + pathMap.put(fullPath, operations); | ||
| 271 | + } else { | ||
| 272 | + operations.set(method, methodNode); | ||
| 273 | + } | ||
| 274 | + } | ||
| 275 | + | ||
| 276 | + private void addJsonSchemaDefinition(File srcDirectory, ObjectNode definitions, DocletTag tag) { | ||
| 277 | + final File definitionsDirectory; | ||
| 278 | + if (resourceDirectory != null) { | ||
| 279 | + definitionsDirectory = new File(resourceDirectory, "definitions"); | ||
| 280 | + } else if (srcDirectory != null) { | ||
| 281 | + definitionsDirectory = new File(srcDirectory + "/src/main/resources/definitions"); | ||
| 282 | + } else { | ||
| 283 | + definitionsDirectory = null; | ||
| 284 | + } | ||
| 285 | + if (tag != null) { | ||
| 286 | + tag.getParameters().forEach(param -> { | ||
| 287 | + try { | ||
| 288 | + File config; | ||
| 289 | + if (definitionsDirectory != null) { | ||
| 290 | + config = new File(definitionsDirectory.getAbsolutePath() + "/" + param + ".json"); | ||
| 291 | + } else { | ||
| 292 | + config = resources.stream().filter(f -> f.getName().equals(param + ".json")).findFirst().orElse(null); | ||
| 293 | + } | ||
| 294 | + definitions.set(param, mapper.readTree(config)); | ||
| 295 | + } catch (IOException e) { | ||
| 296 | + throw new RuntimeException(String.format("Could not process %s in %s@%s: %s", | ||
| 297 | + tag.getName(), tag.getContext(), tag.getLineNumber(), | ||
| 298 | + e.getMessage()), e); | ||
| 299 | + } | ||
| 300 | + }); | ||
| 301 | + } | ||
| 302 | + } | ||
| 303 | + | ||
| 304 | + private void processConsumesProduces(ObjectNode methodNode, String type, String io) { | ||
| 305 | + if (!io.equals("")) { | ||
| 306 | + ArrayNode array = mapper.createArrayNode(); | ||
| 307 | + methodNode.set(type, array); | ||
| 308 | + array.add(io); | ||
| 309 | + } | ||
| 310 | + } | ||
| 311 | + | ||
| 312 | + private void addSummaryDescriptions(ObjectNode methodNode, String comment) { | ||
| 313 | + String summary = "", description; | ||
| 314 | + if (comment != null) { | ||
| 315 | + if (comment.contains(".")) { | ||
| 316 | + int periodIndex = comment.indexOf("."); | ||
| 317 | + summary = comment.substring(0, periodIndex); | ||
| 318 | + description = comment.length() > periodIndex + 1 ? | ||
| 319 | + comment.substring(periodIndex + 1).trim() : ""; | ||
| 320 | + } else { | ||
| 321 | + description = comment; | ||
| 322 | + } | ||
| 323 | + methodNode.put("summary", summary); | ||
| 324 | + methodNode.put("description", description); | ||
| 325 | + } | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + // Temporary solution to add responses to a method | ||
| 329 | + private void addResponses(ObjectNode methodNode, DocletTag tag, boolean responseJson) { | ||
| 330 | + ObjectNode responses = mapper.createObjectNode(); | ||
| 331 | + methodNode.set("responses", responses); | ||
| 332 | + | ||
| 333 | + ObjectNode success = mapper.createObjectNode(); | ||
| 334 | + success.put("description", "successful operation"); | ||
| 335 | + responses.set("200", success); | ||
| 336 | + if (tag != null && responseJson) { | ||
| 337 | + ObjectNode schema = mapper.createObjectNode(); | ||
| 338 | + tag.getParameters().stream().forEach( | ||
| 339 | + param -> schema.put("$ref", "#/definitions/" + param)); | ||
| 340 | + success.set("schema", schema); | ||
| 341 | + } | ||
| 342 | + | ||
| 343 | + ObjectNode defaultObj = mapper.createObjectNode(); | ||
| 344 | + defaultObj.put("description", "Unexpected error"); | ||
| 345 | + responses.set("default", defaultObj); | ||
| 346 | + } | ||
| 347 | + | ||
| 348 | + // Checks if the annotations has a value of JSON and returns the string | ||
| 349 | + // that Swagger requires | ||
| 350 | + private String getIOType(JavaAnnotation annotation) { | ||
| 351 | + if (annotation.getNamedParameter("value").toString().equals(JSON)) { | ||
| 352 | + return "application/json"; | ||
| 353 | + } else if (annotation.getNamedParameter("value").toString().equals(OCTET_STREAM)) { | ||
| 354 | + return "application/octet_stream"; | ||
| 355 | + } | ||
| 356 | + return ""; | ||
| 357 | + } | ||
| 358 | + | ||
| 359 | + // If the annotation has a Path tag, returns the value with leading and | ||
| 360 | + // trailing double quotes and slash removed. | ||
| 361 | + private String getPath(JavaAnnotation annotation) { | ||
| 362 | + String path = annotation.getNamedParameter("value").toString(); | ||
| 363 | + return path == null ? null : path.replaceAll("(^[\\\"/]*|[/\\\"]*$)", ""); | ||
| 364 | + } | ||
| 365 | + | ||
| 366 | + // Processes parameters of javaMethod and enters the proper key-values into the methodNode | ||
| 367 | + private void processParameters(JavaMethod javaMethod, ObjectNode methodNode, String method, DocletTag tag) { | ||
| 368 | + ArrayNode parameters = mapper.createArrayNode(); | ||
| 369 | + methodNode.set("parameters", parameters); | ||
| 370 | + boolean required = true; | ||
| 371 | + | ||
| 372 | + for (JavaParameter javaParameter : javaMethod.getParameters()) { | ||
| 373 | + ObjectNode individualParameterNode = mapper.createObjectNode(); | ||
| 374 | + Optional<JavaAnnotation> optional = javaParameter.getAnnotations().stream().filter( | ||
| 375 | + annotation -> annotation.getType().getName().equals(PATH_PARAM) || | ||
| 376 | + annotation.getType().getName().equals(QUERY_PARAM)).findAny(); | ||
| 377 | + JavaAnnotation pathType = optional.orElse(null); | ||
| 378 | + | ||
| 379 | + String annotationName = javaParameter.getName(); | ||
| 380 | + | ||
| 381 | + | ||
| 382 | + if (pathType != null) { //the parameter is a path or query parameter | ||
| 383 | + individualParameterNode.put("name", | ||
| 384 | + pathType.getNamedParameter("value") | ||
| 385 | + .toString().replace("\"", "")); | ||
| 386 | + if (pathType.getType().getName().equals(PATH_PARAM)) { | ||
| 387 | + individualParameterNode.put("in", "path"); | ||
| 388 | + } else if (pathType.getType().getName().equals(QUERY_PARAM)) { | ||
| 389 | + individualParameterNode.put("in", "query"); | ||
| 390 | + } | ||
| 391 | + individualParameterNode.put("type", getType(javaParameter.getType())); | ||
| 392 | + } else { // the parameter is a body parameter | ||
| 393 | + individualParameterNode.put("name", annotationName); | ||
| 394 | + individualParameterNode.put("in", "body"); | ||
| 395 | + | ||
| 396 | + // Adds the reference to the Json model for the input | ||
| 397 | + // that goes in the post or put operation | ||
| 398 | + if (tag != null && (method.toLowerCase().equals("post") || | ||
| 399 | + method.toLowerCase().equals("put"))) { | ||
| 400 | + ObjectNode schema = mapper.createObjectNode(); | ||
| 401 | + tag.getParameters().stream().forEach(param -> { | ||
| 402 | + schema.put("$ref", "#/definitions/" + param); | ||
| 403 | + }); | ||
| 404 | + individualParameterNode.set("schema", schema); | ||
| 405 | + } | ||
| 406 | + } | ||
| 407 | + for (DocletTag p : javaMethod.getTagsByName("param")) { | ||
| 408 | + if (p.getValue().contains(annotationName)) { | ||
| 409 | + String description = ""; | ||
| 410 | + if (p.getValue().split(" ", 2).length >= 2) { | ||
| 411 | + description = p.getValue().split(" ", 2)[1].trim(); | ||
| 412 | + if (description.contains("optional")) { | ||
| 413 | + required = false; | ||
| 414 | + } | ||
| 415 | + } else { | ||
| 416 | + throw new RuntimeException(String.format("No description for parameter \"%s\" in " + | ||
| 417 | + "method \"%s\" in %s (line %d)", | ||
| 418 | + p.getValue(), javaMethod.getName(), | ||
| 419 | + javaMethod.getDeclaringClass().getName(), | ||
| 420 | + javaMethod.getLineNumber())); | ||
| 421 | + } | ||
| 422 | + individualParameterNode.put("description", description); | ||
| 423 | + } | ||
| 424 | + } | ||
| 425 | + individualParameterNode.put("required", required); | ||
| 426 | + parameters.add(individualParameterNode); | ||
| 427 | + } | ||
| 428 | + } | ||
| 429 | + | ||
| 430 | + // Returns the Swagger specified strings for the type of a parameter | ||
| 431 | + private String getType(JavaType javaType) { | ||
| 432 | + String type = javaType.getFullyQualifiedName(); | ||
| 433 | + String value; | ||
| 434 | + if (type.equals(String.class.getName())) { | ||
| 435 | + value = "string"; | ||
| 436 | + } else if (type.equals("int")) { | ||
| 437 | + value = "integer"; | ||
| 438 | + } else if (type.equals(boolean.class.getName())) { | ||
| 439 | + value = "boolean"; | ||
| 440 | + } else if (type.equals(long.class.getName())) { | ||
| 441 | + value = "number"; | ||
| 442 | + } else { | ||
| 443 | + value = ""; | ||
| 444 | + } | ||
| 445 | + return value; | ||
| 446 | + } | ||
| 447 | + | ||
| 448 | + // Writes the swagger.json file using the supplied JSON root. | ||
| 449 | + private void genCatalog(File dstDirectory, ObjectNode root) { | ||
| 450 | + File swaggerCfg = new File(dstDirectory, JSON_FILE); | ||
| 451 | + if (dstDirectory.exists() || dstDirectory.mkdirs()) { | ||
| 452 | + try (FileWriter fw = new FileWriter(swaggerCfg); | ||
| 453 | + PrintWriter pw = new PrintWriter(fw)) { | ||
| 454 | + pw.println(root.toString()); | ||
| 455 | + } catch (IOException e) { | ||
| 456 | + throw new RuntimeException("Unable to write " + JSON_FILE, e); | ||
| 457 | + } | ||
| 458 | + } else { | ||
| 459 | + throw new RuntimeException("Unable to create " + dstDirectory); | ||
| 460 | + } | ||
| 461 | + } | ||
| 462 | + | ||
| 463 | + // Generates the registrator Java component. | ||
| 464 | + private void genRegistrator(File dstDirectory, String webContext, | ||
| 465 | + String apiTitle, String apiVersion, | ||
| 466 | + String apiPackage, String apiDescription) { | ||
| 467 | + File dir = new File(dstDirectory, resourceDirectory != null ? GEN_SRC : "."); | ||
| 468 | + File reg = new File(dir, apiRegistratorPath(apiPackage)); | ||
| 469 | + File pkg = reg.getParentFile(); | ||
| 470 | + if (pkg.exists() || pkg.mkdirs()) { | ||
| 471 | + try { | ||
| 472 | + String src = new String(ByteStreams.toByteArray(getClass().getResourceAsStream(REG_SRC))); | ||
| 473 | + src = src.replace("${api.package}", apiPackage) | ||
| 474 | + .replace("${web.context}", webContext) | ||
| 475 | + .replace("${api.title}", apiTitle) | ||
| 476 | + .replace("${api.description}", apiDescription); | ||
| 477 | + Files.write(src.getBytes(), reg); | ||
| 478 | + } catch (IOException e) { | ||
| 479 | + throw new RuntimeException("Unable to write " + reg, e); | ||
| 480 | + } | ||
| 481 | + } else { | ||
| 482 | + throw new RuntimeException("Unable to create " + reg); | ||
| 483 | + } | ||
| 484 | + } | ||
| 485 | + | ||
| 486 | + private String shortText(String comment) { | ||
| 487 | + int i = comment.indexOf('.'); | ||
| 488 | + return i > 0 ? comment.substring(0, i) : comment; | ||
| 489 | + } | ||
| 490 | + | ||
| 491 | + public static String apiRegistratorPath(String apiPackage) { | ||
| 492 | + return apiPackage.replaceAll("\\.", "/") + "/ApiDocRegistrator.java"; | ||
| 493 | + } | ||
| 494 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.onosjar; | ||
| 17 | + | ||
| 18 | +import com.facebook.buck.io.ProjectFilesystem; | ||
| 19 | +import com.facebook.buck.rules.SourcePathResolver; | ||
| 20 | +import com.facebook.buck.step.AbstractExecutionStep; | ||
| 21 | +import com.facebook.buck.step.ExecutionContext; | ||
| 22 | +import com.facebook.buck.step.StepExecutionResult; | ||
| 23 | +import com.google.common.collect.ImmutableSortedSet; | ||
| 24 | + | ||
| 25 | +import java.io.File; | ||
| 26 | +import java.io.IOException; | ||
| 27 | +import java.nio.file.Path; | ||
| 28 | +import java.util.List; | ||
| 29 | +import java.util.stream.Collectors; | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * Buck build step to trigger SwaggerGenerator. | ||
| 33 | + */ | ||
| 34 | +public class SwaggerStep extends AbstractExecutionStep { | ||
| 35 | + | ||
| 36 | + private final ProjectFilesystem filesystem; | ||
| 37 | + | ||
| 38 | + private final ImmutableSortedSet<Path> srcs; | ||
| 39 | + private final ImmutableSortedSet<Path> resources; | ||
| 40 | + private final Path genSourcesOutput; | ||
| 41 | + private final Path genResourcesOutput; | ||
| 42 | + | ||
| 43 | + private final String webContext; | ||
| 44 | + private final String apiTitle; | ||
| 45 | + private final String apiVersion; | ||
| 46 | + private final String apiPackage; | ||
| 47 | + private final String apiDescription; | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + public SwaggerStep(ProjectFilesystem filesystem, | ||
| 51 | + ImmutableSortedSet<Path> srcs, | ||
| 52 | + ImmutableSortedSet<Path> resources, | ||
| 53 | + Path genSourcesOutput, Path genResourcesOutput, | ||
| 54 | + String webContext, String apiTitle, String apiVersion, | ||
| 55 | + String apiPackage, String apiDescription) { | ||
| 56 | + super("swagger"); | ||
| 57 | + this.filesystem = filesystem; | ||
| 58 | + this.srcs = srcs; | ||
| 59 | + this.resources = resources; | ||
| 60 | + this.genSourcesOutput = genSourcesOutput; | ||
| 61 | + this.genResourcesOutput = genResourcesOutput; | ||
| 62 | + this.webContext = webContext; | ||
| 63 | + this.apiTitle = apiTitle; | ||
| 64 | + this.apiVersion = apiVersion; | ||
| 65 | + this.apiPackage = apiPackage; | ||
| 66 | + this.apiDescription = apiDescription; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + @Override | ||
| 70 | + public StepExecutionResult execute(ExecutionContext executionContext) | ||
| 71 | + throws IOException, InterruptedException { | ||
| 72 | + try { | ||
| 73 | + List<File> srcFiles = srcs.stream() | ||
| 74 | + .map(src -> filesystem.resolve(src).toFile()) | ||
| 75 | + .collect(Collectors.toList()); | ||
| 76 | + List<File> resourceFiles = resources.stream() | ||
| 77 | + .map(rsrc -> filesystem.resolve(rsrc).toFile()) | ||
| 78 | + .collect(Collectors.toList()); | ||
| 79 | + new SwaggerGenerator(srcFiles, resourceFiles, null, null, | ||
| 80 | + filesystem.resolve(genSourcesOutput).toFile(), | ||
| 81 | + filesystem.resolve(genResourcesOutput).toFile(), | ||
| 82 | + webContext, | ||
| 83 | + apiTitle, | ||
| 84 | + apiVersion, | ||
| 85 | + apiPackage, | ||
| 86 | + apiDescription).execute(); | ||
| 87 | + | ||
| 88 | + return StepExecutionResult.SUCCESS; | ||
| 89 | + } catch (Exception e) { | ||
| 90 | + e.printStackTrace(); | ||
| 91 | + // FIXME print the exception | ||
| 92 | + return StepExecutionResult.ERROR; | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + Path apiRegistratorPath() { | ||
| 97 | + return genSourcesOutput.resolve(SwaggerGenerator.apiRegistratorPath(apiPackage)); | ||
| 98 | + } | ||
| 99 | +} |
| 1 | +/* | ||
| 2 | + * Auto-generated by OnosSwaggerMojo. | ||
| 3 | + * | ||
| 4 | + * Copyright 2015-present Open Networking Laboratory | ||
| 5 | + * | ||
| 6 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 7 | + * you may not use this file except in compliance with the License. | ||
| 8 | + * You may obtain a copy of the License at | ||
| 9 | + * | ||
| 10 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 11 | + * | ||
| 12 | + * Unless required by applicable law or agreed to in writing, software | ||
| 13 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 14 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 15 | + * See the License for the specific language governing permissions and | ||
| 16 | + * limitations under the License. | ||
| 17 | + */ | ||
| 18 | +package ${api.package}; | ||
| 19 | + | ||
| 20 | +import org.apache.felix.scr.annotations.Component; | ||
| 21 | +import org.onosproject.rest.AbstractApiDocRegistrator; | ||
| 22 | +import org.onosproject.rest.ApiDocProvider; | ||
| 23 | + | ||
| 24 | +@Component(immediate = true) | ||
| 25 | +public class ApiDocRegistrator extends AbstractApiDocRegistrator { | ||
| 26 | + public ApiDocRegistrator() { | ||
| 27 | + super(new ApiDocProvider("${web.context}", | ||
| 28 | + "${api.title}", | ||
| 29 | + ApiDocRegistrator.class.getClassLoader())); | ||
| 30 | + } | ||
| 31 | +} |
| ... | @@ -34,5 +34,29 @@ if [ -n "$FORCE_UPDATE" ] || [ ! -f "buck" ] || [ "$REQUIRED_VERSION" != "$(cat | ... | @@ -34,5 +34,29 @@ if [ -n "$FORCE_UPDATE" ] || [ ! -f "buck" ] || [ "$REQUIRED_VERSION" != "$(cat |
| 34 | fi | 34 | fi |
| 35 | popd > /dev/null | 35 | popd > /dev/null |
| 36 | 36 | ||
| 37 | +BUCK=$ONOS_ROOT/bin/buck | ||
| 38 | +PLUGINS=$ONOS_ROOT/bucklets/plugins | ||
| 39 | +ONOS_PLUGIN=$PLUGINS/onosjar.jar | ||
| 40 | + | ||
| 41 | +if [ ! -f "$ONOS_PLUGIN" -o -n "$ONOS_BUILD_PLUGIN" ]; then | ||
| 42 | + echo "Building ONOS Buck plugins..." | ||
| 43 | + | ||
| 44 | + # Build it first | ||
| 45 | + pluginJar=$(NO_BUCKD=1 $BUCK build //tools/build/buck-plugin:onosjar --show-output 2>/dev/null | grep onosjar.jar | cut -d\ -f2) | ||
| 46 | + | ||
| 47 | + CHK_NEW=$(cksum $pluginJar | cut -d' ' -f1-2) | ||
| 48 | + CHK_OLD=$(cksum $ONOS_PLUGIN 2>/dev/null | cut -d' ' -f1-2) | ||
| 49 | + if [ "$CHK_NEW" != "$CHK_OLD" ]; then | ||
| 50 | + # diff plugins... if different, copy and restart buckd | ||
| 51 | + # Then install it | ||
| 52 | + mkdir -p $PLUGINS | ||
| 53 | + cp $ONOS_ROOT/$pluginJar $PLUGINS | ||
| 54 | + echo "Updated to the latest plugin." | ||
| 55 | + $BUCK clean 2>/dev/null | ||
| 56 | + else | ||
| 57 | + echo "Plugin was already up to date." | ||
| 58 | + fi | ||
| 59 | +fi | ||
| 60 | + | ||
| 37 | # Finally, run the Buck command... | 61 | # Finally, run the Buck command... |
| 38 | -$ONOS_ROOT/bin/buck "$@" | 62 | +$BUCK "$@" | ... | ... |
| ... | @@ -14,4 +14,8 @@ osgi_jar_with_tests ( | ... | @@ -14,4 +14,8 @@ osgi_jar_with_tests ( |
| 14 | deps = COMPILE_DEPS, | 14 | deps = COMPILE_DEPS, |
| 15 | test_deps = TEST_DEPS, | 15 | test_deps = TEST_DEPS, |
| 16 | web_context = '/onos/v1', | 16 | web_context = '/onos/v1', |
| 17 | + api_title = 'ONOS Core REST API', | ||
| 18 | + api_version = '1.0', | ||
| 19 | + api_description = 'ONOS Core REST API', | ||
| 20 | + api_package = 'org.onosproject.rest.impl', | ||
| 17 | ) | 21 | ) | ... | ... |
-
Please register or login to post a comment