/*
 * Copyright 2018 NAVER Corp.
 *
 * 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.navercorp.pinpoint.bootstrap.classloader;

import sun.misc.Launcher;
import sun.misc.Resource;
import sun.misc.URLClassPath;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Enumeration;

/**
 * @author Woonduk Kang(emeroad)
 */
class LauncherBootLoader implements BootLoader {

    private final URLClassPath bootstrapClassPath = getBootstrapClassPath();

    private static final Method FIND_BOOTSTRAP_CLASS_OR_NULL = findBootstrapClassOrNullMethod();

    private static Method findBootstrapClassOrNullMethod() {
        try {
            Method findBootstrapClassOrNull = ClassLoader.class.getDeclaredMethod("findBootstrapClassOrNull", String.class);
            findBootstrapClassOrNull.setAccessible(true);
            return findBootstrapClassOrNull;
        } catch (NoSuchMethodException e) {
            throw new IllegalStateException("ClassLoader.findBootstrapClassOrNull() not found", e);
        }
    }

    LauncherBootLoader() {
    }

    private static URLClassPath getBootstrapClassPath() {
        // pre classload
        @SuppressWarnings("unused")
        Enumeration urlEnumeration = new URLEnumeration(null);
        return Launcher.getBootstrapClassPath();
    }

    @Override
    public URL findResource(String name) {
        final Resource res = bootstrapClassPath.getResource(name);
        if (res == null) {
            return null;
        }
        return res.getURL();
    }

    @Override
    public Class<?> findBootstrapClassOrNull(ClassLoader classLoader, String name) {
        try {
            return (Class<?>) FIND_BOOTSTRAP_CLASS_OR_NULL.invoke(classLoader, name);
        } catch (IllegalAccessException ex) {
            throw new IllegalStateException("findBootstrapClassOrNull() access fail " + ex.getMessage(), ex);
        } catch (InvocationTargetException ex) {
            throw new IllegalStateException("findBootstrapClassOrNull() internal error " + ex.getMessage(), ex);
        }
    }

    @Override
    public Enumeration<URL> findResources(String name) throws IOException {
        final Enumeration<Resource> enumeration = bootstrapClassPath.getResources(name);
        return new URLEnumeration(enumeration);
    }

    private static class URLEnumeration implements Enumeration<URL> {
        private final Enumeration<Resource> enumeration;

        public URLEnumeration(Enumeration<Resource> enumeration) {
            this.enumeration = enumeration;
        }

        public URL nextElement() {
            Resource resource = enumeration.nextElement();
            return resource.getURL();
        }

        public boolean hasMoreElements() {
            return enumeration.hasMoreElements();
        }
    }
}

@@ -929,16 +929,22 @@
 ad)%0A */%0A
+final 
 class La
@@ -1218,24 +1218,396 @@
 lMethod() %7B%0A
+        // findBootstrapClassOrNull() jdk Compatibility%0A        // oracleJdk%0A        // oracleJdk 9~10 : reflection is not recommended%0A%0A        // old OracleJdk :%0A        // oracleJdk6_24 : success%0A%0A        // openjdk%0A        // openjdk8 : success%0A        // openjdk7 : success%0A        // openjdk6 : fail (findBootstrapClass0)%0A        NoSuchMethodException rootException;%0A
         try 
@@ -1876,24 +1876,25 @@
 eption e
+x
 ) %7B%0A    
         
@@ -1877,32 +1877,399 @@
 ption ex) %7B%0A    
+        rootException = ex;%0A        %7D%0A        try %7B%0A            // for openjdk6%0A            Method findBootstrapClass0 = ClassLoader.class.getDeclaredMethod(%22findBootstrapClass0%22, String.class);%0A            findBootstrapClass0.setAccessible(true);%0A            return findBootstrapClass0;%0A        %7D catch (NoSuchMethodException ignore) %7B%0A            // skip%0A        %7D%0A
         throw ne
@@ -2329,18 +2329,20 @@
 ssOrNull
-()
+ api
  not fou
@@ -2346,29 +2346,31 @@
 found%22, 
-e);%0A        %7D
+rootException);
 %0A    %7D%0A%0A
@@ -3764,29 +3764,30 @@
 ;%0A%0A        p
-ublic
+rivate
  URLEnumerat

Fix openjdk6 compatibility