<commit_before>/*
 * Copyright 2000-2012 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.compiler;

import com.intellij.ProjectTopics;
import com.intellij.application.options.PathMacrosImpl;
import com.intellij.compiler.server.impl.CompileServerClasspathManager;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.notification.Notification;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathMacros;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.compiler.CompilationStatusListener;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.compiler.CompilerTopics;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.ShutDownTracker;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.problems.Problem;
import com.intellij.problems.WolfTheProblemSolver;
import com.intellij.util.Alarm;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.net.NetUtils;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.api.*;
import org.jetbrains.jps.client.CompileServerClient;
import org.jetbrains.jps.server.ClasspathBootstrap;
import org.jetbrains.jps.server.Server;

import javax.tools.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author <NAME>
 *         Date: 9/6/11
 */
public class CompileServerManager implements ApplicationComponent{
  private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.CompileServerManager");
  private static final String COMPILE_SERVER_SYSTEM_ROOT = "compile-server";
  private static final String LOGGER_CONFIG = "log.xml";
  private static final String DEFAULT_LOGGER_CONFIG = "defaultLogConfig.xml";
  private volatile OSProcessHandler myProcessHandler;
  private final File mySystemDirectory;
  @Nullable
  private volatile CompileServerClient myClient;
  private final SequentialTaskExecutor myTaskExecutor = new SequentialTaskExecutor(new AsyncTaskExecutor() {
    @Override
    public void submit(Runnable runnable) {
      ApplicationManager.getApplication().executeOnPooledThread(runnable);
    }
  });
  private final ProjectManager myProjectManager;
  private static final int MAKE_TRIGGER_DELAY = 5 * 1000 /*5 seconds*/;
  private final Map<RequestFuture, Project> myAutomakeFutures = new HashMap<RequestFuture, Project>();
  private final CompileServerClasspathManager myClasspathManager = new CompileServerClasspathManager();
  private final AsyncTaskExecutor myAsyncExec = new AsyncTaskExecutor() {
    @Override
    public void submit(Runnable runnable) {
      ApplicationManager.getApplication().executeOnPooledThread(runnable);
    }
  };

