/*******************************************************************************
 * Copyright (c) 2010-present Sonatype, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Stuart McCulloch (Sonatype, Inc.) - initial API and implementation
 *******************************************************************************/
package org.eclipse.sisu.launch;

import java.util.Collections;
import java.util.Map;

import javax.inject.Inject;

import org.eclipse.sisu.Parameters;
import org.eclipse.sisu.inject.MutableBeanLocator;
import org.eclipse.sisu.space.BeanScanning;
import org.eclipse.sisu.space.SpaceModule;
import org.eclipse.sisu.space.URLClassSpace;
import org.eclipse.sisu.wire.ParameterKeys;
import org.eclipse.sisu.wire.WireModule;

import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provides;

/**
 * Bootstrap class that creates a static {@link Injector} by scanning the current class-path for beans.
 */
public final class Main
    implements Module
{
    // ----------------------------------------------------------------------
    // Implementation fields
    // ----------------------------------------------------------------------

    private final Map<?, ?> properties;

    private final String[] args;

    // ----------------------------------------------------------------------
    // Constructors
    // ----------------------------------------------------------------------

    private Main( final Map<?, ?> properties, final String... args )
    {
        this.properties = Collections.unmodifiableMap( properties );
        this.args = args;
    }

    // ----------------------------------------------------------------------
    // Public entry points
    // ----------------------------------------------------------------------

    public static void main( final String... args )
    {
        boot( System.getProperties(), args );
    }

    public static <T> T boot( final Class<T> type, final String... args )
    {
        return boot( System.getProperties(), args ).getInstance( type );
    }

    public static Injector boot( final Map<?, ?> properties, final String... args )
    {
        final BeanScanning scanning = BeanScanning.select( properties );
        final Module app = wire( scanning, new Main( properties, args ) );
        final Injector injector = Guice.createInjector( app );

        return injector;
    }

    public static Module wire( final BeanScanning scanning, final Module... bindings )
    {
        final Module[] modules = new Module[bindings.length + 1];
        System.arraycopy( bindings, 0, modules, 0, bindings.length );

        final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
        modules[bindings.length] = new SpaceModule( new URLClassSpace( tccl ), scanning );

        return new WireModule( modules );
    }

    // ----------------------------------------------------------------------
    // Public methods
    // ----------------------------------------------------------------------

    public void configure( final Binder binder )
    {
        binder.bind( ParameterKeys.PROPERTIES ).toInstance( properties );
        binder.bind( ShutdownThread.class ).asEagerSingleton();
    }

    // ----------------------------------------------------------------------
    // Implementation methods
    // ----------------------------------------------------------------------

    @Provides
    @Parameters
    String[] parameters()
    {
        return args.clone();
    }

    // ----------------------------------------------------------------------
    // Implementation types
    // ----------------------------------------------------------------------

    static final class ShutdownThread
        extends Thread
    {
        private final MutableBeanLocator locator;

        @Inject
        ShutdownThread( final MutableBeanLocator locator )
        {
            this.locator = locator;

            Runtime.getRuntime().addShutdownHook( this );
        }

        @Override
        public void run()
        {
            locator.clear();
        }
    }
}

@@ -2381,79 +2381,640 @@
 tic 
-Injector boot( final Map%3C?, ?%3E properties, final String... args )%0A    %7B
+%3CT%3E T boot( final Class%3CT%3E type, final String%5B%5D args, final Module... bindings )%0A    %7B%0A        return boot( System.getProperties(), args, bindings ).getInstance( type );%0A    %7D%0A%0A    public static Injector boot( final Map%3C?, ?%3E properties, final String... args )%0A    %7B%0A        return boot( properties, args, new Module%5B0%5D );%0A    %7D%0A%0A    public static Injector boot( final Map%3C?, ?%3E properties, final String%5B%5D args, final Module... bindings )%0A    %7B%0A        final Module%5B%5D modules = new Module%5Bbindings.length + 1%5D;%0A        System.arraycopy( bindings, 0, modules, 1, bindings.length );%0A        modules%5B0%5D = new Main( properties, args );%0A
 %0A   
@@ -3130,36 +3130,15 @@
 ng, 
-new Main( properties, args )
+modules
  );%0A

Extend Main with entry point to boot application with additional bindings (#50)