# ModuleInstance.java

    /*
     * Copyright (c) 2008-2012, Rickard Öberg. All Rights Reserved.
     * Copyright (c) 2012, Kent Sølvsten. All Rights Reserved.
     * Copyright (c) 2008-2013, Niclas Hedhman. All Rights Reserved.
     * Copyright (c) 2012-2015, Paul Merlin. All Rights Reserved.
     *
     * 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.qi4j.runtime.structure;

    import java.lang.reflect.AccessibleObject;
    import java.lang.reflect.Type;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.Stack;
    import java.util.concurrent.ConcurrentHashMap;
    import org.qi4j.api.activation.Activation;
    import org.qi4j.api.activation.ActivationEventListener;
    import org.qi4j.api.activation.ActivationException;
    import org.qi4j.api.activation.PassivationException;
    import org.qi4j.api.association.AssociationDescriptor;
    import org.qi4j.api.common.ConstructionException;
    import org.qi4j.api.common.Visibility;
    import org.qi4j.api.composite.AmbiguousTypeException;
    import org.qi4j.api.composite.Composite;
    import org.qi4j.api.composite.ModelDescriptor;
    import org.qi4j.api.composite.NoSuchTransientException;
    import org.qi4j.api.composite.TransientBuilder;
    import org.qi4j.api.composite.TransientDescriptor;
    import org.qi4j.api.entity.EntityComposite;
    import org.qi4j.api.entity.EntityDescriptor;
    import org.qi4j.api.entity.EntityReference;
    import org.qi4j.api.entity.IdentityGenerator;
    import org.qi4j.api.metrics.MetricsProvider;
    import org.qi4j.api.object.NoSuchObjectException;
    import org.qi4j.api.object.ObjectDescriptor;
    import org.qi4j.api.property.Property;
    import org.qi4j.api.property.PropertyDescriptor;
    import org.qi4j.api.query.QueryBuilder;
    import org.qi4j.api.query.QueryBuilderFactory;
    import org.qi4j.api.service.NoSuchServiceException;
    import org.qi4j.api.service.ServiceDescriptor;
    import org.qi4j.api.service.ServiceReference;
    import org.qi4j.api.structure.Module;
    import org.qi4j.api.unitofwork.UnitOfWork;
    import org.qi4j.api.unitofwork.UnitOfWorkException;
    import org.qi4j.api.unitofwork.UnitOfWorkFactory;
    import org.qi4j.api.usecase.Usecase;
    import org.qi4j.api.util.NullArgumentException;
    import org.qi4j.api.value.NoSuchValueException;
    import org.qi4j.api.value.ValueBuilder;
    import org.qi4j.api.value.ValueComposite;
    import org.qi4j.api.value.ValueDescriptor;
    import org.qi4j.api.value.ValueSerialization;
    import org.qi4j.api.value.ValueSerializationException;
    import org.qi4j.functional.Function;
    import org.qi4j.functional.Function2;
    import org.qi4j.functional.Specification;
    import org.qi4j.functional.Specifications;
    import org.qi4j.runtime.activation.ActivationDelegate;
    import org.qi4j.runtime.composite.FunctionStateResolver;
    import org.qi4j.runtime.composite.StateResolver;
    import org.qi4j.runtime.composite.TransientBuilderInstance;
    import org.qi4j.runtime.composite.TransientModel;
    import org.qi4j.runtime.composite.TransientStateInstance;
    import org.qi4j.runtime.composite.TransientsModel;
    import org.qi4j.runtime.composite.UsesInstance;
    import org.qi4j.runtime.entity.EntitiesModel;
    import org.qi4j.runtime.entity.EntityInstance;
    import org.qi4j.runtime.entity.EntityModel;
    import org.qi4j.runtime.injection.InjectionContext;
    import org.qi4j.runtime.object.ObjectModel;
    import org.qi4j.runtime.object.ObjectsModel;
    import org.qi4j.runtime.property.PropertyInstance;
    import org.qi4j.runtime.property.PropertyModel;
    import org.qi4j.runtime.query.QueryBuilderFactoryImpl;
    import org.qi4j.runtime.service.ImportedServicesInstance;
    import org.qi4j.runtime.service.ImportedServicesModel;
    import org.qi4j.runtime.service.ServicesInstance;
    import org.qi4j.runtime.service.ServicesModel;
    import org.qi4j.runtime.unitofwork.UnitOfWorkInstance;
    import org.qi4j.runtime.value.ValueBuilderInstance;
    import org.qi4j.runtime.value.ValueBuilderWithPrototype;
    import org.qi4j.runtime.value.ValueBuilderWithState;
    import org.qi4j.runtime.value.ValueInstance;
    import org.qi4j.runtime.value.ValueModel;
    import org.qi4j.runtime.value.ValuesModel;
    import org.qi4j.spi.entitystore.EntityStore;
    import org.qi4j.spi.metrics.MetricsProviderAdapter;
    import org.qi4j.spi.module.ModelModule;
    import org.qi4j.spi.module.ModuleSpi;
    import org.qi4j.valueserialization.orgjson.OrgJsonValueSerialization;

    import static org.qi4j.api.common.Visibility.application;
    import static org.qi4j.api.common.Visibility.layer;
    import static org.qi4j.api.common.Visibility.module;
    import static org.qi4j.api.util.Classes.RAW_CLASS;
    import static org.qi4j.api.util.Classes.modelTypeSpecification;
    import static org.qi4j.functional.Iterables.cast;
    import static org.qi4j.functional.Iterables.filter;
    import static org.qi4j.functional.Iterables.first;
    import static org.qi4j.functional.Iterables.flatten;
    import static org.qi4j.functional.Iterables.iterable;
    import static org.qi4j.functional.Iterables.map;
    import static org.qi4j.functional.Iterables.toList;

    /**
     * Instance of a Zest Module. Contains the various composites for this Module.
     */
    public class ModuleInstance
        implements Module, ModuleSpi, Activation
    {
        // Constructor parameters
        private final ModuleModel model;
        private final LayerInstance layer;
        private final TransientsModel transients;
        private final ValuesModel values;
        private final ObjectsModel objects;
        private final EntitiesModel entities;
        private final ServicesInstance services;
        private final ImportedServicesInstance importedServices;
        // Eager instance objects
        private final ActivationDelegate activation;
        private final TypeLookup typeLookup;
        private final QueryBuilderFactory queryBuilderFactory;
        private final ClassLoader classLoader;
        private final EntityFunction entityFunction;
        // Lazy assigned on accessors
        private EntityStore store;
        private IdentityGenerator generator;
        private ValueSerialization valueSerialization;
        private MetricsProvider metrics;

        @SuppressWarnings( "LeakingThisInConstructor" )
        public ModuleInstance( ModuleModel moduleModel, LayerInstance layerInstance, TransientsModel transientsModel,
                               EntitiesModel entitiesModel, ObjectsModel objectsModel, ValuesModel valuesModel,
                               ServicesModel servicesModel, ImportedServicesModel importedServicesModel
        )
        {
            // Constructor parameters
            model = moduleModel;
            layer = layerInstance;
            transients = transientsModel;
            values = valuesModel;
            objects = objectsModel;
            entities = entitiesModel;
            services = servicesModel.newInstance( this );
            importedServices = importedServicesModel.newInstance( this );

            // Eager instance objects
            activation = new ActivationDelegate( this );
            typeLookup = new TypeLookup( this );
            queryBuilderFactory = new QueryBuilderFactoryImpl( this );
            classLoader = new ModuleClassLoader( this, Thread.currentThread().getContextClassLoader() );
            entityFunction = new EntityFunction( this );

            // Activation
            services.registerActivationEventListener( activation );
            importedServices.registerActivationEventListener( activation );
        }

        @Override
        public String toString()
        {
            return model.toString();
        }

        // Implementation of Module
        @Override
        public String name()
        {
            return model.name();
        }

        @Override
        public ClassLoader classLoader()
        {
            return classLoader;
        }

        @Override
        public EntityDescriptor entityDescriptor( String name )
        {
            try
            {
                Class<?> type = classLoader().loadClass( name );
                ModelModule<EntityModel> entityModel = typeLookup.lookupEntityModel( type );
                if( entityModel == null )
                {
                    return null;
                }
                return entityModel.model();
            }
            catch( ClassNotFoundException e )
            {
                return null;
            }
        }

        @Override
        public ObjectDescriptor objectDescriptor( String typeName )
        {
            try
            {
                Class<?> type = classLoader().loadClass( typeName );
                ModelModule<ObjectModel> objectModel = typeLookup.lookupObjectModel( type );
                if( objectModel == null )
                {
                    return null;
                }
                return objectModel.model();
            }
            catch( ClassNotFoundException e )
            {
                return null;
            }
        }

        @Override
        public TransientDescriptor transientDescriptor( String name )
        {
            try
            {
                Class<?> type = classLoader().loadClass( name );
                ModelModule<TransientModel> transientModel = typeLookup.lookupTransientModel( type );
                if( transientModel == null )
                {
                    return null;
                }
                return transientModel.model();
            }
            catch( ClassNotFoundException e )
            {
                return null;
            }
        }

        @Override
        public ValueDescriptor valueDescriptor( String name )
        {
            try
            {
                Class<?> type = classLoader().loadClass( name );
                ModelModule<ValueModel> valueModel = typeLookup.lookupValueModel( type );
                if( valueModel == null )
                {
                    return null;
                }
                return valueModel.model();
            }
            catch( ClassNotFoundException e )
            {
                return null;
            }
        }

        // Implementation of MetaInfoHolder
        @Override
        public <T> T metaInfo( Class<T> infoType )
        {
            return model.metaInfo( infoType );
        }

        // Implementation of ObjectFactory
        @Override
        public <T> T newObject( Class<T> mixinType, Object... uses )
            throws NoSuchObjectException
        {
            NullArgumentException.validateNotNull( "mixinType", mixinType );
            ModelModule<ObjectModel> modelModule = typeLookup.lookupObjectModel( mixinType );

            if( modelModule == null )
            {
                throw new NoSuchObjectException( mixinType.getName(), name() );
            }

            InjectionContext injectionContext = new InjectionContext( modelModule.module(), UsesInstance.EMPTY_USES.use( uses ) );
            return mixinType.cast( modelModule.model().newInstance( injectionContext ) );
        }

        @Override
        public void injectTo( Object instance, Object... uses )
            throws ConstructionException
        {
            NullArgumentException.validateNotNull( "instance", instance );
            ModelModule<ObjectModel> modelModule = typeLookup.lookupObjectModel( instance.getClass() );

            if( modelModule == null )
            {
                throw new NoSuchObjectException( instance.getClass().getName(), name() );
            }

            InjectionContext injectionContext = new InjectionContext( modelModule.module(), UsesInstance.EMPTY_USES.use( uses ) );
            modelModule.model().inject( injectionContext, instance );
        }

        // Implementation of TransientBuilderFactory
        @Override
        public <T> TransientBuilder<T> newTransientBuilder( Class<T> mixinType )
            throws NoSuchTransientException
        {
            NullArgumentException.validateNotNull( "mixinType", mixinType );
            ModelModule<TransientModel> modelModule = typeLookup.lookupTransientModel( mixinType );

            if( modelModule == null )
            {
                throw new NoSuchTransientException( mixinType.getName(), name() );
            }

            Map<AccessibleObject, Property<?>> properties = new HashMap<>();
            for( PropertyModel propertyModel : modelModule.model().state().properties() )
            {
                Property<?> property = new PropertyInstance<>( propertyModel.getBuilderInfo(),
                                                               propertyModel.initialValue( modelModule.module() ) );
                properties.put( propertyModel.accessor(), property );
            }

            TransientStateInstance state = new TransientStateInstance( properties );

            return new TransientBuilderInstance<>( modelModule, state, UsesInstance.EMPTY_USES );
        }

        @Override
        public <T> T newTransient( final Class<T> mixinType, Object... uses )
            throws NoSuchTransientException, ConstructionException
        {
            return newTransientBuilder( mixinType ).use( uses ).newInstance();
        }

        // Implementation of ValueBuilderFactory
        @Override
        public <T> T newValue( Class<T> mixinType )
            throws NoSuchValueException, ConstructionException
        {
            return newValueBuilder( mixinType ).newInstance();
        }

        @Override
        public <T> ValueBuilder<T> newValueBuilder( Class<T> mixinType )
            throws NoSuchValueException
        {
            NullArgumentException.validateNotNull( "mixinType", mixinType );
            ModelModule<ValueModel> compositeModelModule = typeLookup.lookupValueModel( mixinType );

            if( compositeModelModule == null )
            {
                throw new NoSuchValueException( mixinType.getName(), name() );
            }

            StateResolver stateResolver = new InitialStateResolver( compositeModelModule.module() );
            return new ValueBuilderInstance<>( compositeModelModule, this, stateResolver );
        }

        @Override
        public <T> ValueBuilder<T> newValueBuilderWithState( Class<T> mixinType,
                                                             Function<PropertyDescriptor, Object> propertyFunction,
                                                             Function<AssociationDescriptor, EntityReference> associationFunction,
                                                             Function<AssociationDescriptor, Iterable<EntityReference>> manyAssociationFunction,
                                                             Function<AssociationDescriptor, Map<String, EntityReference>> namedAssociationFunction
        )
        {
            NullArgumentException.validateNotNull( "propertyFunction", propertyFunction );
            NullArgumentException.validateNotNull( "associationFunction", associationFunction );
            NullArgumentException.validateNotNull( "manyAssociationFunction", manyAssociationFunction );
            NullArgumentException.validateNotNull( "namedAssociationFunction", namedAssociationFunction );

            ModelModule<ValueModel> compositeModelModule = typeLookup.lookupValueModel( mixinType );

            if( compositeModelModule == null )
            {
                throw new NoSuchValueException( mixinType.getName(), name() );
            }

            StateResolver stateResolver = new FunctionStateResolver(
                propertyFunction, associationFunction, manyAssociationFunction, namedAssociationFunction
            );
            return new ValueBuilderWithState<>( compositeModelModule, this, stateResolver );
        }

        private static class InitialStateResolver
            implements StateResolver
        {
            private final Module module;

            private InitialStateResolver( Module module )
            {
                this.module = module;
            }

            @Override
            public Object getPropertyState( PropertyDescriptor propertyDescriptor )
            {
                return propertyDescriptor.initialValue( module );
            }

            @Override
            public EntityReference getAssociationState( AssociationDescriptor associationDescriptor )
            {
                return null;
            }

            @Override
            public List<EntityReference> getManyAssociationState( AssociationDescriptor associationDescriptor )
            {
                return new ArrayList<>();
            }

            @Override
            public Map<String, EntityReference> getNamedAssociationState( AssociationDescriptor associationDescriptor )
            {
                return new HashMap<>();
            }
        }

        @Override
        @SuppressWarnings( "unchecked" )
        public <T> ValueBuilder<T> newValueBuilderWithPrototype( T prototype )
        {
            NullArgumentException.validateNotNull( "prototype", prototype );

            ValueInstance valueInstance = ValueInstance.valueInstanceOf( (ValueComposite) prototype );
            Class<Composite> valueType = (Class<Composite>) first( valueInstance.types() );

            ModelModule<ValueModel> modelModule = typeLookup.lookupValueModel( valueType );

            if( modelModule == null )
            {
                throw new NoSuchValueException( valueType.getName(), name() );
            }

            return new ValueBuilderWithPrototype<>( modelModule, this, prototype );
        }

        @Override
        public <T> T newValueFromSerializedState( Class<T> mixinType, String serializedState )
            throws NoSuchValueException, ConstructionException
        {
            NullArgumentException.validateNotNull( "mixinType", mixinType );
            ModelModule<ValueModel> modelModule = typeLookup.lookupValueModel( mixinType );

            if( modelModule == null )
            {
                throw new NoSuchValueException( mixinType.getName(), name() );
            }

            try
            {
                return valueSerialization().deserialize( modelModule.model().valueType(), serializedState );
            }
            catch( ValueSerializationException ex )
            {
                throw new ConstructionException( "Could not create value from serialized state", ex );
            }
        }

        // Implementation of UnitOfWorkFactory
        @Override
        public UnitOfWork newUnitOfWork()
        {
            return newUnitOfWork( Usecase.DEFAULT );
        }

        @Override
        public UnitOfWork newUnitOfWork( long currentTime )
        {
            return newUnitOfWork( Usecase.DEFAULT, currentTime );
        }

        @Override
        public UnitOfWork newUnitOfWork( Usecase usecase )
        {
            return newUnitOfWork( usecase == null ? Usecase.DEFAULT : usecase, System.currentTimeMillis() );
        }

        @Override
        public UnitOfWork newUnitOfWork( Usecase usecase, long currentTime )
        {
            UnitOfWorkInstance unitOfWorkInstance = new UnitOfWorkInstance( usecase, currentTime, metricsProvider() );
            return new ModuleUnitOfWork( ModuleInstance.this, unitOfWorkInstance );
        }

        @Override
        public boolean isUnitOfWorkActive()
        {
            Stack<UnitOfWorkInstance> stack = UnitOfWorkInstance.getCurrent();
            return !stack.isEmpty();
        }

        @Override
        public UnitOfWork currentUnitOfWork()
        {
            Stack<UnitOfWorkInstance> stack = UnitOfWorkInstance.getCurrent();
            if( stack.size() == 0 )
            {
                throw new IllegalStateException( "No current UnitOfWork active" );
            }
            return new ModuleUnitOfWork( ModuleInstance.this, stack.peek() );
        }

        @Override
        public UnitOfWork getUnitOfWork( EntityComposite entity )
        {
            EntityInstance instance = EntityInstance.entityInstanceOf( entity );
            return instance.unitOfWork();
        }

        // Implementation of QueryBuilderFactory
        @Override
        public <T> QueryBuilder<T> newQueryBuilder( final Class<T> resultType )
        {
            return queryBuilderFactory.newQueryBuilder( resultType );
        }

        // Implementation of ServiceFinder
        @Override
        public <T> ServiceReference<T> findService( Class<T> serviceType )
        {
            return typeLookup.lookupServiceReference( (Type) serviceType );
        }

        @Override
        public <T> ServiceReference<T> findService( Type serviceType )
        {
            return typeLookup.lookupServiceReference( serviceType );
        }

        @Override
        public <T> Iterable<ServiceReference<T>> findServices( Class<T> serviceType )
        {
            return typeLookup.lookupServiceReferences( (Type) serviceType );
        }

        @Override
        public <T> Iterable<ServiceReference<T>> findServices( Type serviceType )
        {
            return typeLookup.lookupServiceReferences( serviceType );
        }

        // Implementation of Activation
        @Override
        @SuppressWarnings( "unchecked" )
        public void activate()
            throws ActivationException
        {
            activation.activate( model.newActivatorsInstance(), iterable( services, importedServices ) );
        }

        @Override
        public void passivate()
            throws PassivationException
        {
            activation.passivate();
        }

        @Override
        public void registerActivationEventListener( ActivationEventListener listener )
        {
            activation.registerActivationEventListener( listener );
        }

        @Override
        public void deregisterActivationEventListener( ActivationEventListener listener )
        {
            activation.deregisterActivationEventListener( listener );
        }

        // Other methods
        /* package */ ModuleModel model()
        {
            return model;
        }

        public LayerInstance layerInstance()
        {
            return layer;
        }

        public TypeLookup typeLookup()
        {
            return typeLookup;
        }

        public Function2<EntityReference, Type, Object> getEntityFunction()
        {
            return entityFunction;
        }

        private static class EntityFunction
            implements Function2<EntityReference, Type, Object>
        {

            private final UnitOfWorkFactory uowf;

            private EntityFunction( UnitOfWorkFactory uowf )
            {
                this.uowf = uowf;
            }

            @Override
            public Object map( EntityReference entityReference, Type type )
            {
                return uowf.currentUnitOfWork().get( RAW_CLASS.map( type ), entityReference.identity() );
            }
        }

        public EntityStore entityStore()
        {
            synchronized( this )
            {
                if( store == null )
                {
                    ServiceReference<EntityStore> service = findService( EntityStore.class );
                    if( service == null )
                    {
                        throw new UnitOfWorkException( "No EntityStore service available in module " + name() );
                    }
                    store = service.get();
                }
            }
            return store;
        }

        public IdentityGenerator identityGenerator()
        {
            synchronized( this )
            {
                if( generator == null )
                {
                    ServiceReference<IdentityGenerator> service = findService( IdentityGenerator.class );
                    generator = service.get();
                }
                return generator;
            }
        }

        public ValueSerialization valueSerialization()
        {
            synchronized( this )
            {
                if( valueSerialization == null )
                {
                    try
                    {
                        ServiceReference<ValueSerialization> service = findService( ValueSerialization.class );
                        valueSerialization = service.get();
                    }
                    catch( NoSuchServiceException e )
                    {
                        valueSerialization = new OrgJsonValueSerialization( layer.applicationInstance(), this, this );
                    }
                }
            }
            return valueSerialization;
        }

        /* package */ MetricsProvider metricsProvider()
        {
            synchronized( this )
            {
                if( metrics == null )
                {
                    try
                    {
                        ServiceReference<MetricsProvider> service = findService( MetricsProvider.class );
                        metrics = service.get();
                    }
                    catch( NoSuchServiceException e )
                    {
                        metrics = new MetricsProviderAdapter();
                    }
                }
            }
            return metrics;
        }

        public Iterable<ModelModule<ObjectDescriptor>> visibleObjects( Visibility visibility )
        {
            return map( ModelModule.<ObjectDescriptor>modelModuleFunction( this ),
                        filter( new VisibilitySpecification( visibility ), objects.models() ) );
        }

        public Iterable<ModelModule<TransientDescriptor>> visibleTransients( Visibility visibility )
        {
            return map( ModelModule.<TransientDescriptor>modelModuleFunction( this ),
                        filter( new VisibilitySpecification( visibility ), transients.models() ) );
        }

        public Iterable<ModelModule<EntityDescriptor>> visibleEntities( Visibility visibility )
        {
            return map( ModelModule.<EntityDescriptor>modelModuleFunction( this ),
                        filter( new VisibilitySpecification( visibility ), entities.models() ) );
        }

        public Iterable<ModelModule<ValueDescriptor>> visibleValues( Visibility visibility )
        {
            return map( ModelModule.<ValueDescriptor>modelModuleFunction( this ),
                        filter( new VisibilitySpecification( visibility ), values.models() ) );
        }

        public Iterable<ServiceReference<?>> visibleServices( Visibility visibility )
        {
            return flatten( services.visibleServices( visibility ),
                            importedServices.visibleServices( visibility ) );
        }

        // Module ClassLoader
        private static class ModuleClassLoader
            extends ClassLoader
        {

            private final ModuleInstance moduleInstance;
            private final Map<String, Class<?>> classes = new ConcurrentHashMap<>();

            private ModuleClassLoader( ModuleInstance moduleInstance, ClassLoader classLoader )
            {
                super( classLoader );
                this.moduleInstance = moduleInstance;
            }

            @Override
            protected Class<?> findClass( String name )
                throws ClassNotFoundException
            {
                Class<?> clazz = classes.get( name );
                if( clazz == null )
                {
                    Specification<ModelDescriptor> modelTypeSpecification = modelTypeSpecification( name );
                    Specification<ModelModule<ModelDescriptor>> translate = Specifications.translate( ModelModule.modelFunction(), modelTypeSpecification );
                    // Check module
                    {
                        Iterable<ModelModule<ModelDescriptor>> i = cast( flatten(
                            cast( moduleInstance.visibleObjects( Visibility.module ) ),
                            cast( moduleInstance.visibleEntities( Visibility.module ) ),
                            cast( moduleInstance.visibleTransients( Visibility.module ) ),
                            cast( moduleInstance.visibleValues( Visibility.module ) ) ) );

                        Iterable<ModelModule<ModelDescriptor>> moduleModels = filter( translate, i );
                        Iterator<ModelModule<ModelDescriptor>> iter = moduleModels.iterator();
                        if( iter.hasNext() )
                        {
                            clazz = first( iter.next().model().types() );

                            if( iter.hasNext() )
                            {
                                // Ambiguous exception
                                throw new ClassNotFoundException(
                                    name,
                                    new AmbiguousTypeException(
                                        "More than one model matches the classname " + name + ":" + toList( moduleModels )
                                    )
                                );
                            }
                        }
                    }

                    // Check layer
                    if( clazz == null )
                    {
                        Iterable<ModelModule<ModelDescriptor>> flatten = cast( flatten(
                            cast( moduleInstance.layerInstance().visibleObjects( Visibility.layer ) ),
                            cast( moduleInstance.layerInstance().visibleTransients( Visibility.layer ) ),
                            cast( moduleInstance.layerInstance().visibleEntities( Visibility.layer ) ),
                            cast( moduleInstance.layerInstance().visibleValues( Visibility.layer ) ),
                            cast( moduleInstance.layerInstance().visibleObjects( Visibility.application ) ),
                            cast( moduleInstance.layerInstance().visibleTransients( Visibility.application ) ),
                            cast( moduleInstance.layerInstance().visibleEntities( Visibility.application ) ),
                            cast( moduleInstance.layerInstance().visibleValues( Visibility.application ) ) ) );
                        Iterable<ModelModule<ModelDescriptor>> layerModels = filter( translate, flatten );
                        Iterator<ModelModule<ModelDescriptor>> iter = layerModels.iterator();
                        if( iter.hasNext() )
                        {
                            clazz = first( iter.next().model().types() );

                            if( iter.hasNext() )
                            {
                                // Ambiguous exception
                                throw new ClassNotFoundException(
                                    name,
                                    new AmbiguousTypeException(
                                        "More than one model matches the classname " + name + ":" + toList( layerModels ) )
                                );
                            }
                        }
                    }

                    // Check used layers
                    if( clazz == null )
                    {
                        Iterable<ModelModule<ModelDescriptor>> flatten = cast( flatten(
                            cast( moduleInstance.layerInstance().usedLayersInstance().visibleObjects() ),
                            cast( moduleInstance.layerInstance().usedLayersInstance().visibleTransients() ),
                            cast( moduleInstance.layerInstance().usedLayersInstance().visibleEntities() ),
                            cast( moduleInstance.layerInstance().usedLayersInstance().visibleValues() ) ) );
                        Iterable<ModelModule<ModelDescriptor>> usedLayersModels = filter( translate, flatten );
                        Iterator<ModelModule<ModelDescriptor>> iter = usedLayersModels.iterator();
                        if( iter.hasNext() )
                        {
                            clazz = first( iter.next().model().types() );

                            if( iter.hasNext() )
                            {
                                // Ambiguous exception
                                throw new ClassNotFoundException(
                                    name,
                                    new AmbiguousTypeException(
                                        "More than one model matches the classname " + name + ":" + toList( usedLayersModels )
                                    )
                                );
                            }
                        }
                    }

                    if( clazz == null )
                    {
                        throw new ClassNotFoundException( name );
                    }
                    classes.put( name, clazz );
                }

                return clazz;
            }
        }

        public Iterable<ModelModule<ValueDescriptor>> findVisibleValueTypes()
        {
            return flatten( visibleValues( Visibility.module ),
                layerInstance().visibleValues( Visibility.layer ),
                layerInstance().visibleValues( Visibility.application ),
                layerInstance().usedLayersInstance().visibleValues()
            );
        }

        public Iterable<ModelModule<EntityDescriptor>> findVisibleEntityTypes()
        {
            return flatten( visibleEntities( Visibility.module ),
                layerInstance().visibleEntities( Visibility.layer ),
                layerInstance().visibleEntities( Visibility.application ),
                layerInstance().usedLayersInstance().visibleEntities()
            );
        }
        public Iterable<ModelModule<TransientDescriptor>> findVisibleTransientTypes()
        {
            return flatten( visibleTransients( Visibility.module ),
                layerInstance().visibleTransients( Visibility.layer ),
                layerInstance().visibleTransients( Visibility.application ),
                layerInstance().usedLayersInstance().visibleTransients()
            );
        }
        public Iterable<ModelModule<ServiceDescriptor>> findVisibleServiceTypes()
        {
            return flatten( visibleServices( Visibility.module ),
                layerInstance().visibleServices( Visibility.layer ),
                layerInstance().visibleServices( Visibility.application ),
                layerInstance().usedLayersInstance().visibleServices()
            );
        }
        public Iterable<ModelModule<ObjectDescriptor>> findVisibleObjectTypes()
        {
            return flatten( visibleObjects( Visibility.module ),
                layerInstance().visibleObjects( Visibility.layer ),
                layerInstance().visibleObjects( Visibility.application ),
                layerInstance().usedLayersInstance().visibleObjects()
            );
        }
    }