diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/UserAccount.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/UserAccount.java index 235f03c..49b66b0 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/UserAccount.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/UserAccount.java @@ -1,15 +1,23 @@ package de.bitsharesmunich.graphenej; -import com.google.gson.*; -import de.bitsharesmunich.graphenej.interfaces.ByteSerializable; -import de.bitsharesmunich.graphenej.interfaces.JsonSerializable; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; import java.io.ByteArrayOutputStream; import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; import java.lang.reflect.Type; -import java.util.ArrayList; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import de.bitsharesmunich.graphenej.interfaces.ByteSerializable; +import de.bitsharesmunich.graphenej.interfaces.JsonSerializable; /** * Class tha represents a graphene user account. @@ -18,8 +26,39 @@ import java.util.ArrayList; public class UserAccount extends GrapheneObject implements ByteSerializable, JsonSerializable { public static final String PROXY_TO_SELF = "1.2.5"; + public static final String KEY_MEMBERSHIP_EXPIRATION_DATE = "membership_expiration_date"; + public static final String KEY_REGISTRAR = "registrar"; + public static final String KEY_REFERRER = "referrer"; + public static final String KEY_LIFETIME_REFERRER = "lifetime_referrer"; + public static final String KEY_NETWORK_FEE_PERCENTAGE = "network_fee_percentage"; + public static final String KEY_LIFETIME_REFERRER_FEE_PERCENTAGE = "lifetime_referrer_fee_percentage"; + public static final String KEY_REFERRER_REWARD_PERCENTAGE = "referrer_rewards_percentage"; + public static final String KEY_NAME = "name"; + public static final String KEY_OWNER = "owner"; + public static final String KEY_ACTIVE = "active"; + public static final String KEY_OPTIONS = "options"; + public static final String KEY_STATISTICS = "statistics"; + public static final String KEY_WHITELISTING_ACCOUNTS = "whitelisting_accounts"; + public static final String KEY_BLACKLISTING_ACCOUNTS = "blacklisting_accounts"; + public static final String KEY_WHITELISTED_ACCOUNTS = "whitelisted_accounts"; + public static final String KEY_BLACKLISTED_ACCOUNTS = "blacklisted_accounts"; + public static final String KEY_OWNER_SPECIAL_AUTHORITY = "owner_special_authority"; + public static final String KEY_ACTIVE_SPECIAL_AUTHORITY = "active_special_authority"; + public static final String KEY_N_CONTROL_FLAGS = "top_n_control_flags"; + + private long membershipExpirationDate; + private String registrar; + private String referrer; + private String lifetimeReferrer; + private long networkFeePercentage; + private long lifetimeReferrerFeePercentage; + private long referrerRewardsPercentage; + private String name; + private Authority owner; + private Authority active; + private AccountOptions options; + private String statistics; - private String accountName; /** * Constructor that expects a user account in the string representation. @@ -37,24 +76,24 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso */ public UserAccount(String id, String name){ super(id); - this.accountName = name; + this.name = name; } /** * Getter for the account name field. * @return: The name of this account. */ - public String getAccountName() { - return accountName; + public String getName() { + return name; } /** * Setter for the account name field. - * @param accountName: The account name. + * @param name: The account name. */ - public void setAccountName(String accountName) { - this.accountName = accountName; + public void setName(String name) { + this.name = name; } @Override @@ -94,6 +133,140 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso return this.toJsonString(); } + public long getMembershipExpirationDate() { + return membershipExpirationDate; + } + + public void setMembershipExpirationDate(long membershipExpirationDate) { + this.membershipExpirationDate = membershipExpirationDate; + } + + public String getRegistrar() { + return registrar; + } + + public void setRegistrar(String registrar) { + this.registrar = registrar; + } + + public String getReferrer() { + return referrer; + } + + public void setReferrer(String referrer) { + this.referrer = referrer; + } + + public String getLifetimeReferrer() { + return lifetimeReferrer; + } + + public void setLifetimeReferrer(String lifetimeReferrer) { + this.lifetimeReferrer = lifetimeReferrer; + } + + public long getNetworkFeePercentage() { + return networkFeePercentage; + } + + public void setNetworkFeePercentage(long networkFeePercentage) { + this.networkFeePercentage = networkFeePercentage; + } + + public long getLifetimeReferrerFeePercentage() { + return lifetimeReferrerFeePercentage; + } + + public void setLifetimeReferrerFeePercentage(long lifetimeReferrerFeePercentage) { + this.lifetimeReferrerFeePercentage = lifetimeReferrerFeePercentage; + } + + public long getReferrerRewardsPercentage() { + return referrerRewardsPercentage; + } + + public void setReferrerRewardsPercentage(long referrerRewardsPercentage) { + this.referrerRewardsPercentage = referrerRewardsPercentage; + } + + public Authority getOwner() { + return owner; + } + + public void setOwner(Authority owner) { + this.owner = owner; + } + + public Authority getActive() { + return active; + } + + public void setActive(Authority active) { + this.active = active; + } + + public AccountOptions getOptions() { + return options; + } + + public void setOptions(AccountOptions options) { + this.options = options; + } + + public String getStatistics() { + return statistics; + } + + public void setStatistics(String statistics) { + this.statistics = statistics; + } + + /** + * Deserializer used to build a UserAccount instance from the full JSON-formatted response obtained + * by the 'get_objects' API call. + */ + public static class UserAccountFullDeserializer implements JsonDeserializer { + + @Override + public UserAccount deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject jsonAccount = json.getAsJsonObject(); + + SimpleDateFormat dateFormat = new SimpleDateFormat(Util.TIME_DATE_FORMAT); + + // Retrieving and deserializing fields + String id = jsonAccount.get(KEY_ID).getAsString(); + String name = jsonAccount.get(KEY_NAME).getAsString(); + UserAccount userAccount = new UserAccount(id, name); + AccountOptions options = context.deserialize(jsonAccount.get(KEY_OPTIONS), AccountOptions.class); + Authority owner = context.deserialize(jsonAccount.get(KEY_OWNER), Authority.class); + Authority active = context.deserialize(jsonAccount.get(KEY_ACTIVE), Authority.class); + + // Setting deserialized fields into the created instance + userAccount.setRegistrar(jsonAccount.get(KEY_REGISTRAR).getAsString()); + + // Handling the deserialization and assignation of the membership date, which internally + // is stored as a long POSIX time value + try{ + Date date = dateFormat.parse(jsonAccount.get(KEY_MEMBERSHIP_EXPIRATION_DATE).getAsString()); + userAccount.setMembershipExpirationDate(date.getTime()); + } catch (ParseException e) { + System.out.println("ParseException. Msg: "+e.getMessage()); + } + + // Setting the other fields + userAccount.setReferrer(jsonAccount.get(KEY_REFERRER).getAsString()); + userAccount.setLifetimeReferrer(jsonAccount.get(KEY_LIFETIME_REFERRER).getAsString()); + userAccount.setNetworkFeePercentage(jsonAccount.get(KEY_NETWORK_FEE_PERCENTAGE).getAsLong()); + userAccount.setLifetimeReferrerFeePercentage(jsonAccount.get(KEY_LIFETIME_REFERRER_FEE_PERCENTAGE).getAsLong()); + userAccount.setReferrerRewardsPercentage(jsonAccount.get(KEY_REFERRER_REWARD_PERCENTAGE).getAsLong()); + userAccount.setOwner(owner); + userAccount.setActive(active); + userAccount.setOptions(options); + userAccount.setStatistics(jsonAccount.get(KEY_STATISTICS).getAsString()); + return userAccount; + } + } + /** * Custom deserializer used to deserialize user accounts provided as response from the 'lookup_accounts' api call. * This response contains serialized user accounts in the form [[{id1},{name1}][{id1},{name1}]]. diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetObjects.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetObjects.java index 33347da..548dfcd 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetObjects.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetObjects.java @@ -1,15 +1,13 @@ package de.bitsharesmunich.graphenej.api; +import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; import com.neovisionaries.ws.client.WebSocket; import com.neovisionaries.ws.client.WebSocketFrame; -import de.bitsharesmunich.graphenej.AssetAmount; -import de.bitsharesmunich.graphenej.RPC; -import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener; -import de.bitsharesmunich.graphenej.models.ApiCall; -import de.bitsharesmunich.graphenej.models.BitAssetData; -import de.bitsharesmunich.graphenej.models.WitnessResponse; import java.io.Serializable; import java.lang.reflect.Type; @@ -17,6 +15,18 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import de.bitsharesmunich.graphenej.AccountOptions; +import de.bitsharesmunich.graphenej.Asset; +import de.bitsharesmunich.graphenej.AssetAmount; +import de.bitsharesmunich.graphenej.Authority; +import de.bitsharesmunich.graphenej.GrapheneObject; +import de.bitsharesmunich.graphenej.RPC; +import de.bitsharesmunich.graphenej.UserAccount; +import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener; +import de.bitsharesmunich.graphenej.models.ApiCall; +import de.bitsharesmunich.graphenej.models.BitAssetData; +import de.bitsharesmunich.graphenej.models.WitnessResponse; + /** * Created by nelson on 1/8/17. */ @@ -48,16 +58,40 @@ public class GetObjects extends BaseGrapheneHandler { String response = frame.getPayloadText(); GsonBuilder gsonBuilder = new GsonBuilder(); - //TODO: Uncomment this line after the deserializer is implemented. gsonBuilder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer()); -// gsonBuilder.registerTypeAdapter(BitAssetData.class, new BitAssetData.BitAssetDeserializer()); + gsonBuilder.registerTypeAdapter(Asset.class, new Asset.AssetDeserializer()); + gsonBuilder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountFullDeserializer()); + gsonBuilder.registerTypeAdapter(Authority.class, new Authority.AuthorityDeserializer()); + gsonBuilder.registerTypeAdapter(AccountOptions.class, new AccountOptions.AccountOptionsDeserializer()); + Gson gson = gsonBuilder.create(); - // Only homogeneus array is currently supported - if(ids.get(0).split("\\.")[1].equals("4")){ - Type BitAssetDataType = new TypeToken>>(){}.getType(); - WitnessResponse> witnessResponse = gsonBuilder.create().fromJson(response, BitAssetDataType); - mListener.onSuccess(witnessResponse); + List parsedResult = new ArrayList<>(); + + JsonParser parser = new JsonParser(); + JsonArray resultArray = parser.parse(response).getAsJsonObject().get(WitnessResponse.KEY_RESULT).getAsJsonArray(); + for(JsonElement element : resultArray){ + String id = element.getAsJsonObject().get(GrapheneObject.KEY_ID).getAsString(); + GrapheneObject grapheneObject = new GrapheneObject(id); + switch (grapheneObject.getObjectType()){ + case ASSET_OBJECT: + Asset asset = gson.fromJson(element, Asset.class); + parsedResult.add(asset); + break; + case ACCOUNT_OBJECT: + UserAccount account = gson.fromJson(element, UserAccount.class); + parsedResult.add(account); + break; + case ASSET_BITASSET_DATA: + Type BitAssetDataType = new TypeToken>>(){}.getType(); + WitnessResponse> witnessResponse = gsonBuilder.create().fromJson(response, BitAssetDataType); + BitAssetData bitAssetData = witnessResponse.result.get(0); + parsedResult.add(bitAssetData); + } } + + WitnessResponse> output = new WitnessResponse<>(); + output.result = parsedResult; + mListener.onSuccess(output); websocket.disconnect(); } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/BitAssetData.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/BitAssetData.java index eaf36ac..5625a03 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/BitAssetData.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/BitAssetData.java @@ -1,5 +1,6 @@ package de.bitsharesmunich.graphenej.models; +import de.bitsharesmunich.graphenej.GrapheneObject; import de.bitsharesmunich.graphenej.Price; /** @@ -8,8 +9,7 @@ import de.bitsharesmunich.graphenej.Price; * * Created by nelson on 1/8/17. */ -public class BitAssetData { - public String id; +public class BitAssetData extends GrapheneObject { public Object[] feeds; public AssetFeed current_feed; public String current_feed_publication_time; @@ -18,4 +18,8 @@ public class BitAssetData { public boolean is_prediction_market; public Price settlement_price; public long settlement_fund; + + public BitAssetData(String id) { + super(id); + } } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/WitnessResponse.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/WitnessResponse.java index 3e5e7da..0f7dc78 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/WitnessResponse.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/WitnessResponse.java @@ -4,5 +4,8 @@ package de.bitsharesmunich.graphenej.models; * Generic witness response */ public class WitnessResponse extends BaseResponse{ + public static final String KEY_ID = "id"; + public static final String KEY_RESULT = "result"; + public T result; } diff --git a/graphenej/src/test/java/de/bitsharesmunich/graphenej/api/GetObjectsTest.java b/graphenej/src/test/java/de/bitsharesmunich/graphenej/api/GetObjectsTest.java new file mode 100644 index 0000000..3db0618 --- /dev/null +++ b/graphenej/src/test/java/de/bitsharesmunich/graphenej/api/GetObjectsTest.java @@ -0,0 +1,139 @@ +package de.bitsharesmunich.graphenej.api; + +import com.neovisionaries.ws.client.WebSocketException; + +import junit.framework.Assert; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import de.bitsharesmunich.graphenej.Asset; +import de.bitsharesmunich.graphenej.GrapheneObject; +import de.bitsharesmunich.graphenej.UserAccount; +import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener; +import de.bitsharesmunich.graphenej.models.BaseResponse; +import de.bitsharesmunich.graphenej.models.BitAssetData; +import de.bitsharesmunich.graphenej.models.WitnessResponse; + +/** + * Testing the {@link GetObjects} API wrapper and its deserialization + * + * Created by nelson on 5/10/17. + */ +public class GetObjectsTest extends BaseApiTest{ + private final Asset asset = new Asset("1.3.0", "BTS", 5); + private final UserAccount account = new UserAccount("1.2.116354"); + private final String bitAssetId = "2.4.13"; + + @Test + public void testGetAsset(){ + try{ + ArrayList ids = new ArrayList<>(); + ids.add(asset.getObjectId()); + mWebSocket.addListener(new GetObjects(ids, new WitnessResponseListener() { + @Override + public void onSuccess(WitnessResponse response) { + System.out.println("onSuccess"); + List result = (List) response.result; + System.out.println("Got " + result.size() + " result"); + Assert.assertEquals("Making sure we only get one address back", 1, result.size()); + synchronized (GetObjectsTest.this){ + GetObjectsTest.this.notifyAll(); + } + } + + @Override + public void onError(BaseResponse.Error error) { + System.out.println("onError"); + synchronized (GetObjectsTest.this){ + GetObjectsTest.this.notifyAll(); + } + } + })); + + mWebSocket.connect(); + synchronized (this){ + wait(); + } + }catch (WebSocketException e) { + System.out.println("WebSocketException. Msg: " + e.getMessage()); + } catch (InterruptedException e) { + System.out.println("InterruptedException. Msg: "+e.getMessage()); + } + } + + @Test + public void testGetAccount(){ + try{ + ArrayList ids = new ArrayList<>(); + ids.add(account.getObjectId()); + mWebSocket.addListener(new GetObjects(ids, new WitnessResponseListener() { + + @Override + public void onSuccess(WitnessResponse response) { + System.out.println("onSuccess"); + List result = (List) response.result; + UserAccount userAccount = (UserAccount) result.get(0); + System.out.println("Account name: "+userAccount.getName()); + System.out.println("json string: "+userAccount.toJsonString()); + System.out.println("owner: "+userAccount.getOwner().getKeyAuthList().get(0).getAddress()); + System.out.println("active: "+userAccount.getActive().getKeyAuthList().get(0).getAddress()); + System.out.println("memo: "+userAccount.getOptions().getMemoKey().getAddress()); + synchronized (GetObjectsTest.this){ + GetObjectsTest.this.notifyAll(); + } + } + + @Override + public void onError(BaseResponse.Error error) { + System.out.println("onError"); + synchronized (GetObjectsTest.this){ + GetObjectsTest.this.notifyAll(); + } + } + })); + + mWebSocket.connect(); + synchronized (this){ + wait(); + } + }catch (WebSocketException e) { + System.out.println("WebSocketException. Msg: " + e.getMessage()); + } catch (InterruptedException e) { + System.out.println("InterruptedException. Msg: "+e.getMessage()); + } + } + + @Test + public void testBitAssetData(){ + try{ + ArrayList ids = new ArrayList<>(); + ids.add(bitAssetId); + mWebSocket.addListener(new GetObjects(ids, new WitnessResponseListener() { + + @Override + public void onSuccess(WitnessResponse response) { + System.out.println("onSuccess"); + List list = (List) response.result; + BitAssetData bitAssetData = (BitAssetData) list.get(0); + System.out.println("feed time: " + bitAssetData.current_feed_publication_time); + } + + @Override + public void onError(BaseResponse.Error error) { + System.out.println("onError"); + } + })); + + mWebSocket.connect(); + synchronized (this){ + wait(); + } + }catch (WebSocketException e) { + System.out.println("WebSocketException. Msg: " + e.getMessage()); + } catch (InterruptedException e) { + System.out.println("InterruptedException. Msg: "+e.getMessage()); + } } +} \ No newline at end of file