Telling the Deserializing LimitOrderCreateOperation objects in the stream coming in the SubscriptionMessagesHub

This commit is contained in:
Nelson R. Perez 2017-04-27 18:00:24 -05:00
parent 37f52283a9
commit 457164b002
6 changed files with 162 additions and 13 deletions

View file

@ -1,11 +1,16 @@
package de.bitsharesmunich.graphenej; package de.bitsharesmunich.graphenej;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import com.google.gson.*; import com.google.gson.GsonBuilder;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable; import com.google.gson.JsonArray;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable; 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 com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
import org.bitcoinj.core.DumpedPrivateKey; import org.bitcoinj.core.DumpedPrivateKey;
import org.bitcoinj.core.ECKey; import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Sha256Hash;
@ -19,6 +24,11 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
import de.bitsharesmunich.graphenej.operations.LimitOrderCreateOperation;
import de.bitsharesmunich.graphenej.operations.TransferOperation;
/** /**
* Class used to represent a generic Graphene transaction. * Class used to represent a generic Graphene transaction.
*/ */
@ -263,10 +273,9 @@ public class Transaction implements ByteSerializable, JsonSerializable {
for (JsonElement jsonOperation : jsonObject.get(KEY_OPERATIONS).getAsJsonArray()) { for (JsonElement jsonOperation : jsonObject.get(KEY_OPERATIONS).getAsJsonArray()) {
int operationId = jsonOperation.getAsJsonArray().get(0).getAsInt(); int operationId = jsonOperation.getAsJsonArray().get(0).getAsInt();
if (operationId == OperationType.TRANSFER_OPERATION.ordinal()) { if (operationId == OperationType.TRANSFER_OPERATION.ordinal()) {
System.out.println("Transfer operation detected!");
operation = context.deserialize(jsonOperation, TransferOperation.class); operation = context.deserialize(jsonOperation, TransferOperation.class);
} else if (operationId == OperationType.LIMIT_ORDER_CREATE_OPERATION.ordinal()) { } else if (operationId == OperationType.LIMIT_ORDER_CREATE_OPERATION.ordinal()) {
//TODO: Add operation deserialization support operation = context.deserialize(jsonOperation, LimitOrderCreateOperation.class);
} else if (operationId == OperationType.LIMIT_ORDER_CANCEL_OPERATION.ordinal()) { } else if (operationId == OperationType.LIMIT_ORDER_CANCEL_OPERATION.ordinal()) {
//TODO: Add operation deserialization support //TODO: Add operation deserialization support
} else if (operationId == OperationType.CALL_ORDER_UPDATE_OPERATION.ordinal()) { } else if (operationId == OperationType.CALL_ORDER_UPDATE_OPERATION.ordinal()) {

View file

@ -15,6 +15,7 @@ import java.util.Map;
import de.bitsharesmunich.graphenej.AssetAmount; import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.RPC; import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.Transaction; import de.bitsharesmunich.graphenej.Transaction;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionHub; import de.bitsharesmunich.graphenej.interfaces.SubscriptionHub;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener; import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener; import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
@ -22,6 +23,7 @@ import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.DynamicGlobalProperties; import de.bitsharesmunich.graphenej.models.DynamicGlobalProperties;
import de.bitsharesmunich.graphenej.models.SubscriptionResponse; import de.bitsharesmunich.graphenej.models.SubscriptionResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse; import de.bitsharesmunich.graphenej.models.WitnessResponse;
import de.bitsharesmunich.graphenej.operations.LimitOrderCreateOperation;
import de.bitsharesmunich.graphenej.operations.TransferOperation; import de.bitsharesmunich.graphenej.operations.TransferOperation;
/** /**
@ -54,7 +56,9 @@ public class SubscriptionMessagesHub extends BaseGrapheneHandler implements Subs
builder.registerTypeAdapter(SubscriptionResponse.class, mSubscriptionDeserializer); builder.registerTypeAdapter(SubscriptionResponse.class, mSubscriptionDeserializer);
builder.registerTypeAdapter(Transaction.class, new Transaction.TransactionDeserializer()); builder.registerTypeAdapter(Transaction.class, new Transaction.TransactionDeserializer());
builder.registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer()); builder.registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer());
builder.registerTypeAdapter(LimitOrderCreateOperation.class, new LimitOrderCreateOperation.LimitOrderCreateDeserializer());
builder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer()); builder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer());
builder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountSimpleDeserializer());
builder.registerTypeAdapter(DynamicGlobalProperties.class, new DynamicGlobalProperties.DynamicGlobalPropertiesDeserializer()); builder.registerTypeAdapter(DynamicGlobalProperties.class, new DynamicGlobalProperties.DynamicGlobalPropertiesDeserializer());
this.gson = builder.create(); this.gson = builder.create();
} }
@ -104,7 +108,7 @@ public class SubscriptionMessagesHub extends BaseGrapheneHandler implements Subs
}else if(currentId == SUBCRIPTION_REQUEST){ }else if(currentId == SUBCRIPTION_REQUEST){
// There's nothing to handle here. // There's nothing to handle here.
}else{ }else{
SubscriptionResponse subscriptionResponse = gson.fromJson(message, SubscriptionResponse.class); gson.fromJson(message, SubscriptionResponse.class);
} }
currentId++; currentId++;
} }

View file

@ -120,8 +120,8 @@ public class SubscriptionResponse {
JsonArray subArray = paramsArray.get(1).getAsJsonArray().get(0).getAsJsonArray(); JsonArray subArray = paramsArray.get(1).getAsJsonArray().get(0).getAsJsonArray();
for(JsonElement object : subArray){ for(JsonElement object : subArray){
if(object.isJsonObject()){ if(object.isJsonObject()){
GrapheneObject grapheneObject = new GrapheneObject(object.getAsJsonObject().get(KEY_ID).getAsString()); GrapheneObject grapheneObject = new GrapheneObject(object.getAsJsonObject().get(KEY_ID).getAsString());
int listenerTypeCount = 0; int listenerTypeCount = 0;
if(this.listenerTypeCount.containsKey(grapheneObject.getObjectType())){ if(this.listenerTypeCount.containsKey(grapheneObject.getObjectType())){
listenerTypeCount = this.listenerTypeCount.get(grapheneObject.getObjectType()); listenerTypeCount = this.listenerTypeCount.get(grapheneObject.getObjectType());

View file

@ -2,10 +2,15 @@ package de.bitsharesmunich.graphenej.operations;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.TimeZone; import java.util.TimeZone;
@ -151,4 +156,78 @@ public class LimitOrderCreateOperation extends BaseOperation {
return Bytes.concat(feeBytes, sellerBytes, amountBytes, minAmountBytes, expirationBytes, fillOrKill, extensions); return Bytes.concat(feeBytes, sellerBytes, amountBytes, minAmountBytes, expirationBytes, fillOrKill, extensions);
} }
/**
* Deserializer used to convert the JSON-formatted representation of a limit_order_create_operation
* into its java object version.
*
* The following is an example of the serialized form of this operation:
*
* [
* 1,
* {
* "fee": {
* "amount": 14676,
* "asset_id": "1.3.0"
* },
* "seller": "1.2.36449",
* "amount_to_sell": {
* "amount": 945472,
* "asset_id": "1.3.850"
* },
* "min_to_receive": {
* "amount": 4354658,
* "asset_id": "1.3.861"
* },
* "expiration": "1963-11-25T06:31:44",
* "fill_or_kill": false,
* "extensions": []
* }
* ]
*
*
*/
public static class LimitOrderCreateDeserializer implements JsonDeserializer<LimitOrderCreateOperation> {
@Override
public LimitOrderCreateOperation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if(json.isJsonArray()){
// This block is used just to check if we are in the first step of the deserialization
// when we are dealing with an array.
JsonArray serializedTransfer = json.getAsJsonArray();
if(serializedTransfer.get(0).getAsInt() != OperationType.LIMIT_ORDER_CREATE_OPERATION.ordinal()){
// If the operation type does not correspond to a transfer operation, we return null
return null;
}else{
// Calling itself recursively, this is only done once, so there will be no problems.
return context.deserialize(serializedTransfer.get(1), LimitOrderCreateOperation.class);
}
}else{
// This block is called in the second recursion and takes care of deserializing the
// limit order data itself.
JsonObject jsonObject = json.getAsJsonObject();
AssetAmount fee = context.deserialize(jsonObject.get(KEY_FEE), AssetAmount.class);
UserAccount seller = context.deserialize(jsonObject.get(KEY_SELLER), UserAccount.class);
AssetAmount amountToSell = context.deserialize(jsonObject.get(KEY_AMOUNT_TO_SELL), AssetAmount.class);
AssetAmount minToReceive = context.deserialize(jsonObject.get(KEY_MIN_TO_RECEIVE), AssetAmount.class);
String expiration = jsonObject.get(KEY_EXPIRATION).getAsString();
boolean fillOrKill = jsonObject.get(KEY_FILL_OR_KILL).getAsBoolean();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(Util.TIME_DATE_FORMAT);
int expirationPosix = 0;
try {
Date expirationDate = simpleDateFormat.parse(expiration);
expirationPosix = (int) (expirationDate.getTime() / 1000);
} catch (ParseException e) {
e.printStackTrace();
}
// Creating an instance of the LimitOrderCreateOperation and setting the fee
LimitOrderCreateOperation operation = new LimitOrderCreateOperation(seller, amountToSell, minToReceive, expirationPosix, fillOrKill);
operation.setFee(fee);
return operation;
}
}
}
} }

View file

@ -1,6 +1,7 @@
package de.bitsharesmunich.graphenej; package de.bitsharesmunich.graphenej;
import org.junit.Assert; import junit.framework.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -8,7 +9,6 @@ import org.junit.Test;
* Created by nelson on 4/18/17. * Created by nelson on 4/18/17.
*/ */
public class BrainKeyTest { public class BrainKeyTest {
// public final String TEST_BRAINKEY = "SOAPILY GASSING FIFIE OZONATE WHYO TOPLINE PRISMY ZEUGMA GLOTTIC DAVEN CORODY PFUI";
public final String TEST_BRAINKEY = "BARIC BICKERN LITZ TIPFUL JINGLED POOL TUMBAK PURIST APOPYLE DURAIN SATLIJK FAUCAL"; public final String TEST_BRAINKEY = "BARIC BICKERN LITZ TIPFUL JINGLED POOL TUMBAK PURIST APOPYLE DURAIN SATLIJK FAUCAL";
private BrainKey mBrainKey; private BrainKey mBrainKey;
@ -20,9 +20,6 @@ public class BrainKeyTest {
@Test @Test
public void testAddress(){ public void testAddress(){
Address address = mBrainKey.getPublicAddress(Address.BITSHARES_PREFIX); Address address = mBrainKey.getPublicAddress(Address.BITSHARES_PREFIX);
// Assert.assertEquals("Assert that the address created is the expected one",
// "BTS7yT2vnjGAxPocqsnDfoJv3DHUtCNGWwqvc7mWRikkqwuhKtT5s",
// address.toString());
Assert.assertEquals("Assert that the address created is the expected one", Assert.assertEquals("Assert that the address created is the expected one",
"BTS61UqqgE3ARuTGcckzARsdQm4EMFdBEwYyi1pbwyHrZZWrCDhT2", "BTS61UqqgE3ARuTGcckzARsdQm4EMFdBEwYyi1pbwyHrZZWrCDhT2",
address.toString()); address.toString());

View file

@ -3,11 +3,16 @@ package de.bitsharesmunich.graphenej.api;
import com.neovisionaries.ws.client.WebSocketException; import com.neovisionaries.ws.client.WebSocketException;
import org.junit.Test; import org.junit.Test;
import java.io.Serializable;
import java.util.List; import java.util.List;
import de.bitsharesmunich.graphenej.ObjectType; import de.bitsharesmunich.graphenej.ObjectType;
import de.bitsharesmunich.graphenej.Transaction;
import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener; import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener; import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.BaseResponse; import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.BroadcastedTransaction;
import de.bitsharesmunich.graphenej.models.DynamicGlobalProperties; import de.bitsharesmunich.graphenej.models.DynamicGlobalProperties;
import de.bitsharesmunich.graphenej.models.SubscriptionResponse; import de.bitsharesmunich.graphenej.models.SubscriptionResponse;
import de.bitsharesmunich.graphenej.models.WitnessResponse; import de.bitsharesmunich.graphenej.models.WitnessResponse;
@ -82,4 +87,59 @@ public class SubscriptionMessagesHubTest extends BaseApiTest {
System.out.println("InterruptedException. Msg: "+e.getMessage()); System.out.println("InterruptedException. Msg: "+e.getMessage());
} }
} }
/**
* This is a basic test that will only display a count of operations per received broadcasted transactions.
*/
@Test
public void testBroadcastedTransactionDeserializer(){
try{
mMessagesHub = new SubscriptionMessagesHub("", "", mErrorListener);
mMessagesHub.addSubscriptionListener(new SubscriptionListener() {
private int MAX_MESSAGES = 15;
private int messageCounter = 0;
@Override
public ObjectType getInterestObjectType() {
return ObjectType.TRANSACTION_OBJECT;
}
@Override
public void onSubscriptionUpdate(SubscriptionResponse response) {
if(response.params.size() == 2){
List<Serializable> payload = (List) response.params.get(1);
if(payload.size() > 0){
for(Serializable item : payload){
if(item instanceof BroadcastedTransaction){
BroadcastedTransaction broadcastedTransaction = (BroadcastedTransaction) item;
Transaction tx = broadcastedTransaction.getTransaction();
System.out.println(String.format("Got %d operations", tx.getOperations().size()));
}
}
}
}
// Waiting for MAX_MESSAGES messages before releasing the wait lock
messageCounter++;
if(messageCounter > MAX_MESSAGES){
synchronized (SubscriptionMessagesHubTest.this){
SubscriptionMessagesHubTest.this.notifyAll();
}
}
}
});
mWebSocket.addListener(mMessagesHub);
mWebSocket.connect();
// Holding this thread while we get update notifications
synchronized (this){
wait();
}
} catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
}
}
} }