// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.debugger.engine;

import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RemoteConnection;
import com.intellij.util.SystemProperties;
import com.sun.jdi.connect.AttachingConnector;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * @author egor
 */
public class SAPidRemoteConnection extends RemoteConnection {
  @NonNls private static final String SA_PID_ATTACHING_CONNECTOR_NAME = "sun.jvm.hotspot.jdi.SAPIDAttachingConnector";
  private static ClassLoader BASE_SA_JDI_CLASS_LOADER;

  private final String myPid;
  private final String mySAJarPath;

  public SAPidRemoteConnection(String pid, String saJarPath) {
    super(false, null, null, false);
    myPid = pid;
    mySAJarPath = saJarPath;
  }

  public String getPid() {
    return myPid;
  }

  public AttachingConnector getConnector() throws ExecutionException {
    try {
      Class<?> connectorClass = Class.forName(SA_PID_ATTACHING_CONNECTOR_NAME,
                                              true,
                                              new JBSAJDIClassLoader(getBaseSAJDIClassLoader(), mySAJarPath));
      return (AttachingConnector)connectorClass.newInstance();
    }
    catch (Exception e) {
      throw new ExecutionException("Unable to create SAPIDAttachingConnector", e);
    }
  }

  public static boolean isSAPidAttachAvailable() {
    return getBaseSAJDIClassLoader() != null;
  }

  @Nullable
  private static synchronized ClassLoader getBaseSAJDIClassLoader() {
    if (BASE_SA_JDI_CLASS_LOADER == null) {
      File saJdiJar = new File(SystemProperties.getJavaHome(), "../lib/sa-jdi.jar");
      if (saJdiJar.exists()) {
        try {
          BASE_SA_JDI_CLASS_LOADER = new JBSAJDIClassLoader(SAPidRemoteConnection.class.getClassLoader(), saJdiJar.getCanonicalPath());
        }
        catch (IOException ignored) {
        }
      }
    }
    return BASE_SA_JDI_CLASS_LOADER;
  }

  private static class JBSAJDIClassLoader extends URLClassLoader {
    JBSAJDIClassLoader(ClassLoader parent, String classPath) {
      super(new URL[0], parent);
      try {
        addURL(new File(classPath).toURI().toURL());
      }
      catch (MalformedURLException mue) {
        throw new RuntimeException(mue);
      }
    }

    @Override
    public synchronized Class loadClass(String name) throws ClassNotFoundException {
      Class c = findLoadedClass(name);
      if (c == null) {
        /* to avoid loading same native library multiple times
         *  from multiple class loaders (which results in getting a
         *  UnsatisifiedLinkageError from System.loadLibrary).
         */

        if (name.startsWith("sun.jvm.hotspot.") && !name.startsWith("sun.jvm.hotspot.debugger.")) {
          return findClass(name);
        }
        return super.loadClass(name);
      }
      return c;
    }

    @Nullable
    @Override
    public URL getResource(String name) {
      if ("sa.properties".equals(name)) {
        URL resource = findResource(name);
        if (resource != null) {
          return resource;
        }
      }
      return super.getResource(name);
    }
  }
}

@@ -417,16 +417,58 @@
 NonNls;%0A
+import org.jetbrains.annotations.NotNull;%0A
 import o
@@ -1479,16 +1479,27 @@
 sLoader(
+mySAJarPath
 ), mySAJ
@@ -1759,16 +1759,35 @@
  return 
+true;%0A    //return 
 getBaseS
@@ -1822,23 +1822,22 @@
  %7D%0A%0A  @N
+otN
 ull
-able
 %0A  priva
@@ -1895,16 +1895,32 @@
 sLoader(
+String saJarPath
 ) %7B%0A    
@@ -2089,24 +2089,137 @@
   try %7B%0A    
+      saJarPath = saJdiJar.getCanonicalPath();%0A        %7D%0A        catch (IOException ignored) %7B%0A        %7D%0A      %7D%0A
       BASE_S
@@ -2315,100 +2315,16 @@
  saJ
-diJar.getCanonicalPath());%0A        %7D%0A        catch (IOException ignored) %7B%0A        %7D%0A      %7D
+arPath);
 %0A   

use debuggee sa-jdi.jar if not available in jb jre - IDEA-168185