  public CompileServerManager(final ProjectManager projectManager) {
    myProjectManager = projectManager;
    final String systemPath = PathManager.getSystemPath();
    File system = new File(systemPath);
    try {
      system = system.getCanonicalFile();
    }
    catch (IOException e) {
      LOG.info(e);
    }
    mySystemDirectory = system;

    projectManager.addProjectManagerListener(new ProjectWatcher());
    final MessageBusConnection conn = ApplicationManager.getApplication().getMessageBus().connect();
    conn.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
      private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
      private final AtomicBoolean myAutoMakeInProgress = new AtomicBoolean(false);
      @Override
      public void before(@NotNull List<? extends VFileEvent> events) {
      }

      @Override
      public void after(@NotNull List<? extends VFileEvent> events) {
        if (shouldTriggerMake(events)) {
          scheduleMake(new Runnable() {
            @Override
            public void run() {
              if (!myAutoMakeInProgress.getAndSet(true)) {
                try {
                  ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
                    @Override
                    public void run() {
                      try {
                        runAutoMake();
                      }
                      finally {
                        myAutoMakeInProgress.set(false);
                      }
                    }
                  });
                }
                catch (RejectedExecutionException ignored) {
                  // we were shut down
                }
              }
              else {
                scheduleMake(this);
              }
            }
          });
        }
      }

      private void scheduleMake(Runnable runnable) {
        myAlarm.cancelAllRequests();
        myAlarm.addRequest(runnable, MAKE_TRIGGER_DELAY);
      }

      private boolean shouldTriggerMake(List<? extends VFileEvent> events) {
        for (VFileEvent event : events) {
          if (event.isFromRefresh() || event.getRequestor() instanceof SavingRequestor) {
            return true;
          }
        }
        return false;
      }
    });

    ShutDownTracker.getInstance().registerShutdownTask(new Runnable() {
      @Override
      public void run() {
        shutdownServer(myClient, myProcessHandler);
      }
    });
  }

  public static CompileServerManager getInstance() {
    return ApplicationManager.getApplication().getComponent(CompileServerManager.class);
  }

  public void notifyFilesChanged(Collection<String> paths) {
    sendNotification(paths, false);
  }

  public void notifyFilesDeleted(Collection<String> paths) {
    sendNotification(paths, true);
  }

  @Nullable
  private static String getProjectPath(final Project project) {
    final String path = project.getPresentableUrl();
    if (path == null) return path;
    final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(path);
    return vFile != null ? vFile.getPath() : null;
  }

  public void sendReloadRequest(final Project project) {
    if (!project.isDefault() && project.isOpen()) {
      myTaskExecutor.submit(new Runnable() {
        @Override
        public void run() {
          try {
            if (!project.isDisposed()) {
              final CompileServerClient client = ensureServerRunningAndClientConnected(false);
              if (client != null) {
                client.sendProjectReloadRequest(Collections.singletonList(getProjectPath(project)));
              }
            }
          }
          catch (Throwable e) {
            LOG.info(e);
          }
        }
      });
    }
  }

  public void sendCancelBuildRequest(final UUID sessionId) {
    myTaskExecutor.submit(new Runnable() {
      @Override
      public void run() {
        try {
          final CompileServerClient client = ensureServerRunningAndClientConnected(false);
          if (client != null) {
            client.sendCancelBuildRequest(sessionId);
          }
        }
        catch (Throwable e) {
          LOG.info(e);
        }
      }
    });
  }

  private void sendNotification(final Collection<String> paths, final boolean isDeleted) {
    if (paths.isEmpty()) {
      return;
    }
    try {
      final CompileServerClient client = ensureServerRunningAndClientConnected(false);
      if (client != null) {
        myTaskExecutor.submit(new Runnable() {
          @Override
          public void run() {
            final Project[] openProjects = myProjectManager.getOpenProjects();
            if (openProjects.length > 0) {
              final Collection<String> changed, deleted;
              if (isDeleted) {
                changed = Collections.emptyList();
                deleted = paths;
              }
              else {
                changed = paths;
                deleted = Collections.emptyList();
              }
              for (Project project : openProjects) {
                try {
                  client.sendFSEvent(getProjectPath(project), changed, deleted);
                }
                catch (Exception e) {
                  LOG.info(e);
                }
              }
            }
          }
        });
      }
    }
    catch (Throwable th) {
      LOG.error(th); // should not happen
    }
  }

  private void runAutoMake() {
    final Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
    if (openProjects.length > 0) {
      final List<RequestFuture> futures = new ArrayList<RequestFuture>();
      for (final Project project : openProjects) {
        if (project.isDefault()) {
          continue;
        }
        final CompilerWorkspaceConfiguration config = CompilerWorkspaceConfiguration.getInstance(project);
        if (!config.useCompileServer() || !config.MAKE_PROJECT_ON_SAVE) {
          continue;
        }
        final RequestFuture future = submitCompilationTask(project, false, true, Collections.<String>emptyList(), Collections.<String>emptyList(),
                                                           Collections.<String>emptyList(), Collections.<String, String>emptyMap(), new AutoMakeResponseHandler(project)<commit_msg>use saved reference to projectmanager instead of getInstance() call<commit_after>/*
 * Copyright 2000-2012 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.compiler;

import com.intellij.ProjectTopics;
import com.intellij.application.options.PathMacrosImpl;
import com.intellij.compiler.server.impl.CompileServerClasspathManager;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.notification.Notification;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathMacros;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.compiler.CompilationStatusListener;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.compiler.CompilerTopics;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.ShutDownTracker;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.problems.Problem;
import com.intellij.problems.WolfTheProblemSolver;
import com.intellij.util.Alarm;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.net.NetUtils;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.api.*;
import org.jetbrains.jps.client.CompileServerClient;
import org.jetbrains.jps.server.ClasspathBootstrap;
import org.jetbrains.jps.server.Server;

import javax.tools.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author <NAME>
 *         Date: 9/6/11
 */
public class CompileServerManager implements ApplicationComponent{
  private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.CompileServerManager");
  private static final String COMPILE_SERVER_SYSTEM_ROOT = "compile-server";
  private static final String LOGGER_CONFIG = "log.xml";
  private static final String DEFAULT_LOGGER_CONFIG = "defaultLogConfig.xml";
  private volatile OSProcessHandler myProcessHandler;
  private final File mySystemDirectory;
  @Nullable
  private volatile CompileServerClient myClient;
  private final SequentialTaskExecutor myTaskExecutor = new SequentialTaskExecutor(new AsyncTaskExecutor() {
    @Override
    public void submit(Runnable runnable) {
      ApplicationManager.getApplication().executeOnPooledThread(runnable);
    }
  });
  private final ProjectManager myProjectManager;
  private static final int MAKE_TRIGGER_DELAY = 5 * 1000 /*5 seconds*/;
  private final Map<RequestFuture, Project> myAutomakeFutures = new HashMap<RequestFuture, Project>();
  private final CompileServerClasspathManager myClasspathManager = new CompileServerClasspathManager();
  private final AsyncTaskExecutor myAsyncExec = new AsyncTaskExecutor() {
    @Override
    public void submit(Runnable runnable) {
      ApplicationManager.getApplication().executeOnPooledThread(runnable);
    }
  };

  public CompileServerManager(final ProjectManager projectManager) {
    myProjectManager = projectManager;
    final String systemPath = PathManager.getSystemPath();
    File system = new File(systemPath);
    try {
      system = system.getCanonicalFile();
    }
    catch (IOException e) {
      LOG.info(e);
    }
    mySystemDirectory = system;

    projectManager.addProjectManagerListener(new ProjectWatcher());
    final MessageBusConnection conn = ApplicationManager.getApplication().getMessageBus().connect();
    conn.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
      private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
      private final AtomicBoolean myAutoMakeInProgress = new AtomicBoolean(false);
      @Override
      public void before(@NotNull List<? extends VFileEvent> events) {
      }

      @Override
      public void after(@NotNull List<? extends VFileEvent> events) {
        if (shouldTriggerMake(events)) {
          scheduleMake(new Runnable() {
            @Override
            public void run() {
              if (!myAutoMakeInProgress.getAndSet(true)) {
                try {
                  ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
                    @Override
                    public void run() {
                      try {
                        runAutoMake();
                      }
                      finally {
                        myAutoMakeInProgress.set(false);
                      }
                    }
                  });
                }
                catch (RejectedExecutionException ignored) {
                  // we were shut down
                }
              }
              else {
                scheduleMake(this);
              }
            }
          });
        }
      }

      private void scheduleMake(Runnable runnable) {
        myAlarm.cancelAllRequests();
        myAlarm.addRequest(runnable, MAKE_TRIGGER_DELAY);
      }

      private boolean shouldTriggerMake(List<? extends VFileEvent> events) {
        for (VFileEvent event : events) {
          if (event.isFromRefresh() || event.getRequestor() instanceof SavingRequestor) {
            return true;
          }
        }
        return false;
      }
    });

    ShutDownTracker.getInstance().registerShutdownTask(new Runnable() {
      @Override
      public void run() {
        shutdownServer(myClient, myProcessHandler);
      }
    });
  }

  public static CompileServerManager getInstance() {
    return ApplicationManager.getApplication().getComponent(CompileServerManager.class);
  }

  public void notifyFilesChanged(Collection<String> paths) {
    sendNotification(paths, false);
  }

  public void notifyFilesDeleted(Collection<String> paths) {
    sendNotification(paths, true);
  }

  @Nullable
  private static String getProjectPath(final Project project) {
    final String path = project.getPresentableUrl();
    if (path == null) return path;
    final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(path);
    return vFile != null ? vFile.getPath() : null;
  }

  public void sendReloadRequest(final Project project) {
    if (!project.isDefault() && project.isOpen()) {
      myTaskExecutor.submit(new Runnable() {
        @Override
        public void run() {
          try {
            if (!project.isDisposed()) {
              final CompileServerClient client = ensureServerRunningAndClientConnected(false);
              if (client != null) {
                client.sendProjectReloadRequest(Collections.singletonList(getProjectPath(project)));
              }
            }
          }
          catch (Throwable e) {
            LOG.info(e);
          }
        }
      });
    }
  }

  public void sendCancelBuildRequest(final UUID sessionId) {
    myTaskExecutor.submit(new Runnable() {
      @Override
      public void run() {
        try {
          final CompileServerClient client = ensureServerRunningAndClientConnected(false);
          if (client != null) {
            client.sendCancelBuildRequest(sessionId);
          }
        }
        catch (Throwable e) {
          LOG.info(e);
        }
      }
    });
  }

  private void sendNotification(final Collection<String> paths, final boolean isDeleted) {
    if (paths.isEmpty()) {
      return;
    }
    try {
      final CompileServerClient client = ensureServerRunningAndClientConnected(false);
      if (client != null) {
        myTaskExecutor.submit(new Runnable() {
          @Override
          public void run() {
            final Project[] openProjects = myProjectManager.getOpenProjects();
            if (openProjects.length > 0) {
              final Collection<String> changed, deleted;
              if (isDeleted) {
                changed = Collections.emptyList();
                deleted = paths;
              }
              else {
                changed = paths;
                deleted = Collections.emptyList();
              }
              for (Project project : openProjects) {
                try {
                  client.sendFSEvent(getProjectPath(project), changed, deleted);
                }
                catch (Exception e) {
                  LOG.info(e);
                }
              }
            }
          }
        });
      }
    }
    catch (Throwable th) {
      LOG.error(th); // should not happen
    }
  }

  private void runAutoMake() {
    final Project[] openProjects = myProjectManager.getOpenProjects();
    if (openProjects.length > 0) {
      final List<RequestFuture> futures = new ArrayList<RequestFuture>();
      for (final Project project : openProjects) {
        if (project.isDefault()) {
          continue;
        }
        final CompilerWorkspaceConfiguration config = CompilerWorkspaceConfiguration.getInstance(project);
        if (!config.useCompileServer() || !config.MAKE_PROJECT_ON_SAVE) {
          continue;
        }
        final RequestFuture future = submitCompilationTask(project, false, true, Collections.<String>emptyList(), Collections.<String>emptyList(),
                                                           Collections.<String>emptyList(), Collections.<String, String>emptyMap(), new AutoMakeResponseHandler(project)
{'fraction_non_alphanumeric': 0.0918037088873338, 'fraction_numerical': 0.002099370188943317, 'mean_word_length': 2.966863289382373, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '419534', 'n_tokens_mistral': 6267, 'n_tokens_neox': 6071, 'n_words': 1293}