commit baa9f32e9bfd37ab11f3f427c45429800b64b04f Author: davassi Date: Thu Oct 6 17:37:28 2016 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0400add --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +/target* +/.classpath +/.project +/.settings +/tomcat.* +/.idea +/*.iml +.classpath +.project +*.class +target/* + diff --git a/README.md b/README.md new file mode 100644 index 0000000..9d331b9 --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +##Introduction + +The JOTA library is a simple Java8 wrapper around IOTA Node's JSON-REST HTTP interface. + +It allows to connect easily using java directly to a local or a remote [[IOTA]](https://iota.readme.io/docs/syncing-to-the-network) node. + +* **Latest release:** 0.0.1 Snapshot +* **Compatibility:** IOTA IRI v1.0.6 +* **API coverage:** 20 of 20 commands fully implemented +* **License:** Apache License 2.0 +* **Readme updated:** 2016-02-17 10:16:43 (UTC) + +A list of all *IOTA* JSON-REST API commands currently supported by jota wrapper can be found in the `Commands` enum (see [here](IotaAPICommands.java) for more details). + +JOTA java wrapper is being designed to be thread-safe and simplest as possible in order to be easily mantainable, accordingly with the ongoing natural evolution of IOTA'api. +All the boilerplate code for connecting to the node rest interface has been gotten rid off by using Retrofit. + +##Technologies & dependencies + +The JOTA library has been designed to be used exclusively with Java 8+. + +Core dependencies: +* Retrofit Client 2.1.0 [[link]](https://square.github.io/retrofit/) +* Gson JSON Processor : + * Annotations 2.5.0 (`jackson-annotations`) [[link]](https://github.com/FasterXML/jackson-annotations) + * Databind 2.5.0 (`jackson-databind`) [[link]](https://github.com/FasterXML/jackson-databind) +* Lombok 1.16.2 [[link]](https://github.com/rzwitserloot/lombok) + +Other dependencies: +* Simple Logging Facade for Java 1.7.21 [[link]](http://www.slf4j.org/) +* Apache Commons Lang 3.3.2 [[link]](http://commons.apache.org/proper/commons-lang/) + + +##Getting started + +Connect to your local node with the default settings is quite straitforward: it requires only 2 lines of code. For example, in order to fetch the Node Info: + + IotaApiProxy api = new IotaApiProxy.Builder.build(); + GetNodeInfoResponse response = api.getNodeInfo(); + +of if you need to connect to a remote node on https: + + IotaApiProxy api = new IotaApiProxy.Builder + .protocol("https") + .nodeAddress("somewhere_remotely") + .port(54321) + .build(); + + GetNodeInfoResponse response = api.getNodeInfo(); + +Next, modify your `pom.xml` to include `btcd-cli4j-core` as a dependency: + + + com.neemre.btcd-cli4j + btcd-cli4j-core + 0.5.1 + + +In order to communicate with *IOTA node*, JOTA needs to be aware of your node's exact configuration. The easiest way of providing this information is via a `node_config.properties` file, for example: + + node.bitcoind.rpc.protocol = http + node.bitcoind.rpc.host = 127.0.0.1 + node.bitcoind.rpc.port = 8332 + node.bitcoind.rpc.user = falcon-pc + node.bitcoind.rpc.password = 3F4DN9QGqWrB4DCdfYMXp8xdDYL4HDFzpaS9r76DbNhw + node.bitcoind.http.auth_scheme = Basic + +That's it! + +##Examples + +There's an extensive list of test coverages on the src/test/java package of the project that can be used as reference. + +##Supporting the project + +If JOTA has been useful to you and you feel like contributing, consider posting a [bug report](https://github.com/priiduneemre/btcd-cli4j/issues) or a [pull request](https://github.com/priiduneemre/btcd-cli4j/pulls). Alternatively, donations are very welcome too! + +* Bitcoin: `12CfEQ7RAEwpS82jFZg1HgjeH8obbpMeL5` +* IOTA: `` +* Ethereum: `` + diff --git a/node_config.properties b/node_config.properties new file mode 100644 index 0000000..1620702 --- /dev/null +++ b/node_config.properties @@ -0,0 +1,5 @@ + +iota.node.protocol=http +iota.node.host=127.0.0.1 +iota.node.port=14265 + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..8c7660e --- /dev/null +++ b/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + com.iota + jota + 0.0.1-SNAPSHOT + JOTA + JOTA library is a simple Java8 wrapper around IOTA Node's JSON-REST HTTP interface. + + + 1.8 + UTF-8 + + + + + + + com.squareup.retrofit2 + retrofit + 2.1.0 + + + + + com.squareup.retrofit2 + converter-gson + 2.1.0 + + + + + org.apache.commons + commons-lang3 + 3.3.2 + + + + + org.slf4j + slf4j-api + 1.7.21 + + + + + ch.qos.logback + logback-classic + 1.1.7 + + + + + commons-io + commons-io + 2.5 + + + + junit + junit + 4.12 + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + ${java-version} + ${java-version} + ${java-version} + ${java-version} + + + + + + + diff --git a/src/main/java/jota/IotaAPICommands.java b/src/main/java/jota/IotaAPICommands.java new file mode 100644 index 0000000..98213fa --- /dev/null +++ b/src/main/java/jota/IotaAPICommands.java @@ -0,0 +1,45 @@ +package jota; + +/** + * IOTA's node command list + */ +public enum IotaAPICommands { + + GET_NODE_INFO("getNodeInfo", 0), + GET_MILESTONE("getMilestone", 0), + GET_NEIGHBORS("getNeighbors", 0), + GET_TIPS("getTips",0), + GET_TRANSFER("getTransfers", 0), // + FIND_TRANSACTIONS("findTransactions", 0), + GET_INCLUSIONS_STATES("getInclusionStates", 0), + GET_BUNDLE("getBundle", 0), + GET_TRYTES("getTrytes", 0), + ANALYZE_TRANSACTIONS("analyzeTransactions", 0), + GET_NEW_ADDRESS("getNewAddress", 0), + PREPARE_TRANSFERS("prepareTransfers", 0), + GET_TRANSACTIONS_TO_APPROVE("getTransactionsToApprove", 0), + ATTACH_TO_TANGLE("attachToTangle", 0), + INTERRUPT_ATTACHING_TO_TANGLE("interruptAttachingToTangle", 0), + PUSH_TRANSACTIONS("pushTransactions", 0), + STORE_TRANSACTIONS("storeTransactions", 0), + TRANSFER("transfer", 0), + REPLAY_TRANSFER("replayTransfer",0), + PULL_TRANSACTIONS("pullTransactions", 0); + + private IotaAPICommands(String command, int params) { + this.command = command; + this.params = params; + } + + private String command; + private int params; + + public String command() { + return command; + } + + public int params() { + return params; + } +} + diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java new file mode 100644 index 0000000..421abee --- /dev/null +++ b/src/main/java/jota/IotaAPIProxy.java @@ -0,0 +1,226 @@ +package jota; + +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.Optional; +import java.util.Properties; + +import jota.dto.request.*; +import jota.dto.response.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import retrofit2.Call; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * IotaAPIProxy Builder. Usage: + * + * IotaApiProxy api = IotaApiProxy.Builder + * .protocol("http") + * .nodeAddress("localhost") + * .port(12345) + * .build(); + * + * GetNodeInfoResponse response = api.getNodeInfo(); + * + * @author davassi + */ +public class IotaAPIProxy { + + private static final Logger log = LoggerFactory.getLogger(IotaAPIProxy.class); + + private IotaAPIService service; + + private IotaAPIProxy(final Builder builder) { + protocol = builder.protocol; + host = builder.host; + port = builder.port; + postConstruct(); + } + + private String protocol, host, port; + + private void postConstruct() { + + final String nodeUrl = protocol + "://" + host + ":" + port; + + final Retrofit retrofit = new Retrofit.Builder() + .baseUrl(nodeUrl) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + + service = retrofit.create(IotaAPIService.class); + + log.debug("Jota-API Java proxy pointing to node url: '{}'", nodeUrl); + } + + public GetNodeInfoResponse getNodeInfo() { + final Call res = service.getNodeInfo(IotaCommandRequest.createNodeInfoRequest()); + return wrapCheckedException(res).body(); + } + + public GetMilestoneResponse getMilestone(Integer index) { + final Call res = service.getMilestone(IotaGetMilestoneRequest.createMilestoneRequest(index)); + return wrapCheckedException(res).body(); + } + + public GetNeighborsResponse getNeighbors() { + final Call res = service.getNeighbors(IotaCommandRequest.createGetNeighborsRequest()); + return wrapCheckedException(res).body(); + } + + public GetTipsResponse getTips() { + final Call res = service.getTips(IotaCommandRequest.createGetTipsRequest()); + return wrapCheckedException(res).body(); + } + + public GetTransfersResponse getTransfers(String seed, Integer securityLevel) { + final Call res = service.getTransfers(IotaGetTransferRequest.createGetTransferRequest(seed, securityLevel)); + return wrapCheckedException(res).body(); + } + + public FindTransactionResponse findTransactions(String [] addresses, String [] digests, String [] approvees, String [] bundles ) { + + final IotaFindTransactionsRequest findTransRequest = IotaFindTransactionsRequest + .createFindTransactionRequest() + .byAddresses(addresses) + .byDigests(digests) + .byApprovees(approvees) + .byBundles(bundles); + + final Call res = service.findTransactions(findTransRequest); + return wrapCheckedException(res).body(); + } + + public FindTransactionResponse findTransactionsByAddresses(String [] addresses) { + return findTransactions(addresses, null, null, null); + } + + public FindTransactionResponse findTransactionsByBundles(String [] bundles) { + return findTransactions(null, null, null, bundles); + } + + public FindTransactionResponse findTransactionsByApprovees(String [] approvees) { + return findTransactions(null, null, approvees, null); + } + + public FindTransactionResponse findTransactionsByDigests(String [] digests) { + return findTransactions(null, digests, null, null); + } + + public GetInclusionStateResponse getInclusionStates(String[] transactions, String[] tips) { + final Call res = service.getInclusionStates(IotaGetInclusionStateRequest + .createGetInclusionStateRequest(transactions, tips)); + return wrapCheckedException(res).body(); + } + + public GetInclusionStateResponse getInclusionStates(Collection transactions, Collection tips) { + final Call res = service.getInclusionStates(IotaGetInclusionStateRequest + .createGetInclusionStateRequest(transactions, tips)); + return wrapCheckedException(res).body(); + } + + protected static Response wrapCheckedException(final Call call) { + try { + final Response res = call.execute(); + if (res.code() == 400) { + throw new IllegalAccessError(res.errorBody().toString()); + } + return res; + } catch (IOException e) { + log.error("Execution of the API call raised exception. IOTA Node not reachable?", e); + throw new IllegalStateException(e.getMessage()); + } + } + + private static final String env(String env, String def) { + return Optional.ofNullable(System.getenv(env)).orElseGet(() -> { + log.warn("Enviroment variable '{}' is not defined, and actual value has not been specified. " + + "Rolling back to default value: '{}'", env, def); + return def; + }); + } + + public static class Builder { + + String protocol, host, port; + + public IotaAPIProxy build() { + + if (protocol == null || host == null || port == null) { + + // check properties files. + if (!checkPropertiesFiles()) { + + // last resort: best effort on enviroment variable, + // before assigning default values. + checkEnviromentVariables(); + } + } + + return new IotaAPIProxy(this); + } + + private boolean checkPropertiesFiles() { + + try (BufferedReader reader = Files.newBufferedReader(Paths.get("node_config.properties"))) { + final Properties nodeConfig = new Properties(); + nodeConfig.load(reader); + + Optional.ofNullable(nodeConfig.getProperty("iota.node.protocol")) + .filter(v -> protocol == null) + .ifPresent(v -> protocol = v); + + Optional.ofNullable(nodeConfig.getProperty("iota.node.host")) + .filter(v -> host == null) + .ifPresent(v -> host = v); + + Optional.ofNullable(nodeConfig.getProperty("iota.node.port")) + .filter(v -> port == null) + .ifPresent(v -> port = v); + + } catch (IOException e1) { + log.debug("node_config.properties not found. Rolling back for another solution..."); + } + return (port != null && protocol != null && host != null); + } + + private void checkEnviromentVariables() { + + Optional.of(env("IOTA_NODE_PROTOCOL", "http")) + .filter(v -> protocol == null) + .ifPresent(v -> protocol = v); + + Optional.ofNullable(env("IOTA_NODE_HOST", "localhost")) + .filter(v -> host == null) + .ifPresent(v -> host = v); + + Optional.ofNullable(env("IOTA_NODE_PORT", "14265")) + .filter(v -> port == null) + .ifPresent(v -> port = v); + } + + public Builder host(String host) { + this.host = host; + return this; + } + + public Builder port(String port) { + this.port = port; + return this; + } + + public Builder protocol(String protocol) { + this.protocol = protocol; + return this; + } + + } + +} diff --git a/src/main/java/jota/IotaAPIService.java b/src/main/java/jota/IotaAPIService.java new file mode 100644 index 0000000..0e4c20a --- /dev/null +++ b/src/main/java/jota/IotaAPIService.java @@ -0,0 +1,180 @@ +package jota; + +import jota.dto.request.*; +import jota.dto.response.*; +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.Headers; +import retrofit2.http.POST; + +/** + * IOTA API Proxy Service definition using Retrofit2 + * + * @author davassi + */ +public interface IotaAPIService { + + public static final String CONTENT_TYPE_HEADER = "Content-Type: application/json"; + public static final String USER_AGENT_HEADER = "User-Agent: JOTA-API wrapper"; + + /** + * Returns information about your node. + * + * curl http://localhost:14265 \ -X POST \ -H 'Content-Type: + * application/json' \ -d '{"command": "getNodeInfo"}' + * + * @return a {@code NodeInfoResponse} object, if succesfull. + */ + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call getNodeInfo(@Body IotaCommandRequest request); + + /** + * Returns a milestone from a given index. + * + * curl http://localhost:14265 \ -X POST \ -H 'Content-Type: + * application/json' \ -d '{"command": "getMilestone", "index": 8059}' + * + * @return + */ + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call getMilestone(@Body IotaGetMilestoneRequest request); + + /** + * Get the list of latest tips (unconfirmed transactions). + * + * curl http://localhost:14265 -X POST -H 'Content-Type: application/json' + * -d '{"command": "getNeighbors"}' + */ + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call getNeighbors(@Body IotaCommandRequest request); + + /** + * Get the list of latest tips (unconfirmed transactions). + * + * curl http://localhost:14265 \ -X POST \ -H 'Content-Type: + * application/json' \ -d '{"command": "getTips"}' + */ + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call getTips(@Body IotaCommandRequest request); + + /** + * Get the list of latest tips (unconfirmed transactions). + * + * curl http://localhost:14265 \ -X POST \ -H 'Content-Type: + * application/json' \ -d '{"command": "getTips"}' + */ + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call getTransfers(@Body IotaGetTransferRequest request); + + + /** + * Find the transactions which match the specified input and return + * + * curl http://localhost:14265 \ -X POST \ -H 'Content-Type: application/json' \ + * -d '{"command": "findTransactions", "addresses": ["RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"]}' + */ + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call findTransactions(@Body IotaFindTransactionsRequest request); + + + /** + * Get the inclusion states of a set of transactions. This is for determining if a transaction was accepted and confirmed by the network or not. You can search for multiple tips (and thus, milestones) to get past inclusion states of transactions. + * + * curl http://localhost:14265 -X POST -H 'Content-Type: application/json' + * -d '{"command": "getInclusionStates", "transactions"Q9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"], "tips" : []}' + * + * + */ + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call getInclusionStates(@Body IotaGetInclusionStateRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call getBundle(@Body IotaGetBundleRequest request); + + /* + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call getTrytes(@Body IotaGetTrytesRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call analyzeTransactions(@Body IotaAnalyzeTransactionRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call getNewAddress(@Body IotaGetNewAddressRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call prepareTransfers(@Body IotaPrepareTransfersRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call getTransactionsToApprove(@Body IotaGetTransactionsToApproveRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call attachToTangle(@Body IotaAttachToTangleRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call interruptAttachingToTangle(@Body IotaInterruptAttachingToTangleRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call pushTransactions(@Body IotaPushTransactionsRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call storeTransactions(@Body IotaStoreTransactionsRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call transfer(@Body IotaTransferRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call replayTransfer(@Body IotaReplayTransferRequest request); + + @Headers({ CONTENT_TYPE_HEADER, USER_AGENT_HEADER }) + @POST("./") + Call pullTransactions(@Body IotaPullTransactionsRequest request); + + * Get the list of transactions which were bundled with the specified tail transaction. + * This call returns the full value of all individual transactions, not just the hashes. + */ + + + + + + + + + + + + + + + + + + + + + + + + + + +} diff --git a/src/main/java/jota/dto/request/IotaCommandRequest.java b/src/main/java/jota/dto/request/IotaCommandRequest.java new file mode 100644 index 0000000..f21db1f --- /dev/null +++ b/src/main/java/jota/dto/request/IotaCommandRequest.java @@ -0,0 +1,24 @@ +package jota.dto.request; + +import jota.IotaAPICommands; + +public class IotaCommandRequest { + + final String command; + + protected IotaCommandRequest(IotaAPICommands command) { + this.command = command.command(); + } + + public static IotaCommandRequest createNodeInfoRequest() { + return new IotaCommandRequest(IotaAPICommands.GET_NODE_INFO); + } + + public static IotaCommandRequest createGetTipsRequest() { + return new IotaCommandRequest(IotaAPICommands.GET_TIPS); + } + + public static IotaCommandRequest createGetNeighborsRequest() { + return new IotaCommandRequest(IotaAPICommands.GET_NEIGHBORS); + } +} diff --git a/src/main/java/jota/dto/request/IotaFindTransactionsRequest.java b/src/main/java/jota/dto/request/IotaFindTransactionsRequest.java new file mode 100644 index 0000000..537fb4f --- /dev/null +++ b/src/main/java/jota/dto/request/IotaFindTransactionsRequest.java @@ -0,0 +1,42 @@ +package jota.dto.request; + +import jota.IotaAPICommands; + +public class IotaFindTransactionsRequest extends IotaCommandRequest { + + private IotaFindTransactionsRequest() { + super(IotaAPICommands.FIND_TRANSACTIONS); + } + + private String[] bundles; // List of bundle hashes. The hashes need to be extended to 81chars by padding the hash with 9's. + private String[] addresses; + private String[] digests; + private String[] approvees; + + public static IotaFindTransactionsRequest createFindTransactionRequest() { + return new IotaFindTransactionsRequest(); + } + + public IotaFindTransactionsRequest byBundles(String [] bundles) { + this.bundles = bundles; + return this; + } + + public IotaFindTransactionsRequest byAddresses(String [] addresses) { + this.addresses = addresses; + return this; + } + + public IotaFindTransactionsRequest byDigests(String [] digests) { + this.digests = digests; + return this; + } + + public IotaFindTransactionsRequest byApprovees(String [] approvees) { + this.approvees = approvees; + return this; + } + + + +} diff --git a/src/main/java/jota/dto/request/IotaGetBundleRequest.java b/src/main/java/jota/dto/request/IotaGetBundleRequest.java new file mode 100644 index 0000000..490ec66 --- /dev/null +++ b/src/main/java/jota/dto/request/IotaGetBundleRequest.java @@ -0,0 +1,18 @@ +package jota.dto.request; + +import jota.IotaAPICommands; + +public class IotaGetBundleRequest extends IotaCommandRequest { + + private String transaction; + + private IotaGetInclusionStateRequest(final String transaction) { + super(IotaAPICommands.GET_BUNDLE); + this.transaction = transaction; + } + + public static IotaGetBundleRequest createIotaGetBundleRequest(String transaction) { + return new IotaGetBundleRequest(transaction); + } + +} diff --git a/src/main/java/jota/dto/request/IotaGetInclusionStateRequest.java b/src/main/java/jota/dto/request/IotaGetInclusionStateRequest.java new file mode 100644 index 0000000..4cd7b67 --- /dev/null +++ b/src/main/java/jota/dto/request/IotaGetInclusionStateRequest.java @@ -0,0 +1,29 @@ +package jota.dto.request; + +import jota.IotaAPICommands; + +import java.util.Collection; +import java.util.stream.Collectors; + +public class IotaGetInclusionStateRequest extends IotaCommandRequest { + + private IotaGetInclusionStateRequest(final String[] transactions, final String[] tips) { + super(IotaAPICommands.GET_INCLUSIONS_STATES); + this.transactions = transactions; + this.tips = tips; + } + + private String[] transactions; + private String[] tips; + + public static IotaGetInclusionStateRequest createGetInclusionStateRequest(String[] transactions, String[] tips) { + return new IotaGetInclusionStateRequest(transactions, tips); + } + + public static IotaGetInclusionStateRequest createGetInclusionStateRequest(Collection transactions, Collection tips) { + return createGetInclusionStateRequest( + transactions.toArray(new String[] {}), + tips.toArray(new String[] {})); + } + +} diff --git a/src/main/java/jota/dto/request/IotaGetMilestoneRequest.java b/src/main/java/jota/dto/request/IotaGetMilestoneRequest.java new file mode 100644 index 0000000..b9ce950 --- /dev/null +++ b/src/main/java/jota/dto/request/IotaGetMilestoneRequest.java @@ -0,0 +1,17 @@ +package jota.dto.request; + +import jota.IotaAPICommands; + +public class IotaGetMilestoneRequest extends IotaCommandRequest { + + private String index; + + private IotaGetMilestoneRequest(final String index) { + super(IotaAPICommands.GET_MILESTONE); + this.index = index; + } + + public static IotaGetMilestoneRequest createMilestoneRequest(Integer index) { + return new IotaGetMilestoneRequest(String.valueOf(index)); + } +} diff --git a/src/main/java/jota/dto/request/IotaGetTransferRequest.java b/src/main/java/jota/dto/request/IotaGetTransferRequest.java new file mode 100644 index 0000000..15ec5da --- /dev/null +++ b/src/main/java/jota/dto/request/IotaGetTransferRequest.java @@ -0,0 +1,19 @@ +package jota.dto.request; + +import jota.IotaAPICommands; + +public class IotaGetTransferRequest extends IotaCommandRequest { + + private String seed; + private String securityLevel; + + private IotaGetTransferRequest(final String seed, final String securityLevel) { + super(IotaAPICommands.GET_TRANSFER); + this.seed = seed; + this.securityLevel = securityLevel; + } + + public static IotaGetTransferRequest createGetTransferRequest(String seed, Integer securityLevel) { + return new IotaGetTransferRequest(seed, String.valueOf(securityLevel)); + } +} diff --git a/src/main/java/jota/dto/response/AbstractResponse.java b/src/main/java/jota/dto/response/AbstractResponse.java new file mode 100644 index 0000000..cab9488 --- /dev/null +++ b/src/main/java/jota/dto/response/AbstractResponse.java @@ -0,0 +1,30 @@ +package jota.dto.response; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +public abstract class AbstractResponse { + + private Integer duration; + + public Integer getDuration() { + return duration; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + } + + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this, false); + } + + @Override + public boolean equals(Object obj) { + return EqualsBuilder.reflectionEquals(this, obj, false); + } +} diff --git a/src/main/java/jota/dto/response/FindTransactionResponse.java b/src/main/java/jota/dto/response/FindTransactionResponse.java new file mode 100644 index 0000000..2b68e8f --- /dev/null +++ b/src/main/java/jota/dto/response/FindTransactionResponse.java @@ -0,0 +1,10 @@ +package jota.dto.response; + +public class FindTransactionResponse extends AbstractResponse { + + String [] addresses; + + public String[] getAddresses() { + return addresses; + } +} diff --git a/src/main/java/jota/dto/response/GetBundleResponse.java b/src/main/java/jota/dto/response/GetBundleResponse.java new file mode 100644 index 0000000..1333014 --- /dev/null +++ b/src/main/java/jota/dto/response/GetBundleResponse.java @@ -0,0 +1,93 @@ +package jota.dto.response; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +public class GetBundleResponse extends AbstractResponse { + + private Transactions[] transactions; + + private String warning; + + public String getWarning() { + return warning; + } + + public Transactions[] getTransactions() { + return transactions; + } + + static class Transactions { + private String signatureMessageChunk; + private String index; + private String approvalNonce; + private String hash; + private String digest; + private String type; + private String timestamp; + private String trunkTransaction; + private String branchTransaction; + private String signatureNonce; + private String address; + private String value; + private String bundle; + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + } + + public String getAddress() { + return address; + } + + public String getApprovalNonce() { + return approvalNonce; + } + + public String getBranchTransaction() { + return branchTransaction; + } + + public String getBundle() { + return bundle; + } + + public String getDigest() { + return digest; + } + + public String getHash() { + return hash; + } + + public String getIndex() { + return index; + } + + public String getSignatureMessageChunk() { + return signatureMessageChunk; + } + + public String getSignatureNonce() { + return signatureNonce; + } + + public String getTimestamp() { + return timestamp; + } + + public String getType() { + return type; + } + + public String getTrunkTransaction() { + return trunkTransaction; + } + + public String getValue() { + return value; + } + + } +} diff --git a/src/main/java/jota/dto/response/GetInclusionStateResponse.java b/src/main/java/jota/dto/response/GetInclusionStateResponse.java new file mode 100644 index 0000000..966257e --- /dev/null +++ b/src/main/java/jota/dto/response/GetInclusionStateResponse.java @@ -0,0 +1,9 @@ +package jota.dto.response; + +public class GetInclusionStateResponse extends AbstractResponse { + boolean [] states; + + public boolean[] getStates() { + return states; + } +} diff --git a/src/main/java/jota/dto/response/GetMilestoneResponse.java b/src/main/java/jota/dto/response/GetMilestoneResponse.java new file mode 100644 index 0000000..7e3ecbe --- /dev/null +++ b/src/main/java/jota/dto/response/GetMilestoneResponse.java @@ -0,0 +1,10 @@ +package jota.dto.response; + +public class GetMilestoneResponse extends AbstractResponse { + + private String milestone; + + public String getMilestone() { + return milestone; + } +} diff --git a/src/main/java/jota/dto/response/GetNeighborsResponse.java b/src/main/java/jota/dto/response/GetNeighborsResponse.java new file mode 100644 index 0000000..3b915a0 --- /dev/null +++ b/src/main/java/jota/dto/response/GetNeighborsResponse.java @@ -0,0 +1,27 @@ +package jota.dto.response; + +public class GetNeighborsResponse extends AbstractResponse { + + private Neighbors[] neighbors; + + public Neighbors[] getNeighbors() { + return neighbors; + } + + static class Neighbors { + + private String numberOfAllTransactions; + private String address; + private String numberOfNewTransactions; + + public String getAddress() { + return address; + } + public String getNumberOfAllTransactions() { + return numberOfAllTransactions; + } + public String getNumberOfNewTransactions() { + return numberOfNewTransactions; + } + } +} diff --git a/src/main/java/jota/dto/response/GetNodeInfoResponse.java b/src/main/java/jota/dto/response/GetNodeInfoResponse.java new file mode 100644 index 0000000..30fac67 --- /dev/null +++ b/src/main/java/jota/dto/response/GetNodeInfoResponse.java @@ -0,0 +1,66 @@ +package jota.dto.response; + +public class GetNodeInfoResponse extends AbstractResponse { + + private String incomingPacketsBacklog; + private String appName; + private String transactionsToRequest; + private String jreTotalMemory; + private String time; + private String neighbors; + private String milestoneIndex; + private String appVersion; + private String jreAvailableProcessors; + private String jreMaxMemory; + private String tips; + private String jreFreeMemory; + + public String getIncomingPacketsBacklog() { + return incomingPacketsBacklog; + } + + public String getAppName() { + return appName; + } + + public String getTransactionsToRequest() { + return transactionsToRequest; + } + + public String getJreTotalMemory() { + return jreTotalMemory; + } + + public String getTime() { + return time; + } + + public String getNeighbors() { + return neighbors; + } + + public String getMilestoneIndex() { + return milestoneIndex; + } + + public String getAppVersion() { + return appVersion; + } + + public String getJreAvailableProcessors() { + return jreAvailableProcessors; + } + + public String getJreMaxMemory() { + return jreMaxMemory; + } + + public String getTips() { + return tips; + } + + public String getJreFreeMemory() { + return jreFreeMemory; + } + +} diff --git a/src/main/java/jota/dto/response/GetTipsResponse.java b/src/main/java/jota/dto/response/GetTipsResponse.java new file mode 100644 index 0000000..e45fb7e --- /dev/null +++ b/src/main/java/jota/dto/response/GetTipsResponse.java @@ -0,0 +1,10 @@ +package jota.dto.response; + +public class GetTipsResponse extends AbstractResponse { + + private String[] hashes; + + public String[] getHashes() { + return hashes; + } +} diff --git a/src/main/java/jota/dto/response/GetTransfersResponse.java b/src/main/java/jota/dto/response/GetTransfersResponse.java new file mode 100644 index 0000000..9d9960e --- /dev/null +++ b/src/main/java/jota/dto/response/GetTransfersResponse.java @@ -0,0 +1,34 @@ +package jota.dto.response; + +public class GetTransfersResponse extends AbstractResponse { + + private Transfers[] transfers; + + public static class Transfers { + private String timestamp; + private String address; + private String hash; + private String persistence; + private String value; + + public String getAddress() { + return address; + } + public String getHash() { + return hash; + } + public String getPersistence() { + return persistence; + } + public String getTimestamp() { + return timestamp; + } + public String getValue() { + return value; + } + } + + public Transfers[] getTransfers() { + return transfers; + } +} diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java new file mode 100644 index 0000000..f329993 --- /dev/null +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -0,0 +1,89 @@ +package jota; + +import static org.junit.Assert.assertThat; + +import jota.dto.response.*; +import org.hamcrest.core.IsNull; +import org.junit.Before; +import org.junit.Test; + +/** + * Let's do some test coverage. + * + * @author davassi + */ +public class IotaAPIProxyTest { + + private IotaAPIProxy proxy; + + @Before + public void createProxyInstance() { + proxy = new IotaAPIProxy.Builder().build(); + } + + @Test + public void shouldCreateIotaApiProxyInstanceWithDefaultValues() { + IotaAPIProxy proxy = new IotaAPIProxy.Builder().build(); + assertThat(proxy, IsNull.notNullValue()); + } + + @Test(expected = IllegalStateException.class) + public void shouldNotCreateIotaApiProxyInstanceWithDefaultValues() { + new IotaAPIProxy.Builder().host("a_very_wrong_ip_address").build().getNodeInfo(); + } + + @Test + public void shouldGetNodeInfo() { + GetNodeInfoResponse nodeInfo = proxy.getNodeInfo(); + assertThat(nodeInfo, IsNull.notNullValue()); + } + + @Test + public void shouldGetMilestone() { + GetMilestoneResponse milestone = proxy.getMilestone(1000); + assertThat(milestone, IsNull.notNullValue()); + } + + @Test + public void shouldGetNeighbors() { + GetNeighborsResponse neighbors = proxy.getNeighbors(); + assertThat(neighbors, IsNull.notNullValue()); + } + + @Test + public void shouldGetTips() { + GetTipsResponse tips = proxy.getTips(); + assertThat(tips, IsNull.notNullValue()); + } + + @Test + public void shouldFindTransactionsByAddresses() { + FindTransactionResponse trans = proxy.findTransactionsByAddresses(new String[]{"123ABC"}); + assertThat(trans, IsNull.notNullValue()); + } + + @Test + public void shouldFindTransactionsByApprovees() { + FindTransactionResponse trans = proxy.findTransactionsByApprovees(new String[]{"123ABC"}); + assertThat(trans, IsNull.notNullValue()); + } + + @Test + public void shouldFindTransactionsByBundles() { + FindTransactionResponse trans = proxy.findTransactionsByBundles(new String[]{"123ABC"}); + assertThat(trans, IsNull.notNullValue()); + } + + @Test + public void shouldFindTransactionsByDigests() { + FindTransactionResponse trans = proxy.findTransactionsByDigests(new String[]{"123ABC"}); + assertThat(trans, IsNull.notNullValue()); + } + + @Test + public void shouldGetInclusionStates() { + GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{"123ABC"}, + new String[]{"123"}); + assertThat(res, IsNull.notNullValue()); + } +}