This is an automated email from the ASF dual-hosted git repository. ningjiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/servicecomb-toolkit.git
commit 138610e7aadce35c2b92064f55cc9612f577296f Author: MabinGo <bin...@huawei.com> AuthorDate: Tue May 21 08:37:19 2019 +0800 Add plugin to support generating contract by code Signed-off-by: MabinGo <bin...@huawei.com> --- common/pom.xml | 93 ++++++++++++ .../apache/servicecomb/toolkit/ContractsUtils.java | 167 +++++++++++++++++++++ .../servicecomb/toolkit/ImmediateClassLoader.java | 57 +++++++ pom.xml | 2 + toolkit-maven-plugin/pom.xml | 107 +++++++++++++ .../toolkit/plugin/ContractGenerator.java | 61 ++++++++ .../toolkit/plugin/GenerateContractsDocMojo.java | 83 ++++++++++ .../toolkit/plugin/GenerateContractsMojo.java | 59 ++++++++ 8 files changed, 629 insertions(+) diff --git a/common/pom.xml b/common/pom.xml new file mode 100755 index 0000000..4b9bbd9 --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<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>toolkit</artifactId> + <groupId>org.apache.servicecomb</groupId> + <version>0.1.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>toolkit-common</artifactId> + + <dependencies> + + <dependency> + <groupId>org.eclipse.jgit</groupId> + <artifactId>org.eclipse.jgit</artifactId> + <version>5.3.0.201903130848-r</version> + </dependency> + + <dependency> + <groupId>org.apache.servicecomb</groupId> + <artifactId>swagger-generator-springmvc</artifactId> + <version>1.2.0</version> + </dependency> + + <dependency> + <groupId>org.apache.servicecomb</groupId> + <artifactId>swagger-generator-jaxrs</artifactId> + <version>1.2.0</version> + </dependency> + + <dependency> + <groupId>org.apache.servicecomb</groupId> + <artifactId>provider-rest-common</artifactId> + <version>1.2.0</version> + </dependency> + + <dependency> + <groupId>org.apache.servicecomb</groupId> + <artifactId>provider-pojo</artifactId> + <version>1.2.0</version> + <exclusions> + <exclusion> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/common/src/main/java/org/apache/servicecomb/toolkit/ContractsUtils.java b/common/src/main/java/org/apache/servicecomb/toolkit/ContractsUtils.java new file mode 100755 index 0000000..032e458 --- /dev/null +++ b/common/src/main/java/org/apache/servicecomb/toolkit/ContractsUtils.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URL; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +import org.apache.servicecomb.provider.pojo.RpcSchema; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.SwaggerUtils; +import org.apache.servicecomb.swagger.generator.core.CompositeSwaggerGeneratorContext; +import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator; +import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.models.Swagger; + +public class ContractsUtils { + + private static CompositeSwaggerGeneratorContext compositeSwaggerGeneratorContext = new CompositeSwaggerGeneratorContext(); + + private static Logger LOGGER = LoggerFactory.getLogger(ContractsUtils.class); + + public static Map<String, Swagger> getContractsFromFileSystem(String dir) throws IOException { + + Map<String, Swagger> contracts = new HashMap<>(); + File outputDir = new File(dir); + + Files.walkFileTree(Paths.get(outputDir.toURI()), new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + contracts.put(file.toFile().getName(), SwaggerUtils.parseSwagger(file.toUri().toURL())); + return super.visitFile(file, attrs); + } + }); + + return contracts; + } + + public static Map<String, byte[]> getFilesGroupByFilename(String dir) throws IOException { + + Map<String, byte[]> contracts = new HashMap<>(); + File outputDir = new File(dir); + + Files.walkFileTree(Paths.get(outputDir.toURI()), new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + contracts.put(file.toFile().getName(), Files.readAllBytes(file)); + return super.visitFile(file, attrs); + } + }); + + return contracts; + } + + public static void generateAndOutputContracts(String outputDir, String format, URL[] classpathUrls) { + + ImmediateClassLoader immediateClassLoader = new ImmediateClassLoader(classpathUrls, + Thread.currentThread().getContextClassLoader()); + + try { + + Vector allClass = getAllClass(immediateClassLoader); + + for (int i = 0; i < allClass.size(); i++) { + + Class loadClass = (Class) allClass.get(i); + if (!canProcess(loadClass)) { + continue; + } + + SwaggerGeneratorContext generatorContext = + compositeSwaggerGeneratorContext.selectContext(loadClass); + + SwaggerGenerator generator = new SwaggerGenerator(generatorContext, loadClass); + + String swaggerString = SwaggerUtils.swaggerToString(generator.generate()); + + File outputFile = new File(outputDir + File.separator + loadClass.getSimpleName() + format); + + if (!outputFile.exists()) { + if (!outputFile.getParentFile().exists()) { + outputFile.getParentFile().mkdirs(); + } + outputFile.createNewFile(); + } + + Files.write(Paths.get(outputFile.toURI()), swaggerString.getBytes()); + } + } catch (IOException e) { + LOGGER.error(e.getMessage()); + } + } + + private static boolean canProcess(Class<?> loadClass) { + + if (loadClass == null) { + return false; + } + RestSchema restSchema = loadClass.getAnnotation(RestSchema.class); + if (restSchema != null) { + return true; + } + + RestController controller = loadClass.getAnnotation(RestController.class); + if (controller != null) { + return true; + } + + RpcSchema rpcSchema = loadClass.getAnnotation(RpcSchema.class); + if (rpcSchema != null) { + return true; + } + + RequestMapping requestMapping = loadClass.getAnnotation(RequestMapping.class); + if (requestMapping != null) { + return true; + } + + return false; + } + + + private static Vector getAllClass(ClassLoader classLoader) { + Field classesField; + try { + classesField = ClassLoader.class.getDeclaredField("classes"); + classesField.setAccessible(true); + + if (classesField.get(classLoader) instanceof Vector) { + return (Vector) classesField.get(classLoader); + } + } catch (Exception e) { + LOGGER.warn("cannot get all class from ClassLoader " + classLoader.getClass()); + } + return new Vector<>(); + } +} diff --git a/common/src/main/java/org/apache/servicecomb/toolkit/ImmediateClassLoader.java b/common/src/main/java/org/apache/servicecomb/toolkit/ImmediateClassLoader.java new file mode 100755 index 0000000..421aa1a --- /dev/null +++ b/common/src/main/java/org/apache/servicecomb/toolkit/ImmediateClassLoader.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; + +public class ImmediateClassLoader extends URLClassLoader { + + private String classPath; + + public ImmediateClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + for (URL url : urls) { + if (url != null) { + File file = new File(url.getPath()); + classPath = file.getAbsolutePath(); + scanClassFile(file); + } + } + } + + private void scanClassFile(File file) { + if (file.exists()) { + if (file.isFile() && file.getName().endsWith(".class")) { + try { + String className = file.getAbsolutePath().replace(classPath + File.separator, "") + .replace(File.separator, ".") + .replace(".class", ""); + loadClass(className); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } else if (file.isDirectory()) { + for (File f : file.listFiles()) { + scanClassFile(f); + } + } + } + } +} diff --git a/pom.xml b/pom.xml index d97307d..9943324 100755 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,8 @@ <module>code-generator</module> <module>toolkit-cli</module> <module>doc-generator</module> + <module>common</module> + <module>toolkit-maven-plugin</module> </modules> </project> diff --git a/toolkit-maven-plugin/pom.xml b/toolkit-maven-plugin/pom.xml new file mode 100755 index 0000000..b51f335 --- /dev/null +++ b/toolkit-maven-plugin/pom.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<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>toolkit</artifactId> + <groupId>org.apache.servicecomb</groupId> + <version>0.1.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <packaging>maven-plugin</packaging> + <artifactId>toolkit-maven-plugin</artifactId> + + <dependencies> + + <dependency> + <groupId>org.apache.servicecomb</groupId> + <artifactId>doc-generator</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + <version>3.6.0</version> + </dependency> + + <dependency> + <groupId>org.apache.maven.plugin-tools</groupId> + <artifactId>maven-plugin-annotations</artifactId> + <version>3.6.0</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-core</artifactId> + <version>3.6.0</version> + </dependency> + + <dependency> + <groupId>org.codehaus.plexus</groupId> + <artifactId>plexus-archiver</artifactId> + <version>2.1</version> + </dependency> + <dependency> + <groupId>org.apache.servicecomb</groupId> + <artifactId>toolkit-common</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-plugin-plugin</artifactId> + <version>3.5</version> + <configuration> + <goalPrefix>toolkit</goalPrefix> + <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound> + </configuration> + <executions> + <execution> + <id>generate-descriptor</id> + <goals> + <goal>descriptor</goal> + </goals> + </execution> + <execution> + <id>generated-helpmojo</id> + <goals> + <goal>helpmojo</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + + +</project> diff --git a/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/ContractGenerator.java b/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/ContractGenerator.java new file mode 100755 index 0000000..85bce32 --- /dev/null +++ b/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/ContractGenerator.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.plugin; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +import org.apache.maven.artifact.DependencyResolutionRequiredException; +import org.apache.maven.project.MavenProject; +import org.apache.servicecomb.toolkit.ContractsUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ContractGenerator { + + private static Logger LOGGER = LoggerFactory.getLogger(ContractGenerator.class); + + private MavenProject project; + + public ContractGenerator(MavenProject project) { + this.project = project; + } + + public void generateAndOutput(String outputDir, String format) { + + List runtimeClasspaths = null; + try { + runtimeClasspaths = project.getRuntimeClasspathElements(); + } catch (DependencyResolutionRequiredException e) { + LOGGER.error(e.getMessage()); + } + URL[] runtimeUrls = new URL[runtimeClasspaths.size()]; + for (int i = 0; i < runtimeClasspaths.size(); i++) { + String element = (String) runtimeClasspaths.get(i); + try { + runtimeUrls[i] = new File(element).toURI().toURL(); + } catch (MalformedURLException e) { + LOGGER.error(e.getMessage()); + } + } + + ContractsUtils.generateAndOutputContracts(outputDir, format, runtimeUrls); + } +} diff --git a/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/GenerateContractsDocMojo.java b/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/GenerateContractsDocMojo.java new file mode 100755 index 0000000..200d177 --- /dev/null +++ b/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/GenerateContractsDocMojo.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.plugin; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Execute; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; +import org.apache.servicecomb.docgen.DocGeneratorManager; +import org.apache.servicecomb.swagger.SwaggerUtils; + +@Mojo(name = "generateDoc", defaultPhase = LifecyclePhase.COMPILE, requiresDependencyResolution = ResolutionScope.COMPILE) +@Execute(goal = "generateDoc", + phase = LifecyclePhase.COMPILE +) +public class GenerateContractsDocMojo extends AbstractMojo { + + @Parameter(defaultValue = "${project}", required = true, readonly = true) + private MavenProject project; + + @Parameter(defaultValue = "contracts") + private String outputDir; + + @Parameter(defaultValue = ".yaml") + private String format; + + @Parameter(defaultValue = "build/doc") + private String docOutputDir; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + ContractGenerator contractGenerator = new ContractGenerator(project); + contractGenerator.generateAndOutput(outputDir, format); + + try { + + Files.walkFileTree(Paths.get(outputDir), new SimpleFileVisitor<Path>() { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + + DocGeneratorManager.generate(SwaggerUtils.parseSwagger(file.toUri().toURL()), + docOutputDir + File.separator + + file.toFile().getName().substring(0, file.toFile().getName().indexOf(".")) + ".html", + "html"); + return super.visitFile(file, attrs); + } + }); + } catch (IOException e) { + getLog().error(e.getMessage()); + } + } +} diff --git a/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/GenerateContractsMojo.java b/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/GenerateContractsMojo.java new file mode 100755 index 0000000..9d1b599 --- /dev/null +++ b/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/GenerateContractsMojo.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.plugin; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Execute; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; + +@Mojo(name = "generateContracts", defaultPhase = LifecyclePhase.COMPILE, requiresDependencyResolution = ResolutionScope.RUNTIME) +@Execute(goal = "generateContracts", + phase = LifecyclePhase.COMPILE +) +public class GenerateContractsMojo + extends AbstractMojo { + + @Parameter(defaultValue = "${project}", required = true, readonly = true) + private MavenProject project; + + @Parameter(defaultValue = "contracts") + private String outputDir; + + @Parameter(defaultValue = ".yaml") + private String format; + + @Override + public void execute() + throws MojoExecutionException { + + ContractGenerator contractGenerator = new ContractGenerator(project); + contractGenerator.generateAndOutput(outputDir, format); + } + + /** + * @param project the project to set + */ + public void setProject(MavenProject project) { + this.project = project; + } +}