From ad2e41454808d79ce5eac3a2cfa7a7424aba2ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius?= Date: Wed, 19 Jul 2017 21:29:42 -0300 Subject: [PATCH] Implementating node hop at NodeConnection and tests --- .../graphenej/api/BaseGrapheneHandler.java | 12 +- .../graphenej/api/GetAccountByName.java | 2 - .../graphenej/api/GetAccounts.java | 40 +++- .../graphenej/api/GetAllAssetHolders.java | 23 ++- .../graphenej/api/GetBlockHeader.java | 24 ++- .../graphenej/api/GetKeyReferences.java | 44 ++++- .../graphenej/api/GetLimitOrders.java | 13 +- .../graphenej/api/GetMarketHistory.java | 31 ++- .../graphenej/api/GetRequiredFees.java | 26 ++- .../api/SubscriptionMessagesHub.java | 43 ++++ .../graphenej/api/android/NodeConnection.java | 24 ++- .../api/android/WebsocketWorkerThread.java | 31 +++ .../interfaces/NodeErrorListener.java | 10 + .../api/android/NodeConnectionTest.java | 186 +++++++++++++++++- 14 files changed, 483 insertions(+), 26 deletions(-) create mode 100644 graphenej/src/main/java/de/bitsharesmunich/graphenej/interfaces/NodeErrorListener.java diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/BaseGrapheneHandler.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/BaseGrapheneHandler.java index e6dbab2..ea9437b 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/BaseGrapheneHandler.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/BaseGrapheneHandler.java @@ -3,6 +3,10 @@ package de.bitsharesmunich.graphenej.api; import com.neovisionaries.ws.client.WebSocket; import com.neovisionaries.ws.client.WebSocketAdapter; import com.neovisionaries.ws.client.WebSocketException; + +import org.w3c.dom.Node; + +import de.bitsharesmunich.graphenej.interfaces.NodeErrorListener; import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener; import de.bitsharesmunich.graphenej.models.BaseResponse; @@ -14,6 +18,7 @@ import de.bitsharesmunich.graphenej.models.BaseResponse; public abstract class BaseGrapheneHandler extends WebSocketAdapter { protected WitnessResponseListener mListener; + protected NodeErrorListener mErrorListener; /** * The 'id' field of a message to the node. This is used in order to multiplex different messages @@ -30,11 +35,14 @@ public abstract class BaseGrapheneHandler extends WebSocketAdapter { public BaseGrapheneHandler(WitnessResponseListener listener){ this.mListener = listener; } + public BaseGrapheneHandler(NodeErrorListener listener){ + this.mErrorListener = listener; + } @Override public void onError(WebSocket websocket, WebSocketException cause) throws Exception { System.out.println("onError. cause: "+cause.getMessage()); - mListener.onError(new BaseResponse.Error(cause.getMessage())); + mErrorListener.onError(new BaseResponse.Error(cause.getMessage())); websocket.disconnect(); } @@ -44,7 +52,7 @@ public abstract class BaseGrapheneHandler extends WebSocketAdapter { for (StackTraceElement element : cause.getStackTrace()){ System.out.println(element.getFileName()+"#"+element.getClassName()+":"+element.getLineNumber()); } - mListener.onError(new BaseResponse.Error(cause.getMessage())); + mErrorListener.onError(new BaseResponse.Error(cause.getMessage())); websocket.disconnect(); } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAccountByName.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAccountByName.java index a5fe247..4998c40 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAccountByName.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAccountByName.java @@ -27,8 +27,6 @@ import de.bitsharesmunich.graphenej.models.WitnessResponse; * The request returns account data that refer to the name. * * @see get_account_by_name API doc - * - * Created by nelson on 11/15/16. */ public class GetAccountByName extends BaseGrapheneHandler { diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAccounts.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAccounts.java index 90e6855..aa14bc3 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAccounts.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAccounts.java @@ -21,8 +21,13 @@ import de.bitsharesmunich.graphenej.models.ApiCall; import de.bitsharesmunich.graphenej.models.WitnessResponse; /** + * Class that implements get_accounts request handler. * - * @author henry + * Get a list of accounts by ID. + * + * The request returns the accounts corresponding to the provided IDs. + * + * @see get_accounts API doc */ public class GetAccounts extends BaseGrapheneHandler { private String accountId; @@ -30,8 +35,14 @@ public class GetAccounts extends BaseGrapheneHandler { private WitnessResponseListener mListener; private boolean mOneTime; - /* - * Construtor + /** + * Default Constructor + * @param accountId ID of the account to retrieve + * @param oneTime boolean value indicating if websocket must be closed (true) or not (false) + * after the response + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. */ public GetAccounts(String accountId, boolean oneTime, WitnessResponseListener listener){ super(listener); @@ -40,6 +51,15 @@ public class GetAccounts extends BaseGrapheneHandler { this.mListener = listener; } + /** + * Using this constructor the websocket connection closes after the response. + * @param accounts list with the accounts to retrieve + * @param oneTime boolean value indicating if websocket must be closed (true) or not (false) + * after the response + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetAccounts(List accounts, boolean oneTime, WitnessResponseListener listener){ super(listener); this.userAccounts = accounts; @@ -47,10 +67,24 @@ public class GetAccounts extends BaseGrapheneHandler { this.mListener = listener; } + /** + * Using this constructor the websocket connection closes after the response. + * @param accountId ID of the account to retrieve + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetAccounts(String accountId, WitnessResponseListener listener){ this(accountId, true, listener); } + /** + * Using this constructor the websocket connection closes after the response. + * @param accounts list with the accounts to retrieve + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetAccounts(List accounts, WitnessResponseListener listener){ this(accounts, true, listener); } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAllAssetHolders.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAllAssetHolders.java index b4c986b..26f10f1 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAllAssetHolders.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetAllAssetHolders.java @@ -16,7 +16,13 @@ import java.util.List; import java.util.Map; /** - * Created by nelson on 1/25/17. + * Class that implements get_all_asset_holders request handler. + * + * Get a list of all system assets with holders count. + * + * The request returns the list of all assets with holders count. + * + * @see get_all_asset_holders API doc */ public class GetAllAssetHolders extends BaseGrapheneHandler { private final static int LOGIN_ID = 1; @@ -28,11 +34,26 @@ public class GetAllAssetHolders extends BaseGrapheneHandler { private boolean mOneTime; + /** + * Constructor + * @param oneTime boolean value indicating if websocket must be closed (true) or not (false) + * after the response + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetAllAssetHolders(boolean oneTime, WitnessResponseListener listener) { super(listener); this.mOneTime = oneTime; } + /** + * Using this constructor the websocket connection closes after the response. + * + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetAllAssetHolders(WitnessResponseListener listener) { this(true, listener);} @Override diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetBlockHeader.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetBlockHeader.java index cd3bdf1..02d08a0 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetBlockHeader.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetBlockHeader.java @@ -19,7 +19,13 @@ import de.bitsharesmunich.graphenej.models.BlockHeader; import de.bitsharesmunich.graphenej.models.WitnessResponse; /** - * Created by nelson on 12/13/16. + * Class that implements get_block_header request handler. + * + * Retrieve a block header. + * + * The request returns the header of the referenced block, or null if no matching block was found + * + * @see get_block_header API doc */ public class GetBlockHeader extends BaseGrapheneHandler { @@ -36,6 +42,15 @@ public class GetBlockHeader extends BaseGrapheneHandler { private boolean mOneTime; + /** + * Constructor + * @param blockNumber height of the block whose header should be returned + * @param oneTime boolean value indicating if websocket must be closed (true) or not (false) + * after the response + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetBlockHeader(long blockNumber, boolean oneTime, WitnessResponseListener listener){ super(listener); this.blockNumber = blockNumber; @@ -43,6 +58,13 @@ public class GetBlockHeader extends BaseGrapheneHandler { this.mListener = listener; } + /** + * Using this constructor the websocket connection closes after the response. + * @param blockNumber height of the block whose header should be returned + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetBlockHeader(long blockNumber, WitnessResponseListener listener){ this(blockNumber, true, listener); } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetKeyReferences.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetKeyReferences.java index 9639ac5..d32b1d0 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetKeyReferences.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetKeyReferences.java @@ -19,7 +19,13 @@ import de.bitsharesmunich.graphenej.models.ApiCall; import de.bitsharesmunich.graphenej.models.WitnessResponse; /** - * Created by nelson on 11/15/16. + * Class that implements get_key_references request handler. + * + * Retrieve the keys that refer to the address/list of addresses. + * + * The request returns all accounts that refer to the key or account id in their owner or active authorities. + * + * @see get_key_references API doc */ public class GetKeyReferences extends BaseGrapheneHandler { @@ -27,14 +33,32 @@ public class GetKeyReferences extends BaseGrapheneHandler { private boolean mOneTime; + /** + * Constructor + * + * @param address address to be query + * @param oneTime boolean value indicating if websocket must be closed (true) or not (false) + * after the response + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetKeyReferences(Address address, boolean oneTime, WitnessResponseListener listener){ super(listener); addresses = new ArrayList<>(); addresses.add(address); this.mOneTime = oneTime; - } + /** + * + * @param addresses list of addresses to be query + * @param oneTime boolean value indicating if websocket must be closed (true) or not (false) + * after the response + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetKeyReferences(List
addresses, boolean oneTime, WitnessResponseListener listener) { super(listener); this.addresses = addresses; @@ -42,10 +66,26 @@ public class GetKeyReferences extends BaseGrapheneHandler { this.mOneTime = oneTime; } + /** + * Using this constructor the websocket connection closes after the response. + * + * @param address + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetKeyReferences(Address address, WitnessResponseListener listener){ this(address, true, listener); } + /** + * Using this constructor the websocket connection closes after the response. + * + * @param addresses + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetKeyReferences(List
addresses, WitnessResponseListener listener) { this(addresses, true, listener); } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetLimitOrders.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetLimitOrders.java index b73429c..f399f0e 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetLimitOrders.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetLimitOrders.java @@ -30,7 +30,6 @@ import de.bitsharesmunich.graphenej.models.WitnessResponse; * * @see get_limit_orders API doc * - * Created by nelson on 1/5/17. */ public class GetLimitOrders extends BaseGrapheneHandler { @@ -50,12 +49,12 @@ public class GetLimitOrders extends BaseGrapheneHandler { * @param limit maximum number of orders to retrieve * @param oneTime boolean value indicating if websocket must be closed (true) or not (false) * after the response - * @param mListener A class implementing the WitnessResponseListener interface. This should + * @param listener A class implementing the WitnessResponseListener interface. This should * be implemented by the party interested in being notified about the success/failure * of the transaction broadcast operation. */ - public GetLimitOrders(String a, String b, int limit, boolean oneTime, WitnessResponseListener mListener) { - super(mListener); + public GetLimitOrders(String a, String b, int limit, boolean oneTime, WitnessResponseListener listener) { + super(listener); this.a = a; this.b = b; this.limit = limit; @@ -69,12 +68,12 @@ public class GetLimitOrders extends BaseGrapheneHandler { * @param a id of asset being sold * @param b id of asset being purchased * @param limit maximum number of orders to retrieve - * @param mListener A class implementing the WitnessResponseListener interface. This should + * @param listener A class implementing the WitnessResponseListener interface. This should * be implemented by the party interested in being notified about the success/failure * of the transaction broadcast operation. */ - public GetLimitOrders(String a, String b, int limit, WitnessResponseListener mListener) { - this(a, b, limit, true, mListener); + public GetLimitOrders(String a, String b, int limit, WitnessResponseListener listener) { + this(a, b, limit, true, listener); } @Override diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetMarketHistory.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetMarketHistory.java index 9311a4c..07b65d0 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetMarketHistory.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetMarketHistory.java @@ -23,7 +23,11 @@ import de.bitsharesmunich.graphenej.models.BucketObject; import de.bitsharesmunich.graphenej.models.WitnessResponse; /** - * Created by nelson on 12/22/16. + * Class that implements get_market_history request handler. + * + * + * @see get_market_history API doc + * */ public class GetMarketHistory extends BaseGrapheneHandler { @@ -46,6 +50,20 @@ public class GetMarketHistory extends BaseGrapheneHandler { private boolean mOneTime; + /** + * Constructor + * + * @param base + * @param quote + * @param bucket + * @param start + * @param end + * @param oneTime boolean value indicating if websocket must be closed (true) or not (false) + * after the response + * @param listener a class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetMarketHistory(Asset base, Asset quote, long bucket, Date start, Date end, boolean oneTime, WitnessResponseListener listener){ super(listener); this.base = base; @@ -57,6 +75,17 @@ public class GetMarketHistory extends BaseGrapheneHandler { this.mListener = listener; } + /** + * Using this constructor the websocket connection closes after the response. + * + * @param base + * @param quote + * @param bucket + * @param start + * @param end + * @param listener a class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + */ public GetMarketHistory(Asset base, Asset quote, long bucket, Date start, Date end, WitnessResponseListener listener){ this(base, quote, bucket, start, end, true, listener); } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetRequiredFees.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetRequiredFees.java index 890bd21..418c51d 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetRequiredFees.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetRequiredFees.java @@ -23,7 +23,11 @@ import java.util.List; import java.util.Map; /** - * Created by nelson on 11/15/16. + * Class that implements get_required_fees request handler. + * + * For each operation calculate the required fee in the specified asset type. + * + * @see get_required_fees API doc */ public class GetRequiredFees extends WebSocketAdapter { @@ -33,6 +37,17 @@ public class GetRequiredFees extends WebSocketAdapter { private boolean mOneTime; + /** + * Constructor + * + * @param operations list of operations that fee should be calculated + * @param asset specify the asset of the operations + * @param oneTime boolean value indicating if websocket must be closed (true) or not (false) + * after the response + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetRequiredFees(List operations, Asset asset, boolean oneTime, WitnessResponseListener listener){ this.operations = operations; this.asset = asset; @@ -40,6 +55,15 @@ public class GetRequiredFees extends WebSocketAdapter { this.mListener = listener; } + /** + * Using this constructor the websocket connection closes after the response. + * + * @param operations list of operations that fee should be calculated + * @param asset specify the asset of the operations + * @param listener A class implementing the WitnessResponseListener interface. This should + * be implemented by the party interested in being notified about the success/failure + * of the transaction broadcast operation. + */ public GetRequiredFees(List operations, Asset asset, WitnessResponseListener listener){ this(operations, asset, true, listener); } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/SubscriptionMessagesHub.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/SubscriptionMessagesHub.java index 605a649..747d01b 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/SubscriptionMessagesHub.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/SubscriptionMessagesHub.java @@ -18,6 +18,7 @@ import de.bitsharesmunich.graphenej.RPC; import de.bitsharesmunich.graphenej.Transaction; import de.bitsharesmunich.graphenej.UserAccount; import de.bitsharesmunich.graphenej.errors.RepeatedRequestIdException; +import de.bitsharesmunich.graphenej.interfaces.NodeErrorListener; import de.bitsharesmunich.graphenej.interfaces.SubscriptionHub; import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener; import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener; @@ -107,6 +108,48 @@ public class SubscriptionMessagesHub extends BaseGrapheneHandler implements Subs this(user, password, false, errorListener); } + /** + * Constructor used to create a subscription message hub that will call the set_subscribe_callback + * API with the clear_filter parameter set to false, meaning that it will only receive automatic updates + * from objects we register. + * + * A list of ObjectTypes must be provided, otherwise we won't get any update. + * + * @param user: User name, in case the node to which we're going to connect to requires authentication + * @param password: Password, same as above + * @param clearFilter: Whether to automatically subscribe of not to the notification feed. + * @param errorListener: Callback that will be fired in case there is an error. + */ + public SubscriptionMessagesHub(String user, String password, boolean clearFilter, NodeErrorListener errorListener){ + super(errorListener); + this.user = user; + this.password = password; + this.clearFilter = clearFilter; + this.mSubscriptionDeserializer = new SubscriptionResponse.SubscriptionResponseDeserializer(); + GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(SubscriptionResponse.class, mSubscriptionDeserializer); + builder.registerTypeAdapter(Transaction.class, new Transaction.TransactionDeserializer()); + builder.registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer()); + builder.registerTypeAdapter(LimitOrderCreateOperation.class, new LimitOrderCreateOperation.LimitOrderCreateDeserializer()); + builder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer()); + builder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountSimpleDeserializer()); + builder.registerTypeAdapter(DynamicGlobalProperties.class, new DynamicGlobalProperties.DynamicGlobalPropertiesDeserializer()); + this.gson = builder.create(); + } + + /** + * Constructor used to create a subscription message hub that will call the set_subscribe_callback + * API with the clear_filter parameter set to false, meaning that it will only receive updates + * from objects we register. + * + * @param user: User name, in case the node to which we're going to connect to requires authentication + * @param password: Password, same as above + * @param errorListener: Callback that will be fired in case there is an error. + */ + public SubscriptionMessagesHub(String user, String password, NodeErrorListener errorListener){ + this(user, password, false, errorListener); + } + @Override public void addSubscriptionListener(SubscriptionListener listener){ this.mSubscriptionDeserializer.addSubscriptionListener(listener); diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/android/NodeConnection.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/android/NodeConnection.java index c02d9ba..a28249a 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/android/NodeConnection.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/android/NodeConnection.java @@ -6,7 +6,9 @@ import java.util.List; import de.bitsharesmunich.graphenej.api.BaseGrapheneHandler; import de.bitsharesmunich.graphenej.api.SubscriptionMessagesHub; import de.bitsharesmunich.graphenej.errors.RepeatedRequestIdException; +import de.bitsharesmunich.graphenej.interfaces.NodeErrorListener; import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener; +import de.bitsharesmunich.graphenej.models.BaseResponse; /** * Created by nelson on 6/26/17. @@ -24,9 +26,14 @@ public class NodeConnection { private WebsocketWorkerThread mThread; private SubscriptionMessagesHub mMessagesHub; private long requestCounter = SubscriptionMessagesHub.MANUAL_SUBSCRIPTION_ID + 1; + private WitnessResponseListener mErrorListener; private static NodeConnection instance; + private String mUser; + private String mPassword; + private boolean mSubscribe; + /* * Ger the instance of the NodeConnection which is inteded to be used as a Singleton. */ @@ -47,6 +54,7 @@ public class NodeConnection { * @param url: URL of the node */ public void addNodeUrl(String url){ + System.out.println("addNodeUrl: "+url); this.mUrlList.add(url); } @@ -77,6 +85,15 @@ public class NodeConnection { this.mUrlList.clear(); } + private NodeErrorListener mInternalErrorListener = new NodeErrorListener() { + @Override + public void onError(BaseResponse.Error error) { + System.out.println("NodeConnect Error. Msg: "+error); + + connect(mUser, mPassword, mSubscribe, mErrorListener); + } + }; + /** * Method that will try to connect to one of the nodes. If the connection fails * a subsequent call to this method will try to connect with the next node in the @@ -84,7 +101,12 @@ public class NodeConnection { */ public void connect(String user, String password, boolean subscribe, WitnessResponseListener errorListener) { if(this.mUrlList.size() > 0){ - mThread = new WebsocketWorkerThread(this.mUrlList.get(mUrlIndex)); + mUser = user; + mPassword = password; + mSubscribe = subscribe; + System.out.println("Connecting to: "+ this.mUrlList.get(mUrlIndex)); + mErrorListener = errorListener; + mThread = new WebsocketWorkerThread(this.mUrlList.get(mUrlIndex), mInternalErrorListener); mUrlIndex = mUrlIndex + 1 % this.mUrlList.size(); mMessagesHub = new SubscriptionMessagesHub(user, password, subscribe, errorListener); diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/android/WebsocketWorkerThread.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/android/WebsocketWorkerThread.java index 91aeba8..d14a0b2 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/android/WebsocketWorkerThread.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/android/WebsocketWorkerThread.java @@ -10,6 +10,8 @@ import java.security.NoSuchAlgorithmException; import javax.net.ssl.SSLContext; +import de.bitsharesmunich.graphenej.interfaces.NodeErrorListener; +import de.bitsharesmunich.graphenej.models.BaseResponse; import de.bitsharesmunich.graphenej.test.NaiveSSLContext; /** @@ -23,6 +25,7 @@ public class WebsocketWorkerThread extends Thread { private final int TIMEOUT = 5000; private WebSocket mWebSocket; + private NodeErrorListener mErrorListener; public WebsocketWorkerThread(String url){ try { @@ -45,12 +48,40 @@ public class WebsocketWorkerThread extends Thread { } } + /** + * Constructor with connection error listener + * @param url + * @param errorListener + */ + public WebsocketWorkerThread(String url, NodeErrorListener errorListener){ + try { + WebSocketFactory factory = new WebSocketFactory().setConnectionTimeout(TIMEOUT); + + if(DEBUG){ + SSLContext context = NaiveSSLContext.getInstance("TLS"); + + // Set the custom SSL context. + factory.setSSLContext(context); + } + + mWebSocket = factory.createSocket(url); + mErrorListener = errorListener; + } catch (IOException e) { + System.out.println("IOException. Msg: "+e.getMessage()); + } catch(NullPointerException e){ + System.out.println("NullPointerException at WebsocketWorkerThreas. Msg: "+e.getMessage()); + } catch (NoSuchAlgorithmException e) { + System.out.println("NoSuchAlgorithmException. Msg: "+e.getMessage()); + } + } + @Override public void run() { try { mWebSocket.connect(); } catch (WebSocketException e) { System.out.println("WebSocketException. Msg: "+e.getMessage()); + mErrorListener.onError(new BaseResponse.Error(e.getMessage())); } } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/interfaces/NodeErrorListener.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/interfaces/NodeErrorListener.java new file mode 100644 index 0000000..f0386b7 --- /dev/null +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/interfaces/NodeErrorListener.java @@ -0,0 +1,10 @@ +package de.bitsharesmunich.graphenej.interfaces; + +import de.bitsharesmunich.graphenej.models.BaseResponse; + +/** + * Interface to be implemented by any listener to network errors. + */ +public interface NodeErrorListener { + void onError(BaseResponse.Error error); +} diff --git a/graphenej/src/test/java/de/bitsharesmunich/graphenej/api/android/NodeConnectionTest.java b/graphenej/src/test/java/de/bitsharesmunich/graphenej/api/android/NodeConnectionTest.java index 9536b1f..140e3bf 100644 --- a/graphenej/src/test/java/de/bitsharesmunich/graphenej/api/android/NodeConnectionTest.java +++ b/graphenej/src/test/java/de/bitsharesmunich/graphenej/api/android/NodeConnectionTest.java @@ -6,8 +6,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; +import com.google.common.primitives.UnsignedLong; import de.bitsharesmunich.graphenej.Asset; +import de.bitsharesmunich.graphenej.OperationType; import de.bitsharesmunich.graphenej.api.GetAccounts; import de.bitsharesmunich.graphenej.api.GetAccountBalances; import de.bitsharesmunich.graphenej.api.GetAccountByName; @@ -15,13 +17,17 @@ import de.bitsharesmunich.graphenej.api.GetAllAssetHolders; import de.bitsharesmunich.graphenej.api.GetBlockHeader; import de.bitsharesmunich.graphenej.api.GetKeyReferences; import de.bitsharesmunich.graphenej.api.GetLimitOrders; +import de.bitsharesmunich.graphenej.api.GetRequiredFees; import de.bitsharesmunich.graphenej.errors.RepeatedRequestIdException; import de.bitsharesmunich.graphenej.errors.MalformedAddressException; import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener; import de.bitsharesmunich.graphenej.models.BaseResponse; import de.bitsharesmunich.graphenej.models.WitnessResponse; +import de.bitsharesmunich.graphenej.AssetAmount; import de.bitsharesmunich.graphenej.UserAccount; import de.bitsharesmunich.graphenej.Address; +import de.bitsharesmunich.graphenej.BaseOperation; +import de.bitsharesmunich.graphenej.operations.TransferOperation; /** * Created by nelson on 6/26/17. @@ -31,7 +37,8 @@ public class NodeConnectionTest { private String NODE_URL_2 = System.getenv("NODE_URL_2"); private String NODE_URL_3 = System.getenv("NODE_URL_3"); private String NODE_URL_4 = System.getenv("NODE_URL_4"); - private String ACCOUNT_ID = System.getenv("ACCOUNT_ID"); + private String ACCOUNT_ID_1 = System.getenv("ACCOUNT_ID_1"); + private String ACCOUNT_ID_2 = System.getenv("ACCOUNT_ID_2"); private String ACCOUNT_NAME = System.getenv("ACCOUNT_NAME"); private long BlOCK_TEST_NUMBER = Long.parseLong(System.getenv("BlOCK_TEST_NUMBER")); private Asset BTS = new Asset("1.3.0"); @@ -102,12 +109,13 @@ public class NodeConnectionTest { */ public void testNodeHopFeature(){ nodeConnection = NodeConnection.getInstance(); - nodeConnection.addNodeUrl(NODE_URL_4); + //nodeConnection.addNodeUrl(NODE_URL_4); //Test adding a "sublist" ArrayList urlList = new ArrayList(){{ add(NODE_URL_3); add(NODE_URL_3); }}; + //nodeConnection.addNodeUrls(urlList); nodeConnection.addNodeUrl(NODE_URL_1); nodeConnection.connect("", "", true, mErrorListener); @@ -129,7 +137,7 @@ public class NodeConnectionTest { /** * Test for GetAccountBalances Handler. * - * Request balances for a valid account (Need to setup the ACCOUNT_ID env with desired account id) + * Request balances for a valid account (Need to setup the ACCOUNT_ID_1 env with desired account id) * */ @Test @@ -140,7 +148,7 @@ public class NodeConnectionTest { System.out.println("Adding GetAccountBalances here"); try{ - UserAccount userAccount = new UserAccount(ACCOUNT_ID); + UserAccount userAccount = new UserAccount(ACCOUNT_ID_1); ArrayList assetList = new ArrayList<>(); assetList.add(BTS); assetList.add(BITDOLAR); @@ -162,7 +170,7 @@ public class NodeConnectionTest { } try{ - UserAccount userAccount = new UserAccount(ACCOUNT_ID); + UserAccount userAccount = new UserAccount(ACCOUNT_ID_1); System.out.println("Test: Request to all account' assets balance"); nodeConnection.addRequestHandler(new GetAccountBalances(userAccount, null, false, new WitnessResponseListener(){ @Override @@ -229,6 +237,73 @@ public class NodeConnectionTest { } } + /** + * Test for GetAccounts Handler. + * + * Request for a valid account name by name (Need to setup the ACCOUNT_NAME env with desired + * account name) + * + */ + public void testGetAccountsRequest(){ + nodeConnection = NodeConnection.getInstance(); + nodeConnection.addNodeUrl(NODE_URL_1); + + ArrayList accountList = new ArrayList(){{ + add(new UserAccount(ACCOUNT_ID_1)); + add(new UserAccount(ACCOUNT_ID_2)); + }}; + + nodeConnection.connect("", "", false, mErrorListener); + + System.out.println("Adding GetAccounts for one Account ID."); + try{ + nodeConnection.addRequestHandler(new GetAccounts(ACCOUNT_ID_1, false, new WitnessResponseListener(){ + @Override + public void onSuccess(WitnessResponse response) { + System.out.println("GetAccounts.onSuccess"); + } + + @Override + public void onError(BaseResponse.Error error) { + System.out.println("GetAccounts.onError. Msg: "+ error.message); + } + })); + }catch(RepeatedRequestIdException e){ + System.out.println("RepeatedRequestIdException. Msg: "+e.getMessage()); + } + + System.out.println("Adding GetAccounts for a list of Account IDs."); + try{ + nodeConnection.addRequestHandler(new GetAccounts(accountList, false, new WitnessResponseListener(){ + @Override + public void onSuccess(WitnessResponse response) { + System.out.println("GetAccounts.onSuccess"); + } + + @Override + public void onError(BaseResponse.Error error) { + System.out.println("GetAccounts.onError. Msg: "+ error.message); + } + })); + }catch(RepeatedRequestIdException e){ + System.out.println("RepeatedRequestIdException. Msg: "+e.getMessage()); + } + + + try{ + // Holding this thread while we get update notifications + synchronized (this){ + wait(); + } + }catch(InterruptedException e){ + System.out.println("InterruptedException. Msg: "+e.getMessage()); + } + } + + /** + * Test for GetAllAssetHolders Handler. + * + */ @Test public void testGetAllAssetHoldersRequest(){ nodeConnection = NodeConnection.getInstance(); @@ -262,6 +337,12 @@ public class NodeConnectionTest { } } + /** + * Test for GetBlockHeader Handler. + * + * Request for a valid account block header (Need to setup the BlOCK_TEST_NUMBER env with desired + * block height) + */ @Test public void testGetBlockHeaderRequest(){ nodeConnection = NodeConnection.getInstance(); @@ -297,6 +378,10 @@ public class NodeConnectionTest { } } + /** + * Test for GetKeyReferences Handler. + * + */ @Test public void testGetKeyReferencesRequest(){ nodeConnection = NodeConnection.getInstance(); @@ -365,6 +450,97 @@ public class NodeConnectionTest { } } + /** + * Test for GetMarketHistory Handler. + * + * Request for a valid account block header (Need to setup the BlOCK_TEST_NUMBER env with desired + * block height) + */ + @Test + public void testGetMarketHistoryRequest(){ + nodeConnection = NodeConnection.getInstance(); + nodeConnection.addNodeUrl(NODE_URL_1); + nodeConnection.connect("", "", false, mErrorListener); + + + System.out.println("Adding GetBlockHeader request"); + try{ + nodeConnection.addRequestHandler(new GetBlockHeader(BlOCK_TEST_NUMBER,false, new WitnessResponseListener(){ + @Override + public void onSuccess(WitnessResponse response) { + System.out.println("GetBlockHeader.onSuccess"); + } + + @Override + public void onError(BaseResponse.Error error) { + System.out.println("GetBlockHeader.onError. Msg: "+ error.message); + } + })); + }catch(RepeatedRequestIdException e){ + System.out.println("RepeatedRequestIdException. Msg: "+e.getMessage()); + } + + + try{ + // Holding this thread while we get update notifications + synchronized (this){ + wait(); + } + }catch(InterruptedException e){ + System.out.println("InterruptedException. Msg: "+e.getMessage()); + } + } + + /** + * Test for GetRequiredFees Handler. + * + */ + @Test + public void testGetRequiredFeesRequest(){ + nodeConnection = NodeConnection.getInstance(); + nodeConnection.addNodeUrl(NODE_URL_1); + nodeConnection.connect("", "", false, mErrorListener); + + UserAccount userAccount_from = new UserAccount(ACCOUNT_ID_1); + UserAccount userAccount_to = new UserAccount(ACCOUNT_ID_2); + + //Test with 2 BTS + Asset testAsset = new Asset("1.3.0"); + AssetAmount assetAmountTest = new AssetAmount(UnsignedLong.valueOf(200000), testAsset); + + TransferOperation transferOperation = new TransferOperation(userAccount_from, userAccount_to, assetAmountTest, assetAmountTest); + + ArrayList operations = new ArrayList<>(); + operations.add(transferOperation); + + System.out.println("Adding GetRequiredFees request"); + try{ + nodeConnection.addRequestHandler(new GetRequiredFees(operations, testAsset, false, new WitnessResponseListener(){ + @Override + public void onSuccess(WitnessResponse response) { + System.out.println("GetRequiredFees.onSuccess"); + } + + @Override + public void onError(BaseResponse.Error error) { + System.out.println("GetRequiredFees.onError. Msg: "+ error.message); + } + })); + }catch(RepeatedRequestIdException e){ + System.out.println("RepeatedRequestIdException. Msg: "+e.getMessage()); + } + + + try{ + // Holding this thread while we get update notifications + synchronized (this){ + wait(); + } + }catch(InterruptedException e){ + System.out.println("InterruptedException. Msg: "+e.getMessage()); + } + } + private WitnessResponseListener mErrorListener = new WitnessResponseListener() {