chroniclechronicle-queuechronicle-wire

Chronicle Queue: How to read excepts/documents with different WireKey?


Assume a chronicle queue, and a producer that writes 2 types of messages into the queue. Each type of message is written with a different "WireKey".

// Writes: {key1: TestMessage}
appender.writeDocument(w -> w.write("key1").text("TestMessage"));

// Writes: {key2: AnotherTextMessage}
appender.writeDocument(w -> w.write("key2").text("AnotherTextMessage"));

Question:

How can I write a single-threaded consumer that can read both types of messages and handle them differently?

What I've tried:

// This can read both types of messages, but cannot
// tell which type a message belongs to.
tailer.readDocument(wire -> {
    wire.read().text();
});
// This only reads type "key1" messages, skips all "key2" messages.
tailer.readDocument(wire -> {
    wire.read("key1").text();
});
// This crashes. (because it advances the read position illegally?)
tailer.readDocument(wire -> {
    wire.read("key1").text();
    wire.read("key2").text();
});

I was hoping I can do something like wire.readKey() and get the WireKey of a document, then proceed to read the document and handle it dynamically. How can I do this?

Note: I'm aware this can be accomplished using methodReader and methodWriter, and it seems like documentation/demo recommends this approach (?) But I'd prefer not to use that API, and be explicit about reading and writing messages. I assume there has to be a way to accomplish this use case.

Thank you.


Solution

  • You are correct, e.g. MethodReader accomplishes it.

    You can do it two ways

    // a reused StringBuilder
    StringBuilder sb = new StringBuilder();
    wire.read(sb); // populate the StringBuilder
    

    or a more convenient method is

    String name = wire.readEvent(String.class);
    switch(name) {
        case "key1":
            String text1 = wire.getValueIn().text();
            // do something with text1
            break;
    
        case "key2":
            String text2 = wire.getValueIn().text();
            // do something with text1
            break;
    
        default:
            // log unexpected key
    }
    

    For other readers who don't know about MethodReader, the same messages can be accomplished with

    interface MyEvents {
        void key1(String text1);
        void key2(String text2);
    }
    
    MyEvents me = wire.methodWriter(MyEvents.class);
    me.key1("text1");
    me.key2("text2");
    
    MyEvents me2 = new MyEvents() {
        public void key1(String text1) {
            // handle text1
        }
        public void key2(String text2) {
            // handle text2
        }
    };
    
    Reader reader = wire.methodReader(me2;
    do {
    } while(reader.readeOne());
    

    NOTE: The content is the same, so you can mix and match the two options

    You can use a Chronicle Queue instead of a Wire to persist this information