org.apache.ode.jacob.examples.helloworld.HelloWorld.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ode.jacob.examples.helloworld.HelloWorld.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.ode.jacob.examples.helloworld;

import java.util.Collections;
import java.util.List;

import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.ode.jacob.ChannelRef;
import org.apache.ode.jacob.Message;
import org.apache.ode.jacob.MessageListener;
import org.apache.ode.jacob.RunnableProcess;
import org.apache.ode.jacob.examples.sequence.Sequence;
import org.apache.ode.jacob.oo.Channel;
import org.apache.ode.jacob.oo.ReceiveProcess;
import org.apache.ode.jacob.oo.Synch;
import org.apache.ode.jacob.oo.Val;
import org.apache.ode.jacob.soup.jackson.JacksonExecutionQueueImpl;
import org.apache.ode.jacob.soup.jackson.JacobModule;
import org.apache.ode.jacob.vpu.JacobVPU;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.smile.SmileFactory;

import static org.apache.ode.jacob.Jacob.instance;
import static org.apache.ode.jacob.Jacob.newChannel;
import static org.apache.ode.jacob.Jacob.newCommChannel;
import static org.apache.ode.jacob.Jacob.object;
import static org.apache.ode.jacob.Jacob.sendMessage;
import static org.apache.ode.jacob.Jacob.subscribe;

/**
 * Simple Hello World example to showcase different
 * features and approaches of the Jacob API.
 * 
 * Inspired by http://scienceblogs.com/goodmath/2007/04/16/back-to-calculus-a-better-intr-1/
 * 
 * @author Tammo van Lessen
 * 
 */
@SuppressWarnings("serial")
public class HelloWorld extends RunnableProcess {

    public static interface Callback<T, R extends Channel> extends Channel {

        public void invoke(T value, R callback);

    }

    static class ReliablePrinterProcess extends RunnableProcess {
        private Callback<String, Synch> in;

        @JsonCreator
        public ReliablePrinterProcess(@JsonProperty("in") Callback<String, Synch> in) {
            this.in = in;
        }

        public void run() {
            object(true, new ReceiveProcess().setChannel(in).setReceiver(new ReliablePrinterCallback()));
        }

        static class ReliablePrinterCallback implements Callback<String, Synch> {
            public void invoke(String value, Synch callback) {
                System.out.println(value);
                callback.ret();
            }
        }
    }

    static class ReliableStringEmitterProcess extends RunnableProcess {
        private String str;
        private Callback<String, Synch> to;

        @JsonCreator
        public ReliableStringEmitterProcess(@JsonProperty("str") String str,
                @JsonProperty("to") Callback<String, Synch> to) {
            this.str = str;
            this.to = to;
        }

        public void run() {
            Synch callback = newChannel(Synch.class, "callback channel to ACK " + str);
            object(new ReceiveProcess().setChannel(callback).setReceiver(new ReliableStringEmitterSynch(str)));
            to.invoke(str, callback);
        }

        static class ReliableStringEmitterSynch implements Synch {
            private String str;

            @JsonCreator
            public ReliableStringEmitterSynch(@JsonProperty("str") String str) {
                this.str = str;
            }

            public void ret() {
                System.out.println(str + " ACKed");
            }
        }
    }

    static class PrinterProcess extends RunnableProcess {
        private Val _in;

        @JsonCreator
        public PrinterProcess(@JsonProperty("in") Val in) {
            _in = in;
        }

        public void run() {
            object(true, new ReceiveProcess().setChannel(_in).setReceiver(new PrinterProcessVal()));
        }

        static class PrinterProcessVal implements Val {
            public void val(Object o) {
                System.out.println(o);
            }
        }
    }

    static class StringEmitterProcess extends RunnableProcess {
        private String str;
        private Val to;

        @JsonCreator
        public StringEmitterProcess(@JsonProperty("str") String str, @JsonProperty("to") Val to) {
            this.str = str;
            this.to = to;
        }

        public void run() {
            to.val(str);
        }
    }

    static class ForwarderProcess extends RunnableProcess {
        private Val in;
        private Val out;

        @JsonCreator
        public ForwarderProcess(@JsonProperty("in") Val in, @JsonProperty("out") Val out) {
            this.in = in;
            this.out = out;
        }

        public void run() {
            object(true, new ReceiveProcess().setChannel(in).setReceiver(new ForwarderProcessVal(out)));
        }

        static class ForwarderProcessVal implements Val {
            private Val out;

            @JsonCreator
            public ForwarderProcessVal(@JsonProperty("out") Val out) {
                this.out = out;
            }

            public void val(Object o) {
                out.val(o);
            }
        }

    }

    protected void simpleHelloWorld() {
        // new(out)
        final Val out = newChannel(Val.class, "simpleHelloWorld-out");
        // new(x)
        final Val x = newChannel(Val.class, "simpleHelloWorld-x");
        // *(?out(str).!sysout(str))
        instance(new PrinterProcess(out));
        // *(?x(str).!out(str))
        instance(new ForwarderProcess(x, out));

        // !out(hello) | !out(world)
        instance(new StringEmitterProcess("Hello", x));
        instance(new StringEmitterProcess("World", x));
    }

