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

org.dbrain.binder.system.app.BindingBuilderImpl Maven / Gradle / Ivy

There is a newer version: 0.13
Show newest version
/*
 * Copyright [2015] [Eric Poitras]
 *
 *     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.
 */

package org.dbrain.binder.system.app;

import org.dbrain.binder.app.App;
import org.dbrain.binder.app.Binder;
import org.dbrain.binder.app.ServiceConfigurator;
import org.dbrain.binder.system.lifecycle.BaseClassAnalyzer;
import org.dbrain.binder.system.util.AnnotationBuilder;
import org.glassfish.hk2.api.ClassAnalyzer;
import org.glassfish.hk2.api.Descriptor;
import org.glassfish.hk2.api.DynamicConfiguration;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.FactoryDescriptors;
import org.glassfish.hk2.api.MultiException;
import org.glassfish.hk2.api.PerLookup;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.AbstractActiveDescriptor;
import org.glassfish.hk2.utilities.ActiveDescriptorBuilder;
import org.glassfish.hk2.utilities.BuilderHelper;
import org.glassfish.hk2.utilities.reflection.ParameterizedTypeImpl;

import javax.inject.Named;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * Service configuration description.
 */
public class BindingBuilderImpl implements ServiceConfigurator {

    private ServiceProvider provider;

    private ServiceDisposer disposer;

    private final Set services = new HashSet<>();

    private final Set qualifiers = new HashSet<>();

    private Class scope;

    private boolean useProxy = false;

    public BindingBuilderImpl( App app, Binder.BindingContext cc, DynamicConfiguration dc, Class serviceProviderClass ) {
        Objects.requireNonNull( app );
        Objects.requireNonNull( cc );
        Objects.requireNonNull( dc );
        Objects.requireNonNull( serviceProviderClass );

        cc.onBind( ( binder ) -> {
            try {
                // Retrieve an instance of the service locator.
                ServiceLocator sl = app.getInstance( ServiceLocator.class );

                Factory factory = null;
                if ( provider != null || disposer != null ) {
                    ServiceProvider finalProvider = provider;
                    ServiceDisposer finalDisposer = disposer;
                    if ( finalProvider == null ) {
                        finalProvider = new StandardProvider<>( app, serviceProviderClass );
                    }
                    if ( finalDisposer == null ) {
                        finalDisposer = new StandardDisposer<>( app, serviceProviderClass );
                    }
                    factory = new StandardFactory<>( finalProvider, finalDisposer );
                }

                AbstractActiveDescriptor factoryDescriptor;
                ActiveDescriptorBuilder serviceDescriptor;
                if ( factory != null ) {
                    factoryDescriptor = BuilderHelper.createConstantDescriptor( factory );
                    factoryDescriptor.addContractType( Factory.class );
                    serviceDescriptor = BuilderHelper.activeLink( factory.getClass() );
                } else {
                    factoryDescriptor = null;
                    serviceDescriptor = BuilderHelper.activeLink( serviceProviderClass );
                }

                List finalServices = new ArrayList<>( services );
                if ( finalServices.size() == 0 ) {
                    finalServices.add( serviceProviderClass );
                }
                for ( Type service : finalServices ) {
                    serviceDescriptor.to( service );
                    if ( factoryDescriptor != null ) {
                        factoryDescriptor.addContractType( new ParameterizedTypeImpl( Factory.class, service ) );
                    }
                }

                for ( Annotation a : qualifiers ) {
                    serviceDescriptor.qualifiedBy( a );
                    if ( factoryDescriptor != null ) {
                        factoryDescriptor.addQualifierAnnotation( a );
                    }
                }

                if ( scope != null ) {
                    serviceDescriptor.in( scope );
                } else {
                    serviceDescriptor.in( PerLookup.class );
                }

                if ( useProxy ) {
                    serviceDescriptor.proxy();
                }

                if ( factoryDescriptor == null ) {
                    dc.bind( sl.reifyDescriptor( serviceDescriptor.build() ) );
                } else {
                    dc.bind( new FactoryDescriptorsImpl( factoryDescriptor, serviceDescriptor.buildProvideMethod() ) );
                }
            } catch ( RuntimeException e ) {
                throw e;
            } catch ( Exception e ) {
                throw new MultiException( e );
            }

        } );
    }

