I was working on a supervisor that lazy creates actors based on some key
and then will forward messages to that actor. However, it just seems like I
am doing something frightfully common. So I was wondering if anyone knows
something in Akka that already does this and I should use that. I have
looked but didn't find anything. If not then it seems this might be a good
thing to put in the core API. A slice of what I am working on is below. Any
advice is appreciated.
public class LazyActorSupervisor<K, A> extends UntypedActor {
private final static String LOG_TAG =
LazyActorSupervisor.class.getSimpleName();
private LoggingAdapter log = Logging.getLogger(getContext().system(), this);
private Map<K, ActorRef> directory = new HashMap<>();
private Class<K> keyType;
private Class<A> childType;
/**
* @param keyType The type of key being used in the directory.
* @param childType The type of child actor.
*/
public LazyActorSupervisor(final Class<K> keyType, final Class<A>
childType) {
this.keyType = keyType;
this.childType = childType;
}
/**
* Finds the child actor or creates that actor if the actor does not exist.
It is possible that the subclass
* may decline to create the actor, passing back a null actor ref and thus
causing that to be returned to the
* caller.
*
* @param key The key to look for.
*/
protected ActorRef findOrCreate(final K key) {
ActorRef child = directory.get(key);
if (child == null || child.isTerminated()) {
if (child != null && child.isTerminated()) removeChild(key);
child = createChildActor(key);
if (child != null) {
directory.put(key, child);
context().watch(child);
if (log.isDebugEnabled()) log.debug(String.format("[%s] Created
Child Actor for key %s", LOG_TAG, key));
return child;
}
}
// FIXME decide if we want to send them to an error actor or something.
Do we leave that up to subclass?
return null;
}
/**
* Creates the child actor from the given key. This can be overridden by
subclasses which have more complex
* use cases or used as is in which case it will create a props for the
actor with the key as an argument.
*
* @param key The key to use.
*/
protected ActorRef createChildActor(final K key) {
return context().actorOf(Props.create(childType, key));
}
/**
* Removes a child ref from the directory by key.
*
* @param key The key of the ref to remove.
*/
private void removeChild(final K key) {
final ActorRef ref = directory.get(key);
if (ref == null) return; // nothing to do
context().unwatch(ref);
directory.remove(key);
}
/**
* removes a child ref from the directory and un-watches it.
*
* @param ref The ref to remove.
*/
private void removeChild(final ActorRef ref) {
directory.entrySet().stream().filter(e -> e.getValue().equals(ref))
.findAny().map(e -> {
context().unwatch(ref);
directory.remove(e.getKey());
return null;
});
}
@Override
public void onReceive(final Object message) throws Exception {
if (message instanceof FindLazySupervisedActor) {
@SuppressWarnings("unchecked") final FindLazySupervisedActor<K>
findMsg = (FindLazySupervisedActor<K>) message;
sender().tell(findOrCreate(findMsg.getKey()), getSelf());
} else if (message instanceof Terminated) {
final Terminated terminated = (Terminated) message;
removeChild(terminated.actor());
} else {
unhandled(message);
}
}
/**
* The type of key being used in the directory.
*/
public Class<K> getKeyType() {
return keyType;
}
/**
* The type of child actor.
*/
public Class<A> getChildType() {
return childType;
}
}
--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ:
>>>>>>>>>> http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka
User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.