lundi 14 octobre 2019

Using one mapping implementation across multiple services

I define an interface for all my mapper components that extract out values using xpath from xml fields. It takes a payload converted as document as input along with a wrapped trade model to return the same with the field populated:

interface Mapper {
    Model<Trade> map(Document document, Model<Trade> model);
}

I define one parent class as abstraction for child classes to provide the xpath expression:

abstract class TradeMapper implements Mapper {
    abstract String getXpathExpression();
}

An implementation of one of the mappers as Spring component:

@Component
class QuantityMapper extends TradeMapper {
    @Override
    public Model<Trade> map(Document document, Model<Trade> model) {
        //implementation logic to get qty and populate the trade model
    }

    @Override
    String getXpathExpression() {
        return "XXX";
    }
}

@Component
class IdMapper extends TradeMapper {
    @Override
    public Model<Trade> map(Document document, Model<Trade> model) {
        //implementation logic to get id and populate the trade model
    }
}

In my application, I receive two types of trades. Let's say initial and actual. Both of these need to be converted to Trade model at some point in the event lifecycle. For initial I pass the Message which is then converted into a String message --> to Document type --> then using the mappers to build the Trade object for further processing. This is all good.

@Service
class TradeRequestService {
    @Autowired
    private List<TradeMapper> mappers;

    void callback(Model<Message> model) {
        String message = model.getPayload(model);
        Document document = getDocument(message);
        mappers.forEach(tradeMapper -> tradeMapper.map(document, model));
    }

    private Document getDocument(String message) {
        return XmlUtils.toDoc(message);
    }
}

My problem is at the entry point and for the actual type message.

/**
 * Message Entry Point
 */
@Service
class MessageReceiver {
    @Autowired
    private List<TradeMapper> mappers;

    void callback(String message) {
        if (message.contains("initial")) {
            return model.withPayload(new Message(message)); //callback in TradeRequestService then receives this model for conversion
        } else if (message.contains("actual")) {
            // derive id from String
        } else {
            return null;
        }
    }

}

In my application, I need to already have derived the Id for actual type message using the IdMapper at the MessageReceiver service level before the model is passed to TradeRequestService callback. The id is required at the entry point to derive some meta information prior to processing subsequent event callbacks.

I am struggling to convert the actual type message at entry point to Document and using the IdMapper to get the Id out as it is string and the contract is Document. How can I re-structure the code so that I can derive the Id from the String payload at entry point? Should conversion to Document and Id mapping move to a common interface?

Aucun commentaire:

Enregistrer un commentaire