├── .circleci └── config.yml ├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main └── java │ └── com │ └── rqlite │ ├── NodeUnavailableException.java │ ├── Rqlite.java │ ├── RqliteFactory.java │ ├── dto │ ├── ExecuteResults.java │ ├── GenericResults.java │ ├── ParameterizedStatement.java │ ├── Pong.java │ └── QueryResults.java │ └── impl │ ├── ExecuteRequest.java │ ├── GenericRequest.java │ ├── ParameterizedStatementContent.java │ ├── PingRequest.java │ ├── QueryRequest.java │ ├── RequestFactory.java │ ├── RqliteImpl.java │ └── RqliteNode.java └── test └── java └── com └── rqlite ├── RqliteClientTest.java ├── RqliteFactoryTest.java ├── RqliteFailoverTest.java └── impl └── RequestFactoryTest.java /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Java Gradle CircleCI 2.0 configuration file 2 | # See: https://circleci.com/docs/language-java/ 3 | version: 2 4 | 5 | # Define a job to be invoked later in a workflow. 6 | # See: https://circleci.com/docs/configuration-reference/#jobs 7 | jobs: 8 | build: 9 | # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. 10 | # See: https://circleci.com/docs/configuration-reference/#docker-machine-macos-windows-executor 11 | docker: 12 | # specify the version you desire here 13 | - image: circleci/openjdk:8-jdk 14 | - image: rqlite/rqlite:latest 15 | 16 | # Specify service dependencies here if necessary 17 | # CircleCI maintains a library of pre-built images 18 | # documented at https://circleci.com/docs/circleci-images/ 19 | # - image: circleci/postgres:9.4 20 | 21 | working_directory: ~/repo 22 | 23 | environment: 24 | # Customize the JVM maximum heap limit 25 | JVM_OPTS: -Xmx3200m 26 | TERM: dumb 27 | # Add steps to the job 28 | # See: https://circleci.com/docs/configuration-reference/#steps 29 | steps: 30 | - checkout 31 | 32 | # Download and cache dependencies 33 | - restore_cache: 34 | keys: 35 | - v1-dependencies-{{ checksum "build.gradle" }} 36 | # fallback to using the latest cache if no exact match is found 37 | - v1-dependencies- 38 | 39 | - run: gradle dependencies 40 | 41 | - save_cache: 42 | paths: 43 | - ~/.gradle 44 | key: v1-dependencies-{{ checksum "build.gradle" }} 45 | 46 | # run tests! 47 | - run: gradle test 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | 24 | .classpath 25 | .project 26 | .settings/ 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 rqlite http://www.rqlite.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rqlite-java 2 | [![Google Group](https://img.shields.io/badge/Google%20Group--blue.svg)](https://groups.google.com/group/rqlite) 3 | 4 | This is a basic Java client library for [rqlite](https://github.com/rqlite/rqlite). rqlite is a lightweight, distributed relational database, which uses SQLite as its storage engine. Significant development and testing remains, and pull requests are welcome. 5 | 6 | ## Quick start 7 | ```java 8 | // Declare variables. 9 | ExecuteResults results = null; 10 | QueryResults rows = null; 11 | 12 | // Get a connection to a rqlite node. 13 | Rqlite rqlite = RqliteFactory.connect("http", "localhost", 4001); 14 | 15 | // Create a table. 16 | results = rqlite.Execute("CREATE TABLE foo (id integer not null primary key, name text)"); 17 | System.out.println(results.toString()); 18 | 19 | // Insert a record. 20 | results = rqlite.Execute("INSERT INTO foo(name) VALUES(\"fiona\")"); 21 | System.out.println(results.toString()); 22 | 23 | // Query all records in the table. 24 | rows = rqlite.Query("SELECT * FROM foo", Rqlite.ReadConsistencyLevel.WEAK); 25 | System.out.println(rows.toString()); 26 | ``` 27 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.rqlite 4 | rqlite-java 5 | 0.0.1-SNAPSHOT 6 | 7 | 8 | 9 | org.apache.maven.plugins 10 | maven-compiler-plugin 11 | 12 | 8 13 | 8 14 | 15 | 16 | 17 | 18 | rqlite Java client 19 | A Java client for rqlite, the lightweight, distributed relational database built on SQLite 20 | 21 | 22 | com.google.http-client 23 | google-http-client 24 | 1.22.0 25 | 26 | 27 | com.google.http-client 28 | google-http-client-jackson2 29 | 1.36.0 30 | 31 | 32 | junit 33 | junit 34 | 4.13.1 35 | test 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/NodeUnavailableException.java: -------------------------------------------------------------------------------- 1 | package com.rqlite; 2 | 3 | /** 4 | * This exception is thrown when rqlite-java cannot connect to a rqlite node. 5 | **/ 6 | public class NodeUnavailableException extends Exception { 7 | public NodeUnavailableException(String message){ 8 | super(message); 9 | } 10 | } -------------------------------------------------------------------------------- /src/main/java/com/rqlite/Rqlite.java: -------------------------------------------------------------------------------- 1 | package com.rqlite; 2 | 3 | import com.rqlite.dto.ExecuteResults; 4 | import com.rqlite.dto.ParameterizedStatement; 5 | import com.rqlite.dto.Pong; 6 | import com.rqlite.dto.QueryResults; 7 | 8 | public interface Rqlite { 9 | 10 | /** 11 | * ReadConsistencyLevel specifies the consistency level of a query. 12 | */ 13 | public enum ReadConsistencyLevel { 14 | /** Node queries local SQLite database. */ 15 | NONE("none"), 16 | 17 | /** Node performs leader check using master state before querying. */ 18 | WEAK("weak"), 19 | 20 | /** Node performs leader check through the Raft system before querying */ 21 | STRONG("strong"); 22 | 23 | private final String value; 24 | 25 | private ReadConsistencyLevel(final String value) { 26 | this.value = value; 27 | } 28 | 29 | public String value() { 30 | return this.value; 31 | } 32 | } 33 | 34 | /** Query executes a single statement that returns rows. */ 35 | public QueryResults Query(String q, ReadConsistencyLevel lvl) throws NodeUnavailableException; 36 | 37 | /** Query executes a single paramaterized statement that returns rows. */ 38 | public QueryResults Query(ParameterizedStatement q, ReadConsistencyLevel lvl) throws NodeUnavailableException; 39 | 40 | /** Query executes multiple statement that returns rows. */ 41 | public QueryResults Query(String[] q, boolean tx, ReadConsistencyLevel lvl) throws NodeUnavailableException; 42 | 43 | /** Query executes multiple paramaterized statement that returns rows. */ 44 | public QueryResults Query(ParameterizedStatement[] q, boolean tx, ReadConsistencyLevel lvl) throws NodeUnavailableException; 45 | 46 | /** Execute executes a single statement that does not return rows. */ 47 | public ExecuteResults Execute(String q) throws NodeUnavailableException; 48 | 49 | /** Execute executes a single paramaterized statement that does not return rows. */ 50 | public ExecuteResults Execute(ParameterizedStatement q) throws NodeUnavailableException; 51 | 52 | /** Execute executes multiple statement that do not return rows. */ 53 | public ExecuteResults Execute(String[] q, boolean tx) throws NodeUnavailableException; 54 | 55 | /** Execute executes multiple paramaterized statement that do not return rows. */ 56 | public ExecuteResults Execute(ParameterizedStatement[] q, boolean tx) throws NodeUnavailableException; 57 | 58 | // Ping checks communication with the rqlite node. */ 59 | public Pong Ping(); 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/RqliteFactory.java: -------------------------------------------------------------------------------- 1 | package com.rqlite; 2 | 3 | import com.rqlite.impl.RqliteImpl; 4 | 5 | public enum RqliteFactory { 6 | INSTANCE; 7 | 8 | /** 9 | * Create a connection to a rqlite node. 10 | * 11 | * @param proto 12 | * the protocol, either "http" or "https" 13 | * @param host 14 | * the host name of the rqlite note 15 | * @param port 16 | * the port on the rqlite node 17 | * @return a rqlite client instance. 18 | */ 19 | public static Rqlite connect(final String proto, final String host, final Integer port) { 20 | return new RqliteImpl(proto, host, port); 21 | } 22 | 23 | public static Rqlite connect(final String config) { 24 | return new RqliteImpl(config); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/dto/ExecuteResults.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.dto; 2 | 3 | import com.google.api.client.json.GenericJson; 4 | import com.google.api.client.util.Key; 5 | 6 | public class ExecuteResults implements GenericResults { 7 | public static class Result extends GenericJson { 8 | @Key 9 | public String error; 10 | 11 | @Key("last_insert_id") 12 | public int lastInsertId; 13 | 14 | @Key("rows_affected") 15 | public int rowsAffected; 16 | 17 | @Key 18 | public float time; 19 | } 20 | 21 | @Key("results") 22 | public Result[] results; 23 | 24 | @Key 25 | public float time; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/dto/GenericResults.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.dto; 2 | 3 | public interface GenericResults { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/dto/ParameterizedStatement.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.dto; 2 | 3 | import com.google.api.client.json.GenericJson; 4 | 5 | public class ParameterizedStatement extends GenericJson { 6 | public String query; 7 | 8 | public Object[] arguments; 9 | 10 | public ParameterizedStatement(String query, Object[] arguments) { 11 | this.query = query == null ? "" : query; 12 | this.arguments = arguments == null ? new Object[]{} : arguments; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/dto/Pong.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.dto; 2 | 3 | public class Pong implements GenericResults { 4 | public String version; 5 | 6 | public Pong() { 7 | this.version = "unknown"; 8 | } 9 | 10 | public Pong(final String version) { 11 | this.version = version; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/dto/QueryResults.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.dto; 2 | 3 | import com.google.api.client.json.GenericJson; 4 | import com.google.api.client.util.Key; 5 | 6 | public class QueryResults implements GenericResults { 7 | public static class Result extends GenericJson { 8 | @Key 9 | public String error; 10 | 11 | @Key 12 | public String[] columns; 13 | 14 | @Key 15 | public String[] types; 16 | 17 | @Key 18 | public Object[][] values; 19 | 20 | @Key 21 | public float time; 22 | } 23 | 24 | @Key 25 | public Result[] results; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/impl/ExecuteRequest.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.impl; 2 | 3 | import com.google.api.client.http.GenericUrl; 4 | import com.google.api.client.http.HttpRequest; 5 | import com.google.api.client.http.HttpResponse; 6 | import com.rqlite.dto.ExecuteResults; 7 | 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.IOException; 10 | 11 | public class ExecuteRequest extends GenericRequest{ 12 | 13 | private HttpRequest httpRequest; 14 | 15 | public ExecuteRequest(HttpRequest request) { 16 | this.httpRequest = request; 17 | } 18 | 19 | public ExecuteResults execute() throws IOException { 20 | HttpResponse response = this.httpRequest.execute(); 21 | return response.parseAs(ExecuteResults.class); 22 | } 23 | 24 | public String getUrl() { 25 | return this.httpRequest.getUrl().toString(); 26 | } 27 | 28 | public void setUrl(GenericUrl url){ 29 | this.httpRequest.setUrl(url); 30 | } 31 | 32 | public String getMethod() { 33 | return this.httpRequest.getRequestMethod(); 34 | } 35 | 36 | public String getBody() throws IOException { 37 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 38 | this.httpRequest.getContent().writeTo(stream); 39 | return stream.toString(); 40 | } 41 | 42 | public ExecuteRequest enableTransaction(Boolean tx) { 43 | if (tx) { 44 | this.httpRequest.getUrl().put("transaction", tx.toString()); 45 | } else { 46 | this.httpRequest.getUrl().remove("transaction"); 47 | } 48 | return this; 49 | } 50 | 51 | public ExecuteRequest enableTimings(Boolean tm) { 52 | if (tm) { 53 | this.httpRequest.getUrl().put("timings", tm.toString()); 54 | } else { 55 | this.httpRequest.getUrl().remove("timings"); 56 | } 57 | return this; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/impl/GenericRequest.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.impl; 2 | 3 | import com.google.api.client.http.GenericUrl; 4 | import com.google.api.client.http.HttpRequest; 5 | import com.rqlite.dto.GenericResults; 6 | 7 | import java.io.IOException; 8 | 9 | abstract class GenericRequest { 10 | 11 | private HttpRequest httpRequest; 12 | 13 | protected abstract GenericResults execute() throws IOException; 14 | public String getUrl() { 15 | return this.httpRequest.getUrl().toString(); 16 | } 17 | public void setUrl(GenericUrl url){ 18 | this.httpRequest.setUrl(url); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/impl/ParameterizedStatementContent.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.impl; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | import com.fasterxml.jackson.core.JsonFactory; 7 | import com.fasterxml.jackson.core.JsonGenerator; 8 | import com.google.api.client.http.AbstractHttpContent; 9 | import com.rqlite.dto.ParameterizedStatement; 10 | 11 | public class ParameterizedStatementContent extends AbstractHttpContent { 12 | 13 | private final ParameterizedStatement[] stmts; 14 | private static final JsonFactory JSON_FACTORY = new JsonFactory(); 15 | 16 | protected ParameterizedStatementContent(ParameterizedStatement[] stmts) { 17 | super("application/json"); 18 | if (stmts == null) { 19 | stmts = new ParameterizedStatement[]{}; 20 | } 21 | this.stmts = stmts; 22 | } 23 | 24 | @Override 25 | public void writeTo(OutputStream out) throws IOException { 26 | 27 | JsonGenerator json = JSON_FACTORY.createGenerator(out); 28 | json.writeStartArray(); 29 | for (ParameterizedStatement s : stmts) { 30 | json.writeStartArray(); 31 | json.writeString(s.query); 32 | if (s.arguments != null) { 33 | for (Object arg: s.arguments) { 34 | json.writeObject(arg); 35 | } 36 | } 37 | json.writeEndArray(); 38 | } 39 | json.writeEndArray(); 40 | json.close(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/impl/PingRequest.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.impl; 2 | 3 | import com.google.api.client.http.HttpHeaders; 4 | import com.google.api.client.http.HttpRequest; 5 | import com.google.api.client.http.HttpResponse; 6 | import com.rqlite.dto.Pong; 7 | 8 | import java.io.IOException; 9 | 10 | public class PingRequest extends GenericRequest{ 11 | private HttpRequest httpRequest; 12 | 13 | public PingRequest(HttpRequest request) { 14 | this.httpRequest = request; 15 | } 16 | 17 | public Pong execute() throws IOException { 18 | HttpResponse response = this.httpRequest.execute(); 19 | 20 | HttpHeaders headers = response.getHeaders(); 21 | String version = headers.getFirstHeaderStringValue("X-Rqlite-Version"); 22 | 23 | return new Pong(version); 24 | } 25 | 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/impl/QueryRequest.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.impl; 2 | 3 | import com.google.api.client.http.GenericUrl; 4 | import com.google.api.client.http.HttpRequest; 5 | import com.google.api.client.http.HttpResponse; 6 | import com.rqlite.Rqlite.ReadConsistencyLevel; 7 | import com.rqlite.dto.QueryResults; 8 | 9 | import java.io.ByteArrayOutputStream; 10 | import java.io.IOException; 11 | import java.io.OutputStream; 12 | 13 | public class QueryRequest extends GenericRequest { 14 | 15 | private HttpRequest httpRequest; 16 | 17 | public QueryRequest(HttpRequest request) { 18 | this.httpRequest = request; 19 | } 20 | 21 | public QueryResults execute() throws IOException { 22 | HttpResponse response = this.httpRequest.execute(); 23 | return response.parseAs(QueryResults.class); 24 | } 25 | 26 | public String getUrl() { 27 | return this.httpRequest.getUrl().toString(); 28 | } 29 | 30 | public void setUrl(GenericUrl url){ 31 | this.httpRequest.setUrl(url); 32 | } 33 | 34 | public String getMethod() { 35 | return this.httpRequest.getRequestMethod(); 36 | } 37 | 38 | public String getBody() throws IOException { 39 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 40 | this.httpRequest.getContent().writeTo(stream); 41 | return stream.toString(); 42 | } 43 | 44 | public void writeContentTo(OutputStream out) { 45 | return; 46 | } 47 | 48 | public QueryRequest setReadConsistencyLevel(ReadConsistencyLevel lvl) { 49 | this.httpRequest.getUrl().put("level", lvl.toString().toLowerCase()); 50 | return this; 51 | } 52 | 53 | public QueryRequest enableTransaction(Boolean tx) { 54 | if (tx) { 55 | this.httpRequest.getUrl().put("transaction", tx.toString()); 56 | } else { 57 | this.httpRequest.getUrl().remove("transaction"); 58 | } 59 | return this; 60 | } 61 | 62 | public QueryRequest enableTimings(Boolean tm) { 63 | if (tm) { 64 | this.httpRequest.getUrl().put("timings", tm.toString()); 65 | } else { 66 | this.httpRequest.getUrl().remove("timings"); 67 | } 68 | return this; 69 | } 70 | } -------------------------------------------------------------------------------- /src/main/java/com/rqlite/impl/RequestFactory.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.impl; 2 | 3 | import java.io.IOException; 4 | 5 | import com.google.api.client.http.GenericUrl; 6 | import com.google.api.client.http.HttpRequest; 7 | import com.google.api.client.http.HttpRequestFactory; 8 | import com.google.api.client.http.HttpRequestInitializer; 9 | import com.google.api.client.http.HttpTransport; 10 | import com.google.api.client.http.javanet.NetHttpTransport; 11 | import com.google.api.client.http.json.JsonHttpContent; 12 | import com.google.api.client.json.JsonFactory; 13 | import com.google.api.client.json.JsonObjectParser; 14 | import com.google.api.client.json.jackson2.JacksonFactory; 15 | import com.rqlite.dto.ParameterizedStatement; 16 | 17 | public class RequestFactory { 18 | static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport(); 19 | static final JsonFactory JSON_FACTORY = new JacksonFactory(); 20 | 21 | private HttpRequestFactory requestFactory; 22 | 23 | private String proto; 24 | private String host; 25 | private Integer port; 26 | 27 | private GenericUrl executeUrl; 28 | private GenericUrl queryUrl; 29 | private GenericUrl statusUrl; 30 | 31 | public RequestFactory(final String proto, final String host, final Integer port) { 32 | this.proto = proto; 33 | this.host = host; 34 | this.port = port; 35 | 36 | this.executeUrl = new GenericUrl(String.format("%s://%s:%d/db/execute", this.proto, this.host, this.port)); 37 | this.queryUrl = new GenericUrl(String.format("%s://%s:%d/db/query", this.proto, this.host, this.port)); 38 | this.statusUrl = new GenericUrl(String.format("%s://%s:%d/status", this.proto, this.host, this.port)); 39 | 40 | this.requestFactory = HTTP_TRANSPORT.createRequestFactory(new HttpRequestInitializer() { 41 | public void initialize(HttpRequest request) { 42 | request.setParser(new JsonObjectParser(JSON_FACTORY)); 43 | } 44 | }); 45 | } 46 | 47 | public ExecuteRequest buildExecuteRequest(String[] stmts) throws IOException { 48 | HttpRequest request = this.buildPostRequest(this.executeUrl, stmts); 49 | return new ExecuteRequest(request); 50 | } 51 | 52 | public ExecuteRequest buildExecuteRequest(ParameterizedStatement[] stmts) throws IOException { 53 | HttpRequest request = this.buildPostRequest(this.executeUrl, stmts); 54 | return new ExecuteRequest(request); 55 | } 56 | 57 | public QueryRequest buildQueryRequest(String[] stmts) throws IOException { 58 | HttpRequest request = this.buildPostRequest(this.queryUrl, stmts); 59 | return new QueryRequest(request); 60 | } 61 | 62 | public QueryRequest buildQueryRequest(ParameterizedStatement[] stmts) throws IOException { 63 | HttpRequest request = this.buildPostRequest(this.queryUrl, stmts); 64 | return new QueryRequest(request); 65 | } 66 | 67 | public PingRequest buildPingRequest() throws IOException { 68 | HttpRequest request = this.requestFactory.buildGetRequest(this.statusUrl); 69 | return new PingRequest(request); 70 | } 71 | 72 | private HttpRequest buildPostRequest(GenericUrl url, String[] stmts) throws IOException { 73 | HttpRequest request = this.requestFactory.buildPostRequest(url, new JsonHttpContent(JSON_FACTORY, stmts)); 74 | return request.setParser(new JsonObjectParser(JSON_FACTORY)); 75 | } 76 | private HttpRequest buildPostRequest(GenericUrl url, ParameterizedStatement[] stmts) throws IOException { 77 | HttpRequest request = this.requestFactory.buildPostRequest(url, new ParameterizedStatementContent(stmts)); 78 | return request.setParser(new JsonObjectParser(JSON_FACTORY)); 79 | } 80 | 81 | GenericRequest AdoptRequest(GenericRequest request){ 82 | if (request instanceof ExecuteRequest) {request.setUrl(this.executeUrl);} 83 | else if (request instanceof QueryRequest) {request.setUrl(this.queryUrl);} 84 | else {request.setUrl(this.statusUrl);} 85 | return request; 86 | } 87 | 88 | @Override 89 | public String toString() { 90 | return "RequestFactory{" + 91 | "requestFactory=" + requestFactory + 92 | ", proto='" + proto + '\'' + 93 | ", host='" + host + '\'' + 94 | ", port=" + port + 95 | ", executeUrl=" + executeUrl + 96 | ", queryUrl=" + queryUrl + 97 | ", statusUrl=" + statusUrl + 98 | '}'; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/impl/RqliteImpl.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.impl; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | import com.google.api.client.http.HttpResponseException; 13 | import com.google.api.client.http.HttpTransport; 14 | import com.google.api.client.http.javanet.NetHttpTransport; 15 | import com.google.api.client.json.JsonFactory; 16 | import com.google.api.client.json.jackson2.JacksonFactory; 17 | import com.rqlite.NodeUnavailableException; 18 | import com.rqlite.Rqlite; 19 | import com.rqlite.dto.ExecuteResults; 20 | import com.rqlite.dto.GenericResults; 21 | import com.rqlite.dto.ParameterizedStatement; 22 | import com.rqlite.dto.Pong; 23 | import com.rqlite.dto.QueryResults; 24 | 25 | public class RqliteImpl implements Rqlite { 26 | 27 | static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport(); 28 | static final JsonFactory JSON_FACTORY = new JacksonFactory(); 29 | 30 | private RequestFactory requestFactory; 31 | 32 | private List peers; // only initialized if evaluating a config file 33 | private int timeoutDelay = 8000; 34 | 35 | Map nodeRequestFactoryMap = new HashMap<>(); 36 | 37 | public RqliteImpl(final String proto, final String host, final Integer port) { 38 | this.requestFactory = new RequestFactory(proto, host, port); 39 | } 40 | 41 | public RqliteImpl(final String configPath) { 42 | loadPeersFromConfig(configPath); 43 | this.requestFactory = new RequestFactory(peers.get(0).proto, peers.get(0).host, peers.get(0).port); 44 | } 45 | 46 | public void setTimeoutDelay(int delay) { 47 | this.timeoutDelay = delay; 48 | } 49 | 50 | private void loadPeersFromConfig(String configPath){ 51 | this.peers = new ArrayList<>(); 52 | try (BufferedReader br = new BufferedReader(new FileReader(configPath))) { 53 | String line; 54 | while ((line = br.readLine()) != null) { 55 | String[] values = line.split(","); 56 | peers.add(new RqliteNode(values[0], values[1], Integer.valueOf(values[2]))); 57 | } 58 | } catch(FileNotFoundException e) { 59 | e.printStackTrace(); 60 | } catch (IOException e) { 61 | e.printStackTrace(); 62 | } 63 | } 64 | 65 | private GenericResults tryOtherPeers(GenericRequest request, String[] stmts) throws NodeUnavailableException { 66 | // Cycle through the list of nodes in the config file. 67 | long end = System.currentTimeMillis() + timeoutDelay; 68 | if (peers != null) { 69 | while (System.currentTimeMillis() < end) { 70 | for (RqliteNode node : this.peers) { 71 | try { 72 | if (nodeRequestFactoryMap.containsKey(node)) { 73 | requestFactory = nodeRequestFactoryMap.get(node); 74 | } else { 75 | requestFactory = new RequestFactory(node.proto, node.host, node.port); 76 | nodeRequestFactoryMap.put(node, requestFactory); 77 | } 78 | GenericRequest r = requestFactory.AdoptRequest(request); 79 | GenericResults results = r.execute(); 80 | return results; 81 | } catch (IOException e) { 82 | } 83 | } 84 | // pause to avoid churning 85 | try { 86 | Thread.sleep(100); 87 | } catch (InterruptedException e) { 88 | } 89 | } 90 | } 91 | throw new NodeUnavailableException("Could not connect to rqlite node. Please check that the node is online and that your config files point to the correct address."); 92 | } 93 | 94 | private GenericResults tryOtherPeers(GenericRequest request, ParameterizedStatement[] stmts) throws NodeUnavailableException { 95 | // Cycle through the list of nodes in the config file. 96 | long end = System.currentTimeMillis() + timeoutDelay; 97 | if (peers != null) { 98 | while (System.currentTimeMillis() < end) { 99 | for (RqliteNode node : this.peers) { 100 | try { 101 | if (nodeRequestFactoryMap.containsKey(node)) { 102 | requestFactory = nodeRequestFactoryMap.get(node); 103 | } else { 104 | requestFactory = new RequestFactory(node.proto, node.host, node.port); 105 | nodeRequestFactoryMap.put(node, requestFactory); 106 | } 107 | GenericRequest r = requestFactory.AdoptRequest(request); 108 | GenericResults results = r.execute(); 109 | return results; 110 | } catch (IOException e) { 111 | } 112 | } 113 | // pause to avoid churning 114 | try { 115 | Thread.sleep(100); 116 | } catch (InterruptedException e) { 117 | } 118 | } 119 | } 120 | throw new NodeUnavailableException("Could not connect to rqlite node. Please check that the node is online and that your config files point to the correct address."); 121 | } 122 | 123 | public QueryResults Query(String[] stmts, boolean tx, ReadConsistencyLevel lvl) throws NodeUnavailableException { 124 | QueryRequest request; 125 | 126 | try { 127 | request = this.requestFactory.buildQueryRequest(stmts); 128 | } catch (IOException e1) { 129 | // TODO Auto-generated catch block 130 | e1.printStackTrace(); 131 | return null; 132 | } 133 | request.enableTransaction(tx).setReadConsistencyLevel(lvl); 134 | 135 | try { 136 | return request.execute(); 137 | } catch (HttpResponseException responseException) { 138 | return (QueryResults) this.tryOtherPeers(request, stmts); 139 | } catch (IOException e) { 140 | // TODO Auto-generated catch block 141 | return (QueryResults) this.tryOtherPeers(request, stmts); 142 | } 143 | } 144 | @Override 145 | public QueryResults Query(ParameterizedStatement[] stmts, boolean tx, ReadConsistencyLevel lvl) throws NodeUnavailableException { 146 | QueryRequest request; 147 | 148 | try { 149 | request = this.requestFactory.buildQueryRequest(stmts); 150 | } catch (IOException e1) { 151 | // TODO Auto-generated catch block 152 | e1.printStackTrace(); 153 | return null; 154 | } 155 | request.enableTransaction(tx).setReadConsistencyLevel(lvl); 156 | 157 | try { 158 | return request.execute(); 159 | } catch (HttpResponseException responseException) { 160 | return (QueryResults) this.tryOtherPeers(request, stmts); 161 | } catch (IOException e) { 162 | // TODO Auto-generated catch block 163 | return (QueryResults) this.tryOtherPeers(request, stmts); 164 | } 165 | } 166 | 167 | public QueryResults Query(String s, ReadConsistencyLevel lvl) throws NodeUnavailableException { 168 | return this.Query(new String[] { s }, false, lvl); 169 | } 170 | 171 | @Override 172 | public QueryResults Query(ParameterizedStatement q, ReadConsistencyLevel lvl) throws NodeUnavailableException { 173 | return this.Query(new ParameterizedStatement[] { q }, false, lvl); 174 | } 175 | 176 | public ExecuteResults Execute(String[] stmts, boolean tx) throws NodeUnavailableException { 177 | ExecuteRequest request; 178 | try { 179 | request = this.requestFactory.buildExecuteRequest(stmts); 180 | } catch (IOException e1) { 181 | // TODO Auto-generated catch block 182 | e1.printStackTrace(); 183 | return null; 184 | } 185 | request.enableTransaction(tx); 186 | 187 | try { 188 | return request.execute(); 189 | } catch (HttpResponseException responseException) { 190 | return (ExecuteResults) this.tryOtherPeers(request, stmts); 191 | } catch (IOException e) { 192 | // TODO Auto-generated catch block 193 | return (ExecuteResults) this.tryOtherPeers(request, stmts); 194 | } 195 | } 196 | 197 | @Override 198 | public ExecuteResults Execute(ParameterizedStatement[] stmts, boolean tx) throws NodeUnavailableException { 199 | ExecuteRequest request; 200 | try { 201 | request = this.requestFactory.buildExecuteRequest(stmts); 202 | } catch (IOException e1) { 203 | // TODO Auto-generated catch block 204 | e1.printStackTrace(); 205 | return null; 206 | } 207 | request.enableTransaction(tx); 208 | 209 | try { 210 | return request.execute(); 211 | } catch (HttpResponseException responseException) { 212 | return (ExecuteResults) this.tryOtherPeers(request, stmts); 213 | } catch (IOException e) { 214 | // TODO Auto-generated catch block 215 | return (ExecuteResults) this.tryOtherPeers(request, stmts); 216 | } 217 | } 218 | 219 | public ExecuteResults Execute(String s) throws NodeUnavailableException { 220 | return this.Execute(new String[] { s }, false); 221 | } 222 | 223 | @Override 224 | public ExecuteResults Execute(ParameterizedStatement q) throws NodeUnavailableException { 225 | return this.Execute(new ParameterizedStatement[]{ q }, false); 226 | } 227 | 228 | public Pong Ping() { 229 | try { 230 | return this.requestFactory.buildPingRequest().execute(); 231 | } catch (IOException e) { 232 | // TODO Auto-generated catch block 233 | e.printStackTrace(); 234 | return null; 235 | } 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /src/main/java/com/rqlite/impl/RqliteNode.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.impl; 2 | 3 | public class RqliteNode { 4 | public String proto; 5 | public String host; 6 | public Integer port; 7 | 8 | public RqliteNode(String proto, String host, Integer port){ 9 | this.proto = proto; 10 | this.host = host; 11 | this.port = port; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/com/rqlite/RqliteClientTest.java: -------------------------------------------------------------------------------- 1 | package com.rqlite; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import org.junit.After; 6 | import org.junit.Assert; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import com.rqlite.dto.ExecuteResults; 11 | import com.rqlite.dto.ParameterizedStatement; 12 | import com.rqlite.dto.QueryResults; 13 | 14 | public class RqliteClientTest { 15 | 16 | public Rqlite rqlite; 17 | 18 | @Before 19 | public void setup(){ 20 | rqlite = RqliteFactory.connect("http", "localhost", 4001); 21 | } 22 | 23 | @Test 24 | public void testRqliteClientSingle() throws NodeUnavailableException { 25 | ExecuteResults results = null; 26 | QueryResults rows = null; 27 | 28 | try { 29 | 30 | results = rqlite.Execute("CREATE TABLE foo (id integer not null primary key, name text)"); 31 | Assert.assertNotNull(results); 32 | Assert.assertEquals(1, results.results.length); 33 | 34 | results = rqlite.Execute("INSERT INTO foo(name) VALUES(\"fiona\")"); 35 | Assert.assertNotNull(results); 36 | Assert.assertEquals(1, results.results.length); 37 | Assert.assertEquals(1, results.results[0].lastInsertId); 38 | 39 | rows = rqlite.Query("SELECT * FROM foo", Rqlite.ReadConsistencyLevel.WEAK); 40 | Assert.assertNotNull(rows); 41 | Assert.assertEquals(1, rows.results.length); 42 | Assert.assertArrayEquals(new String[]{"id", "name"}, rows.results[0].columns); 43 | Assert.assertArrayEquals(new String[]{"integer", "text"}, rows.results[0].types); 44 | Assert.assertEquals(1, rows.results[0].values.length); 45 | Assert.assertArrayEquals(new Object[]{new BigDecimal(1), "fiona"}, rows.results[0].values[0]); 46 | 47 | results = rqlite.Execute("CREATE TABLE secret_agents (id integer not null primary key, name text, secret text)"); 48 | Assert.assertNotNull(results); 49 | Assert.assertEquals(1, results.results.length); 50 | 51 | results = rqlite.Execute(new ParameterizedStatement("INSERT INTO secret_agents(id, name, secret) VALUES(?, ?, ?)", new Object[]{7, "James Bond", "not-a-secret"})); 52 | Assert.assertNotNull(results); 53 | Assert.assertEquals(1, results.results.length); 54 | Assert.assertNull(results.results[0].error); 55 | Assert.assertEquals(7, results.results[0].lastInsertId); 56 | } catch (NodeUnavailableException e) { 57 | Assert.fail("Failed because rqlite-java could not connect to the node."); 58 | } 59 | } 60 | 61 | @Test 62 | public void testRqliteClientMulti() { 63 | ExecuteResults results = null; 64 | QueryResults rows = null; 65 | 66 | try { 67 | results = rqlite.Execute("CREATE TABLE bar (id integer not null primary key, name text)"); 68 | Assert.assertNotNull(results); 69 | Assert.assertEquals(1, results.results.length); 70 | 71 | String[] s = {"INSERT INTO bar(name) VALUES(\"fiona\")", "INSERT INTO bar(name) VALUES(\"declan\")"}; 72 | results = rqlite.Execute(s, false); 73 | Assert.assertNotNull(results); 74 | Assert.assertEquals(2, results.results.length); 75 | Assert.assertEquals(1, results.results[0].lastInsertId); 76 | Assert.assertEquals(2, results.results[1].lastInsertId); 77 | 78 | String[] q = {"SELECT * FROM bar", "SELECT name FROM bar"}; 79 | rows = rqlite.Query(q, false, Rqlite.ReadConsistencyLevel.WEAK); 80 | Assert.assertNotNull(rows); 81 | Assert.assertNotNull(rows); 82 | Assert.assertEquals(2, rows.results.length); 83 | 84 | // SELECT * FROM bar 85 | Assert.assertArrayEquals(new String[]{"id", "name"}, rows.results[0].columns); 86 | Assert.assertArrayEquals(new String[]{"integer", "text"}, rows.results[0].types); 87 | Assert.assertEquals(2, rows.results[0].values.length); 88 | Assert.assertArrayEquals(new Object[]{new BigDecimal(1), "fiona"}, rows.results[0].values[0]); 89 | Assert.assertArrayEquals(new Object[]{new BigDecimal(2), "declan"}, rows.results[0].values[1]); 90 | 91 | // SELECT name FROM bar 92 | Assert.assertArrayEquals(new String[]{"name"}, rows.results[1].columns); 93 | Assert.assertArrayEquals(new String[]{"text"}, rows.results[1].types); 94 | Assert.assertEquals(2, rows.results[1].values.length); 95 | Assert.assertArrayEquals(new Object[]{"fiona"}, rows.results[1].values[0]); 96 | Assert.assertArrayEquals(new Object[]{"declan"}, rows.results[1].values[1]); 97 | } catch (NodeUnavailableException e) { 98 | Assert.fail("Failed because rqlite-java could not connect to the node."); 99 | } 100 | } 101 | 102 | @Test 103 | public void testRqliteClientSyntax() { 104 | ExecuteResults results = null; 105 | QueryResults rows = null; 106 | try { 107 | results = rqlite.Execute("nonsense"); 108 | Assert.assertNotNull(results); 109 | Assert.assertEquals(1, results.results.length); 110 | Assert.assertEquals(0, results.results[0].rowsAffected); 111 | Assert.assertEquals("near \"nonsense\": syntax error", results.results[0].error); 112 | 113 | rows = rqlite.Query("more nonsense", Rqlite.ReadConsistencyLevel.WEAK); 114 | Assert.assertNotNull(rows); 115 | Assert.assertEquals(1, rows.results.length); 116 | Assert.assertEquals("near \"more\": syntax error", rows.results[0].error); 117 | } catch (NodeUnavailableException e) { 118 | Assert.fail("Failed because rqlite-java could not connect to the node."); 119 | } 120 | } 121 | 122 | @After 123 | public void after() throws Exception { 124 | Rqlite rqlite = RqliteFactory.connect("http", "localhost", 4001); 125 | rqlite.Execute("DROP TABLE foo"); 126 | rqlite.Execute("DROP TABLE bar"); 127 | rqlite.Execute("DROP TABLE secret_agents"); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/test/java/com/rqlite/RqliteFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.rqlite; 2 | 3 | import java.util.Map; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import com.rqlite.dto.Pong; 9 | 10 | public class RqliteFactoryTest { 11 | 12 | @Test 13 | public void testCreateRqliteInstance() { 14 | Rqlite rqlite = RqliteFactory.connect("http", "localhost", 4001); 15 | Assert.assertNotNull(rqlite); 16 | } 17 | 18 | @Test 19 | public void testCreateRqliteInstancePing() { 20 | Rqlite rqlite = RqliteFactory.connect("http", "localhost", 4001); 21 | Pong pong = rqlite.Ping(); 22 | Assert.assertEquals(getRqliteVersion(), pong.version); 23 | } 24 | 25 | private String getRqliteVersion() { 26 | Map getenv = System.getenv(); 27 | if (getenv.containsKey("RQLITE_VERSION")) { 28 | return getenv.get("RQLITE_VERSION"); 29 | } 30 | return "unknown"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/rqlite/RqliteFailoverTest.java: -------------------------------------------------------------------------------- 1 | package com.rqlite; 2 | 3 | import com.rqlite.dto.ExecuteResults; 4 | import com.rqlite.dto.QueryResults; 5 | import org.junit.After; 6 | import org.junit.Assert; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | import java.math.BigDecimal; 12 | import java.nio.file.Files; 13 | import java.nio.file.Paths; 14 | import java.util.UUID; 15 | 16 | public class RqliteFailoverTest { 17 | String rqlitePath; 18 | Process node2; 19 | Process node3; 20 | Process node4; 21 | 22 | @Before 23 | public void setUp() throws IOException{ 24 | // rqlitePath.config should contain one line with a path to the installation directory of Rqlite 25 | try { 26 | rqlitePath = Files.readAllLines(Paths.get("resources/rqlitePath.config")).get(0); 27 | } catch (IOException e){ 28 | System.err.println(e); 29 | } 30 | 31 | //Create 3 nodes 32 | ProcessBuilder pb1 = new ProcessBuilder(rqlitePath + "/./rqlited", 33 | "-node-id", "node.2", 34 | "-http-addr", "localhost:4007", 35 | "-raft-addr", "localhost:4008", 36 | "target/rqlitenodes/node2." + UUID.randomUUID()) ; 37 | node2 = pb1.start(); 38 | 39 | try { 40 | Thread.sleep(2000); //Give this node 2 seconds to establish itself as leader 41 | } catch (InterruptedException e) { } 42 | 43 | ProcessBuilder pb2 = new ProcessBuilder(rqlitePath + "/./rqlited", 44 | "-node-id", "node.3", 45 | "-http-addr", "localhost:4003", 46 | "-raft-addr", "localhost:4004", 47 | "-join", "localhost:4007", 48 | "target/rqlitenodes/node3." + UUID.randomUUID()); 49 | node3 = pb2.start(); 50 | 51 | ProcessBuilder pb3 = new ProcessBuilder(rqlitePath + "/./rqlited", 52 | "-node-id", "node.4", 53 | "-http-addr", "localhost:4005", 54 | "-raft-addr", "localhost:4006", 55 | "-join", "localhost:4007", 56 | "target/rqlitenodes/node4." + UUID.randomUUID()); 57 | node4 = pb3.start(); 58 | } 59 | 60 | @Test 61 | public void testRqliteFailover() throws IOException { 62 | //connect to node.2 with config file 63 | Rqlite rqlite = RqliteFactory.connect("resources/FailoverTest.nodehosts.config"); 64 | ExecuteResults results = null; 65 | QueryResults rows = null; 66 | 67 | try { 68 | results = rqlite.Execute("CREATE TABLE baz (id integer not null primary key, name text)"); 69 | Assert.assertNotNull(results); 70 | Assert.assertEquals(1, results.results.length); 71 | 72 | //Connect to node.2 without config file 73 | Rqlite rqlite2 = RqliteFactory.connect("http", "localhost", 4007); 74 | 75 | //Kill leader node.2 76 | node2.destroy(); 77 | 78 | //see if rqlite with config file has recovered 79 | results = rqlite.Execute("INSERT INTO baz(name) VALUES(\"fiona\")"); 80 | Assert.assertNotNull(results); 81 | Assert.assertEquals(1, results.results.length); 82 | Assert.assertEquals(1, results.results[0].lastInsertId); 83 | 84 | rows = rqlite.Query("SELECT * FROM baz", Rqlite.ReadConsistencyLevel.WEAK); 85 | Assert.assertNotNull(rows); 86 | Assert.assertEquals(1, rows.results.length); 87 | Assert.assertArrayEquals(new String[]{"id", "name"}, rows.results[0].columns); 88 | Assert.assertArrayEquals(new String[]{"integer", "text"}, rows.results[0].types); 89 | Assert.assertEquals(1, rows.results[0].values.length); 90 | Assert.assertArrayEquals(new Object[]{new BigDecimal(1), "fiona"}, rows.results[0].values[0]); 91 | 92 | //rqlite without config file should fail 93 | try { 94 | rows = rqlite2.Query("SELECT * FROM baz", Rqlite.ReadConsistencyLevel.WEAK); 95 | Assert.fail("Expected NodeUnavailableException was not thrown."); 96 | } catch (NodeUnavailableException e) {} 97 | 98 | } catch (Exception e) { 99 | Assert.fail("Failed due to an unexpected exception.\n" + e.getMessage()); 100 | } 101 | } 102 | 103 | @After 104 | public void tearDown(){ 105 | node3.destroy(); 106 | node4.destroy(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/test/java/com/rqlite/impl/RequestFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.rqlite.impl; 2 | 3 | import java.io.IOException; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import com.rqlite.Rqlite; 9 | 10 | public class RequestFactoryTest { 11 | @Test 12 | public void testRequestFactoryQuery() throws IOException { 13 | RequestFactory factory = new RequestFactory("http", "localhost", 4001); 14 | QueryRequest request = factory.buildQueryRequest(new String[] {}); 15 | Assert.assertEquals("http://localhost:4001/db/query", request.getUrl()); 16 | Assert.assertEquals("POST", request.getMethod()); 17 | Assert.assertEquals("[]", request.getBody()); 18 | 19 | request.enableTransaction(true); 20 | Assert.assertEquals("http://localhost:4001/db/query?transaction=true", request.getUrl()); 21 | 22 | request.enableTransaction(false); 23 | Assert.assertEquals("http://localhost:4001/db/query", request.getUrl()); 24 | 25 | request.setReadConsistencyLevel(Rqlite.ReadConsistencyLevel.STRONG); 26 | Assert.assertEquals("http://localhost:4001/db/query?level=strong", request.getUrl()); 27 | 28 | request.setReadConsistencyLevel(Rqlite.ReadConsistencyLevel.WEAK); 29 | Assert.assertEquals("http://localhost:4001/db/query?level=weak", request.getUrl()); 30 | 31 | request.setReadConsistencyLevel(Rqlite.ReadConsistencyLevel.NONE); 32 | Assert.assertEquals("http://localhost:4001/db/query?level=none", request.getUrl()); 33 | } 34 | 35 | @Test 36 | public void testRequestFactorQueryStatement() throws IOException { 37 | RequestFactory factory = new RequestFactory("http", "localhost", 4001); 38 | QueryRequest request = factory.buildQueryRequest(new String[] { "SELECT * FROM foo" }); 39 | Assert.assertEquals("http://localhost:4001/db/query", request.getUrl()); 40 | Assert.assertEquals("POST", request.getMethod()); 41 | Assert.assertEquals("[\"SELECT * FROM foo\"]", request.getBody()); 42 | } 43 | 44 | @Test 45 | public void testRequestFactorQueryStatementMulti() throws IOException { 46 | RequestFactory factory = new RequestFactory("http", "localhost", 4001); 47 | QueryRequest request = factory.buildQueryRequest(new String[] { "SELECT * FROM foo", "SELECT * FROM bar" }); 48 | Assert.assertEquals("http://localhost:4001/db/query", request.getUrl()); 49 | Assert.assertEquals("POST", request.getMethod()); 50 | Assert.assertEquals("[\"SELECT * FROM foo\",\"SELECT * FROM bar\"]", request.getBody()); 51 | } 52 | 53 | @Test 54 | public void testRequestFactorExecute() throws IOException { 55 | RequestFactory factory = new RequestFactory("http", "localhost", 4001); 56 | ExecuteRequest request = factory.buildExecuteRequest(new String[] {}); 57 | Assert.assertEquals("http://localhost:4001/db/execute", request.getUrl()); 58 | Assert.assertEquals("POST", request.getMethod()); 59 | Assert.assertEquals("[]", request.getBody()); 60 | 61 | request.enableTransaction(true); 62 | Assert.assertEquals("http://localhost:4001/db/execute?transaction=true", request.getUrl()); 63 | 64 | request.enableTransaction(false); 65 | Assert.assertEquals("http://localhost:4001/db/execute", request.getUrl()); 66 | } 67 | 68 | @Test 69 | public void testRequestFactorExecuteStatementMulti() throws IOException { 70 | RequestFactory factory = new RequestFactory("http", "localhost", 4001); 71 | ExecuteRequest request = factory.buildExecuteRequest( 72 | new String[] { "INSERT INTO foo(name) VALUES(1)", "INSERT INTO foo(name) VALUES(2)" }); 73 | Assert.assertEquals("http://localhost:4001/db/execute", request.getUrl()); 74 | Assert.assertEquals("POST", request.getMethod()); 75 | Assert.assertEquals("[\"INSERT INTO foo(name) VALUES(1)\",\"INSERT INTO foo(name) VALUES(2)\"]", 76 | request.getBody()); 77 | } 78 | 79 | } 80 | --------------------------------------------------------------------------------