/*
* Software is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
*
* The Initial Developer of the Original Code is Paweł Kamiński.
* All Rights Reserved.
*/
package com.fourtyfourblocks.akka;
import akka.actor.ActorRef;
import akka.actor.Identify;
import akka.actor.Kill;
import akka.actor.PoisonPill;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import akka.japi.Creator;
import com.fourtyfourblocks.akka.messages.Message;
import org.slf4j.MDC;
import scala.concurrent.duration.Duration;
import javax.inject.Inject;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* date : 10.09.13
* author : pawel
* file name : GenericActor
* <p/>
* description :
*/
public abstract class GenericActor extends UntypedActor implements Actor
{
protected final LoggingAdapter logger = Logging.getLogger(getContext().system(), this);
@Inject
TypeHelper typeHelper;
@Override
public <T> boolean is(Object message, Class<T> clazz)
{
return typeHelper.is(message, clazz);
}
@Override
public <T> T cast(Object message, Class<T> clazz)
{
return typeHelper.cast(message, clazz);
}
@Override
public void tell(ActorRef pid, Object message)
{
pid.tell(message, getSelf());
}
/**
* in my opinion it is bad idea to lookup actor if he is just a worker.
* it is better to create your own worker instance and delegate events to it.
*
* @param path of the actor
* @param message to be sent
*/
@Override
public void tell(String path, Object message)
{
getContext().actorSelection(path).tell(message, getSelf());
}
@Override
public String identify(String path)
{
final String id = UUID.randomUUID().toString();
getContext().actorSelection(path).tell(new Identify(id), getSelf());
return id;
}
@Override
public void kill(ActorRef pid)
{
pid.tell(Kill.getInstance(), getSelf());
}
@Override
public void poison(ActorRef pid)
{
pid.tell(PoisonPill.getInstance(), getSelf());
}
@Override
public void stop(ActorRef pid)
{
getContext().stop(pid);
}
@Override
public <T> void replay(T message)
{
getSender().tell(message, getSelf());
}
@Override
public Props configure(Creator<? extends UntypedActor> creator)
{
return Props.create(creator);
}
@Override
public Props configure(Class<? extends UntypedActor> clazz)
{
return Props.create(clazz);
}
@Override
public ActorRef create(Props props)
{
return create(props, null);
}
@Override
public ActorRef createAndWatch(Props props)
{
final ActorRef actorRef = create(props);
getContext().watch(actorRef);
return actorRef;
}
@Override
public ActorRef create(Props props, String uniqueName)
{
return getContext().actorOf(props, uniqueName);
}
@Override
public ActorRef createAndWatch(Props props, String uniqueName)
{
final ActorRef actorRef = create(props, uniqueName);
getContext().watch(actorRef);
return actorRef;
}
@Override
public void watch(ActorRef actorRef)
{
getContext().watch(actorRef);
}
@Override
public void become(Behaviour behaviour)
{
getContext().become(behaviour, true);
}
@Override
public void pushBehaviour(Behaviour behaviour)
{
getContext().become(behaviour, false);
}
@Override
public void popBehaviour()
{
getContext().unbecome();
}
/**
* Do not override this method, look at #onMessage method that is more convenient or #become method to specify Behaviour
*
* @param o object to react to
* @throws Exception
*/
@Override
public void onReceive(Object o) throws Exception
{
if (is(o, Message.class))
{
MDC.put(Message.MDC_LOGGER_KEY, cast(o, Message.class).getMDC());
}
logger.info("received message {}.", o);
onMessage(o);
MDC.remove(Message.MDC_LOGGER_KEY);
}
public void onMessage(Object message) throws Exception
{
unhandled(message);
}
@Override
public void stopTimeout()
{
getContext().setReceiveTimeout(Duration.Undefined());
}
protected void requestTimeout()
{
requestTimeout(2);
}
protected void requestTimeout(int duration)
{
requestTimeout(duration, TimeUnit.SECONDS);
}
@Override
public void requestTimeout(int duration, TimeUnit unit)
{
getContext().setReceiveTimeout(Duration.create(duration, unit));
}
}