| /* |
| * 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() |
| ); |
| } |
| } |