/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.openejb.config;

import org.apache.openejb.OpenEJBException;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.util.DaemonThreadFactory;
import org.apache.openejb.util.URLs;
import org.apache.xbean.finder.UrlSet;
import org.apache.xbean.finder.filter.Filters;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import static java.util.Arrays.asList;
import static org.apache.openejb.config.NewLoaderLogic.applyBuiltinExcludes;
import static org.apache.openejb.util.URLs.toFile;

/**
 * TLD file urls cached on a per classloader basis.  Helps with sharing TLD
 * files between webapps by placing them in a parent classloader.
 *
 * Each webapp will be able to retrieve the cached version of the URLs and
 * therefore only needs to scan its own libraries, the parent libraries will
 * already have been scanned.
 *
 * For a tiny bit of performance, we will scan the StandardClassloader at boot
 * in a separate thread so it should be primed in advance of any deployment.
 *
 * @version $Rev$ $Date$
 */
public class TldScanner {

    // first cache, it is the faster one but not relevant between temp and runtime phases
    private static final Map<ClassLoader, Set<URL>> cache = new WeakHashMap<ClassLoader, Set<URL>>();

    // tld by classloader identified by hash on urls (same hash for temp and runtime classloaders)
    // a bit longer to compute but let scanning be reused over temp and runtime classloaders
    private static final Map<Integer, Set<URL>> cacheByhashCode = new WeakHashMap<Integer, Set<URL>>();

    public static Set<URL> scan(final ClassLoader classLoader) throws OpenEJBException {
        if (skip()) {
            return Collections.emptySet();
        }

        if (classLoader == null) {
            return Collections.emptySet();
        }

        final Set<URL> urls = cache.get(classLoader);
        if (urls != null) {
            return urls;
        }

        final Set<URL> result = scanClassLoaderForTagLibs(classLoader);
        cache.put(classLoader, result);

        return result;
    }

    private static boolean skip() {
        return !"true".equalsIgnoreCase(SystemInstance.get().getProperty("openejb.taglib.scan", "true"));
    }

    public static Set<URL> scanClassLoaderForTagLibs(final ClassLoader classLoader) throws OpenEJBException {
        if (skip()) {
            return Collections.emptySet();
        }

        final Set<URL> tldUrls = new HashSet<>();

        if (classLoader == null) {
            return tldUrls;
        }
        if (classLoader == Object.class.getClassLoader()) {
            return tldUrls;
        }

        final List<URL> urls = urls(classLoader);

        final int hashCodeForUrls = hash(urls);
        final Set<URL> cachedSet = cacheByhashCode.get(hashCodeForUrls);
        if (cachedSet != null) {
            return cachedSet;
        }

        tldUrls.addAll(scan(classLoader.getParent()));

        if (urls.size() > 0) {
            final ExecutorService es = Executors.newFixedThreadPool(
                    Math.min(urls.size(), 2 * Runtime.getRuntime().availableProcessors() + 1),
                    new DaemonThreadFactory("OpenEJB-tld-server-scanning"));

            final Collection<Future<Set<URL>>> futures = new ArrayList<>(urls.size());
            for (URL url : urls) {
                if (url.getProtocol().equals("jar")) {
                    try {
                        String path = url.getPath();
                        if (path.endsWith("!/")) {
                            path = path.substring(0, path.length() - 2);
                        }
                        url = new URL(path);
                    } catch (final MalformedURLException e) {
                        DeploymentLoader.LOGGER.warning("JSP tag library location bad: " + url.toExternalForm(), e);
                        continue;
                    }
                }

                if (!url.getProtocol().equals("file")) {
                    continue;
                }

                final File file;
                try {
                    file = toFile(url).getCanonicalFile().getAbsoluteFile();
                } catch (final IOException e) {
                    DeploymentLoader.LOGGER.warning("JSP tag library location bad: " + url.toExternalForm(), e);
                    continue;
                }

                futures.add(es.submit(new Callable<Set<URL>>() {
                    @Override
                    public Set<URL> call() throws Exception {
                        return scanForTagLibs(file);
                    }
                }));
            }

            es.shutdown();

            for (final Future<Set<URL>> set : futures) {
                try {
                    tldUrls.addAll(set.get());
                } catch (final Exception e) {
                    // no-op
                }
            }
        }

        cacheByhashCode.put(hashCodeForUrls, tldUrls);

        return tldUrls;
    }

