graphenej/graphenej/src/main/java/cy/agorise/graphenej/operations/CustomOperation.java

186 lines
6.6 KiB
Java

package cy.agorise.graphenej.operations;
import com.google.common.primitives.Bytes;
import com.google.gson.*;
import cy.agorise.graphenej.*;
import java.lang.reflect.Type;
import java.util.LinkedList;
import java.util.List;
public class CustomOperation extends BaseOperation {
private static final String KEY_FEE = "fee";
private static final String KEY_PAYER = "payer";
private static final String KEY_REQUIRED_AUTHS = "required_auths";
private static final String KEY_ID = "id";
private static final String KEY_DATA = "data";
private AssetAmount fee;
private UserAccount payer;
private List<UserAccount> requiredAuths;
private int operationId;
private String data;
public CustomOperation(AssetAmount fee, UserAccount payer, int operationId, List<UserAccount> requiredAuths, String data) {
super(OperationType.CUSTOM_OPERATION);
this.fee = fee;
this.payer = payer;
this.operationId = operationId;
this.requiredAuths = new LinkedList<>();
if (requiredAuths != null) {
this.requiredAuths.addAll(requiredAuths);
}
this.data = data;
}
public AssetAmount getFee() {
return fee;
}
@Override
public void setFee(AssetAmount fee) {
this.fee = fee;
}
public UserAccount getPayer() {
return payer;
}
public void setPayer(UserAccount payer) {
this.payer = payer;
}
public List<UserAccount> getRequiredAuths() {
return requiredAuths;
}
public void setRequiredAuths(List<UserAccount> requiredAuths) {
this.requiredAuths = requiredAuths;
}
public int getOperationId() {
return operationId;
}
public void setOperationId(int operationId) {
this.operationId = operationId;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
@Override
public byte[] toBytes() {
byte[] feeBytes = fee.toBytes();
byte[] payerBytes = payer.toBytes();
List<Byte> requiredAuthsSerialized = new LinkedList<>();
if (this.requiredAuths != null) {
for (UserAccount userAccount : this.requiredAuths) {
requiredAuthsSerialized.addAll(Bytes.asList(userAccount.toBytes()));
}
}
byte[] requiredAuthsBytes = Bytes.toArray(requiredAuthsSerialized);
byte[] requiredAuthsLength = {(byte)this.requiredAuths.size()};
byte[] operationIdBytes = Util.revertShort((short)operationId);
byte[] dataLength = Util.serializeLongToBytes(data.length());
byte[] dataBytes = Util.hexlify(data);
return Bytes.concat(feeBytes, payerBytes, requiredAuthsLength, requiredAuthsBytes, operationIdBytes, dataLength, dataBytes);
}
@Override
public String toJsonString() {
return toJsonObject().toString();
}
@Override
public JsonElement toJsonObject() {
JsonArray array = new JsonArray();
array.add(this.getId());
JsonObject jsonObject = new JsonObject();
jsonObject.add(KEY_FEE, fee.toJsonObject());
jsonObject.addProperty(KEY_PAYER, payer.getObjectId());
JsonArray requiredAuthArray = new JsonArray();
if (requiredAuths != null) {
for (UserAccount userAccount : requiredAuths) {
requiredAuthArray.add(userAccount.getObjectId());
}
}
jsonObject.add(KEY_REQUIRED_AUTHS, requiredAuthArray);
jsonObject.addProperty(KEY_ID, operationId);
jsonObject.addProperty(KEY_DATA, Util.bytesToHex(Util.hexlify(data)));
array.add(jsonObject);
return array;
}
/**
* Deserializer used to convert the JSON-formatted representation of a custom_operation
* into its java object version.
*
* The following is an example of the serialized form of this operation:
*
* [
* 35,
* {
* "fee": {
* "amount": 100000,
* "asset_id": "1.3.0"
* },
* "payer": "1.2.20",
* "required_auths": [
* "1.2.20"
* ],
* "id": 61166,
* "data": "736f6d652064617461"
* }
* ]
*/
public static class CustomOperationDeserializer implements JsonDeserializer<CustomOperation> {
@Override
public CustomOperation 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 serializedCustomOperation = json.getAsJsonArray();
if (serializedCustomOperation.get(0).getAsInt() != OperationType.CUSTOM_OPERATION.ordinal()){
// If the operation type does not correspond to a custom operation, we return null
return null;
} else {
// Calling itself recursively, this is only done once, so there will be no problems.
return context.deserialize(serializedCustomOperation.get(1), CustomOperation.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);
String payerId = jsonObject.get(KEY_PAYER) .getAsString();
UserAccount payer = new UserAccount(payerId);
List<UserAccount> requiredAuths = new LinkedList<>();
JsonElement requiredAuthsElement = jsonObject.get(KEY_REQUIRED_AUTHS);
if ((requiredAuthsElement != null) && (requiredAuthsElement.isJsonArray())) {
JsonArray requiredAuthsArray = requiredAuthsElement.getAsJsonArray();
for (JsonElement jsonElement : requiredAuthsArray) {
String userAccountId = jsonElement.getAsString();
requiredAuths.add(new UserAccount(userAccountId));
}
}
int operationId = jsonObject.get(KEY_ID).getAsInt();
String data = new String(Util.hexToBytes(jsonObject.get(KEY_DATA).getAsString()));
return new CustomOperation(fee, payer, operationId, requiredAuths, data);
}
}
}
}