package org.nnsoft.guice.autobind.scanner; /* * Copyright 2012 The 99 Software Foundation * * Licensed 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. */ import static org.nnsoft.guice.autobind.jsr330.Names.named; import static com.google.inject.TypeLiteral.get; import static com.google.inject.Guice.createInjector; import static java.lang.System.getProperty; import static java.util.Collections.addAll; import static java.util.logging.Level.FINE; import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; import java.io.File; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Logger; import org.nnsoft.guice.autobind.annotations.features.AutoBindingFeature; import org.nnsoft.guice.autobind.annotations.features.ImplementationBindingFeature; import org.nnsoft.guice.autobind.annotations.features.ModuleBindingFeature; import org.nnsoft.guice.autobind.annotations.features.MultiBindingFeature; import org.nnsoft.guice.autobind.install.BindingTracer; import org.nnsoft.guice.autobind.install.InstallationContext; import org.nnsoft.guice.autobind.install.bindjob.BindingJob; import org.nnsoft.guice.autobind.scanner.features.ScannerFeature; import com.google.inject.AbstractModule; import com.google.inject.Binder; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.multibindings.Multibinder; /** * The StartupModule is used for creating an initial Injector, which binds and * instantiates the Scanning module. Due the fact that we have multiple Scanner * Implementations, you have to pass the Class for the Scanner and the Packages * which should be scanned. You can override the bindAnnotationListeners-Method, * to add your own {@link ScannerFeature}. */ public abstract class StartupModule extends AbstractModule { protected final Logger _logger = getLogger( getClass().getName() ); protected PackageFilter[] _packages; protected Class<? extends ClasspathScanner> _scanner; protected List<Class<? extends ScannerFeature>> _features = new ArrayList<Class<? extends ScannerFeature>>(); protected boolean bindSystemProperties; protected boolean bindEnvironment; protected boolean bindStartupConfiguration = true; protected boolean verbose = ( getProperty( "org.nnsoft.guice.autobind.verbose" ) != null ? true : false ); public StartupModule( Class<? extends ClasspathScanner> scanner, PackageFilter... filter ) { _packages = ( filter == null ? new PackageFilter[0] : filter ); _scanner = scanner; } @Override public void configure() { List<PackageFilter> packages = new ArrayList<PackageFilter>(); addAll( packages, _packages ); addAll( packages, bindPackages() ); _packages = packages.toArray( new PackageFilter[packages.size()] ); Module scannerModule = new AbstractModule() { @Override protected void configure() { Binder binder = binder(); if ( _logger.isLoggable( FINE ) ) { _logger.fine( "Binding ClasspathScanner to " + _scanner.getName() ); for ( PackageFilter p : _packages ) { _logger.fine( "Using Package " + p + " for scanning." ); } } binder.bind( InstallationContext.class ).asEagerSingleton(); binder.bind( ClasspathScanner.class ).to( _scanner ); binder.bind( get( PackageFilter[].class ) ).annotatedWith( named( "packages" ) ).toInstance( _packages ); Set<URL> classpath = findClassPaths(); binder.bind( get( URL[].class ) ).annotatedWith( named( "classpath" ) ).toInstance( classpath.toArray( new URL[classpath.size()] ) ); bindFeatures( binder ); } }; // ConfigurationModule configurationModule = new ConfigurationModule(); // if (bindSystemProperties) { // configurationModule.addConfigurationReader(new SystemPropertiesReader()); // } // if (bindEnvironment) { // configurationModule.addConfigurationReader(new EnvironmentVariablesReader()); // } // if(bindStartupConfiguration){ // URL startup = getClass().getResource("/conf/startup.xml"); // if(startup != null){ // try { // URI startupURI = startup.toURI(); // _logger.log(INFO, "Startup Config is used from Path: "+startupURI); // configurationModule.addConfigurationReader(new PropertiesURLReader(new File(startupURI), true)); // } catch (URISyntaxException e) { // _logger.log(INFO, "Startup Config couldn't be found in Classpath.", e); // } // }else{ // _logger.log(INFO, "Startup Config couldn't be found, so it is not used."); // } // } // Injector internal = Guice.createInjector(scannerModule, configurationModule); Injector internal = createInjector( scannerModule ); binder().install( internal.getInstance( ScannerModule.class ) ); // binder().install(configurationModule); if ( verbose ) { BindingTracer tracer = internal.getInstance( BindingTracer.class ); StringBuilder builder = new StringBuilder( "Following Binding were processed.\n" ); for ( BindingJob job : tracer ) { builder.append( job.toString() ).append( "\n" ); } _logger.info( builder.toString() ); } } protected abstract Multibinder<ScannerFeature> bindFeatures( Binder binder ); protected PackageFilter[] bindPackages() { return new PackageFilter[0]; } protected Set<URL> findClassPaths() { Set<URL> urlSet = new HashSet<URL>(); ClassLoader loader = Thread.currentThread().getContextClassLoader(); while ( loader != null ) { if ( loader instanceof URLClassLoader ) { URL[] urls = ( (URLClassLoader) loader ).getURLs(); Collections.addAll( urlSet, urls ); } loader = loader.getParent(); } String classpath = System.getProperty( "java.class.path" ); if ( classpath != null && classpath.length() > 0 ) { try { URL resource = StartupModule.class.getResource( "/" ); if ( resource == null ) { String className = StartupModule.class.getName().replace( '.', '/' ) + ".class"; resource = StartupModule.class.getResource( className ); if ( resource != null ) { String url = resource.toExternalForm(); url = url.substring( 0, url.length() - className.length() ); resource = new URL( url ); } } if ( resource != null ) { classpath = classpath + File.pathSeparator + new File( resource.toURI() ).getAbsolutePath(); } } catch ( URISyntaxException e ) { // FIXME ignore for now } catch ( MalformedURLException e ) { // FIXME ignore for now } for ( String path : classpath.split( File.pathSeparator ) ) { File file = new File( path ); try { if ( file.exists() ) { urlSet.add( file.toURI().toURL() ); } } catch ( MalformedURLException e ) { _logger.log( INFO, "Found invalid URL in Classpath: " + path, e ); } } } return urlSet; } public StartupModule addFeature( Class<? extends ScannerFeature> listener ) { _features.add( listener ); return this; } public StartupModule bindSystemProperties() { bindSystemProperties = true; return this; } public StartupModule disableStartupConfiguration() { bindStartupConfiguration = false; return this; } public StartupModule bindEnvironment() { bindEnvironment = true; return this; } public void verbose() { verbose = true; } public static StartupModule create( Class<? extends ClasspathScanner> scanner, PackageFilter... filter ) { return new DefaultStartupModule( scanner, filter ); } public static class DefaultStartupModule extends StartupModule { public DefaultStartupModule( Class<? extends ClasspathScanner> scanner, PackageFilter... filter ) { super( scanner, filter ); } @Override protected Multibinder<ScannerFeature> bindFeatures( Binder binder ) { Multibinder<ScannerFeature> listeners = Multibinder.newSetBinder( binder, ScannerFeature.class ); listeners.addBinding().to( AutoBindingFeature.class ); listeners.addBinding().to( ImplementationBindingFeature.class ); listeners.addBinding().to( MultiBindingFeature.class ); listeners.addBinding().to( ModuleBindingFeature.class ); for ( Class<? extends ScannerFeature> listener : _features ) { listeners.addBinding().to( listener ); } return listeners; } @Override protected PackageFilter[] bindPackages() { // return new PackageFilter[] { PackageFilter.create(ConfigurationModule.class, false) }; return new PackageFilter[0]; } } }