package org.freeplane.plugin.remote.server; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import org.docear.messages.Messages.CloseAllOpenMapsRequest; import org.docear.messages.Messages.CloseUnusedMaps; import org.freeplane.features.mapio.MapIO; import org.freeplane.features.mode.ModeController; import org.freeplane.features.mode.mindmapmode.MModeController; import org.freeplane.plugin.remote.server.InternalMessages.ReleaseTimedOutLocks; import org.freeplane.plugin.remote.server.actors.MainActor; import org.freeplane.plugin.remote.server.v10.Actions; import org.jboss.netty.channel.ChannelException; import org.slf4j.Logger; import scala.concurrent.duration.Duration; import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.actor.Cancellable; import akka.actor.PoisonPill; import akka.actor.Props; import com.typesafe.config.ConfigFactory; public class RemoteController { private final ActorSystem system; private final ActorRef mainActor; private final Cancellable closeUnusedMapsJob; private final Cancellable releaseExpiredLocksJob; private final Map<String, OpenMindmapInfo> mapIdInfoMap = new HashMap<String, OpenMindmapInfo>(); private static RemoteController instance; public static RemoteController getInstance() throws ChannelException{ if(instance == null) instance = new RemoteController(); return instance; } private RemoteController() { final Logger logger = getLogger(); //change class loader final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(Activator.class.getClassLoader()); logger.info("starting Remote Plugin..."); system = ActorSystem.create("freeplaneRemote", ConfigFactory.load().getConfig("listener")); mainActor = system.actorOf(new Props(MainActor.class), "main"); logger.info("Main Actor running at path='{}'", mainActor.path()); closeUnusedMapsJob = system.scheduler().schedule( Duration.Zero(), Duration.apply(10, TimeUnit.MINUTES), new Runnable() { @Override public void run() { logger.trace("Scheduling closing of unused maps."); mainActor.tell(new CloseUnusedMaps("self", "", 600000), null); // ten minutes } }, system.dispatcher()); releaseExpiredLocksJob = system.scheduler().schedule( Duration.Zero(), Duration.apply(5, TimeUnit.SECONDS), new Runnable() { @Override public void run() { logger.trace("Scheduling release of locks that timed out."); mainActor.tell(new ReleaseTimedOutLocks(15000L), null); // 15 seconds } }, system.dispatcher()); //set back to original class loader Thread.currentThread().setContextClassLoader(contextClassLoader); } public static boolean isStarted(){ return instance != null; } public static void stop() { getLogger().info("Shutting down remote plugin..."); RemoteController controller = getInstance(); controller.closeUnusedMapsJob.cancel(); controller.releaseExpiredLocksJob.cancel(); controller.mainActor.tell(PoisonPill.getInstance(), null); controller.system.shutdown(); controller.closeMaps(); instance = null; } private void closeMaps() { Actions.closeAllOpenMaps(new CloseAllOpenMapsRequest("self", "")); } public static ModeController getModeController() { return MModeController.getMModeController(); } public static MapIO getMapIO() { return getModeController().getExtension(MapIO.class); } public static Map<String, OpenMindmapInfo> getMapIdInfoMap() { return getInstance().mapIdInfoMap; } public static Logger getLogger() { return org.freeplane.plugin.remote.server.Logger.getLogger(); } public static ActorSystem getActorSystem() { return getInstance().system; } }