package com.gravspace.core;
import java.util.ArrayList;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.dispatch.OnSuccess;
import akka.pattern.Patterns;
import akka.routing.SmallestMailboxRouter;
import akka.util.Timeout;
import com.gravspace.abstractions.ICalculation;
import com.gravspace.abstractions.IWidget;
import com.gravspace.abstractions.IPage;
import com.gravspace.abstractions.PageRoute;
import com.gravspace.abstractions.IDataAccessor;
import com.gravspace.abstractions.IRenderer;
import com.gravspace.abstractions.ITask;
import com.gravspace.handlers.CalculationHandler;
import com.gravspace.handlers.WidgetHandler;
import com.gravspace.handlers.PageHandler;
import com.gravspace.handlers.PersistanceHandler;
import com.gravspace.handlers.RendererHandler;
import com.gravspace.handlers.SessionHandler;
import com.gravspace.handlers.TaskHandler;
import com.gravspace.messages.RenderMessage;
import com.gravspace.messages.RequestMessage;
import com.gravspace.messages.RouterMessage;
import com.gravspace.messages.RouterResponseMessage;
import com.gravspace.page.ProfileDataAccessor;
import com.gravspace.page.ProfileCalculation;
import com.gravspace.page.ProfilePage;
import com.gravspace.page.ProfileRenderer;
import com.gravspace.page.ProfileTask;
import com.gravspace.util.Layers;
public class CoordinatingActor extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
protected HashMap<Layers, ActorRef> routerMap;
public CoordinatingActor(Properties config){
routerMap = new HashMap<Layers, ActorRef>();
routerMap.put(Layers.PAGE, generatePageRouter(
Integer.parseInt((String) config.getProperty("pages", "5")),
getPagePackages(config)));
routerMap.put(Layers.COMPONENT, generateComponentRouter(
Integer.parseInt((String) config.getProperty("widgets", "5")),
getWidgetPackages(config)));
routerMap.put(Layers.RENDERER, generateRenderRouter(
Integer.parseInt((String) config.getProperty("renders", "5")),
getRenderPackages(config)));
routerMap.put(Layers.TASK, generateTaskRouter(
Integer.parseInt((String) config.getProperty("tasks", "5")),
getTaskPackages(config)));
routerMap.put(Layers.CALCULATION, generateCalculationRouter(
Integer.parseInt((String) config.getProperty("calculations", "5")),
getCalculationPackages(config)));
routerMap.put(Layers.DATA_ACCESS, generateDataRouter(
Integer.parseInt((String) config.getProperty("dataaccesors", "5")),
config,
getAccessorPackages(config)));
routerMap.put(Layers.SESSION, this.getContext().actorOf(Props.create(SessionHandler.class)));
}
private List<String> getTaskPackages(Properties config) {
String property = "scan-tasks";
return getAnnotatedPackages(config, property);
}
private List<String> getPagePackages(Properties config) {
String property = "scan-pages";
return getAnnotatedPackages(config, property);
}
private List<String> getCalculationPackages(Properties config) {
String property = "scan-calculations";
List<String> packages = getAnnotatedPackages(config, property);
packages.add("com.gravspace.calculation.form");
return packages;
}
private List<String> getAccessorPackages(Properties config) {
String property = "scan-dataaccessors";
return getAnnotatedPackages(config, property);
}
private List<String> getRenderPackages(Properties config) {
String property = "scan-renderers";
List<String> packages = getAnnotatedPackages(config, property);
packages.add("com.gravspace.defaults");
return packages;
}
private List<String> getWidgetPackages(Properties config) {
String property = "scan-widgets";
return getAnnotatedPackages(config, property);
}
private List<String> getAnnotatedPackages(Properties config, String property) {
List<String> pkgs = extractPackagesFromPropertyString(config,
property);
pkgs.addAll(extractPackagesFromPropertyString(config,
"scan-all"));
return pkgs;
}
private List<String> extractPackagesFromPropertyString(Properties config,
String property) {
List<String> pkgs = new ArrayList<>();
String scanString = config.getProperty(property, "");
if (!StringUtils.isEmpty(scanString.trim())){
String[] packages = scanString.split(",");
for (String pkg: packages){
pkgs.add(pkg);
}
}
return pkgs;
}
private ActorRef generatePageRouter(int actors, List<String> list) {
List<ActorRef> pageActors = new ArrayList<ActorRef>();
// List<PageRoute> routers = new ArrayList<PageRoute>();
List<PageRoute> routers = AnnotationParser.getAnnotatedPages(list);
for (PageRoute route: routers){
log.info(String.format("Registering pages: [%s] [%s]", route.getTemplate().toString(), route.getPageClass().getCanonicalName()));
}
// routers.add(new PageRoute("/test/{value}/", ProfilePage.class));
for (int i = 0; i < actors; i++){
pageActors.add(this.getContext().actorOf(Props.create(PageHandler.class, routerMap, routers), "PageHandler-"+i));
}
return this.getContext().actorOf(
Props.empty().withRouter(SmallestMailboxRouter.create(pageActors)));
}
private ActorRef generateDataRouter(int actors, Properties config, List<String> dataPackages) {
List<ActorRef> dataActors = new ArrayList<ActorRef>();
Map<String, Class<? extends IDataAccessor>> routers = new HashMap<String, Class<? extends IDataAccessor>>();
List<Class<? extends IDataAccessor>> accessors = AnnotationParser.getAnnotatedDataAccessors(dataPackages);
for (Class<? extends IDataAccessor> accessor: accessors){
log.info(String.format("Registering accessor: [%s]", accessor.getCanonicalName()));
routers.put(accessor.getCanonicalName(), accessor);
}
for (int i = 0; i < actors; i++){
dataActors.add(this.getContext().actorOf(Props.create(PersistanceHandler.class, routerMap, routers, config), "DataHandler-"+i));
}
return this.getContext().actorOf(
Props.empty().withRouter(SmallestMailboxRouter.create(dataActors)));
}
private ActorRef generateTaskRouter(int actors, List<String> taskPackages) {
List<ActorRef> taskActors = new ArrayList<ActorRef>();
Map<String, Class<? extends ITask>> routers = new HashMap<String, Class<? extends ITask>>();
List<Class<? extends ITask>> tasks = AnnotationParser.getAnnotatedTasks(taskPackages);
for (Class<? extends ITask> task: tasks){
log.info(String.format("Registering task: [%s]", task.getCanonicalName()));
routers.put(task.getCanonicalName(), task);
}
for (int i = 0; i < actors; i++){
taskActors.add(this.getContext().actorOf(Props.create(TaskHandler.class, routerMap, routers), "TaskHandler-"+i));
}
return this.getContext().actorOf(
Props.empty().withRouter(SmallestMailboxRouter.create(taskActors)));
}
private ActorRef generateCalculationRouter(int actors, List<String> calcPackages) {
List<ActorRef> calcActors = new ArrayList<ActorRef>();
Map<String, Class<? extends ICalculation>> routers = new HashMap<String, Class<? extends ICalculation>>();
List<Class<? extends ICalculation>> calculations = AnnotationParser.getAnnotatedCalculations(calcPackages);
for (Class<? extends ICalculation> calculation: calculations){
log.info(String.format("Registering calculation: [%s]", calculation.getCanonicalName()));
routers.put(calculation.getCanonicalName(), calculation);
}
for (int i = 0; i < actors; i++){
calcActors.add(this.getContext().actorOf(Props.create(CalculationHandler.class, routerMap, routers), "CalculationHandler-"+i));
}
return this.getContext().actorOf(
Props.empty().withRouter(SmallestMailboxRouter.create(calcActors)));
}
private ActorRef generateComponentRouter(int actors, List<String> calcPackages) {
List<ActorRef> widgetActors = new ArrayList<ActorRef>();
Map<String, Class<? extends IWidget>> routers = new HashMap<String, Class<? extends IWidget>>();
List<Class<? extends IWidget>> widgets = AnnotationParser.getAnnotatedWidgets(calcPackages);
for (Class<? extends IWidget> widget: widgets){
log.info(String.format("Registering widget: [%s]", widget.getCanonicalName()));
routers.put(widget.getCanonicalName(), widget);
}
for (int i = 0; i < actors; i++){
widgetActors.add(this.getContext().actorOf(Props.create(WidgetHandler.class, routerMap, routers), "WidgetHandler-"+i));
}
return this.getContext().actorOf(
Props.empty().withRouter(SmallestMailboxRouter.create(widgetActors)));
}
private ActorRef generateRenderRouter(int actors, List<String> renderPackages) {
List<ActorRef> renderers = new ArrayList<ActorRef>();
Map<String, Class<? extends IRenderer>> routers = new HashMap<String, Class<? extends IRenderer>>();
List<Class<? extends IRenderer>> renders = AnnotationParser.getAnnotatedRenderers(renderPackages);
for (Class<? extends IRenderer> renderer: renders){
log.info(String.format("Registering renderer: [%s]", renderer.getCanonicalName()));
routers.put(renderer.getCanonicalName(), renderer);
}
for (int i = 0; i < actors; i++){
renderers.add(this.getContext().actorOf(Props.create(RendererHandler.class, routerMap, routers), "RenderHandler-"+i));
}
return this.getContext().actorOf(
Props.empty().withRouter(SmallestMailboxRouter.create(renderers)));
}
@Override
public void onReceive(Object message) throws Exception {
log.info("Got "+message.getClass().getCanonicalName());
if (message instanceof RequestMessage){
log.info("Got RequestMessage");
Timeout timeout = new Timeout(Duration.create(1, "minute"));
Future<Object> future = Patterns.ask(routerMap.get(Layers.PAGE), message, timeout);
akka.pattern.Patterns.pipe(future, this.getContext().dispatcher()).to(getSender());
} else {
unhandled(message);
}
}
}