package com.intellij.javascript.karma.server;
import com.intellij.concurrency.JobScheduler;
import com.intellij.javascript.karma.execution.KarmaServerSettings;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.util.CatchingConsumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
/**
* @author Sergey Simonchik
*/
public class KarmaServerRegistry {
private static final Logger LOG = Logger.getInstance(KarmaServerRegistry.class);
private final Project myProject;
private final ConcurrentMap<String, KarmaServer> myServerByConfigFile = new ConcurrentHashMap<>();
private final ConcurrentMap<KarmaServerSettings, KarmaServer> myServers = new ConcurrentHashMap<>();
private final ConcurrentMap<KarmaServerSettings, KarmaServerSettings> myStartingServers = new ConcurrentHashMap<>();
public KarmaServerRegistry(@NotNull Project project) {
myProject = project;
}
@NotNull
public static KarmaServerRegistry getInstance(@NotNull Project project) {
return ServiceManager.getService(project, KarmaServerRegistry.class);
}
@Nullable
public KarmaServer getServer(@NotNull KarmaServerSettings serverSettings) {
return myServers.get(serverSettings);
}
public void startServer(@NotNull final KarmaServerSettings serverSettings, final CatchingConsumer<KarmaServer, Exception> consumer) {
KarmaServer prevServer = myServerByConfigFile.get(serverSettings.getConfigurationFilePath());
if (prevServer != null) {
prevServer.onTerminated(new KarmaServerTerminatedListener() {
@Override
public void onTerminated(int exitCode) {
doStartServer(serverSettings, consumer);
}
});
prevServer.shutdownAsync();
}
else {
doStartServer(serverSettings, consumer);
}
}
private void doStartServer(@NotNull final KarmaServerSettings serverSettings,
@NotNull final CatchingConsumer<KarmaServer, Exception> consumer) {
if (myStartingServers.putIfAbsent(serverSettings, serverSettings) != null) {
LOG.warn(new Throwable("Unexpected subsequent karma server starting:" + serverSettings.toString()));
JobScheduler.getScheduler().schedule(() -> startServer(serverSettings, consumer), 100, TimeUnit.MILLISECONDS);
return;
}
ApplicationManager.getApplication().executeOnPooledThread(() -> {
try {
final KarmaServer server;
try {
server = new KarmaServer(myProject, serverSettings);
myServers.put(serverSettings, server);
myServerByConfigFile.put(serverSettings.getConfigurationFilePath(), server);
}
finally {
myStartingServers.remove(serverSettings);
}
server.onTerminated(new KarmaServerTerminatedListener() {
@Override
public void onTerminated(int exitCode) {
myServers.remove(serverSettings, server);
myServerByConfigFile.remove(serverSettings.getConfigurationFilePath(), server);
}
});
ApplicationManager.getApplication().invokeLater(() -> consumer.consume(server));
}
catch (final Exception e) {
ApplicationManager.getApplication().invokeLater(() -> consumer.consume(e));
}
});
}
}