├── Gemfile ├── _config.yml ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .editorconfig ├── settings.gradle.kts ├── src └── main │ └── java │ └── io │ └── reactiverse │ └── elasticsearch │ └── client │ └── package-info.java ├── shim-generator ├── src │ └── main │ │ ├── resources │ │ └── logback.xml │ │ └── java │ │ └── shimgen │ │ ├── NestedClientFinder.java │ │ ├── Analyze.java │ │ └── ShimMaker.java └── build.gradle.kts ├── .github └── workflows │ └── ci-cd.yml ├── integration-tests ├── build.gradle.kts └── src │ └── test │ └── java │ └── integration │ ├── MutinyTests.java │ ├── RxJava2Tests.java │ └── CallbackTests.java ├── README.md ├── gradlew.bat ├── elasticsearch-client-rxjava2 └── build.gradle.kts ├── elasticsearch-client-rxjava3 └── build.gradle.kts ├── elasticsearch-client-mutiny └── build.gradle.kts ├── gradlew └── LICENSE /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'github-pages', group: :jekyll_plugins 4 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | 2 | theme: jekyll-theme-minimal 3 | repository: reactiverse/elasticsearch-client 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.ipr 2 | *.iws 3 | *.iml 4 | .gradle/ 5 | .idea/ 6 | build/ 7 | out/ 8 | **/src/main/generated 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reactiverse/elasticsearch-client/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | trim_trailing_whitespace = true 8 | end_of_line = lf 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 | rootProject.name = "elasticsearch-client" 18 | 19 | include( 20 | "shim-generator", 21 | "integration-tests", 22 | "elasticsearch-client-rxjava2", 23 | "elasticsearch-client-rxjava3", 24 | "elasticsearch-client-mutiny" 25 | ) 26 | -------------------------------------------------------------------------------- /src/main/java/io/reactiverse/elasticsearch/client/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 | @ModuleGen(groupPackage = "io.reactiverse.elasticsearch.client", name = "client") 18 | package io.reactiverse.elasticsearch.client; 19 | 20 | import io.vertx.codegen.annotations.ModuleGen; 21 | -------------------------------------------------------------------------------- /shim-generator/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.github/workflows/ci-cd.yml: -------------------------------------------------------------------------------- 1 | name: Continuous integration and deployment 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | 14 | - uses: actions/checkout@v2 15 | 16 | - name: Set up JDK 8 17 | uses: actions/setup-java@v2 18 | with: 19 | java-version: '8' 20 | distribution: 'adopt' 21 | 22 | - name: Cache Gradle packages 23 | uses: actions/cache@v2 24 | with: 25 | path: | 26 | ~/.gradle/caches 27 | ~/.gradle/wrapper 28 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 29 | restore-keys: | 30 | ${{ runner.os }}-gradle- 31 | 32 | - name: Grant execute permission for gradlew 33 | run: chmod +x gradlew 34 | 35 | - name: Build with Gradle 36 | run: ./gradlew build 37 | 38 | - name: Deploy from the master branch 39 | if: github.ref == 'refs/heads/master' 40 | run: ./gradlew publish -PossrhUsername=${{ secrets.SONATYPE_NEXUS_USERNAME }} -PossrhPassword=${{ secrets.SONATYPE_NEXUS_PASSWORD }} 41 | 42 | - name: Cleanup Gradle Cache 43 | # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions. 44 | # Restoring these files from a GitHub Actions cache might cause problems for future builds. 45 | run: | 46 | rm -f ~/.gradle/caches/modules-2/modules-2.lock 47 | rm -f ~/.gradle/caches/modules-2/gc.properties 48 | -------------------------------------------------------------------------------- /integration-tests/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 | plugins { 18 | java 19 | } 20 | 21 | val vertxVersion = extra["vertxVersion"] 22 | val mutinyBindingsVersion = extra["mutinyBindingsVersion"] 23 | val assertjVersion = extra["assertjVersion"] 24 | val tcVersion = extra["tcVersion"] 25 | val junitVersion = extra["junitVersion"] 26 | 27 | dependencies { 28 | testImplementation(project(":elasticsearch-client-rxjava2")) 29 | testImplementation(project(":elasticsearch-client-mutiny")) 30 | 31 | testImplementation("io.vertx:vertx-junit5:${vertxVersion}") 32 | testImplementation("io.vertx:vertx-junit5-rx-java2:${vertxVersion}") 33 | testImplementation("io.smallrye.reactive:smallrye-mutiny-vertx-junit5:${mutinyBindingsVersion}") 34 | 35 | testImplementation("org.assertj:assertj-core:${assertjVersion}") 36 | testImplementation("org.testcontainers:elasticsearch:${tcVersion}") 37 | testImplementation("org.testcontainers:junit-jupiter:${tcVersion}") 38 | 39 | testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}") 40 | testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}") 41 | } 42 | 43 | tasks.test { 44 | useJUnitPlatform() 45 | } 46 | -------------------------------------------------------------------------------- /shim-generator/src/main/java/shimgen/NestedClientFinder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 shimgen; 18 | 19 | import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; 20 | import com.github.javaparser.ast.body.MethodDeclaration; 21 | import com.github.javaparser.ast.visitor.GenericListVisitorAdapter; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import java.util.Collections; 26 | import java.util.List; 27 | 28 | class NestedClientFinder extends GenericListVisitorAdapter { 29 | 30 | private final Logger logger = LoggerFactory.getLogger(NestedClientFinder.class); 31 | 32 | private ClassOrInterfaceDeclaration currentClass; 33 | 34 | @Override 35 | public List visit(ClassOrInterfaceDeclaration n, Void arg) { 36 | if (n.isPublic()) { 37 | currentClass = n; 38 | logger.info("Visiting class {}", n.getName()); 39 | } 40 | return super.visit(n, arg); 41 | } 42 | 43 | @Override 44 | public List visit(MethodDeclaration n, Void arg) { 45 | if (n.isPublic()) { 46 | logger.info("Looking at {} in {}", n.getName(), currentClass.getName()); 47 | String type = n.getTypeAsString(); 48 | if (type.endsWith("Client") && !Analyze.FILTERED_TYPES.contains(type)) { 49 | return Collections.singletonList(type); 50 | } 51 | } 52 | return super.visit(n, arg); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /shim-generator/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 | val elastic by configurations.creating 18 | 19 | val elasticSourcesDir = "$buildDir/elastic-sources/" 20 | val elasticShimsDir = "${buildDir}/elastic-shims" 21 | 22 | val elasticClientVersion = extra["elasticClientVersion"] 23 | val javaParserVersion = extra["javaParserVersion"] 24 | val logbackVersion = extra["logbackVersion"] 25 | 26 | dependencies { 27 | implementation("ch.qos.logback:logback-classic:${logbackVersion}") 28 | implementation("com.github.javaparser:javaparser-core:${javaParserVersion}") 29 | elastic("org.elasticsearch.client:elasticsearch-rest-high-level-client:${elasticClientVersion}:sources") 30 | } 31 | 32 | tasks { 33 | 34 | create("elastic-unpack") { 35 | val sources = elastic.resolve().filter { it.name.endsWith("-sources.jar") } 36 | sources.forEach { from(zipTree(it)) } 37 | into(elasticSourcesDir) 38 | } 39 | 40 | create("elastic-process") { 41 | main = "shimgen.Analyze" 42 | classpath = sourceSets["main"].runtimeClasspath 43 | args = listOf( 44 | "$elasticSourcesDir/org/elasticsearch/client/RestHighLevelClient.java", 45 | elasticShimsDir, 46 | "io.reactiverse.elasticsearch.client" 47 | ) 48 | description = "Generate the shims from the ElasticSearch source code" 49 | group = "build" 50 | dependsOn("elastic-unpack") 51 | inputs.dir(elasticSourcesDir) 52 | outputs.dir(elasticShimsDir) 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # An Elasticsearch client for Eclipse Vert.x 2 | 3 | [![Build Status](https://travis-ci.org/reactiverse/elasticsearch-client.svg?branch=master)](https://travis-ci.org/reactiverse/elasticsearch-client) 4 | 5 | This client exposes the [Elasticsearch Java High Level REST Client](https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-high.html) for [Eclipse Vert.x](https://vertx.io/) applications. 6 | 7 | ## Overview 8 | 9 | This client is based on automatically generated shims using a source-to-source transformation from the client source code. 10 | 11 | The generated shims ensure that asynchronous event processing respect the Vert.x threading model. 12 | 13 | ## Usage 14 | 15 | The following modules can be used: 16 | 17 | * `elasticsearch-client`: a classic Vert.x API based on callbacks and Vert.x 4.1.0 18 | * `elasticsearch-client-mutiny`: a [Mutiny](https://smallrye.io/smallrye-mutiny/) API of the client 19 | * `elasticsearch-client-rxjava2`: a RxJava 2 API of the client 20 | * `elasticsearch-client-rxjava3`: a RxJava 3 API of the client 21 | 22 | The Maven `groupId` is `io.reactiverse`. 23 | 24 | ## Sample usage 25 | 26 | Here is a sample usage of the RxJava 2 API where an index request is followed by a get request: 27 | 28 | ```java 29 | String yo = "{\"foo\": \"bar\"}"; 30 | IndexRequest req = new IndexRequest("posts", "_doc", "1").source(yo, XContentType.JSON); 31 | client 32 | .rxIndexAsync(req, RequestOptions.DEFAULT) 33 | .flatMap(resp -> client.rxGetAsync(new GetRequest("posts", "_all", "1"), RequestOptions.DEFAULT)) 34 | .subscribe(resp -> { 35 | // Handle the response here 36 | }); 37 | ``` 38 | 39 | ## Legal 40 | 41 | Originally developped by [Julien Ponge](https://julien.ponge.org/). 42 | 43 | Copyright 2018 Red Hat, Inc. 44 | 45 | Licensed under the Apache License, Version 2.0 (the "License"); 46 | you may not use this file except in compliance with the License. 47 | You may obtain a copy of the License at 48 | 49 | http://www.apache.org/licenses/LICENSE-2.0 50 | 51 | Unless required by applicable law or agreed to in writing, software 52 | distributed under the License is distributed on an "AS IS" BASIS, 53 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 54 | See the License for the specific language governing permissions and 55 | limitations under the License. 56 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /integration-tests/src/test/java/integration/MutinyTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Red Hat, Inc. 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 integration; 17 | 18 | import io.reactiverse.elasticsearch.client.mutiny.RestHighLevelClient; 19 | import io.vertx.junit5.VertxExtension; 20 | import io.vertx.junit5.VertxTestContext; 21 | import io.vertx.mutiny.core.Vertx; 22 | import org.apache.http.HttpHost; 23 | import org.elasticsearch.action.get.GetRequest; 24 | import org.elasticsearch.action.index.IndexRequest; 25 | import org.elasticsearch.client.RequestOptions; 26 | import org.elasticsearch.client.RestClient; 27 | import org.elasticsearch.client.RestClientBuilder; 28 | import org.elasticsearch.common.xcontent.XContentType; 29 | import org.junit.jupiter.api.AfterEach; 30 | import org.junit.jupiter.api.BeforeEach; 31 | import org.junit.jupiter.api.Test; 32 | import org.junit.jupiter.api.extension.ExtendWith; 33 | import org.testcontainers.elasticsearch.ElasticsearchContainer; 34 | import org.testcontainers.junit.jupiter.Container; 35 | import org.testcontainers.junit.jupiter.Testcontainers; 36 | 37 | import static org.assertj.core.api.Assertions.assertThat; 38 | 39 | @Testcontainers 40 | @ExtendWith(VertxExtension.class) 41 | public class MutinyTests { 42 | 43 | @Container 44 | private ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.1"); 45 | 46 | private RestHighLevelClient client; 47 | 48 | @BeforeEach 49 | void prepare(Vertx vertx) { 50 | RestClientBuilder builder = RestClient.builder( 51 | new HttpHost(container.getContainerIpAddress(), container.getMappedPort(9200), "http")); 52 | client = RestHighLevelClient.create(vertx, builder); 53 | } 54 | 55 | @AfterEach 56 | void close() { 57 | client.close(); 58 | } 59 | 60 | @Test 61 | void indexThenGet(Vertx vertx, VertxTestContext testContext) { 62 | String yo = "{\"foo\": \"bar\"}"; 63 | IndexRequest req = new IndexRequest("posts", "_doc", "1").source(yo, XContentType.JSON); 64 | client 65 | .indexAsync(req, RequestOptions.DEFAULT) 66 | .chain(resp -> client.getAsync(new GetRequest("posts", "_all", "1"), RequestOptions.DEFAULT)) 67 | .subscribe().with((resp -> testContext.verify(() -> { 68 | assertThat(Thread.currentThread().getName()).startsWith("vert.x-eventloop-thread-"); 69 | assertThat(vertx.getOrCreateContext().isEventLoopContext()).isTrue(); 70 | assertThat(resp.getType()).isEqualTo("_doc"); 71 | assertThat(resp.getSourceAsMap()).hasEntrySatisfying("foo", "bar"::equals); 72 | testContext.completeNow(); 73 | })), testContext::failNow); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /integration-tests/src/test/java/integration/RxJava2Tests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 integration; 18 | 19 | import io.reactiverse.elasticsearch.client.reactivex.RestHighLevelClient; 20 | import io.vertx.junit5.VertxExtension; 21 | import io.vertx.junit5.VertxTestContext; 22 | import io.vertx.reactivex.core.Vertx; 23 | import org.apache.http.HttpHost; 24 | import org.elasticsearch.action.get.GetRequest; 25 | import org.elasticsearch.action.index.IndexRequest; 26 | import org.elasticsearch.client.RequestOptions; 27 | import org.elasticsearch.client.RestClient; 28 | import org.elasticsearch.client.RestClientBuilder; 29 | import org.elasticsearch.common.xcontent.XContentType; 30 | import org.junit.jupiter.api.AfterEach; 31 | import org.junit.jupiter.api.BeforeEach; 32 | import org.junit.jupiter.api.Test; 33 | import org.junit.jupiter.api.extension.ExtendWith; 34 | import org.testcontainers.elasticsearch.ElasticsearchContainer; 35 | import org.testcontainers.junit.jupiter.Container; 36 | import org.testcontainers.junit.jupiter.Testcontainers; 37 | 38 | import static org.assertj.core.api.Assertions.assertThat; 39 | 40 | @Testcontainers 41 | @ExtendWith(VertxExtension.class) 42 | public class RxJava2Tests { 43 | 44 | @Container 45 | private ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.1"); 46 | 47 | private RestHighLevelClient client; 48 | 49 | @BeforeEach 50 | void prepare(Vertx vertx) { 51 | RestClientBuilder builder = RestClient.builder( 52 | new HttpHost(container.getContainerIpAddress(), container.getMappedPort(9200), "http")); 53 | client = RestHighLevelClient.create(vertx, builder); 54 | } 55 | 56 | @AfterEach 57 | void close() { 58 | client.close(); 59 | } 60 | 61 | @Test 62 | void indexThenGet(Vertx vertx, VertxTestContext testContext) { 63 | String yo = "{\"foo\": \"bar\"}"; 64 | IndexRequest req = new IndexRequest("posts", "_doc", "1").source(yo, XContentType.JSON); 65 | client 66 | .rxIndexAsync(req, RequestOptions.DEFAULT) 67 | .flatMap(resp -> client.rxGetAsync(new GetRequest("posts", "_all", "1"), RequestOptions.DEFAULT)) 68 | .subscribe(resp -> testContext.verify(() -> { 69 | assertThat(Thread.currentThread().getName()).startsWith("vert.x-eventloop-thread-"); 70 | assertThat(vertx.getOrCreateContext().isEventLoopContext()).isTrue(); 71 | assertThat(resp.getType()).isEqualTo("_doc"); 72 | assertThat(resp.getSourceAsMap()).hasEntrySatisfying("foo", "bar"::equals); 73 | testContext.completeNow(); 74 | }), testContext::failNow); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /elasticsearch-client-rxjava2/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 | plugins { 18 | `java-library` 19 | `maven-publish` 20 | signing 21 | } 22 | 23 | val vertxVersion = extra["vertxVersion"] 24 | 25 | dependencies { 26 | api(rootProject) 27 | api("io.vertx:vertx-rx-java2:${vertxVersion}") 28 | compileOnly("io.vertx:vertx-codegen:${vertxVersion}") 29 | annotationProcessor("io.vertx:vertx-rx-java2:${vertxVersion}") 30 | annotationProcessor("io.vertx:vertx-rx-java2-gen:${vertxVersion}") 31 | annotationProcessor("io.vertx:vertx-codegen:${vertxVersion}:processor") 32 | } 33 | 34 | sourceSets { 35 | main { 36 | java { 37 | setSrcDirs(listOf("../src/main/generated", "src/main/generated")) 38 | } 39 | } 40 | } 41 | 42 | tasks { 43 | getByName("compileJava") { 44 | options.annotationProcessorGeneratedSourcesDirectory = File("$projectDir/src/main/generated") 45 | } 46 | 47 | getByName("clean") { 48 | delete.add("src/main/generated") 49 | } 50 | 51 | getByName("jar") { 52 | exclude("io/vertx/elasticsearch/client/*.class") 53 | } 54 | 55 | create("sourcesJar") { 56 | from(sourceSets.main.get().allJava) 57 | classifier = "sources" 58 | } 59 | 60 | create("javadocJar") { 61 | from(javadoc) 62 | classifier = "javadoc" 63 | } 64 | 65 | javadoc { 66 | if (JavaVersion.current().isJava9Compatible) { 67 | (options as StandardJavadocDocletOptions).addBooleanOption("html5", true) 68 | } 69 | } 70 | 71 | withType { 72 | onlyIf { project.extra["isReleaseVersion"] as Boolean } 73 | } 74 | } 75 | 76 | publishing { 77 | publications { 78 | create("mavenJava") { 79 | from(components["java"]) 80 | artifact(tasks["sourcesJar"]) 81 | artifact(tasks["javadocJar"]) 82 | pom { 83 | name.set(project.name) 84 | description.set("Reactiverse Elasticsearch client :: RxJava2 bindings") 85 | url.set("https://github.com/reactiverse/elasticsearch-client") 86 | licenses { 87 | license { 88 | name.set("The Apache License, Version 2.0") 89 | url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") 90 | } 91 | } 92 | developers { 93 | developer { 94 | id.set("jponge") 95 | name.set("Julien Ponge") 96 | email.set("julien.ponge@gmail.com") 97 | } 98 | } 99 | scm { 100 | connection.set("scm:git:git@github.com:reactiverse/elasticsearch-client.git") 101 | developerConnection.set("scm:git:git@github.com:reactiverse/elasticsearch-client.git") 102 | url.set("https://github.com/reactiverse/elasticsearch-client") 103 | } 104 | } 105 | } 106 | } 107 | repositories { 108 | // To locally check out the poms 109 | maven { 110 | val releasesRepoUrl = uri("$buildDir/repos/releases") 111 | val snapshotsRepoUrl = uri("$buildDir/repos/snapshots") 112 | name = "BuildDir" 113 | url = if (project.extra["isReleaseVersion"] as Boolean) releasesRepoUrl else snapshotsRepoUrl 114 | } 115 | maven { 116 | val releasesRepoUrl = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/") 117 | val snapshotsRepoUrl = uri("https://oss.sonatype.org/content/repositories/snapshots/") 118 | name = "SonatypeOSS" 119 | url = if (project.extra["isReleaseVersion"] as Boolean) releasesRepoUrl else snapshotsRepoUrl 120 | credentials { 121 | val ossrhUsername: String by project 122 | val ossrhPassword: String by project 123 | username = ossrhUsername 124 | password = ossrhPassword 125 | } 126 | } 127 | } 128 | } 129 | 130 | signing { 131 | sign(publishing.publications["mavenJava"]) 132 | } 133 | -------------------------------------------------------------------------------- /elasticsearch-client-rxjava3/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 | plugins { 18 | `java-library` 19 | `maven-publish` 20 | signing 21 | } 22 | 23 | val vertxVersion = extra["vertxVersion"] 24 | 25 | dependencies { 26 | api(rootProject) 27 | api("io.vertx:vertx-rx-java3:${vertxVersion}") 28 | compileOnly("io.vertx:vertx-codegen:${vertxVersion}") 29 | annotationProcessor("io.vertx:vertx-rx-java3:${vertxVersion}") 30 | annotationProcessor("io.vertx:vertx-rx-java3-gen:${vertxVersion}") 31 | annotationProcessor("io.vertx:vertx-codegen:${vertxVersion}:processor") 32 | } 33 | 34 | sourceSets { 35 | main { 36 | java { 37 | setSrcDirs(listOf("../src/main/generated", "src/main/generated")) 38 | } 39 | } 40 | } 41 | 42 | tasks { 43 | getByName("compileJava") { 44 | options.annotationProcessorGeneratedSourcesDirectory = File("$projectDir/src/main/generated") 45 | } 46 | 47 | getByName("clean") { 48 | delete.add("src/main/generated") 49 | } 50 | 51 | getByName("jar") { 52 | exclude("io/vertx/elasticsearch/client/*.class") 53 | } 54 | 55 | create("sourcesJar") { 56 | from(sourceSets.main.get().allJava) 57 | classifier = "sources" 58 | } 59 | 60 | create("javadocJar") { 61 | from(javadoc) 62 | classifier = "javadoc" 63 | } 64 | 65 | javadoc { 66 | if (JavaVersion.current().isJava9Compatible) { 67 | (options as StandardJavadocDocletOptions).addBooleanOption("html5", true) 68 | } 69 | } 70 | 71 | withType { 72 | onlyIf { project.extra["isReleaseVersion"] as Boolean } 73 | } 74 | } 75 | 76 | publishing { 77 | publications { 78 | create("mavenJava") { 79 | from(components["java"]) 80 | artifact(tasks["sourcesJar"]) 81 | artifact(tasks["javadocJar"]) 82 | pom { 83 | name.set(project.name) 84 | description.set("Reactiverse Elasticsearch client :: RxJava3 bindings") 85 | url.set("https://github.com/reactiverse/elasticsearch-client") 86 | licenses { 87 | license { 88 | name.set("The Apache License, Version 2.0") 89 | url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") 90 | } 91 | } 92 | developers { 93 | developer { 94 | id.set("jponge") 95 | name.set("Julien Ponge") 96 | email.set("julien.ponge@gmail.com") 97 | } 98 | } 99 | scm { 100 | connection.set("scm:git:git@github.com:reactiverse/elasticsearch-client.git") 101 | developerConnection.set("scm:git:git@github.com:reactiverse/elasticsearch-client.git") 102 | url.set("https://github.com/reactiverse/elasticsearch-client") 103 | } 104 | } 105 | } 106 | } 107 | repositories { 108 | // To locally check out the poms 109 | maven { 110 | val releasesRepoUrl = uri("$buildDir/repos/releases") 111 | val snapshotsRepoUrl = uri("$buildDir/repos/snapshots") 112 | name = "BuildDir" 113 | url = if (project.extra["isReleaseVersion"] as Boolean) releasesRepoUrl else snapshotsRepoUrl 114 | } 115 | maven { 116 | val releasesRepoUrl = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/") 117 | val snapshotsRepoUrl = uri("https://oss.sonatype.org/content/repositories/snapshots/") 118 | name = "SonatypeOSS" 119 | url = if (project.extra["isReleaseVersion"] as Boolean) releasesRepoUrl else snapshotsRepoUrl 120 | credentials { 121 | val ossrhUsername: String by project 122 | val ossrhPassword: String by project 123 | username = ossrhUsername 124 | password = ossrhPassword 125 | } 126 | } 127 | } 128 | } 129 | 130 | signing { 131 | sign(publishing.publications["mavenJava"]) 132 | } 133 | -------------------------------------------------------------------------------- /elasticsearch-client-mutiny/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 | plugins { 18 | `java-library` 19 | `maven-publish` 20 | signing 21 | } 22 | 23 | val vertxVersion = extra["vertxVersion"] 24 | val mutinyBindingsVersion = extra["mutinyBindingsVersion"] 25 | 26 | dependencies { 27 | api(rootProject) 28 | api("io.smallrye.reactive:smallrye-mutiny-vertx-core:${mutinyBindingsVersion}") 29 | compileOnly("io.vertx:vertx-codegen:${vertxVersion}") 30 | annotationProcessor("io.smallrye.reactive:vertx-mutiny-generator:${mutinyBindingsVersion}") 31 | annotationProcessor("io.vertx:vertx-codegen:${vertxVersion}:processor") 32 | } 33 | 34 | sourceSets { 35 | main { 36 | java { 37 | setSrcDirs(listOf("../src/main/generated", "src/main/generated")) 38 | } 39 | } 40 | } 41 | 42 | tasks { 43 | getByName("compileJava") { 44 | options.annotationProcessorGeneratedSourcesDirectory = File("$projectDir/src/main/generated") 45 | } 46 | 47 | getByName("clean") { 48 | delete.add("src/main/generated") 49 | } 50 | 51 | getByName("jar") { 52 | exclude("io/vertx/elasticsearch/client/*.class") 53 | } 54 | 55 | create("sourcesJar") { 56 | from(sourceSets.main.get().allJava) 57 | classifier = "sources" 58 | } 59 | 60 | create("javadocJar") { 61 | from(javadoc) 62 | classifier = "javadoc" 63 | } 64 | 65 | javadoc { 66 | if (JavaVersion.current().isJava9Compatible) { 67 | (options as StandardJavadocDocletOptions).addBooleanOption("html5", true) 68 | } 69 | } 70 | 71 | withType { 72 | onlyIf { project.extra["isReleaseVersion"] as Boolean } 73 | } 74 | } 75 | 76 | publishing { 77 | publications { 78 | create("mavenJava") { 79 | from(components["java"]) 80 | artifact(tasks["sourcesJar"]) 81 | artifact(tasks["javadocJar"]) 82 | pom { 83 | name.set(project.name) 84 | description.set("Reactiverse Elasticsearch client :: Mutiny bindings") 85 | url.set("https://github.com/reactiverse/elasticsearch-client") 86 | licenses { 87 | license { 88 | name.set("The Apache License, Version 2.0") 89 | url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") 90 | } 91 | } 92 | developers { 93 | developer { 94 | id.set("jponge") 95 | name.set("Julien Ponge") 96 | email.set("julien.ponge@gmail.com") 97 | } 98 | } 99 | scm { 100 | connection.set("scm:git:git@github.com:reactiverse/elasticsearch-client.git") 101 | developerConnection.set("scm:git:git@github.com:reactiverse/elasticsearch-client.git") 102 | url.set("https://github.com/reactiverse/elasticsearch-client") 103 | } 104 | } 105 | } 106 | } 107 | repositories { 108 | // To locally check out the poms 109 | maven { 110 | val releasesRepoUrl = uri("$buildDir/repos/releases") 111 | val snapshotsRepoUrl = uri("$buildDir/repos/snapshots") 112 | name = "BuildDir" 113 | url = if (project.extra["isReleaseVersion"] as Boolean) releasesRepoUrl else snapshotsRepoUrl 114 | } 115 | maven { 116 | val releasesRepoUrl = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/") 117 | val snapshotsRepoUrl = uri("https://oss.sonatype.org/content/repositories/snapshots/") 118 | name = "SonatypeOSS" 119 | url = if (project.extra["isReleaseVersion"] as Boolean) releasesRepoUrl else snapshotsRepoUrl 120 | credentials { 121 | val ossrhUsername: String by project 122 | val ossrhPassword: String by project 123 | username = ossrhUsername 124 | password = ossrhPassword 125 | } 126 | } 127 | } 128 | } 129 | 130 | signing { 131 | sign(publishing.publications["mavenJava"]) 132 | } 133 | -------------------------------------------------------------------------------- /integration-tests/src/test/java/integration/CallbackTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 integration; 18 | 19 | import io.reactiverse.elasticsearch.client.RestHighLevelClient; 20 | import io.vertx.core.Vertx; 21 | import io.vertx.junit5.VertxExtension; 22 | import io.vertx.junit5.VertxTestContext; 23 | import org.apache.http.HttpHost; 24 | import org.elasticsearch.action.DocWriteResponse; 25 | import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsRequest; 26 | import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsResponse; 27 | import org.elasticsearch.action.get.GetRequest; 28 | import org.elasticsearch.action.index.IndexRequest; 29 | import org.elasticsearch.action.index.IndexResponse; 30 | import org.elasticsearch.client.RequestOptions; 31 | import org.elasticsearch.client.RestClient; 32 | import org.elasticsearch.client.RestClientBuilder; 33 | import org.elasticsearch.common.xcontent.XContentType; 34 | import org.elasticsearch.rest.RestStatus; 35 | import org.junit.jupiter.api.AfterEach; 36 | import org.junit.jupiter.api.BeforeEach; 37 | import org.junit.jupiter.api.Test; 38 | import org.junit.jupiter.api.extension.ExtendWith; 39 | import org.testcontainers.elasticsearch.ElasticsearchContainer; 40 | import org.testcontainers.junit.jupiter.Container; 41 | import org.testcontainers.junit.jupiter.Testcontainers; 42 | 43 | import static org.assertj.core.api.Assertions.assertThat; 44 | 45 | @Testcontainers 46 | @ExtendWith(VertxExtension.class) 47 | class CallbackTests { 48 | 49 | @Container 50 | private ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.1"); 51 | 52 | private RestHighLevelClient client; 53 | 54 | @BeforeEach 55 | void prepare(Vertx vertx) { 56 | RestClientBuilder builder = RestClient.builder( 57 | new HttpHost(container.getContainerIpAddress(), container.getMappedPort(9200), "http")); 58 | client = RestHighLevelClient.create(vertx, builder); 59 | } 60 | 61 | @AfterEach 62 | void close() { 63 | client.close(); 64 | } 65 | 66 | @Test 67 | void index(VertxTestContext testContext) { 68 | String yo = "{\"foo\": \"bar\"}"; 69 | IndexRequest req = new IndexRequest("posts").source(yo, XContentType.JSON); 70 | client.indexAsync(req, RequestOptions.DEFAULT, ar -> { 71 | if (ar.succeeded()) { 72 | IndexResponse response = ar.result(); 73 | testContext.verify(() -> { 74 | assertThat(response.status()).isEqualByComparingTo(RestStatus.CREATED); 75 | assertThat(response.getResult()).isEqualByComparingTo(DocWriteResponse.Result.CREATED); 76 | testContext.completeNow(); 77 | }); 78 | } else { 79 | testContext.failNow(ar.cause()); 80 | } 81 | }); 82 | } 83 | 84 | @Test 85 | void getClusterSettings(VertxTestContext testContext) { 86 | ClusterGetSettingsRequest req = new ClusterGetSettingsRequest(); 87 | client.cluster().getSettingsAsync(req, RequestOptions.DEFAULT, ar -> { 88 | if (ar.succeeded()) { 89 | ClusterGetSettingsResponse response = ar.result(); 90 | testContext.verify(() -> { 91 | assertThat(response).isNotNull(); 92 | assertThat(response.getTransientSettings().isEmpty()).isTrue(); 93 | assertThat(response.getPersistentSettings().isEmpty()).isTrue(); 94 | testContext.completeNow(); 95 | }); 96 | } else { 97 | testContext.failNow(ar.cause()); 98 | } 99 | }); 100 | } 101 | 102 | @Test 103 | void checkThreadingModel(Vertx vertx, VertxTestContext testContext) { 104 | client.existsAsync(new GetRequest(), RequestOptions.DEFAULT, event -> { 105 | testContext.verify(() -> { 106 | assertThat(Thread.currentThread().getName()).startsWith("vert.x-eventloop-thread-"); 107 | assertThat(vertx.getOrCreateContext().isEventLoopContext()).isTrue(); 108 | testContext.completeNow(); 109 | }); 110 | }); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /shim-generator/src/main/java/shimgen/Analyze.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 shimgen; 18 | 19 | import com.github.javaparser.JavaParser; 20 | import com.github.javaparser.ast.CompilationUnit; 21 | import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import java.io.File; 26 | import java.io.IOException; 27 | import java.nio.file.Files; 28 | import java.util.Collections; 29 | import java.util.HashSet; 30 | import java.util.List; 31 | 32 | public class Analyze { 33 | 34 | private static final Logger logger = LoggerFactory.getLogger(Analyze.class); 35 | 36 | static final HashSet FILTERED_TYPES = new HashSet() { 37 | { 38 | add("RestClient"); 39 | add("MigrationClient"); 40 | } 41 | }; 42 | 43 | private static final String autoGeneratedComment = "\n" + 44 | "[NOTE] This is an automatically generated file.\n" + 45 | " Do not make changes to this file but to the shim code generator.\n" + 46 | "\n"; 47 | 48 | private static String pathToMainFile; 49 | private static String pathToGeneration; 50 | private static String targetPackageName; 51 | private static String pathToMainPackage; 52 | 53 | public static void main(String[] args) throws IOException { 54 | 55 | if (args.length != 3) { 56 | logger.error("Expecting 3 arguments: the path to RestHighLevelClient.java, then the path to the code generation directory, then the generated code package name"); 57 | System.exit(1); 58 | } 59 | 60 | pathToMainFile = args[0]; 61 | pathToMainPackage = new File(pathToMainFile).getParent(); 62 | pathToGeneration = args[1]; 63 | targetPackageName = args[2]; 64 | logger.info("Analyzing {}, generating code to {} in package {}", pathToMainFile, pathToGeneration, targetPackageName); 65 | 66 | new Analyze().run(); 67 | } 68 | 69 | private void run() throws IOException { 70 | CompilationUnit unit = JavaParser.parse(new File(pathToMainFile)); 71 | List nestedClients = unit.accept(new NestedClientFinder(), null); 72 | logger.info("Found the following nested clients: {}", nestedClients); 73 | 74 | generatedFilesPackageDir().mkdirs(); 75 | generateCode("RestHighLevelClient"); 76 | for (String nestedClient : nestedClients) { 77 | generateCode(nestedClient); 78 | } 79 | } 80 | 81 | private File generatedFilesPackageDir() { 82 | return new File(pathToGeneration, targetPackageName.replace('.', '/')); 83 | } 84 | 85 | private void generateCode(String unitName) throws IOException { 86 | File inputFile = new File(pathToMainPackage, unitName + ".java"); 87 | CompilationUnit sourceUnit = JavaParser.parse(inputFile); 88 | 89 | CompilationUnit shimInterfaceUnit = new CompilationUnit(); 90 | shimInterfaceUnit.setBlockComment(autoGeneratedComment); 91 | shimInterfaceUnit 92 | .setPackageDeclaration(targetPackageName) 93 | .addImport("io.vertx.core.*") 94 | .addImport("io.vertx.codegen.annotations.*") 95 | .addImport("org.elasticsearch.client.*"); 96 | 97 | ClassOrInterfaceDeclaration shimInterface = shimInterfaceUnit 98 | .addInterface(unitName) 99 | .addAnnotation("VertxGen"); 100 | 101 | CompilationUnit shimImplementationUnit = new CompilationUnit(); 102 | shimImplementationUnit.setBlockComment(autoGeneratedComment); 103 | shimImplementationUnit 104 | .setPackageDeclaration(targetPackageName) 105 | .addImport("io.vertx.core.*") 106 | .addImport("org.elasticsearch.client.*"); 107 | 108 | ClassOrInterfaceDeclaration shimImplementation = shimImplementationUnit 109 | .addClass(unitName + "Impl") 110 | .setPublic(false) 111 | .addImplementedType(unitName); 112 | 113 | sourceUnit.accept(new ShimMaker(shimInterfaceUnit, shimInterface, shimImplementationUnit, shimImplementation), null); 114 | 115 | logger.debug("Interface:\n{} ", shimInterfaceUnit.toString()); 116 | logger.debug("Implementation:\n{} ", shimImplementationUnit.toString()); 117 | Files.write(new File(generatedFilesPackageDir(), unitName + ".java").toPath(), Collections.singletonList(shimInterfaceUnit.toString())); 118 | Files.write(new File(generatedFilesPackageDir(), unitName + "Impl.java").toPath(), Collections.singletonList(shimImplementationUnit.toString())); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 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 | # https://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 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /shim-generator/src/main/java/shimgen/ShimMaker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Red Hat, Inc. 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 shimgen; 18 | 19 | import com.github.javaparser.JavaParser; 20 | import com.github.javaparser.ast.CompilationUnit; 21 | import com.github.javaparser.ast.ImportDeclaration; 22 | import com.github.javaparser.ast.Modifier; 23 | import com.github.javaparser.ast.NodeList; 24 | import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; 25 | import com.github.javaparser.ast.body.ConstructorDeclaration; 26 | import com.github.javaparser.ast.body.MethodDeclaration; 27 | import com.github.javaparser.ast.body.Parameter; 28 | import com.github.javaparser.ast.nodeTypes.NodeWithSimpleName; 29 | import com.github.javaparser.ast.stmt.BlockStmt; 30 | import com.github.javaparser.ast.type.Type; 31 | import com.github.javaparser.ast.type.TypeParameter; 32 | import com.github.javaparser.ast.visitor.VoidVisitorAdapter; 33 | import org.slf4j.Logger; 34 | import org.slf4j.LoggerFactory; 35 | 36 | import java.util.Optional; 37 | import java.util.stream.Collectors; 38 | 39 | class ShimMaker extends VoidVisitorAdapter { 40 | 41 | private final Logger logger = LoggerFactory.getLogger(ShimMaker.class); 42 | 43 | private final CompilationUnit shimInterfaceUnit; 44 | private final ClassOrInterfaceDeclaration shimInterface; 45 | private final CompilationUnit shimImplementationUnit; 46 | private final ClassOrInterfaceDeclaration shimImplementation; 47 | 48 | ShimMaker(CompilationUnit shimInterfaceUnit, ClassOrInterfaceDeclaration shimInterface, CompilationUnit shimImplementationUnit, ClassOrInterfaceDeclaration shimImplementation) { 49 | this.shimInterfaceUnit = shimInterfaceUnit; 50 | this.shimInterface = shimInterface; 51 | this.shimImplementationUnit = shimImplementationUnit; 52 | this.shimImplementation = shimImplementation; 53 | } 54 | 55 | @Override 56 | public void visit(ImportDeclaration n, Void arg) { 57 | shimInterfaceUnit.addImport(n); 58 | shimImplementationUnit.addImport(n); 59 | super.visit(n, arg); 60 | } 61 | 62 | @Override 63 | public void visit(ClassOrInterfaceDeclaration n, Void arg) { 64 | if (n.getNameAsString().equals("RestHighLevelClient")) { 65 | super.visit(n, arg); 66 | return; 67 | } 68 | logger.info("Client class {}, generating a constructor", n.getNameAsString()); 69 | 70 | String delegateType = "org.elasticsearch.client." + n.getNameAsString(); 71 | 72 | shimImplementation 73 | .addField("Vertx", "vertx") 74 | .setPrivate(true) 75 | .setFinal(true); 76 | 77 | shimImplementation 78 | .addField(delegateType, "delegate") 79 | .setPrivate(true) 80 | .setFinal(true); 81 | 82 | String code = "{\n" + 83 | " this.vertx = vertx;\n" + 84 | " this.delegate = delegate;" + 85 | "}\n"; 86 | 87 | shimImplementation 88 | .addConstructor() 89 | .addParameter("Vertx", "vertx") 90 | .addParameter(delegateType, "delegate") 91 | .setBody(JavaParser.parseBlock(code)); 92 | 93 | super.visit(n, arg); 94 | } 95 | 96 | @Override 97 | public void visit(ConstructorDeclaration n, Void arg) { 98 | if (n.isPublic()) { 99 | NodeList parameters = NodeList.nodeList(n.getParameters()); 100 | parameters.add(0, new Parameter(new TypeParameter("Vertx"), "vertx")); 101 | logger.info("Interface factory method with parameters {}", parameters); 102 | 103 | BlockStmt createBlock = new BlockStmt(); 104 | shimInterface 105 | .addMethod("create", Modifier.Keyword.STATIC) 106 | .addSingleMemberAnnotation("GenIgnore", "GenIgnore.PERMITTED_TYPE") 107 | .setType(shimInterface.getNameAsString()) 108 | .setParameters(parameters) 109 | .setBody(createBlock); 110 | String args = parameters 111 | .stream() 112 | .map(Parameter::getNameAsString) 113 | .collect(Collectors.joining(", ")); 114 | String implCreation = "return new " + shimImplementation.getNameAsString() + "(" + args + ");"; 115 | createBlock.addStatement(JavaParser.parseStatement(implCreation)); 116 | 117 | BlockStmt constructorBlock = new BlockStmt(); 118 | ConstructorDeclaration constructor = shimImplementation 119 | .addConstructor() 120 | .setParameters(parameters) 121 | .setBody(constructorBlock); 122 | 123 | parameters.forEach(p -> { 124 | shimImplementation 125 | .addField(p.getType(), p.getNameAsString()) 126 | .setPrivate(true) 127 | .setFinal(true); 128 | constructorBlock 129 | .addStatement(JavaParser.parseStatement("this." + p.getNameAsString() + " = " + p.getNameAsString() + ";")); 130 | }); 131 | 132 | String constructorArgs = parameters 133 | .stream() 134 | .map(Parameter::getNameAsString) 135 | .filter(p -> !"vertx".equals(p)) 136 | .collect(Collectors.joining(", ")); 137 | constructorBlock 138 | .addStatement(JavaParser.parseStatement("this.delegate = new org.elasticsearch.client." + shimInterface.getNameAsString() + "(" + constructorArgs + ");")); 139 | 140 | shimImplementation 141 | .addField("org.elasticsearch.client." + shimInterface.getNameAsString(), "delegate") 142 | .setPrivate(true) 143 | .setFinal(true); 144 | } 145 | super.visit(n, arg); 146 | } 147 | 148 | @Override 149 | public void visit(MethodDeclaration n, Void arg) { 150 | if (isAsyncMethod(n)) { 151 | generateAsyncMethod(n); 152 | } else if (isNestedClientMethod(n)) { 153 | generateNestedClientMethod(n); 154 | } else if (isPassThroughMethod(n)) { 155 | generatePassThrough(n); 156 | } 157 | super.visit(n, arg); 158 | } 159 | 160 | private static final String ASYNC_DISPATCH_TEMPLATE = "{\n" + 161 | " Context context = vertx.getOrCreateContext();\n" + 162 | " delegate.{{METHOD}}({{ARGS}} new ActionListener<{{TYPE}}>() {\n" + 163 | " @Override\n" + 164 | " public void onResponse({{TYPE}} value) {\n" + 165 | " context.runOnContext(v -> handler.handle(Future.succeededFuture(value)));\n" + 166 | " }\n" + 167 | "\n" + 168 | " @Override\n" + 169 | " public void onFailure(Exception e) {\n" + 170 | " context.runOnContext(v -> handler.handle(Future.failedFuture(e)));\n" + 171 | " }\n" + 172 | " });\n" + 173 | " }"; 174 | 175 | private void generateAsyncMethod(MethodDeclaration n) { 176 | logger.info("Async method shim for {}", n.getNameAsString()); 177 | NodeList parameters = NodeList.nodeList(n.getParameters()); 178 | Parameter lastParameter = parameters.get(parameters.size() - 1); 179 | Optional> typeArguments = lastParameter.getType().asClassOrInterfaceType().getTypeArguments(); 180 | if (!typeArguments.isPresent() || typeArguments.get().size() != 1) { 181 | logger.warn("Not processing {} as the last argument is of actual type {}", n.getNameAsString(), lastParameter.getType()); 182 | return; 183 | } 184 | Type parametricType = typeArguments.get().get(0); 185 | lastParameter.setType("Handler>"); 186 | lastParameter.setName("handler"); 187 | 188 | shimInterface 189 | .addMethod(n.getNameAsString()) 190 | .setType("void") 191 | .setParameters(parameters) 192 | .removeBody() 193 | .addSingleMemberAnnotation("GenIgnore", "GenIgnore.PERMITTED_TYPE"); 194 | 195 | NodeList callParameters = NodeList.nodeList(parameters); 196 | callParameters.removeLast(); 197 | String callArgs = callParameters 198 | .stream() 199 | .map(NodeWithSimpleName::getNameAsString) 200 | .collect(Collectors.joining(", ")); 201 | if (!callArgs.isEmpty()) { 202 | callArgs = callArgs + ", "; 203 | } 204 | 205 | String shimCode = ASYNC_DISPATCH_TEMPLATE 206 | .replace("{{METHOD}}", n.getNameAsString()) 207 | .replace("{{ARGS}}", callArgs) 208 | .replace("{{TYPE}}", parametricType.toString()); 209 | 210 | logger.debug("Code -> \n{}", shimCode); 211 | 212 | shimImplementation 213 | .addMethod(n.getNameAsString()) 214 | .setPublic(true) 215 | .addAnnotation("Override") 216 | .setType("void") 217 | .setParameters(parameters) 218 | .setBody(JavaParser.parseBlock(shimCode)); 219 | } 220 | 221 | private void generateNestedClientMethod(MethodDeclaration n) { 222 | String methodName = n.getNameAsString(); 223 | String methodType = n.getTypeAsString(); 224 | if (Analyze.FILTERED_TYPES.contains(methodType)) { 225 | logger.debug("Skipping {} as the return type is being filtered", methodName); 226 | return; 227 | } 228 | logger.info("Nested client method shim for {}", methodName); 229 | 230 | shimInterface 231 | .addMethod(methodName) 232 | .setType(n.getType()) 233 | .setParameters(n.getParameters()) 234 | .removeBody() 235 | .addSingleMemberAnnotation("GenIgnore", "GenIgnore.PERMITTED_TYPE"); 236 | 237 | String callArgs = n.getParameters() 238 | .stream() 239 | .map(NodeWithSimpleName::getNameAsString) 240 | .collect(Collectors.joining(", ")); 241 | 242 | String shimCode = "{ return new " + methodType + "Impl(vertx, delegate." + methodName + "(" + callArgs + ")); }"; 243 | MethodDeclaration impl = shimImplementation 244 | .addMethod(methodName) 245 | .setPublic(true) 246 | .addAnnotation("Override") 247 | .setType(n.getType()) 248 | .setParameters(n.getParameters()) 249 | .setBody(JavaParser.parseBlock(shimCode)); 250 | } 251 | 252 | private void generatePassThrough(MethodDeclaration n) { 253 | logger.info("Passthrough method {}", n.getNameAsString()); 254 | MethodDeclaration method = shimInterface 255 | .addMethod(n.getNameAsString()) 256 | .setType(n.getType()) 257 | .setParameters(n.getParameters()) 258 | .removeBody() 259 | .addSingleMemberAnnotation("GenIgnore", "GenIgnore.PERMITTED_TYPE"); 260 | 261 | String callArgs = n.getParameters() 262 | .stream() 263 | .map(NodeWithSimpleName::getNameAsString) 264 | .collect(Collectors.joining(", ")); 265 | 266 | String shimCode; 267 | if ("void".equals(n.getTypeAsString())) { 268 | shimCode = "delegate." + n.getName() + "(" + callArgs + ");"; 269 | } else { 270 | shimCode = "return delegate." + n.getName() + "(" + callArgs + ");"; 271 | } 272 | shimCode = "{try {\n" + 273 | shimCode + "\n" + 274 | "} catch (Throwable t) {\n" + 275 | " throw new RuntimeException(t);\n" + 276 | "}}"; 277 | 278 | MethodDeclaration impl = shimImplementation 279 | .addMethod(n.getNameAsString()) 280 | .setPublic(true) 281 | .addAnnotation("Override") 282 | .setType(n.getType()) 283 | .setParameters(n.getParameters()) 284 | .setBody(JavaParser.parseBlock(shimCode)); 285 | } 286 | 287 | private boolean isAsyncMethod(MethodDeclaration n) { 288 | return n.isPublic() && n.getNameAsString().endsWith("Async") && !n.isAnnotationPresent("Deprecated"); 289 | } 290 | 291 | private boolean isNestedClientMethod(MethodDeclaration n) { 292 | return n.getTypeAsString().endsWith("Client"); 293 | } 294 | 295 | private boolean isPassThroughMethod(MethodDeclaration n) { 296 | return n.isPublic() && !n.isAnnotationPresent("Deprecated") && n.getNameAsString().equals("close"); 297 | } 298 | } 299 | --------------------------------------------------------------------------------