    @Override
    public ServiceConfigurator toInstance( final T instance ) {
        return providedBy( () -> instance );
    }

    @Override
    public ServiceConfigurator providedBy( ServiceProvider provider ) {
        this.provider = provider;
        return this;
    }

    @Override
    public ServiceConfigurator disposedBy( ServiceDisposer disposer ) {
        this.disposer = disposer;
        return this;
    }

    @Override
    public ServiceConfigurator to( Type type ) {
        services.add( type );
        return this;
    }

    @Override
    public ServiceConfigurator qualifiedBy( Annotation quality ) {
        qualifiers.add( quality );
        return this;
    }

    @Override
    public ServiceConfigurator qualifiedBy( Class quality ) {
        return qualifiedBy( AnnotationBuilder.of( quality ) );
    }

    @Override
    public ServiceConfigurator qualifiedBy( Iterable qualities ) {
        for ( Annotation quality : qualities ) {
            qualifiedBy( quality );
        }
        return this;
    }

    @Override
    public ServiceConfigurator named( String name ) {
        return qualifiedBy( AnnotationBuilder.from( Named.class ).value( name ).build() );
    }

    @Override
    public ServiceConfigurator in( Class scope ) {
        this.scope = scope;
        return this;
    }

    @Override
    public ServiceConfigurator useProxy() {
        this.useProxy = true;
        return this;
    }

    private static class StandardProvider implements ServiceProvider {

        private final ServiceLocator serviceLocator;
        private final Class       implClass;

        public StandardProvider( App app, Class implClass ) {
            this.serviceLocator = app.getInstance( ServiceLocator.class );
            this.implClass = implClass;
        }

        @Override
        public T get() {
            return serviceLocator.create( implClass );
        }
    }

    private static class StandardDisposer implements ServiceDisposer {

        private final App      app;
        private final Class implClass;

        public StandardDisposer( App app, Class implClass ) {
            this.app = app;
            this.implClass = implClass;
        }

        @Override
        public void dispose( T t ) {
            if ( t != null ) {
                ClassAnalyzer analyzer = app.getInstance( ClassAnalyzer.class, BaseClassAnalyzer.BINDER_ANALYZER_NAME );
                Method disposeMethod = analyzer.getPreDestroyMethod( implClass );
                try {
                    if ( disposeMethod != null ) {
                        disposeMethod.invoke( t );
                    }
                } catch ( RuntimeException e ) {
                    throw e;
                } catch ( Exception e ) {
                    throw new MultiException( e );
                }

            }
        }
    }

    private static class StandardFactory implements Factory {

        private ServiceProvider provider;

        private ServiceDisposer disposer;

        public StandardFactory( ServiceProvider provider, ServiceDisposer disposer ) {
            this.provider = provider;
            this.disposer = disposer;
        }

        @Override
        public T provide() {
            try {
                return provider.get();
            } catch ( RuntimeException e ) {
                throw e;
            } catch ( Exception e ) {
                throw new MultiException( e );
            }
        }

        @Override
        public void dispose( T instance ) {
            try {
                disposer.dispose( instance );
            } catch ( RuntimeException e ) {
                throw e;
            } catch ( Exception e ) {
                throw new MultiException( e );
            }
        }
    }

    private static class FactoryDescriptorsImpl implements FactoryDescriptors {
        private final Descriptor serviceDescriptor;
        private final Descriptor factoryDescriptor;

        public FactoryDescriptorsImpl( Descriptor serviceDescriptor, Descriptor factoryDescriptor ) {
            this.serviceDescriptor = serviceDescriptor;
            this.factoryDescriptor = factoryDescriptor;
        }

        @Override
        public Descriptor getFactoryAsAService() {
            return serviceDescriptor;
        }

        @Override
        public Descriptor getFactoryAsAFactory() {
            return factoryDescriptor;
        }

        @Override
        public String toString() {
            return "FactoryDescriptorsImpl(\n" +
                    serviceDescriptor + ",\n" + factoryDescriptor + ",\n\t" + System.identityHashCode( this ) + ")";
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy