natalia.dymnikova.cluster.ActorLogic.java Source code

Java tutorial

Introduction

Here is the source code for natalia.dymnikova.cluster.ActorLogic.java

Source

// Copyright (c) 2016 Natalia Dymnikova
// Available via the MIT license
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.

package natalia.dymnikova.cluster;

import akka.actor.AbstractActor;
import akka.actor.ActorPath;
import akka.actor.ActorRef;
import akka.actor.ActorSelection;
import akka.actor.Props;
import akka.actor.SupervisorStrategy;
import akka.util.Timeout;
import com.google.protobuf.Message;
import com.typesafe.config.ConfigMemorySize;
import natalia.dymnikova.cluster.SpringAkkaExtensionId.AkkaExtension;
import natalia.dymnikova.configuration.ConfigValue;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import scala.Option;
import scala.PartialFunction;
import scala.concurrent.Future;
import scala.runtime.AbstractPartialFunction;
import scala.runtime.BoxedUnit;

import java.io.Serializable;
import java.util.Optional;
import java.util.function.Supplier;

import static com.google.protobuf.TextFormat.shortDebugString;
import static humanize.Humanize.binaryPrefix;
import static org.slf4j.LoggerFactory.getLogger;

/**
 * Base class to encapsulate actor logic. Will be used to stuff an instance of {@link AbstractActor} with behaviour.
 * <p>
 * This class is needed to isolate application logic from an actor implementation because actors derived from
 * {@link AbstractActor} are not testable with simple unit test
 */
public class ActorLogic implements ActorAdapter {
    private final Logger log = getLogger(getClass());

    @Autowired
    protected AkkaExtension extension;

    @ConfigValue("natalia-dymnikova.debug.max-message-size-for-logging")
    private ConfigMemorySize maxLoggingSize;

    private ActorAdapter adapter;

    public ActorLogic(final ActorAdapter adapter) {
        this.adapter = adapter;
    }

    @Override
    public void receive(final PartialFunction<Object, BoxedUnit> receive) {
        adapter.receive(new AbstractPartialFunction<Object, BoxedUnit>() {
            @Override
            public BoxedUnit apply(final Object x) {
                if (log.isTraceEnabled()) {
                    log.trace("Received message {} from {} to {}", logMessage(x), sender(), self());
                }

                try {
                    return receive.apply(x);
                } catch (final Throwable e) {
                    log.error("Error {}: '{}' while processing message {} from {} to {}", e.getClass().getName(),
                            e.getMessage(), logMessage(x), sender(), self(), e);

                    throw e;
                }
            }

            private Object logMessage(final Object x) {
                final Object msg;
                if (x instanceof Message) {
                    final int size = ((Message) x).getSerializedSize();
                    if (size < maxLoggingSize.toBytes()) {
                        msg = x.getClass().getName() + ": " + "{" + shortDebugString((Message) x) + "}";
                    } else {
                        msg = x.getClass().getName() + ": " + "{too big message for logging " + binaryPrefix(size)
                                + "}";
                    }
                } else {
                    msg = x;
                }
                return msg;
            }

            @Override
            public boolean isDefinedAt(final Object x) {
                return receive.isDefinedAt(x);
            }
        });

    }

    @Override
    public void forward(final ActorRef actorRef, final Object msg) {
        adapter.forward(actorRef, msg);
    }

    @Override
    public void forward(final ActorSelection selection, final Object msg) {
        adapter.forward(selection, msg);
    }

    @Override
    public ActorRef actorOf(final Props props) {
        return adapter.actorOf(props);
    }

    @Override
    public Optional<ActorRef> child(final String name) {
        return adapter.child(name);
    }

    @Override
    public Iterable<ActorRef> children() {
        return adapter.children();
    }

    @Override
    public ActorRef actorOf(final Props props, final String name) {
        return adapter.actorOf(props, name);
    }

    @Override
    public String actorSystemName() {
        return adapter.actorSystemName();
    }

    @Override
    public SchedulerService scheduler() {
        return adapter.scheduler();
    }

    @Override
    public ActorSelection actorSelection(final ActorPath actorPath) {
        return adapter.actorSelection(actorPath);
    }

    @Override
    public ActorRef self() {
        return adapter.self();
    }

    @Override
    public ActorRef sender() {
        return adapter.sender();
    }

    @Override
    public ActorRef parent() {
        return adapter.parent();
    }

    @Override
    public void stop(final ActorRef ref) {
        adapter.stop(ref);
    }

    @Override
    public void reply(final Supplier<Object> supplier) {
        adapter.reply(supplier);
    }

    @Override
    public ActorRef watch(final ActorRef actorRef) {
        return adapter.watch(actorRef);
    }

    @Override
    public void unwatch(final ActorRef actorRef) {
        adapter.unwatch(actorRef);
    }

    @Override
    public void become(final PartialFunction<Object, BoxedUnit> behaviour) {
        adapter.become(behaviour);
    }

    @Override
    public void unbecome() {
        adapter.unbecome();
    }

    @Override
    public <T extends Serializable> Future<Object> ask(final ActorSelection selection, final T msg,
            final Timeout timeout) {
        return adapter.ask(selection, msg, timeout);
    }

    // callbacks

    public void preStart() throws Exception {
    }

    public SupervisorStrategy supervisorStrategy() {
        return SupervisorStrategy.defaultStrategy();
    }

    public void postStop() {
    }

    public void preRestart(final Throwable reason, final Option<Object> message) {
    }

    public void postRestart(final Throwable reason) {
    }

    public void unhandled(final Object message) {
    }
}