EventConverterFactory.java
- /*
- * @copyright defined in LICENSE.txt
- */
- package hera.transport;
- import static hera.util.TransportUtils.parseToBlockHash;
- import static hera.util.TransportUtils.parseToTxHash;
- import static org.slf4j.LoggerFactory.getLogger;
- import com.fasterxml.jackson.core.JsonParser;
- import com.fasterxml.jackson.databind.DeserializationContext;
- import com.fasterxml.jackson.databind.JsonDeserializer;
- import com.fasterxml.jackson.databind.JsonNode;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.fasterxml.jackson.databind.module.SimpleModule;
- import com.fasterxml.jackson.databind.node.ArrayNode;
- import com.fasterxml.jackson.databind.node.ObjectNode;
- import com.fasterxml.jackson.databind.node.ValueNode;
- import com.fasterxml.jackson.databind.type.CollectionType;
- import hera.api.function.Function1;
- import hera.api.model.AccountAddress;
- import hera.api.model.BigNumber;
- import hera.api.model.ContractAddress;
- import hera.api.model.Event;
- import hera.spec.AergoSpec;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Map.Entry;
- import org.slf4j.Logger;
- import types.Blockchain;
- public class EventConverterFactory {
- protected final transient Logger logger = getLogger(getClass());
- protected final ObjectMapper mapper = getObjectMapper();
- protected final ModelConverter<AccountAddress,
- com.google.protobuf.ByteString> accountAddressConverter =
- new AccountAddressConverterFactory().create();
- protected final Function1<Event, Blockchain.Event> domainConverter =
- new Function1<Event, Blockchain.Event>() {
- @Override
- public Blockchain.Event apply(final Event domainEvent) {
- throw new UnsupportedOperationException();
- }
- };
- protected final Function1<Blockchain.Event, Event> rpcConverter =
- new Function1<Blockchain.Event, Event>() {
- @Override
- public Event apply(Blockchain.Event rpcEvent) {
- logger.trace("Rpc event: {}", rpcEvent);
- try {
- final ContractAddress contractAddress = accountAddressConverter
- .convertToDomainModel(rpcEvent.getContractAddress()).adapt(ContractAddress.class);
- final CollectionType listType =
- mapper.getTypeFactory().constructCollectionType(List.class, Object.class);
- final List<Object> deserializedArgs =
- mapper.readValue(rpcEvent.getJsonArgs(), listType);
- final Event domainEvent = Event.newBuilder()
- .from(contractAddress)
- .name(rpcEvent.getEventName())
- .args(deserializedArgs)
- .index(rpcEvent.getEventIdx())
- .txHash(parseToTxHash(rpcEvent.getTxHash()))
- .indexInBlock(rpcEvent.getTxIndex())
- .blockHash(parseToBlockHash(rpcEvent.getBlockHash()))
- .blockNumber(rpcEvent.getBlockNo())
- .build();
- logger.trace("Rpc event converted: {}", domainEvent);
- return domainEvent;
- } catch (Exception e) {
- throw new IllegalArgumentException(e);
- }
- }
- };
- public ModelConverter<Event, Blockchain.Event> create() {
- return new ModelConverter<Event, Blockchain.Event>(domainConverter,
- rpcConverter);
- }
- protected ObjectMapper getObjectMapper() {
- final ObjectMapper objectMapper = new ObjectMapper();
- final SimpleModule simpleModule = new SimpleModule();
- simpleModule.addDeserializer(List.class, new CustomDeserializer());
- objectMapper.registerModule(simpleModule);
- return objectMapper;
- }
- protected class CustomDeserializer extends JsonDeserializer<List<Object>> {
- @Override
- public List<Object> deserialize(JsonParser parser, DeserializationContext context)
- throws IOException {
- final List<Object> ret = new ArrayList<>();
- final JsonNode jsonNode = parser.getCodec().readTree(parser);
- logger.trace("Raw event args: {}", jsonNode);
- if (!(jsonNode instanceof ArrayNode)) {
- throw new IllegalStateException("Event args must be array but was " + jsonNode.getClass());
- }
- final Iterator<JsonNode> it = ((ArrayNode) jsonNode).elements();
- while (it.hasNext()) {
- final JsonNode next = it.next();
- ret.add(parseJsonNode(next));
- }
- logger.trace("Parsed event args: {}", ret);
- return ret;
- }
- protected Object parseJsonNode(final JsonNode jsonNode) {
- Object ret = null;
- // null, boolean, string, number
- if (jsonNode.isValueNode()) {
- ret = parseValueNode((ValueNode) jsonNode);
- } else if (jsonNode.isArray()) {
- ret = parseArrayNode((ArrayNode) jsonNode);
- } else if (jsonNode.isObject()) {
- ret = parseObjectNode((ObjectNode) jsonNode);
- } else {
- throw new IllegalArgumentException("Can't process json node " + jsonNode);
- }
- return ret;
- }
- protected Object parseValueNode(final ValueNode valueNode) {
- Object ret;
- if (valueNode.isNull()) {
- ret = null;
- } else if (valueNode.isBoolean()) {
- ret = valueNode.asBoolean();
- } else if (valueNode.isTextual()) {
- ret = valueNode.asText();
- } else if (valueNode.isNumber()) {
- ret = valueNode.numberValue();
- } else {
- throw new IllegalArgumentException("Can't process " + valueNode);
- }
- return ret;
- }
- protected List<Object> parseArrayNode(final ArrayNode arrayNode) {
- final List<Object> ret = new ArrayList<>(arrayNode.size());
- final Iterator<JsonNode> it = arrayNode.elements();
- while (it.hasNext()) {
- final JsonNode next = it.next();
- ret.add(next);
- }
- return ret;
- }
- protected Object parseObjectNode(final ObjectNode objectNode) {
- final Map<String, Object> ret = new HashMap<>(objectNode.size());
- if (isAergoBigNum(objectNode)) {
- return parseBignumNode(objectNode);
- }
- final Iterator<Entry<String, JsonNode>> it = objectNode.fields();
- while (it.hasNext()) {
- final Entry<String, JsonNode> next = it.next();
- ret.put(next.getKey(), parseJsonNode(next.getValue()));
- }
- return ret;
- }
- protected boolean isAergoBigNum(final ObjectNode objectNode) {
- final JsonNode possiblyBignum = objectNode.get(AergoSpec.BIGNUM_JSON_KEY);
- return objectNode.size() == 1 && null != possiblyBignum && possiblyBignum.isTextual();
- }
- protected BigNumber parseBignumNode(final ObjectNode objectNode) {
- try {
- final JsonNode bignumNode = objectNode.get(AergoSpec.BIGNUM_JSON_KEY);
- return new BigNumber(bignumNode.asText());
- } catch (Exception e) {
- throw new IllegalArgumentException(e);
- }
- }
- }
- }