/*
 * Copyright 2008-2012 Red Hat, Inc, and individual contributors.
 * 
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.torquebox.bootstrap.as;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.jar.JarFile;

import org.jboss.logging.Logger;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleClassLoader;
import org.jboss.modules.ModuleLoader;
import org.jboss.modules.ResourceLoader;
import org.jboss.modules.ResourceLoaderSpec;
import org.jboss.modules.ResourceLoaders;
import org.torquebox.bootstrap.JRubyHomeLocator;

public class TorqueBoxBootstrapper {
    private static final Logger log = Logger.getLogger( "org.torquebox.bootstrap" );

    static {
        log.debug( "Bootstrapping TorqueBox" );

        String jrubyHome = JRubyHomeLocator.determineJRubyHome( true );

        if (jrubyHome == null) {
            log.fatal( "Unable to find a JRuby Home" );
        } else {

            log.info( "Bootstrapping TorqueBox with a JRuby home of " + jrubyHome );

            System.setProperty( "jruby.home", jrubyHome );

            File libDir = new File( jrubyHome, "lib" );

            if (!libDir.exists()) {
                // we can't throw here, since any exception will be swallowed, and a NoClassDefFoundError thrown
                // instead since we are in a static initializer
                log.fatal( "============================================================================================" );                        
                log.fatal( "********************************************************************************************" );                        
                log.fatal( "No lib dir found in " + jrubyHome + " - confirm that you are setting JRUBY_HOME properly" );
                log.fatal( "********************************************************************************************" );                        
                log.fatal( "============================================================================================" );
            }
            
            List<ResourceLoaderSpec> loaderSpecs = new ArrayList<ResourceLoaderSpec>();

            for (File child : libDir.listFiles()) {
                if (child.getName().endsWith( ".jar" )) {
                    log.debug( "Adding: " + child );
                    try {
                        ResourceLoader loader = ResourceLoaders.createJarResourceLoader( child.getName(), new JarFile( child ) );
                        ResourceLoaderSpec loaderSpec = ResourceLoaderSpec.createResourceLoaderSpec( loader );
                        loaderSpecs.add( loaderSpec );
                    } catch (IOException e) {
                        log.error( e );
                    }
                }
            }

            swizzleResourceLoaders( loaderSpecs );
        }
    }
    
    private static ResourceLoader[] getExistingResourceLoaders() throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException,
            InvocationTargetException {
        Module module = Module.forClass( TorqueBoxBootstrapper.class );
        ModuleClassLoader cl = module.getClassLoader();

        Method method = ModuleClassLoader.class.getDeclaredMethod( "getResourceLoaders" );
        method.setAccessible( true );
        Object result = method.invoke( cl );

        return (ResourceLoader[]) result;

    }

    private static void swizzleResourceLoaders(List<ResourceLoaderSpec> loaderSpecs) {

        Module module = Module.forClass( TorqueBoxBootstrapper.class );
        ModuleLoader moduleLoader = module.getModuleLoader();

        try {
            for (ResourceLoader each : getExistingResourceLoaders()) {
                loaderSpecs.add( ResourceLoaderSpec.createResourceLoaderSpec( each ) );
            }

            Method method = ModuleLoader.class.getDeclaredMethod( "setAndRefreshResourceLoaders", Module.class, Collection.class );
            method.setAccessible( true );
            log.debug( "Swizzle: " + loaderSpecs );
            method.invoke( moduleLoader, module, loaderSpecs );

            Method refreshMethod = ModuleLoader.class.getDeclaredMethod( "refreshResourceLoaders", Module.class );
            refreshMethod.setAccessible( true );
            refreshMethod.invoke( moduleLoader, module );

            Method relinkMethod = ModuleLoader.class.getDeclaredMethod( "relink", Module.class );
            relinkMethod.setAccessible( true );
            relinkMethod.invoke( moduleLoader, module );
        } catch (SecurityException e) {
            log.fatal( e.getMessage(), e );
        } catch (NoSuchMethodException e) {
            log.fatal( e.getMessage(), e );
        } catch (IllegalArgumentException e) {
            log.fatal( e.getMessage(), e );
        } catch (IllegalAccessException e) {
            log.fatal( e.getMessage(), e );
        } catch (InvocationTargetException e) {
            log.fatal( e.getMessage(), e );
        }

    }

}

@@ -1000,137 +1000,45 @@
 ava.
-lang.reflect.Method;%0Aimport java.util.ArrayList;%0Aimport java.util.Collection;%0Aimport java.util.List;%0Aimport java.util.jar.JarFile
+util.ArrayList;%0Aimport java.util.List
 ;%0A%0Ai
@@ -1098,58 +1098,26 @@
 les.
-Module;%0Aimport org.jboss.modules.ModuleClass
+Resource
 Loader
+Spec
 ;%0Aim
@@ -1129,146 +1129,37 @@
 org.
-jboss.modules.ModuleLoader;%0Aimport org.jboss.modules.ResourceLoader;%0Aimport org.jboss.modules.ResourceLoaderSpec;%0Aimport org.jboss.modules
+projectodd.polyglot.core.util
 .Res
@@ -1169,17 +1169,20 @@
 ceLoader
-s
+Util
 ;%0Aimport
@@ -3032,1273 +3032,372 @@
     
-ResourceLoader loader = ResourceLoaders.createJarResourceLoader( child.getName(), new JarFile( child ) );%0A                        ResourceLoaderSpec loaderSpec = ResourceLoaderSpec.createResourceLoaderSpec( loader );%0A                        loaderSpecs.add( loaderSpec );%0A                    %7D catch (IOException e) %7B%0A                        log.error( e );%0A                    %7D%0A                %7D%0A            %7D%0A%0A            swizzleResourceLoaders( loaderSpecs );%0A        %7D%0A    %7D%0A    %0A    private static ResourceLoader%5B%5D getExistingResourceLoaders() throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException,%0A            InvocationTargetException %7B%0A        Module module = Module.forClass( TorqueBoxBootstrapper.class );%0A        ModuleClassLoader cl = module.getClassLoader();%0A%0A        Method method = ModuleClassLoader.class.getDeclaredMethod( %22getResourceLoaders%22 );%0A        method.setAccessible( true );%0A        Object result = method.invoke( cl );%0A%0A        return (ResourceLoader%5B%5D) result;%0A%0A    %7D%0A%0A    private static void swizzleResourceLoaders(List%3CResourceLoaderSpec%3E loaderSpecs) %7B%0A%0A        Module module = Module.forClass( TorqueBoxBootstrapper.class );%0A        ModuleLoader moduleLoader = module.getModuleLoader();%0A
+loaderSpecs.add( ResourceLoaderUtil.createLoaderSpec( child ) );%0A                    %7D catch (IOException e) %7B%0A                        log.error( e );%0A                    %7D%0A                %7D%0A            %7D%0A%0A            swizzleResourceLoaders( loaderSpecs );%0A        %7D%0A    %7D%0A    %0A    private static void swizzleResourceLoaders(List%3CResourceLoaderSpec%3E loaderSpecs) %7B
 %0A   
@@ -3419,21 +3419,16 @@
         
-for (
 Resource
@@ -3437,863 +3437,91 @@
 ader
- each : getExistingResourceLoaders()) %7B%0A                loaderSpecs.add( ResourceLoaderSpec.createResourceLoaderSpec( each ) );%0A            %7D%0A%0A            Method method = ModuleLoader.class.getDeclaredMethod( %22setAndRefreshResourceLoaders%22, Module.class, Collection.class );%0A            method.setAccessible( true );%0A            log.debug( %22Swizzle: %22 + loaderSpecs );%0A            method.invoke( moduleLoader, module, loaderSpecs );%0A%0A            Method refreshMethod = ModuleLoader.class.getDeclaredMethod( %22refreshResourceLoaders%22, Module.class );%0A            refreshMethod.setAccessible( true );%0A            refreshMethod.invoke( moduleLoader, module );%0A%0A            Method relinkMethod = ModuleLoader.class.getDeclaredMethod( %22relink%22, Module.class );%0A            relinkMethod.setAccessible( true );%0A            relinkMethod.invoke( moduleLoader, modul
+Util.refreshAndRelinkResourceLoaders( TorqueBoxBootstrapper.class, loaderSpecs, tru
 e );

Refactor to use ResourceLoaderUtil from polyglot.