    static Set<URL> scanWarForTagLibs(final File war) {
        final Set<URL> urls = new HashSet<>();

        final File webInfDir = new File(war, "WEB-INF");
        if (!webInfDir.isDirectory()) {
            return urls;
        }


        // skip the lib and classes dir in WEB-INF
        final LinkedList<File> files = new LinkedList<>();
        final File[] list = webInfDir.listFiles();
        if (list != null) {
            for (final File file : list) {
                if ("lib".equals(file.getName()) || "classes".equals(file.getName())) {
                    continue;
                }
                files.add(file);
            }
        }
        final File webInfMetaInf = new File(webInfDir, "classes/META-INF");
        if (webInfMetaInf.exists()) {
            // filter directly to let it be faster in next loop
            files.addAll(asList(webInfMetaInf.listFiles(new FilenameFilter() {
                @Override
                public boolean accept(final File dir, final String name) {
                    return name.endsWith(".tld");
                }
            })));
        }

        if (files.isEmpty()) {
            return urls;
        }

        // recursively scan the directories
        while (!files.isEmpty()) {
            File file = files.removeFirst();
            if (file.isDirectory()) {
                final File[] a = file.listFiles();
                if (a != null) {
                    files.addAll(asList(a));
                }
            } else if (file.getName().endsWith(".tld")) {
                try {
                    file = file.getCanonicalFile().getAbsoluteFile();
                    urls.add(file.toURI().toURL());
                } catch (final IOException e) {
                    DeploymentLoader.LOGGER.warning("JSP tag library location bad: " + file.getAbsolutePath(), e);
                }
            }
        }

        return urls;
    }

    static Set<URL> scanForTagLibs(final File file) {
        final Set<URL> tldLocations = new HashSet<>();
        try {
            final String location = file.toURI().toURL().toExternalForm();

            if (location.endsWith(".jar")) {
                final Set<URL> urls = scanJarForTagLibs(file);
                tldLocations.addAll(urls);
            } else if (file.getName().endsWith(".tld")) {
                final URL url = file.toURI().toURL();
                tldLocations.add(url);
            }
        } catch (final IOException e) {
            DeploymentLoader.LOGGER.warning("Error scanning for JSP tag libraries: " + file.getAbsolutePath(), e);
        }

        return tldLocations;
    }

    static Set<URL> scanJarForTagLibs(final File file) {
        final Set<URL> urls = new HashSet<>();

        if (!file.isFile()) {
            return urls;
        }

        try (JarFile jarFile = new JarFile(file)) {

            final URL jarFileUrl = new URL("jar", "", -1, file.toURI().toURL().toExternalForm() + "!/");
            for (final JarEntry entry : Collections.list(jarFile.entries())) {
                final String name = entry.getName();
                if (!name.startsWith("META-INF/") || !name.endsWith(".tld")) {
                    continue;
                }
                final URL url = new URL(jarFileUrl, name);
                urls.add(url);
            }
        } catch (final IOException e) {
            DeploymentLoader.LOGGER.warning("Error scanning jar for JSP tag libraries: " + file.getAbsolutePath(), e);
        }
        // exception ignored

        return urls;
    }

    // mainly used to forget a classloader (temp one generally) but keep scanning info from classloader urls
    public static void quickClean(final ClassLoader loader) {
        if (loader == null) {
            return;
        }

        cache.remove(loader);
        if (loader.getParent() != TldScanner.class.getClassLoader()) { // for ears
            quickClean(loader.getParent());
        }
    }

    // this method clean the cacheByhash too
    public static void forceCompleteClean(final ClassLoader loader) {
        if (loader == null) {
            return;
        }

        quickClean(loader);
        cacheByhashCode.remove(hash(urls(loader)));

        if (loader.getParent() != TldScanner.class.getClassLoader()) { // for ears
            forceCompleteClean(loader.getParent());
        }
    }

    private static List<URL> urls(final ClassLoader classLoader) {
        UrlSet urlSet = new UrlSet();

        if (classLoader instanceof URLClassLoader) {

            final URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
            try {
                urlSet = new UrlSet(urlClassLoader.getURLs());
            } catch (final NullPointerException npe) { // happen for closeable classloaders like WebappClassLoader when already clean up
                return Collections.emptyList();
            }

        } else {
            try {
                urlSet = new UrlSet(classLoader);
            } catch (final IOException e) {
                DeploymentLoader.LOGGER.warning("Error scanning class loader for JSP tag libraries", e);
            }
        }

        try {
            urlSet = URLs.cullSystemJars(urlSet);
            urlSet = applyBuiltinExcludes(
                    urlSet,
                    Filters.tokens("taglibs-shade", "taglibs-standard-impl", "taglibs-standard-jstlel", "javax.faces-2.", "jakarta.faces-2", "spring-security-taglibs", "spring-webmvc"),
                    Filters.prefixes("commons-jcs-", "myfaces-", "tomcat-websocket.jar")); // myfaces is hardcoded in tomee
        } catch (final IOException e) {
            DeploymentLoader.LOGGER.warning("Error scanning class loader for JSP tag libraries", e);
        }

        return urlSet.getUrls();
    }

    private static int hash(final List<URL> urls) {
        int hash = 0;
        for (final URL u : urls) {
            hash *= 31;
            if (u != null) {
                hash += u.toExternalForm().hashCode(); // url.hashCode() can be slow offline
            }
        }
        return hash;
    }
}
