All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.jbee.inject.bootstrap.Bootstrap Maven / Gradle / Ivy

There is a newer version: 0.6
Show newest version
/*
 *  Copyright (c) 2012, Jan Bernitt 
 *			
 *  Licensed under the Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
 */
package se.jbee.inject.bootstrap;

import static se.jbee.inject.Dependency.dependency;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import se.jbee.inject.Array;
import se.jbee.inject.Injector;
import se.jbee.inject.Injectron;
import se.jbee.inject.Type;
import se.jbee.inject.config.Edition;
import se.jbee.inject.config.Feature;
import se.jbee.inject.config.Globals;
import se.jbee.inject.config.Options;
import se.jbee.inject.config.Presets;
import se.jbee.inject.util.Inject;
import se.jbee.inject.util.Metaclass;
import se.jbee.inject.util.Suppliable;

/**
 * Utility to create an {@link Injector} context from {@link Bundle}s and {@link Module}s.
 * 
 * It allos to use {@link Edition}s and {@link Feature}s to modularize or customize context
 * configurations.
 * 
 * @author Jan Bernitt ([email protected])
 */
public final class Bootstrap {

	public static Injector injector( Class root ) {
		return injector( root, Globals.STANDARD );
	}

	public static Injector injector( Class root, Globals globals ) {
		return injector( root, Inspect.DEFAULT, globals );
	}

	public static Injector injector( Class root, Inspector inspector,
			Globals globals ) {
		return injector( modulariser( globals ).modularise( root ), inspector, Link.BUILDIN );
	}

	public static Injector injector( Module[] modules, Inspector inspector,
			Linker> linker ) {
		return Inject.from( Suppliable.source( linker.link( inspector, modules ) ) );
	}

	public static Modulariser modulariser( Globals globals ) {
		return new BuildinBootstrapper( globals );
	}

	public static Bundler bundler( Globals globals ) {
		return new BuildinBootstrapper( globals );
	}

	public static Suppliable[] suppliables( Class root ) {
		return Link.BUILDIN.link( Inspect.DEFAULT,
				modulariser( Globals.STANDARD ).modularise( root ) );
	}

	public static  Module module( PresetModule module, Presets presets ) {
		return new LazyPresetModule( module, presets );
	}

	public static void eagerSingletons( Injector injector ) {
		for ( Injectron i : injector.resolve( dependency( Injectron[].class ) ) ) {
			if ( i.getExpiry().isNever() ) {
				instance( i );
			}
		}
	}

	public static  T instance( Injectron injectron ) {
		return injectron.instanceFor( dependency( injectron.getResource().getInstance() ) );
	}

	public static void nonnullThrowsReentranceException( Object field ) {
		if ( field != null ) {
			throw new IllegalStateException( "Reentrance not allowed!" );
		}
	}

	public static  T instance( Class type ) {
		return Invoke.constructor( Metaclass.accessible( Inspect.noArgsConstructor( type ) ) );
	}

	private Bootstrap() {
		throw new UnsupportedOperationException( "util" );
	}

	private static final class LazyPresetModule
			implements Module {

		private final PresetModule module;
		private final Presets presets;

		LazyPresetModule( PresetModule module, Presets presets ) {
			super();
			this.module = module;
			this.presets = presets;
		}

		@Override
		public void declare( Bindings bindings, Inspector inspector ) {
			@SuppressWarnings ( "unchecked" )
			final T value = (T) presets.value( Type.supertype( PresetModule.class,
					Type.raw( module.getClass() ) ).parameter( 0 ) );
			module.declare( bindings, inspector, value );
		}
	}

