package org.jboss.shrinkwrap.impl.base.spec;

import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

import junit.framework.Assert;
import org.jboss.shrinkwrap.api.ConfigurationBuilder;
import org.jboss.shrinkwrap.api.Domain;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jboss.shrinkwrap.impl.base.spec.donotchange.DummyClassA;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author Ken Finnigan
 */
public class AddPackageFromWarWithNonRootClassloaderTest {

    private Domain domain;

    private Path temp;

    @Before
    public void setUp() throws IOException {

        ConfigurationBuilder builder = new ConfigurationBuilder();
        WebArchive war = ShrinkWrap.create(WebArchive.class, "my.war");
        war.addClass(DummyClassA.class);

        this.temp = Files.createTempFile("test", ".war");
        war.as(ZipExporter.class).exportTo(temp.toFile(), true);
        URL warUrl = temp.toUri().toURL();

        List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();

        URLClassLoader warCl = new NonRootURLClassloader(new URL[]{warUrl}, null);
        classLoaders.add(warCl);

        ClassLoader shrinkwrapCl = new FilteringClassLoader(this.getClass().getClassLoader());
        classLoaders.add(shrinkwrapCl);

        builder.classLoaders(classLoaders);

        // Create a domain that includes the `donotchange` classes within a .war
        // and the rest, excluding `donotchange` from the regular app classloader.
        this.domain = ShrinkWrap.createDomain(builder.build());
    }

    @After
    public void tearDown() throws IOException {
        Files.delete( this.temp );
    }

    @Test
    public void testAddPackage() {
        // This archive's classloaders should be the app classloader (without `donotchange`)
        // and an .war-based classloader including the `donotchange` within WEB-INF/classes/...

        JavaArchive jar = this.domain.getArchiveFactory().create(JavaArchive.class);
        jar.addPackage("org.jboss.shrinkwrap.impl.base.spec.donotchange" );
        Assert.assertNotNull( jar.get( "/" + DummyClassA.class.getName().replace( '.', '/' ) + ".class" ) );
    }

    /** Classloader to ensure the donotchange bits are not loaded through
     * the app-classloader, while still enabling the default ShrinkWrap
     * bits to be found through the junit test.
     */
    private static class FilteringClassLoader extends ClassLoader {

        public FilteringClassLoader(ClassLoader parent) {
            super(parent);
        }

        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            if (name.contains("donotchange")) {
                return null;
            }
            return super.loadClass(name);
        }

        @Override
        public Enumeration<URL> getResources(String name) throws IOException {
            if (name.contains("donotchange")) {
                return Collections.emptyEnumeration();
            }
            return super.getResources(name);
        }

    }

    private static class NonRootURLClassloader extends URLClassLoader {

        public NonRootURLClassloader(URL[] urls, ClassLoader parent) {
            super(urls, parent);
        }

        @Override
        public Enumeration<URL> findResources(String name) throws IOException {
            return super.findResources("WEB-INF/classes/" + name);
        }
    }
}