    protected void reliableHelloWorld() {
        // reliable version of the code above
        // (new(callback).!out(hello).?callback) | (new(callback).!out(world).?callback)

        // new(rout)
        @SuppressWarnings("unchecked")
        Callback<String, Synch> rout = newChannel(Callback.class, "reliableHelloWorld-rout");
        // *(?rout(str).!sysout(str))
        instance(new ReliablePrinterProcess(rout));
        // (new(callback).!out(hello).?callback)
        instance(new ReliableStringEmitterProcess("Hello", rout));
        // (new(callback).!out(world).?callback)
        instance(new ReliableStringEmitterProcess("World", rout));
    }

    protected void sequencedHelloWorld() {
        // send hello world as a sequence
        // !out(hello).!out(world)

        // new(out)
        final Val out = newChannel(Val.class, "sequencedHelloWorld-out");

        // *(?out(str).!sysout(str))
        instance(new PrinterProcess(out));

        final String[] greeting = { "Hello", "World" };

        instance(new HWSequence(greeting, out, null));
    }

    protected void calculusHelloWorld() {
        // new(out)
        final ChannelRef out = newCommChannel("calculusHelloWorld-out");
        // new(x)
        final ChannelRef x = newCommChannel("calculusHelloWorld-x");

        // *(?out(str).!sysout(str))
        subscribe(true, out, new PrinterMessageListener());
        // *(?x(str).!out(str))
        subscribe(true, x, new ForwarderMessageListener(out));
        // !out(hello) | !out(world)
        instance(new StringEmitterRunnable("Hello", x));
        instance(new StringEmitterRunnable("World", x));
    }

    static class PrinterMessageListener implements MessageListener {

        @Override
        public void onMessage(Message msg) {
            System.out.println(msg.getBody());
        }

    }

    static class ForwarderMessageListener implements MessageListener {
        private ChannelRef to;

        @JsonCreator
        public ForwarderMessageListener(@JsonProperty("to") ChannelRef to) {
            this.to = to;
        }

        @Override
        public void onMessage(Message msg) {
            Message msg2 = new Message(to, null, msg.getAction());
            msg2.setBody(msg.getBody());
            sendMessage(msg2);
        }
    }

    static class StringEmitterRunnable extends RunnableProcess {
        private String str;
        private ChannelRef to;

        @JsonCreator
        public StringEmitterRunnable(@JsonProperty("str") String str, @JsonProperty("to") ChannelRef to) {
            this.str = str;
            this.to = to;
        }

        public void run() {
            Message msg = new Message(to, null, "printHW");
            msg.setBody(str);
            sendMessage(msg);
        }
    }

    static class HWSequence extends Sequence {

        private final String[] greetings;
        private final Val out;

        @JsonCreator
        public HWSequence(@JsonProperty("greetings") String[] greetings, @JsonProperty("out") Val out,
                @JsonProperty("done") Synch done) {
            super(greetings.length, done);
            this.greetings = greetings;
            this.out = out;
        }

        @Override
        protected RunnableProcess doStep(int step, Synch done) {
            return new SequenceItemEmitter(greetings[step], done, out);
        }

        static class SequenceItemEmitter extends RunnableProcess {
            private final String string;
            private final Synch done;
            private final Val out;

            @JsonCreator
            public SequenceItemEmitter(@JsonProperty("string") String string, @JsonProperty("done") Synch done,
                    @JsonProperty("out") Val out) {
                this.string = string;
                this.done = done;
                this.out = out;
            }

            @Override
            public void run() {
                instance(new StringEmitterProcess(string, out));
                done.ret();
            }
        }
    }

    @Override
    public void run() {
        simpleHelloWorld();
        reliableHelloWorld();
        sequencedHelloWorld();
        calculusHelloWorld();
    }

    @SuppressWarnings("unchecked")
    public static void main(String args[]) throws Exception {
        // enable logging
        // BasicConfigurator.configure();
        List<Logger> loggers = Collections.<Logger>list(LogManager.getCurrentLoggers());
        loggers.add(LogManager.getRootLogger());
        for (Logger logger : loggers) {
            logger.setLevel(Level.OFF);
        }

        SmileFactory sf = null;
        // // enable smile:
        // sf = new SmileFactory();
        // sf.enable(SmileGenerator.Feature.CHECK_SHARED_STRING_VALUES);
        // sf.enable(SmileGenerator.Feature.ENCODE_BINARY_AS_7BIT);

        ObjectMapper mapper = new ObjectMapper(sf);
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

        mapper.registerModule(new JacobModule());

        JacobVPU vpu = new JacobVPU();
        JacksonExecutionQueueImpl queue = new JacksonExecutionQueueImpl();
        vpu.setContext(queue);

        long start = System.currentTimeMillis();
        vpu.inject(new HelloWorld());
        while (vpu.execute()) {
            queue = loadAndRestoreQueue(mapper, (JacksonExecutionQueueImpl) vpu.getContext());
            vpu.setContext(queue);
            System.out.println(vpu.isComplete() ? "<0>" : ".");
            //vpu.dumpState();
        }
        System.out.println("Runtime in ms: " + (System.currentTimeMillis() - start));
        vpu.dumpState();
    }

    public static JacksonExecutionQueueImpl loadAndRestoreQueue(ObjectMapper mapper, JacksonExecutionQueueImpl in)
            throws Exception {
        byte[] json = mapper.writeValueAsBytes(in);
        // print json
        // System.out.println(new String(json));
        JacksonExecutionQueueImpl q2 = mapper.readValue(json, JacksonExecutionQueueImpl.class);
        return q2;
    }

}