	private static class BuildinBootstrapper
			implements Bootstrapper, Bundler, Modulariser {

		private final Map, Set>> bundleChildren = new IdentityHashMap, Set>>();
		private final Map, List> bundleModules = new IdentityHashMap, List>();
		private final Set> uninstalled = new HashSet>();
		private final Set> installed = new HashSet>();
		private final LinkedList> stack = new LinkedList>();
		private final Globals globals;

		BuildinBootstrapper( Globals globals ) {
			super();
			this.globals = globals;
		}

		@Override
		public void install( Class bundle ) {
			if ( uninstalled.contains( bundle ) || installed.contains( bundle ) ) {
				return;
			}
			if ( !globals.edition.featured( bundle ) ) {
				uninstalled.add( bundle ); // this way we will never ask again - something not featured is finally not featured
				return;
			}
			installed.add( bundle );
			if ( !stack.isEmpty() ) {
				final Class parent = stack.peek();
				Set> children = bundleChildren.get( parent );
				if ( children == null ) {
					children = new LinkedHashSet>();
					bundleChildren.put( parent, children );
				}
				children.add( bundle );
			}
			stack.push( bundle );
			Bootstrap.instance( bundle ).bootstrap( this );
			if ( stack.pop() != bundle ) {
				throw new IllegalStateException( bundle.getCanonicalName() );
			}
		}

		@Override
		public > void install( Class> bundle,
				final Class property ) {
			if ( !globals.edition.featured( property ) ) {
				return;
			}
			final Options options = globals.options;
			Bootstrap.instance( bundle ).bootstrap( new ModularBootstrapper() {

				@Override
				public void install( Class bundle, C module ) {
					if ( options.isChosen( property, module ) ) { // null is a valid value to define what happens when no configuration is present
						BuildinBootstrapper.this.install( bundle );
					}
				}
			} );
		}

		@Override
		public final  & ModularBundle> void install( M... modules ) {
			if ( modules.length > 0 ) {
				final M bundle = modules[0];
				if ( !globals.edition.featured( bundle.getClass() ) ) {
					return;
				}
				final EnumSet installing = EnumSet.of( bundle, modules );
				bundle.bootstrap( new ModularBootstrapper() {

					@Override
					public void install( Class bundle, M module ) {
						if ( installing.contains( module ) ) {
							BuildinBootstrapper.this.install( bundle );
						}
					}
				} );
			}
		}

		@Override
		public void install( Module module ) {
			Class bundle = stack.peek();
			if ( uninstalled.contains( bundle ) || !globals.edition.featured( module.getClass() ) ) {
				return;
			}
			List modules = bundleModules.get( bundle );
			if ( modules == null ) {
				modules = new ArrayList();
				bundleModules.put( bundle, modules );
			}
			modules.add( module );
		}

		@Override
		public  void install( PresetModule module ) {
			install( module( module, globals.presets ) );
		}

		@Override
		public Module[] modularise( Class root ) {
			return modulesOf( bundle( root ) );
		}

		@SuppressWarnings ( "unchecked" )
		@Override
		public Class[] bundle( Class root ) {
			if ( !installed.contains( root ) ) {
				install( root );
			}
			Set> installed = new LinkedHashSet>();
			addAllInstalledIn( root, installed );
			return Array.of( installed, Class.class );
		}

		private Module[] modulesOf( Class[] bundles ) {
			List installed = new ArrayList( bundles.length );
			for ( Class b : bundles ) {
				List modules = bundleModules.get( b );
				if ( modules != null ) {
					installed.addAll( modules );
				}
			}
			return Array.of( installed, Module.class );
		}

		@Override
		public void uninstall( Class bundle ) {
			if ( uninstalled.contains( bundle ) ) {
				return;
			}
			uninstalled.add( bundle );
			installed.remove( bundle );
			for ( Set> c : bundleChildren.values() ) {
				c.remove( bundle );
			}
			bundleModules.remove( bundle ); // we are sure we don't need its modules
		}

		@Override
		public final  & ModularBundle> void uninstall( M... modules ) {
			if ( modules.length > 0 ) {
				final EnumSet uninstalling = EnumSet.of( modules[0], modules );
				modules[0].bootstrap( new ModularBootstrapper() {

					@Override
					public void install( Class bundle, M module ) {
						if ( uninstalling.contains( module ) ) {
							uninstall( bundle );
						}
					}
				} );
			}
		}

		private void addAllInstalledIn( Class bundle,
				Set> accu ) {
			accu.add( bundle );
			Set> children = bundleChildren.get( bundle );
			if ( children == null ) {
				return;
			}
			for ( Class c : children ) {
				if ( !accu.contains( c ) ) {
					addAllInstalledIn( c, accu );
				}
			}
		}

	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy