http://git-wip-us.apache.org/repos/asf/zest-java/blob/a5be013f/core/runtime/src/main/java/org/apache/zest/runtime/structure/ModuleInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/structure/ModuleInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/structure/ModuleInstance.java index bb9aa65..4bf431f 100644 --- a/core/runtime/src/main/java/org/apache/zest/runtime/structure/ModuleInstance.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/structure/ModuleInstance.java @@ -23,9 +23,7 @@ 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 java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -42,7 +40,6 @@ import org.apache.zest.api.composite.ModelDescriptor; import org.apache.zest.api.composite.NoSuchTransientException; import org.apache.zest.api.composite.TransientBuilder; import org.apache.zest.api.composite.TransientDescriptor; -import org.apache.zest.api.entity.EntityComposite; import org.apache.zest.api.entity.EntityDescriptor; import org.apache.zest.api.entity.EntityReference; import org.apache.zest.api.entity.IdentityGenerator; @@ -58,10 +55,8 @@ import org.apache.zest.api.service.NoSuchServiceException; import org.apache.zest.api.service.ServiceDescriptor; import org.apache.zest.api.service.ServiceReference; import org.apache.zest.api.structure.Module; -import org.apache.zest.api.unitofwork.UnitOfWork; import org.apache.zest.api.unitofwork.UnitOfWorkException; import org.apache.zest.api.unitofwork.UnitOfWorkFactory; -import org.apache.zest.api.usecase.Usecase; import org.apache.zest.api.util.NullArgumentException; import org.apache.zest.api.value.NoSuchValueException; import org.apache.zest.api.value.ValueBuilder; @@ -73,13 +68,10 @@ import org.apache.zest.runtime.activation.ActivationDelegate; import org.apache.zest.runtime.composite.FunctionStateResolver; import org.apache.zest.runtime.composite.StateResolver; import org.apache.zest.runtime.composite.TransientBuilderInstance; -import org.apache.zest.runtime.composite.TransientModel; import org.apache.zest.runtime.composite.TransientStateInstance; import org.apache.zest.runtime.composite.TransientsModel; import org.apache.zest.runtime.composite.UsesInstance; import org.apache.zest.runtime.entity.EntitiesModel; -import org.apache.zest.runtime.entity.EntityInstance; -import org.apache.zest.runtime.entity.EntityModel; import org.apache.zest.runtime.injection.InjectionContext; import org.apache.zest.runtime.object.ObjectModel; import org.apache.zest.runtime.object.ObjectsModel; @@ -90,21 +82,18 @@ import org.apache.zest.runtime.service.ImportedServicesInstance; import org.apache.zest.runtime.service.ImportedServicesModel; import org.apache.zest.runtime.service.ServicesInstance; import org.apache.zest.runtime.service.ServicesModel; -import org.apache.zest.runtime.unitofwork.UnitOfWorkInstance; import org.apache.zest.runtime.value.ValueBuilderInstance; import org.apache.zest.runtime.value.ValueBuilderWithPrototype; import org.apache.zest.runtime.value.ValueBuilderWithState; import org.apache.zest.runtime.value.ValueInstance; -import org.apache.zest.runtime.value.ValueModel; import org.apache.zest.runtime.value.ValuesModel; import org.apache.zest.spi.entitystore.EntityStore; import org.apache.zest.spi.metrics.MetricsProviderAdapter; -import org.apache.zest.spi.module.ModelModule; import org.apache.zest.spi.module.ModuleSpi; +import org.apache.zest.spi.structure.ModelModule; import org.apache.zest.valueserialization.orgjson.OrgJsonValueSerialization; import static java.util.stream.Stream.concat; -import static org.apache.zest.api.util.Classes.RAW_CLASS; import static org.apache.zest.api.util.Classes.modelTypeSpecification; import static org.apache.zest.functional.Iterables.iterable; import static org.apache.zest.runtime.legacy.Specifications.translate; @@ -126,15 +115,15 @@ public class ModuleInstance private final ImportedServicesInstance importedServices; // Eager instance objects private final ActivationDelegate activation; - private final TypeLookup typeLookup; + private final TypeLookupImpl 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; + private UnitOfWorkFactory uowf; @SuppressWarnings( "LeakingThisInConstructor" ) public ModuleInstance( ModuleModel moduleModel, LayerInstance layerInstance, TransientsModel transientsModel, @@ -147,17 +136,16 @@ public class ModuleInstance layer = layerInstance; transients = transientsModel; values = valuesModel; - objects = objectsModel; entities = entitiesModel; services = servicesModel.newInstance( this ); + objects = objectsModel; importedServices = importedServicesModel.newInstance( this ); // Eager instance objects activation = new ActivationDelegate( this ); - typeLookup = new TypeLookup( this ); + typeLookup = new TypeLookupImpl( this ); queryBuilderFactory = new QueryBuilderFactoryImpl( this ); classLoader = new ModuleClassLoader( this, Thread.currentThread().getContextClassLoader() ); - entityFunction = new EntityFunction( this ); // Activation services.registerActivationEventListener( activation ); @@ -316,7 +304,7 @@ public class ModuleInstance } InjectionContext injectionContext = new InjectionContext( modelModule.module(), UsesInstance.EMPTY_USES.use( uses ) ); - return mixinType.cast( ((ObjectModel) modelModule.model()).newInstance( injectionContext ) ); + return mixinType.cast( ( (ObjectModel) modelModule.model() ).newInstance( injectionContext ) ); } @Override @@ -332,7 +320,7 @@ public class ModuleInstance } InjectionContext injectionContext = new InjectionContext( modelModule.module(), UsesInstance.EMPTY_USES.use( uses ) ); - ((ObjectModel) modelModule.model()).inject( injectionContext, instance ); + ( (ObjectModel) modelModule.model() ).inject( injectionContext, instance ); } // Implementation of TransientBuilderFactory @@ -352,7 +340,7 @@ public class ModuleInstance modelModule.model().state().properties().forEach( propertyModel -> { - Property<?> property = new PropertyInstance<>( ((PropertyModel) propertyModel).getBuilderInfo(), + Property<?> property = new PropertyInstance<>( ( (PropertyModel) propertyModel ).getBuilderInfo(), propertyModel.initialValue( modelModule.module() ) ); properties.put( propertyModel.accessor(), property ); } ); @@ -495,57 +483,6 @@ public class ModuleInstance } } - // 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 ) @@ -617,42 +554,24 @@ public class ModuleInstance return layer; } - public TypeLookup typeLookup() + @Override + public TypeLookupImpl typeLookup() { return typeLookup; } - public BiFunction<EntityReference, Type, Object> getEntityFunction() - { - return entityFunction; - } - - private static class EntityFunction - implements BiFunction<EntityReference, Type, Object> - { - - private final UnitOfWorkFactory uowf; - - private EntityFunction( UnitOfWorkFactory uowf ) - { - this.uowf = uowf; - } - - @Override - public Object apply( EntityReference entityReference, Type type ) - { - return uowf.currentUnitOfWork().get( RAW_CLASS.apply( type ), entityReference.identity() ); - } - } - public EntityStore entityStore() { synchronized( this ) { if( store == null ) { - ServiceReference<EntityStore> service = findService( EntityStore.class ); - if( service == null ) + ServiceReference<EntityStore> service = null; + try + { + service = findService( EntityStore.class ); + } + catch( NoSuchServiceException e ) { throw new UnitOfWorkException( "No EntityStore service available in module " + name() ); } @@ -662,6 +581,27 @@ public class ModuleInstance return store; } + public UnitOfWorkFactory unitOfWorkFactory() + { + synchronized( this ) + { + if( uowf == null ) + { + ServiceReference<UnitOfWorkFactory> service = null; + try + { + service = findService( UnitOfWorkFactory.class ); + } + catch( NoSuchServiceException e ) + { + throw new UnitOfWorkException( "No UnitOfWorkFactory service available in module " + name() ); + } + uowf = service.get(); + } + } + return uowf; + } + public IdentityGenerator identityGenerator() { synchronized( this ) @@ -695,7 +635,7 @@ public class ModuleInstance return valueSerialization; } - /* package */ MetricsProvider metricsProvider() + public MetricsProvider metricsProvider() { synchronized( this ) {
http://git-wip-us.apache.org/repos/asf/zest-java/blob/a5be013f/core/runtime/src/main/java/org/apache/zest/runtime/structure/ModuleUnitOfWork.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/structure/ModuleUnitOfWork.java b/core/runtime/src/main/java/org/apache/zest/runtime/structure/ModuleUnitOfWork.java deleted file mode 100755 index b5303d5..0000000 --- a/core/runtime/src/main/java/org/apache/zest/runtime/structure/ModuleUnitOfWork.java +++ /dev/null @@ -1,769 +0,0 @@ -/* - * Copyright (c) 2009, Rickard Ãberg. All Rights Reserved. - * Copyright (c) 2013-2015, Niclas Hedhman. All Rights Reserved. - * Copyright (c) 2013-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.apache.zest.runtime.structure; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.function.Function; -import java.util.function.Predicate; -import org.apache.zest.api.association.AssociationDescriptor; -import org.apache.zest.api.association.AssociationStateHolder; -import org.apache.zest.api.common.QualifiedName; -import org.apache.zest.api.composite.Composite; -import org.apache.zest.api.entity.EntityBuilder; -import org.apache.zest.api.entity.EntityComposite; -import org.apache.zest.api.entity.EntityDescriptor; -import org.apache.zest.api.entity.EntityReference; -import org.apache.zest.api.entity.Identity; -import org.apache.zest.api.entity.IdentityGenerator; -import org.apache.zest.api.entity.LifecycleException; -import org.apache.zest.api.property.Property; -import org.apache.zest.api.property.PropertyDescriptor; -import org.apache.zest.api.property.StateHolder; -import org.apache.zest.api.query.Query; -import org.apache.zest.api.query.QueryBuilder; -import org.apache.zest.api.query.QueryExecutionException; -import org.apache.zest.api.query.grammar.OrderBy; -import org.apache.zest.api.service.NoSuchServiceException; -import org.apache.zest.api.unitofwork.ConcurrentEntityModificationException; -import org.apache.zest.api.unitofwork.EntityTypeNotFoundException; -import org.apache.zest.api.unitofwork.NoSuchEntityException; -import org.apache.zest.api.unitofwork.UnitOfWork; -import org.apache.zest.api.unitofwork.UnitOfWorkCallback; -import org.apache.zest.api.unitofwork.UnitOfWorkCompletionException; -import org.apache.zest.api.unitofwork.UnitOfWorkFactory; -import org.apache.zest.api.usecase.Usecase; -import org.apache.zest.api.util.NullArgumentException; -import org.apache.zest.api.value.ValueBuilder; -import org.apache.zest.api.value.ValueComposite; -import org.apache.zest.functional.Iterables; -import org.apache.zest.runtime.association.AssociationInstance; -import org.apache.zest.runtime.association.ManyAssociationInstance; -import org.apache.zest.runtime.association.NamedAssociationInstance; -import org.apache.zest.runtime.composite.FunctionStateResolver; -import org.apache.zest.runtime.entity.EntityInstance; -import org.apache.zest.runtime.entity.EntityModel; -import org.apache.zest.runtime.property.PropertyModel; -import org.apache.zest.runtime.unitofwork.EntityBuilderInstance; -import org.apache.zest.runtime.unitofwork.UnitOfWorkInstance; -import org.apache.zest.runtime.value.ValueInstance; -import org.apache.zest.spi.entity.EntityState; -import org.apache.zest.spi.entity.EntityStatus; -import org.apache.zest.spi.entity.NamedAssociationState; -import org.apache.zest.spi.entitystore.EntityStore; -import org.apache.zest.spi.module.ModelModule; -import org.apache.zest.spi.query.EntityFinder; -import org.apache.zest.spi.query.EntityFinderException; -import org.apache.zest.spi.query.QueryBuilderSPI; -import org.apache.zest.spi.query.QuerySource; - -import static org.apache.zest.api.entity.EntityReference.parseEntityReference; - -/** - * JAVADOC - */ -public class ModuleUnitOfWork - implements UnitOfWork -{ - private static final QualifiedName IDENTITY_STATE_NAME; - - static - { - try - { - IDENTITY_STATE_NAME = QualifiedName.fromAccessor( Identity.class.getMethod( "identity" ) ); - } - catch( NoSuchMethodException e ) - { - throw new InternalError( "Zest Core Runtime codebase is corrupted. Contact Zest team: ModuleUnitOfWork" ); - } - } - - private final UnitOfWorkInstance uow; - private final ModuleInstance module; - - ModuleUnitOfWork( ModuleInstance module, UnitOfWorkInstance uow ) - { - this.module = module; - this.uow = uow; - } - - public ModuleInstance module() - { - return module; - } - - public UnitOfWorkInstance instance() - { - return uow; - } - - @Override - public UnitOfWorkFactory unitOfWorkFactory() - { - return module; - } - - @Override - public long currentTime() - { - return uow.currentTime(); - } - - @Override - public Usecase usecase() - { - return uow.usecase(); - } - - @Override - public <T> T metaInfo( Class<T> infoType ) - { - return uow.metaInfo().get( infoType ); - } - - @Override - public void setMetaInfo( Object metaInfo ) - { - uow.metaInfo().set( metaInfo ); - } - - @Override - @SuppressWarnings( { "raw", "unchecked" } ) - public <T> Query<T> newQuery( QueryBuilder<T> queryBuilder ) - { - QueryBuilderSPI queryBuilderSPI = (QueryBuilderSPI) queryBuilder; - - return queryBuilderSPI.newQuery( new UoWQuerySource( this ) ); - } - - @Override - public <T> T newEntity( Class<T> type ) - throws EntityTypeNotFoundException, LifecycleException - { - return newEntity( type, null ); - } - - @Override - public <T> T newEntity( Class<T> type, String identity ) - throws EntityTypeNotFoundException, LifecycleException - { - return newEntityBuilder( type, identity ).newInstance(); - } - - @Override - public <T> EntityBuilder<T> newEntityBuilder( Class<T> type ) - throws EntityTypeNotFoundException - { - return newEntityBuilder( type, null ); - } - - @Override - public <T> EntityBuilder<T> newEntityBuilder( Class<T> type, String identity ) - throws EntityTypeNotFoundException - { - ModelModule<EntityDescriptor> model = module.typeLookup().lookupEntityModel( type ); - - if( model == null ) - { - throw new EntityTypeNotFoundException( type.getName(), - module.name(), - module.findVisibleEntityTypes().map( ModelModule.toStringFunction ) - ); - } - - EntityStore entityStore = model.module().entityStore(); - - // Generate id if necessary - if( identity == null ) - { - IdentityGenerator idGen = model.module().identityGenerator(); - if( idGen == null ) - { - throw new NoSuchServiceException( IdentityGenerator.class.getName(), model.module().name() ); - } - identity = idGen.generate( model.model().types().findFirst().orElse( null ) ); - } - EntityBuilder<T> builder; - - builder = new EntityBuilderInstance<>( model, - this, - uow.getEntityStoreUnitOfWork( entityStore ), - identity ); - return builder; - } - - @Override - public <T> EntityBuilder<T> newEntityBuilderWithState( - Class<T> type, - Function<PropertyDescriptor, Object> propertyFunction, - Function<AssociationDescriptor, EntityReference> associationFunction, - Function<AssociationDescriptor, Iterable<EntityReference>> manyAssociationFunction, - Function<AssociationDescriptor, Map<String, EntityReference>> namedAssociationFunction - ) - throws EntityTypeNotFoundException - { - return newEntityBuilderWithState( type, null, - propertyFunction, - associationFunction, - manyAssociationFunction, - namedAssociationFunction ); - } - - @Override - public <T> EntityBuilder<T> newEntityBuilderWithState( - Class<T> type, String identity, - Function<PropertyDescriptor, Object> propertyFunction, - Function<AssociationDescriptor, EntityReference> associationFunction, - Function<AssociationDescriptor, Iterable<EntityReference>> manyAssociationFunction, - Function<AssociationDescriptor, Map<String, EntityReference>> namedAssociationFunction - ) - throws EntityTypeNotFoundException - { - NullArgumentException.validateNotNull( "propertyFunction", propertyFunction ); - NullArgumentException.validateNotNull( "associationFunction", associationFunction ); - NullArgumentException.validateNotNull( "manyAssociationFunction", manyAssociationFunction ); - NullArgumentException.validateNotNull( "namedAssociationFunction", namedAssociationFunction ); - - ModelModule<EntityDescriptor> model = module.typeLookup().lookupEntityModel( type ); - - if( model == null ) - { - throw new EntityTypeNotFoundException( type.getName(), - module.name(), - module.findVisibleEntityTypes().map( ModelModule.toStringFunction ) - ); - } - - EntityStore entityStore = model.module().entityStore(); - - FunctionStateResolver stateResolver = new FunctionStateResolver( - propertyFunction, associationFunction, manyAssociationFunction, namedAssociationFunction - ); - - if( identity == null ) - { - // Use identity from StateResolver if available - PropertyModel identityModel = (PropertyModel) model.model().state().findPropertyModelByQualifiedName( IDENTITY_STATE_NAME ); - identity = (String) stateResolver.getPropertyState( identityModel ); - if( identity == null ) - { - // Generate identity - IdentityGenerator idGen = model.module().identityGenerator(); - if( idGen == null ) - { - throw new NoSuchServiceException( IdentityGenerator.class.getName(), model.module().name() ); - } - identity = idGen.generate( model.model().types().findFirst().orElse( null )); - } - } - - return new EntityBuilderInstance<>( model, - this, - uow.getEntityStoreUnitOfWork( entityStore ), - identity, - stateResolver ); - } - - @Override - public <T> T get( Class<T> type, String identity ) - throws EntityTypeNotFoundException, NoSuchEntityException - { - Iterable<ModelModule<EntityDescriptor>> models = module.typeLookup().lookupEntityModels( type ); - - if( !models.iterator().hasNext() ) - { - throw new EntityTypeNotFoundException( type.getName(), - module.name(), - module.findVisibleEntityTypes().map( ModelModule.toStringFunction ) - ); - } - - return uow.get( parseEntityReference( identity ), this, models, type ); - } - - @Override - @SuppressWarnings( "unchecked" ) - public <T> T get( T entity ) - throws EntityTypeNotFoundException - { - EntityComposite entityComposite = (EntityComposite) entity; - EntityInstance compositeInstance = EntityInstance.entityInstanceOf( entityComposite ); - ModelModule<EntityDescriptor> model = new ModelModule<>( compositeInstance.module(), compositeInstance.entityModel() ); - Class<T> type = (Class<T>) compositeInstance.types().findFirst().orElse( null ); - return uow.get( compositeInstance.identity(), this, Collections.singletonList( model ), type ); - } - - @Override - public void remove( Object entity ) - throws LifecycleException - { - uow.checkOpen(); - - EntityComposite entityComposite = (EntityComposite) entity; - - EntityInstance compositeInstance = EntityInstance.entityInstanceOf( entityComposite ); - - if( compositeInstance.status() == EntityStatus.NEW ) - { - compositeInstance.remove( this ); - uow.remove( compositeInstance.identity() ); - } - else if( compositeInstance.status() == EntityStatus.LOADED || compositeInstance.status() == EntityStatus.UPDATED ) - { - compositeInstance.remove( this ); - } - else - { - throw new NoSuchEntityException( compositeInstance.identity(), compositeInstance.types(), usecase() ); - } - } - - @SuppressWarnings( "DuplicateThrows" ) - @Override - public void complete() - throws UnitOfWorkCompletionException, ConcurrentEntityModificationException - { - uow.complete(); - } - - @Override - public void discard() - { - uow.discard(); - } - - @Override - public void close() - { - discard(); - } - - @Override - public boolean isOpen() - { - return uow.isOpen(); - } - - @Override - public boolean isPaused() - { - return uow.isPaused(); - } - - @Override - public void pause() - { - uow.pause(); - } - - @Override - public void resume() - { - uow.resume(); - } - - @Override - public void addUnitOfWorkCallback( UnitOfWorkCallback callback ) - { - uow.addUnitOfWorkCallback( callback ); - } - - @Override - public void removeUnitOfWorkCallback( UnitOfWorkCallback callback ) - { - uow.removeUnitOfWorkCallback( callback ); - } - - @Override - public boolean equals( Object o ) - { - if( this == o ) - { - return true; - } - if( o == null || getClass() != o.getClass() ) - { - return false; - } - - ModuleUnitOfWork that = (ModuleUnitOfWork) o; - - return uow.equals( that.uow ); - } - - @Override - public int hashCode() - { - return uow.hashCode(); - } - - @Override - public String toString() - { - return uow.toString(); - } - - public void addEntity( EntityInstance instance ) - { - uow.addEntity( instance ); - } - - @Override - public <T extends Identity> T toValue( Class<T> primaryType, T entityComposite ) - { - Function<PropertyDescriptor, Object> propertyFunction = new ToValuePropertyMappingFunction( entityComposite ); - Function<AssociationDescriptor, EntityReference> assocationFunction = new ToValueAssociationMappingFunction<>( entityComposite ); - Function<AssociationDescriptor, Iterable<EntityReference>> manyAssocFunction = new ToValueManyAssociationMappingFunction<>( entityComposite ); - Function<AssociationDescriptor, Map<String, EntityReference>> namedAssocFunction = new ToValueNameAssociationMappingFunction<>( entityComposite ); - - @SuppressWarnings( "unchecked" ) - ValueBuilder<T> builder = module().newValueBuilderWithState( - primaryType, propertyFunction, assocationFunction, manyAssocFunction, namedAssocFunction ); - return builder.newInstance(); - } - - @Override - public <T extends Identity> T toEntity( Class<T> primaryType, T valueComposite ) - { - Function<PropertyDescriptor, Object> propertyFunction = new ToEntityPropertyMappingFunction<>( valueComposite ); - Function<AssociationDescriptor, EntityReference> assocationFunction = new ToEntityAssociationMappingFunction<>( valueComposite ); - Function<AssociationDescriptor, Iterable<EntityReference>> manyAssocFunction = new ToEntityManyAssociationMappingFunction<>( valueComposite ); - Function<AssociationDescriptor, Map<String, EntityReference>> namedAssocFunction = new ToEntityNameAssociationMappingFunction<>( valueComposite ); - - String identity = valueComposite.identity().get(); - try - { - T entity = get( primaryType, identity ); - // If successful, then this entity is to by modified. - EntityInstance instance = EntityInstance.entityInstanceOf( (EntityComposite) entity ); - EntityState state = instance.entityState(); - FunctionStateResolver stateResolver = new FunctionStateResolver( propertyFunction, - assocationFunction, - manyAssocFunction, - namedAssocFunction ); - EntityModel model = (EntityModel) EntityInstance.entityInstanceOf( (EntityComposite) entity ).descriptor(); - stateResolver.populateState( model, state ); - return entity; - } - catch( NoSuchEntityException e ) - { - EntityBuilder<T> entityBuilder = newEntityBuilderWithState( primaryType, - identity, - propertyFunction, - assocationFunction, - manyAssocFunction, - namedAssocFunction ); - return entityBuilder.newInstance(); - } - } - - private static class UoWQuerySource implements QuerySource - { - private final ModuleUnitOfWork moduleUnitOfWork; - - private UoWQuerySource( ModuleUnitOfWork moduleUnitOfWork ) - { - this.moduleUnitOfWork = moduleUnitOfWork; - } - - @Override - public <T> T find( Class<T> resultType, - Predicate<Composite> whereClause, - Iterable<OrderBy> orderBySegments, - Integer firstResult, - Integer maxResults, - Map<String, Object> variables - ) - { - final EntityFinder entityFinder = moduleUnitOfWork.module().findService( EntityFinder.class ).get(); - - try - { - final EntityReference foundEntity = entityFinder.findEntity( resultType, whereClause, variables == null ? Collections - .<String, Object>emptyMap() : variables ); - if( foundEntity != null ) - { - try - { - return moduleUnitOfWork.get( resultType, foundEntity.identity() ); - } - catch( NoSuchEntityException e ) - { - return null; // Index is out of sync - entity has been removed - } - } - // No entity was found - return null; - } - catch( EntityFinderException e ) - { - throw new QueryExecutionException( "Finder caused exception", e ); - } - } - - @Override - public <T> long count( Class<T> resultType, - Predicate<Composite> whereClause, - Iterable<OrderBy> orderBySegments, - Integer firstResult, - Integer maxResults, - Map<String, Object> variables - ) - { - final EntityFinder entityFinder = moduleUnitOfWork.module().findService( EntityFinder.class ).get(); - - try - { - return entityFinder.countEntities( resultType, whereClause, variables == null ? Collections.<String, Object>emptyMap() : variables ); - } - catch( EntityFinderException e ) - { - e.printStackTrace(); - return 0; - } - } - - @Override - public <T> Iterator<T> iterator( final Class<T> resultType, - Predicate<Composite> whereClause, - Iterable<OrderBy> orderBySegments, - Integer firstResult, - Integer maxResults, - Map<String, Object> variables - ) - { - final EntityFinder entityFinder = moduleUnitOfWork.module().findService( EntityFinder.class ).get(); - - try - { - final Iterator<EntityReference> foundEntities = entityFinder.findEntities( resultType, - whereClause, - Iterables.toArray( OrderBy.class, orderBySegments ), - firstResult, - maxResults, - variables == null ? Collections - .<String, Object>emptyMap() : variables ) - .iterator(); - - return new Iterator<T>() - { - @Override - public boolean hasNext() - { - return foundEntities.hasNext(); - } - - @Override - public T next() - { - final EntityReference foundEntity = foundEntities.next(); - try - { - return moduleUnitOfWork.get( resultType, foundEntity.identity() ); - } - catch( NoSuchEntityException e ) - { - // Index is out of sync - entity has been removed - return null; - } - } - - @Override - public void remove() - { - throw new UnsupportedOperationException(); - } - }; - } - catch( EntityFinderException e ) - { - throw new QueryExecutionException( "Query '" + toString() + "' could not be executed", e ); - } - } - - @Override - public String toString() - { - return "UnitOfWork( " + moduleUnitOfWork.usecase().name() + " )"; - } - } - - private class ToValuePropertyMappingFunction - implements Function<PropertyDescriptor, Object> - { - private Object entity; - - public ToValuePropertyMappingFunction( Object entity ) - { - this.entity = entity; - } - - @Override - public Object apply( PropertyDescriptor propertyDescriptor ) - { - EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState(); - return entityState.propertyValueOf( propertyDescriptor.qualifiedName() ); - } - } - - private class ToValueAssociationMappingFunction<T> - implements Function<AssociationDescriptor, EntityReference> - { - private final T entity; - - public ToValueAssociationMappingFunction( T entity ) - { - this.entity = entity; - } - - @Override - public EntityReference apply( AssociationDescriptor associationDescriptor ) - { - EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState(); - return entityState.associationValueOf( associationDescriptor.qualifiedName() ); - } - } - - private class ToValueManyAssociationMappingFunction<T> - implements Function<AssociationDescriptor, Iterable<EntityReference>> - { - private final T entity; - - public ToValueManyAssociationMappingFunction( T entity ) - { - this.entity = entity; - } - - @Override - public Iterable<EntityReference> apply( AssociationDescriptor associationDescriptor ) - { - EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState(); - return entityState.manyAssociationValueOf( associationDescriptor.qualifiedName() ); - } - } - - private class ToValueNameAssociationMappingFunction<T> - implements Function<AssociationDescriptor, Map<String, EntityReference>> - { - private final T entity; - - public ToValueNameAssociationMappingFunction( T entity ) - { - this.entity = entity; - } - - @Override - public Map<String, EntityReference> apply( AssociationDescriptor associationDescriptor ) - { - Map<String, EntityReference> result = new HashMap<>(); - EntityState entityState = EntityInstance.entityInstanceOf( (EntityComposite) entity ).entityState(); - final NamedAssociationState state = entityState.namedAssociationValueOf( associationDescriptor.qualifiedName() ); - for( String name : state ) - { - result.put( name, state.get( name ) ); - } - return result; - } - } - - private class ToEntityPropertyMappingFunction<T> - implements Function<PropertyDescriptor, Object> - { - private final T value; - - public ToEntityPropertyMappingFunction( T value ) - { - this.value = value; - } - - @Override - public Object apply( PropertyDescriptor propertyDescriptor ) - { - StateHolder state = ValueInstance.valueInstanceOf( (ValueComposite) value ).state(); - Property<Object> property = state.propertyFor( propertyDescriptor.accessor() ); - return property.get(); - } - } - - private class ToEntityAssociationMappingFunction<T> - implements Function<AssociationDescriptor, EntityReference> - { - - private final T value; - - public ToEntityAssociationMappingFunction( T value ) - { - this.value = value; - } - - @Override - public EntityReference apply( AssociationDescriptor associationDescriptor ) - { - AssociationStateHolder state = ValueInstance.valueInstanceOf( (ValueComposite) value ).state(); - AssociationInstance<T> association = (AssociationInstance<T>) state.associationFor( associationDescriptor.accessor() ); - return association.getAssociationState().get(); - } - } - - private class ToEntityManyAssociationMappingFunction<T> - implements Function<AssociationDescriptor, Iterable<EntityReference>> - { - - private final T value; - - public ToEntityManyAssociationMappingFunction( T valueComposite ) - { - this.value = valueComposite; - } - - @Override - public Iterable<EntityReference> apply( AssociationDescriptor associationDescriptor ) - { - AssociationStateHolder state = ValueInstance.valueInstanceOf( (ValueComposite) value ).state(); - ManyAssociationInstance<T> association = - (ManyAssociationInstance<T>) state.manyAssociationFor( associationDescriptor.accessor() ); - return association.getManyAssociationState(); - } - } - - private class ToEntityNameAssociationMappingFunction<T> - implements Function<AssociationDescriptor, Map<String, EntityReference>> - { - private final T value; - - public ToEntityNameAssociationMappingFunction( T valueComposite ) - { - this.value = valueComposite; - } - - @Override - public Map<String, EntityReference> apply( AssociationDescriptor associationDescriptor ) - { - AssociationStateHolder state = ValueInstance.valueInstanceOf( (ValueComposite) value ).state(); - NamedAssociationInstance<T> association = - (NamedAssociationInstance<T>) state.namedAssociationFor( associationDescriptor.accessor() ); - HashMap<String, EntityReference> result = new HashMap<>(); - for( Map.Entry<String, EntityReference> entry : association.getEntityReferences() ) - { - result.put( entry.getKey(), entry.getValue() ); - } - return result; - } - } -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a5be013f/core/runtime/src/main/java/org/apache/zest/runtime/structure/TypeLookup.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/structure/TypeLookup.java b/core/runtime/src/main/java/org/apache/zest/runtime/structure/TypeLookup.java deleted file mode 100755 index 6947b73..0000000 --- a/core/runtime/src/main/java/org/apache/zest/runtime/structure/TypeLookup.java +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright (c) 2008-2012, Rickard Ãberg. - * Copyright (c) 2008-2012, Niclas Hedhman. - * Copyright (c) 2012, Paul Merlin. - * - * 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.apache.zest.runtime.structure; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.WildcardType; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.apache.zest.api.common.Visibility; -import org.apache.zest.api.composite.AmbiguousTypeException; -import org.apache.zest.api.composite.ModelDescriptor; -import org.apache.zest.api.composite.TransientDescriptor; -import org.apache.zest.api.entity.EntityDescriptor; -import org.apache.zest.api.object.ObjectDescriptor; -import org.apache.zest.api.service.NoSuchServiceException; -import org.apache.zest.api.service.ServiceReference; -import org.apache.zest.api.type.HasTypes; -import org.apache.zest.api.value.ValueDescriptor; -import org.apache.zest.spi.module.ModelModule; - -import static java.util.stream.Stream.concat; -import static org.apache.zest.api.common.Visibility.application; -import static org.apache.zest.api.common.Visibility.layer; -import static org.apache.zest.api.common.Visibility.module; -import static org.apache.zest.api.util.Classes.RAW_CLASS; -import static org.apache.zest.api.util.Classes.interfacesOf; -import static org.apache.zest.functional.Iterables.first; - -/** - * Central place for Composite Type lookups. - */ -public class TypeLookup -{ - - // Constructor parameters - private final ModuleInstance moduleInstance; - // Eager instance objects - private final Map<Class<?>, ModelModule<ObjectDescriptor>> objectModels; - private final Map<Class<?>, ModelModule<TransientDescriptor>> transientModels; - private final Map<Class<?>, ModelModule<ValueDescriptor>> valueModels; - private final Map<Class<?>, List<ModelModule<EntityDescriptor>>> allEntityModels; - private final Map<Class<?>, ModelModule<EntityDescriptor>> unambiguousEntityModels; - private final Map<Type, ServiceReference<?>> serviceReferences; - private final Map<Type, List<ServiceReference<?>>> servicesReferences; - - /** - * Create a new TypeLookup bound to the given ModuleInstance. - * - * @param moduleInstance ModuleInstance bound to this TypeLookup - */ - TypeLookup( ModuleInstance moduleInstance ) - { - // Constructor parameters - this.moduleInstance = moduleInstance; - - // Eager instance objects - objectModels = new ConcurrentHashMap<>(); - transientModels = new ConcurrentHashMap<>(); - valueModels = new ConcurrentHashMap<>(); - allEntityModels = new ConcurrentHashMap<>(); - unambiguousEntityModels = new ConcurrentHashMap<>(); - serviceReferences = new ConcurrentHashMap<>(); - servicesReferences = new ConcurrentHashMap<>(); - } - - /** - * Lookup first Object Model matching the given Type. - * - * <p>First, if Object Models exactly match the given type, the closest one (Visibility then Assembly order) is returned. - * Multiple <b>exact</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> - * - * <p>Second, if Object Models match a type assignable to the given type, the closest one (Visibility then Assembly order) is returned. - * Multiple <b>assignable</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> - * - * <p>Type lookup is done lazily and cached.</p> - * - * @param type Looked up Type - * - * @return First matching Object Model - */ - ModelModule<ObjectDescriptor> lookupObjectModel( final Class type ) - { - ModelModule<ObjectDescriptor> model = objectModels.get( type ); - if( model == null ) - { - List<ModelModule<ObjectDescriptor>> allModels = allObjects().collect( Collectors.toList() ); - model = ambiguityMatching( type, allModels, new ExactTypeMatching<>( type ) ); - if( model == null ) - { - model = ambiguityMatching( type, allModels, new AssignableFromTypeMatching<>( type ) ); - } - if( model != null ) - { - objectModels.put( type, model ); - } - } - return model; - } - - /** - * Lookup first Transient Model matching the given Type. - * - * <p>First, if Transient Models exactly match the given type, the closest one (Visibility then Assembly order) is returned. - * Multiple <b>exact</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> - * - * <p>Second, if Transient Models match a type assignable to the given type, the closest one (Visibility then Assembly order) is returned. - * Multiple <b>assignable</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> - * - * <p>Type lookup is done lazily and cached.</p> - * - * @param type Looked up Type - * - * @return First matching Transient Model - */ - ModelModule<TransientDescriptor> lookupTransientModel( final Class type ) - { - ModelModule<TransientDescriptor> model = transientModels.get( type ); - if( model == null ) - { - List<ModelModule<TransientDescriptor>> allModels = allTransients().collect( Collectors.toList() ); - model = ambiguityMatching( type, allModels, new ExactTypeMatching<>( type ) ); - if( model == null ) - { - model = ambiguityMatching( type, allModels, new AssignableFromTypeMatching<>( type ) ); - } - if( model != null ) - { - transientModels.put( type, model ); - } - } - return model; - } - - /** - * Lookup first Value Model matching the given Type. - * - * <p>First, if Value Models exactly match the given type, the closest one (Visibility then Assembly order) is returned. - * Multiple <b>exact</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> - * - * <p>Second, if Value Models match a type assignable to the given type, the closest one (Visibility then Assembly order) is returned. - * Multiple <b>assignable</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> - * - * <p>Type lookup is done lazily and cached.</p> - * - * @param type Looked up Type - * - * @return First matching Value Model - */ - public ModelModule<ValueDescriptor> lookupValueModel( final Class type ) - { - ModelModule<ValueDescriptor> model = valueModels.get( type ); - if( model == null ) - { - List<ModelModule<ValueDescriptor>> allModels = allValues().collect( Collectors.toList() ); - model = ambiguityMatching( type, allModels, new ExactTypeMatching<>( type ) ); - if( model == null ) - { - model = ambiguityMatching( type, allModels, new AssignableFromTypeMatching<>( type ) ); - } - if( model != null ) - { - valueModels.put( type, model ); - } - } - return model; - } - - /** - * Lookup first Entity Model matching the given Type. - * - * <p>First, if Entity Models exactly match the given type, the closest one (Visibility then Assembly order) is returned. - * Multiple <b>exact</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> - * - * <p>Second, if Entity Models match a type assignable to the given type, the closest one (Visibility then Assembly order) is returned. - * Multiple <b>assignable</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> - * - * <p>Type lookup is done lazily and cached.</p> - * - * <p><b>Should be used for creational use cases only.</b> For non-creational use cases see - * {@link #lookupEntityModels(java.lang.Class)}.</p> - * - * @param type Looked up Type - * - * @return First matching Entity Model - */ - ModelModule<EntityDescriptor> lookupEntityModel( final Class type ) - { - ModelModule<EntityDescriptor> model = unambiguousEntityModels.get( type ); - - if( model == null ) - { - List<ModelModule<EntityDescriptor>> allModels = allEntities().collect( Collectors.toList() ); - model = ambiguityMatching( type, allModels, new ExactTypeMatching<>( type ) ); - if( model == null ) - { - model = ambiguityMatching( type, allModels, new AssignableFromTypeMatching<>( type ) ); - } - if( model != null ) - { - unambiguousEntityModels.put( type, model ); - } - } - return model; - } - - /** - * Lookup all Entity Models matching the given Type. - * - * <p>Returned Iterable contains, in order, Entity Models that: </p> - * - * <ul> - * <li>exactly match the given type, in Visibility then Assembly order ;</li> - * <li>match a type assignable to the given type, in Visibility then Assembly order.</li> - * </ul> - * - * <p>Multiple <b>exact</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> - * <p>Multiple <b>assignable</b> matches are <b>allowed</b> to enable polymorphic fetches and queries.</p> - * - * <p>Type lookup is done lazily and cached.</p> - * - * <p><b>Should be used for non-creational use cases only.</b> For creational use cases see - * {@link #lookupEntityModel(java.lang.Class)}.</p> - * - * @param type Looked up Type - * - * @return All matching Entity Models - */ - Iterable<ModelModule<EntityDescriptor>> lookupEntityModels( final Class type ) - { - List<ModelModule<EntityDescriptor>> result = allEntityModels.get( type ); - if( result == null ) - { - result = concat( - allEntities().filter( ref -> new ExactTypeMatching<>( type ).test( ref.model() ) ), - allEntities().filter( ref -> new AssignableFromTypeMatching<>( type ).test( ref.model() ) ) - ).distinct().collect( Collectors.toList() ); - allEntityModels.put( type, result ); - } - return result; - } - - /** - * Lookup first ServiceReference matching the given Type. - * - * <p>Type lookup is done lazily and cached.</p> - * - * <p>See {@link #lookupServiceReferences(Type)}.</p> - * - * @param <T> Service Type - * @param serviceType Looked up Type - * - * @return First matching ServiceReference - */ - <T> ServiceReference<T> lookupServiceReference( Type serviceType ) - { - @SuppressWarnings( "unchecked" ) - ServiceReference<T> serviceReference = (ServiceReference<T>) serviceReferences.get( serviceType ); - if( serviceReference == null ) - { - // Lazily resolve ServiceReference - serviceReference = first( lookupServiceReferences( serviceType ) ); - if( serviceReference != null ) - { - serviceReferences.put( serviceType, serviceReference ); - } - } - - if( serviceReference == null ) - { - throw new NoSuchServiceException( RAW_CLASS.apply( serviceType ).getName(), moduleInstance.name() ); - } - return serviceReference; - } - - /** - * Lookup all ServiceReferences matching the given Type. - * - * <p>Returned Iterable contains, in order, ServiceReferences that: </p> - * - * <ul> - * <li>exactly match the given type, in Visibility then Assembly order ;</li> - * <li>match a type assignable to the given type, in Visibility then Assembly order.</li> - * </ul> - * - * <p>Multiple <b>exact</b> matches with the same Visibility are <b>allowed</b> to enable polymorphic lookup/injection.</p> - * <p>Multiple <b>assignable</b> matches with the same Visibility are <b>allowed</b> for the very same reason.</p> - * - * <p>Type lookup is done lazily and cached.</p> - * - * @param <T> Service Type - * @param type Looked up Type - * - * @return All matching ServiceReferences - */ - <T> List<ServiceReference<T>> lookupServiceReferences( final Type type ) - { - List<ServiceReference<?>> serviceRefs = servicesReferences.get( type ); - if( serviceRefs == null ) - { - serviceRefs = concat( - allServices() - .filter( new ExactTypeMatching<>( type ) ), - allServices() - .filter( new AssignableFromTypeMatching<>( type ) - ) - ).distinct().collect( Collectors.toList() ); - servicesReferences.put( type, serviceRefs ); - } - List<ServiceReference<T>> result = new ArrayList<>(); - //noinspection unchecked - serviceRefs.forEach( ref -> result.add( (ServiceReference<T>) ref ) ); - return result; - } - - public Stream<Class<?>> allVisibleObjects() - { - return allObjects().flatMap( model -> model.model().types() ); - } - - private Stream<ModelModule<ObjectDescriptor>> allObjects() - { - return concat( moduleInstance.visibleObjects( module ), - concat( - moduleInstance.layerInstance().visibleObjects( layer ), - concat( - moduleInstance.layerInstance().visibleObjects( application ), - moduleInstance.layerInstance().usedLayersInstance().visibleObjects() - ) - ) - ); - } - - private Stream<ModelModule<TransientDescriptor>> allTransients() - { - return concat( moduleInstance.visibleTransients( module ), - concat( - moduleInstance.layerInstance().visibleTransients( layer ), - concat( - moduleInstance.layerInstance().visibleTransients( application ), - moduleInstance.layerInstance().usedLayersInstance().visibleTransients() - ) - ) - ); - } - - private Stream<ModelModule<ValueDescriptor>> allValues() - { - return concat( moduleInstance.visibleValues( module ), - concat( - moduleInstance.layerInstance().visibleValues( layer ), - concat( - moduleInstance.layerInstance().visibleValues( application ), - moduleInstance.layerInstance().usedLayersInstance().visibleValues() - ) - ) - ); - } - - private Stream<ModelModule<EntityDescriptor>> allEntities() - { - return concat( moduleInstance.visibleEntities( module ), - concat( - moduleInstance.layerInstance().visibleEntities( layer ), - concat( - moduleInstance.layerInstance().visibleEntities( application ), - moduleInstance.layerInstance().usedLayersInstance().visibleEntities() - ) - ) - ); - } - - private Stream<ServiceReference<?>> allServices() - { - return concat( moduleInstance.visibleServices( module ), - concat( - moduleInstance.layerInstance().visibleServices( layer ), - concat( - moduleInstance.layerInstance().visibleServices( application ), - moduleInstance.layerInstance().usedLayersInstance().visibleServices() - ) - ) - ); - } - - private <T extends ModelDescriptor> ModelModule<T> ambiguityMatching( - Class type, - List<ModelModule<T>> modelModules, - TypeMatching<T> matching - ) - { - List<ModelModule<T>> models = modelModules.stream() - .filter( ref -> matching.test( ref.model() ) ) - .filter( new SameVisibility<>() ) - .distinct() - .collect( Collectors.toList() ); - - if( models.size() > 1 ) - { - throw new AmbiguousTypeException( "More than one type matches " + type.getName() + ": " + models + "]" ); - } - if( models.isEmpty() ) - { - return null; - } - return models.get( 0 ); - } - - private static abstract class TypeMatching<T extends HasTypes> - implements Predicate<T> - { - protected final Type lookedUpType; - - protected TypeMatching( Type lookedUpType ) - { - this.lookedUpType = lookedUpType; - } - - @Override - public final boolean test( T model ) - { - if( lookedUpType instanceof Class ) - { - return model.types().anyMatch( checkMatch( lookedUpType ) ); - } - else - { - if( lookedUpType instanceof ParameterizedType ) - { - // Foo<Bar> check - // First check Foo - ParameterizedType parameterizedType = (ParameterizedType) lookedUpType; - Type rawType = parameterizedType.getRawType(); - if( !model.types().anyMatch( checkMatch( rawType ) ) ) - { - return false; - } - // Then check Bar - return interfacesOf( model.types() ).anyMatch( intf -> intf.equals( lookedUpType ) ); - } - else if( lookedUpType instanceof WildcardType ) - { - return true; - } - return false; - } - } - - protected abstract Predicate<Type> checkMatch( Type matchTo ); - } - - private static final class ExactTypeMatching<T extends HasTypes> extends TypeMatching<T> - { - private ExactTypeMatching( Type lookedUpType ) - { - super( lookedUpType ); - } - - protected Predicate<Type> checkMatch( Type matchTo ) - { - return matchTo::equals; - } - } - - private static final class AssignableFromTypeMatching<T extends HasTypes> extends TypeMatching<T> - { - private AssignableFromTypeMatching( Type lookedUpType ) - { - super( lookedUpType ); - } - - protected Predicate<Type> checkMatch( Type matchTo ) - { - // TODO; what to do if there is ParameterizedType here?? Now set to ClassCastException and see if anything surfaces -// if( matchTo instanceof Class ) - { - Class<?> clazz = (Class<?>) matchTo; - return candidate -> - !candidate.equals( matchTo ) && clazz.isAssignableFrom( (Class<?>) candidate ); - } -// return candidate -> candidate.equals( matchTo ); - } - } - - /** - * This Predicate will filter out all Models that doesn't have the same visisbility as the first one. - */ - private class SameVisibility<T extends ModelDescriptor> - implements Predicate<ModelModule<T>> - { - private Visibility current = null; - - @Override - public boolean test( ModelModule<T> model ) - { - if( current == null ) - { - current = model.model().visibility(); - return true; - } - return current == model.model().visibility(); - } - } -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a5be013f/core/runtime/src/main/java/org/apache/zest/runtime/structure/TypeLookupImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/structure/TypeLookupImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/structure/TypeLookupImpl.java new file mode 100755 index 0000000..7835aaa --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/structure/TypeLookupImpl.java @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2008-2012, Rickard Ãberg. + * Copyright (c) 2008-2012, Niclas Hedhman. + * Copyright (c) 2012, Paul Merlin. + * + * 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.apache.zest.runtime.structure; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.zest.api.common.Visibility; +import org.apache.zest.api.composite.AmbiguousTypeException; +import org.apache.zest.api.composite.ModelDescriptor; +import org.apache.zest.api.composite.TransientDescriptor; +import org.apache.zest.api.entity.EntityDescriptor; +import org.apache.zest.api.object.ObjectDescriptor; +import org.apache.zest.api.service.NoSuchServiceException; +import org.apache.zest.api.service.ServiceReference; +import org.apache.zest.api.type.HasTypes; +import org.apache.zest.api.value.ValueDescriptor; +import org.apache.zest.spi.structure.ModelModule; +import org.apache.zest.spi.structure.TypeLookup; + +import static java.util.stream.Stream.concat; +import static org.apache.zest.api.common.Visibility.application; +import static org.apache.zest.api.common.Visibility.layer; +import static org.apache.zest.api.common.Visibility.module; +import static org.apache.zest.api.util.Classes.RAW_CLASS; +import static org.apache.zest.api.util.Classes.interfacesOf; +import static org.apache.zest.functional.Iterables.first; + +/** + * Central place for Composite Type lookups. + */ +public class TypeLookupImpl + implements TypeLookup +{ + + // Constructor parameters + private final ModuleInstance moduleInstance; + // Eager instance objects + private final Map<Class<?>, ModelModule<ObjectDescriptor>> objectModels; + private final Map<Class<?>, ModelModule<TransientDescriptor>> transientModels; + private final Map<Class<?>, ModelModule<ValueDescriptor>> valueModels; + private final Map<Class<?>, List<ModelModule<EntityDescriptor>>> allEntityModels; + private final Map<Class<?>, ModelModule<EntityDescriptor>> unambiguousEntityModels; + private final Map<Type, ServiceReference<?>> serviceReferences; + private final Map<Type, List<ServiceReference<?>>> servicesReferences; + + /** + * Create a new TypeLookup bound to the given ModuleInstance. + * + * @param moduleInstance ModuleInstance bound to this TypeLookup + */ + TypeLookupImpl( ModuleInstance moduleInstance ) + { + // Constructor parameters + this.moduleInstance = moduleInstance; + + // Eager instance objects + objectModels = new ConcurrentHashMap<>(); + transientModels = new ConcurrentHashMap<>(); + valueModels = new ConcurrentHashMap<>(); + allEntityModels = new ConcurrentHashMap<>(); + unambiguousEntityModels = new ConcurrentHashMap<>(); + serviceReferences = new ConcurrentHashMap<>(); + servicesReferences = new ConcurrentHashMap<>(); + } + + /** + * Lookup first Object Model matching the given Type. + * + * <p>First, if Object Models exactly match the given type, the closest one (Visibility then Assembly order) is returned. + * Multiple <b>exact</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> + * + * <p>Second, if Object Models match a type assignable to the given type, the closest one (Visibility then Assembly order) is returned. + * Multiple <b>assignable</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> + * + * <p>Type lookup is done lazily and cached.</p> + * + * @param type Looked up Type + * + * @return First matching Object Model + */ + ModelModule<ObjectDescriptor> lookupObjectModel( final Class type ) + { + ModelModule<ObjectDescriptor> model = objectModels.get( type ); + if( model == null ) + { + List<ModelModule<ObjectDescriptor>> allModels = allObjects().collect( Collectors.toList() ); + model = ambiguityMatching( type, allModels, new ExactTypeMatching<>( type ) ); + if( model == null ) + { + model = ambiguityMatching( type, allModels, new AssignableFromTypeMatching<>( type ) ); + } + if( model != null ) + { + objectModels.put( type, model ); + } + } + return model; + } + + /** + * Lookup first Transient Model matching the given Type. + * + * <p>First, if Transient Models exactly match the given type, the closest one (Visibility then Assembly order) is returned. + * Multiple <b>exact</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> + * + * <p>Second, if Transient Models match a type assignable to the given type, the closest one (Visibility then Assembly order) is returned. + * Multiple <b>assignable</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> + * + * <p>Type lookup is done lazily and cached.</p> + * + * @param type Looked up Type + * + * @return First matching Transient Model + */ + ModelModule<TransientDescriptor> lookupTransientModel( final Class type ) + { + ModelModule<TransientDescriptor> model = transientModels.get( type ); + if( model == null ) + { + List<ModelModule<TransientDescriptor>> allModels = allTransients().collect( Collectors.toList() ); + model = ambiguityMatching( type, allModels, new ExactTypeMatching<>( type ) ); + if( model == null ) + { + model = ambiguityMatching( type, allModels, new AssignableFromTypeMatching<>( type ) ); + } + if( model != null ) + { + transientModels.put( type, model ); + } + } + return model; + } + + /** + * Lookup first Value Model matching the given Type. + * + * <p>First, if Value Models exactly match the given type, the closest one (Visibility then Assembly order) is returned. + * Multiple <b>exact</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> + * + * <p>Second, if Value Models match a type assignable to the given type, the closest one (Visibility then Assembly order) is returned. + * Multiple <b>assignable</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> + * + * <p>Type lookup is done lazily and cached.</p> + * + * @param type Looked up Type + * + * @return First matching Value Model + */ + public ModelModule<ValueDescriptor> lookupValueModel( final Class type ) + { + ModelModule<ValueDescriptor> model = valueModels.get( type ); + if( model == null ) + { + List<ModelModule<ValueDescriptor>> allModels = allValues().collect( Collectors.toList() ); + model = ambiguityMatching( type, allModels, new ExactTypeMatching<>( type ) ); + if( model == null ) + { + model = ambiguityMatching( type, allModels, new AssignableFromTypeMatching<>( type ) ); + } + if( model != null ) + { + valueModels.put( type, model ); + } + } + return model; + } + + /** + * Lookup first Entity Model matching the given Type. + * + * <p>First, if Entity Models exactly match the given type, the closest one (Visibility then Assembly order) is returned. + * Multiple <b>exact</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> + * + * <p>Second, if Entity Models match a type assignable to the given type, the closest one (Visibility then Assembly order) is returned. + * Multiple <b>assignable</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> + * + * <p>Type lookup is done lazily and cached.</p> + * + * <p><b>Should be used for creational use cases only.</b> For non-creational use cases see + * {@link #lookupEntityModels(java.lang.Class)}.</p> + * + * @param type Looked up Type + * + * @return First matching Entity Model + */ + @Override + public ModelModule<EntityDescriptor> lookupEntityModel( final Class type ) + { + ModelModule<EntityDescriptor> model = unambiguousEntityModels.get( type ); + + if( model == null ) + { + List<ModelModule<EntityDescriptor>> allModels = allEntities().collect( Collectors.toList() ); + model = ambiguityMatching( type, allModels, new ExactTypeMatching<>( type ) ); + if( model == null ) + { + model = ambiguityMatching( type, allModels, new AssignableFromTypeMatching<>( type ) ); + } + if( model != null ) + { + unambiguousEntityModels.put( type, model ); + } + } + return model; + } + + /** + * Lookup all Entity Models matching the given Type. + * + * <p>Returned Iterable contains, in order, Entity Models that: </p> + * + * <ul> + * <li>exactly match the given type, in Visibility then Assembly order ;</li> + * <li>match a type assignable to the given type, in Visibility then Assembly order.</li> + * </ul> + * + * <p>Multiple <b>exact</b> matches with the same Visibility are <b>forbidden</b> and result in an AmbiguousTypeException.</p> + * <p>Multiple <b>assignable</b> matches are <b>allowed</b> to enable polymorphic fetches and queries.</p> + * + * <p>Type lookup is done lazily and cached.</p> + * + * <p><b>Should be used for non-creational use cases only.</b> For creational use cases see + * {@link #lookupEntityModel(java.lang.Class)}.</p> + * + * @param type Looked up Type + * + * @return All matching Entity Models + */ + @Override + public Iterable<ModelModule<EntityDescriptor>> lookupEntityModels( final Class type ) + { + List<ModelModule<EntityDescriptor>> result = allEntityModels.get( type ); + if( result == null ) + { + result = concat( + allEntities().filter( ref -> new ExactTypeMatching<>( type ).test( ref.model() ) ), + allEntities().filter( ref -> new AssignableFromTypeMatching<>( type ).test( ref.model() ) ) + ).distinct().collect( Collectors.toList() ); + allEntityModels.put( type, result ); + } + return result; + } + + /** + * Lookup first ServiceReference matching the given Type. + * + * <p>Type lookup is done lazily and cached.</p> + * + * <p>See {@link #lookupServiceReferences(Type)}.</p> + * + * @param <T> Service Type + * @param serviceType Looked up Type + * + * @return First matching ServiceReference + */ + @Override + public <T> ServiceReference<T> lookupServiceReference( Type serviceType ) + { + @SuppressWarnings( "unchecked" ) + ServiceReference<T> serviceReference = (ServiceReference<T>) serviceReferences.get( serviceType ); + if( serviceReference == null ) + { + // Lazily resolve ServiceReference + serviceReference = first( lookupServiceReferences( serviceType ) ); + if( serviceReference != null ) + { + serviceReferences.put( serviceType, serviceReference ); + } + } + + if( serviceReference == null ) + { + throw new NoSuchServiceException( RAW_CLASS.apply( serviceType ).getName(), moduleInstance.name() ); + } + return serviceReference; + } + + /** + * Lookup all ServiceReferences matching the given Type. + * + * <p>Returned Iterable contains, in order, ServiceReferences that: </p> + * + * <ul> + * <li>exactly match the given type, in Visibility then Assembly order ;</li> + * <li>match a type assignable to the given type, in Visibility then Assembly order.</li> + * </ul> + * + * <p>Multiple <b>exact</b> matches with the same Visibility are <b>allowed</b> to enable polymorphic lookup/injection.</p> + * <p>Multiple <b>assignable</b> matches with the same Visibility are <b>allowed</b> for the very same reason.</p> + * + * <p>Type lookup is done lazily and cached.</p> + * + * @param <T> Service Type + * @param type Looked up Type + * + * @return All matching ServiceReferences + */ + @Override + public <T> List<ServiceReference<T>> lookupServiceReferences( final Type type ) + { + List<ServiceReference<?>> serviceRefs = servicesReferences.get( type ); + if( serviceRefs == null ) + { + serviceRefs = concat( + allServices() + .filter( new ExactTypeMatching<>( type ) ), + allServices() + .filter( new AssignableFromTypeMatching<>( type ) + ) + ).distinct().collect( Collectors.toList() ); + servicesReferences.put( type, serviceRefs ); + } + List<ServiceReference<T>> result = new ArrayList<>(); + //noinspection unchecked + serviceRefs.forEach( ref -> result.add( (ServiceReference<T>) ref ) ); + return result; + } + + @Override + public Stream<Class<?>> allVisibleObjects() + { + return allObjects().flatMap( model -> model.model().types() ); + } + + @Override + public Stream<ModelModule<ObjectDescriptor>> allObjects() + { + return concat( moduleInstance.visibleObjects( module ), + concat( + moduleInstance.layerInstance().visibleObjects( layer ), + concat( + moduleInstance.layerInstance().visibleObjects( application ), + moduleInstance.layerInstance().usedLayersInstance().visibleObjects() + ) + ) + ); + } + + @Override + public Stream<ModelModule<TransientDescriptor>> allTransients() + { + return concat( moduleInstance.visibleTransients( module ), + concat( + moduleInstance.layerInstance().visibleTransients( layer ), + concat( + moduleInstance.layerInstance().visibleTransients( application ), + moduleInstance.layerInstance().usedLayersInstance().visibleTransients() + ) + ) + ); + } + + @Override + public Stream<ModelModule<ValueDescriptor>> allValues() + { + return concat( moduleInstance.visibleValues( module ), + concat( + moduleInstance.layerInstance().visibleValues( layer ), + concat( + moduleInstance.layerInstance().visibleValues( application ), + moduleInstance.layerInstance().usedLayersInstance().visibleValues() + ) + ) + ); + } + + @Override + public Stream<ModelModule<EntityDescriptor>> allEntities() + { + return concat( moduleInstance.visibleEntities( module ), + concat( + moduleInstance.layerInstance().visibleEntities( layer ), + concat( + moduleInstance.layerInstance().visibleEntities( application ), + moduleInstance.layerInstance().usedLayersInstance().visibleEntities() + ) + ) + ); + } + + @Override + public Stream<ServiceReference<?>> allServices() + { + return concat( moduleInstance.visibleServices( module ), + concat( + moduleInstance.layerInstance().visibleServices( layer ), + concat( + moduleInstance.layerInstance().visibleServices( application ), + moduleInstance.layerInstance().usedLayersInstance().visibleServices() + ) + ) + ); + } + + private <T extends ModelDescriptor> ModelModule<T> ambiguityMatching( + Class type, + List<ModelModule<T>> modelModules, + TypeMatching<T> matching + ) + { + List<ModelModule<T>> models = modelModules.stream() + .filter( ref -> matching.test( ref.model() ) ) + .filter( new SameVisibility<>() ) + .distinct() + .collect( Collectors.toList() ); + + if( models.size() > 1 ) + { + throw new AmbiguousTypeException( "More than one type matches " + type.getName() + ": " + models + "]" ); + } + if( models.isEmpty() ) + { + return null; + } + return models.get( 0 ); + } + + private static abstract class TypeMatching<T extends HasTypes> + implements Predicate<T> + { + protected final Type lookedUpType; + + protected TypeMatching( Type lookedUpType ) + { + this.lookedUpType = lookedUpType; + } + + @Override + public final boolean test( T model ) + { + if( lookedUpType instanceof Class ) + { + return model.types().anyMatch( checkMatch( lookedUpType ) ); + } + else + { + if( lookedUpType instanceof ParameterizedType ) + { + // Foo<Bar> check + // First check Foo + ParameterizedType parameterizedType = (ParameterizedType) lookedUpType; + Type rawType = parameterizedType.getRawType(); + if( !model.types().anyMatch( checkMatch( rawType ) ) ) + { + return false; + } + // Then check Bar + return interfacesOf( model.types() ).anyMatch( intf -> intf.equals( lookedUpType ) ); + } + else if( lookedUpType instanceof WildcardType ) + { + return true; + } + return false; + } + } + + protected abstract Predicate<Type> checkMatch( Type matchTo ); + } + + private static final class ExactTypeMatching<T extends HasTypes> extends TypeMatching<T> + { + private ExactTypeMatching( Type lookedUpType ) + { + super( lookedUpType ); + } + + protected Predicate<Type> checkMatch( Type matchTo ) + { + return matchTo::equals; + } + } + + private static final class AssignableFromTypeMatching<T extends HasTypes> extends TypeMatching<T> + { + private AssignableFromTypeMatching( Type lookedUpType ) + { + super( lookedUpType ); + } + + protected Predicate<Type> checkMatch( Type matchTo ) + { + // TODO; what to do if there is ParameterizedType here?? Now set to ClassCastException and see if anything surfaces +// if( matchTo instanceof Class ) + { + Class<?> clazz = (Class<?>) matchTo; + return candidate -> + !candidate.equals( matchTo ) && clazz.isAssignableFrom( (Class<?>) candidate ); + } +// return candidate -> candidate.equals( matchTo ); + } + } + + /** + * This Predicate will filter out all Models that doesn't have the same visisbility as the first one. + */ + private class SameVisibility<T extends ModelDescriptor> + implements Predicate<ModelModule<T>> + { + private Visibility current = null; + + @Override + public boolean test( ModelModule<T> model ) + { + if( current == null ) + { + current = model.model().visibility(); + return true; + } + return current == model.model().visibility(); + } + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a5be013f/core/runtime/src/main/java/org/apache/zest/runtime/structure/UsedLayersInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/structure/UsedLayersInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/structure/UsedLayersInstance.java index 5a9bc94..ebf4b9c 100644 --- a/core/runtime/src/main/java/org/apache/zest/runtime/structure/UsedLayersInstance.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/structure/UsedLayersInstance.java @@ -17,13 +17,12 @@ package org.apache.zest.runtime.structure; import java.util.List; import java.util.stream.Stream; import org.apache.zest.api.common.Visibility; -import org.apache.zest.api.composite.ModelDescriptor; import org.apache.zest.api.composite.TransientDescriptor; import org.apache.zest.api.entity.EntityDescriptor; import org.apache.zest.api.object.ObjectDescriptor; import org.apache.zest.api.service.ServiceReference; import org.apache.zest.api.value.ValueDescriptor; -import org.apache.zest.spi.module.ModelModule; +import org.apache.zest.spi.structure.ModelModule; /** * JAVADOC http://git-wip-us.apache.org/repos/asf/zest-java/blob/a5be013f/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/EntityBuilderInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/EntityBuilderInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/EntityBuilderInstance.java index 425e851..ed8d137 100755 --- a/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/EntityBuilderInstance.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/EntityBuilderInstance.java @@ -25,8 +25,7 @@ import org.apache.zest.api.entity.LifecycleException; import org.apache.zest.runtime.composite.FunctionStateResolver; import org.apache.zest.runtime.entity.EntityInstance; import org.apache.zest.runtime.entity.EntityModel; -import org.apache.zest.spi.module.ModelModule; -import org.apache.zest.runtime.structure.ModuleUnitOfWork; +import org.apache.zest.spi.structure.ModelModule; import org.apache.zest.spi.entity.EntityState; import org.apache.zest.spi.entitystore.EntityStoreUnitOfWork; import org.apache.zest.spi.module.ModuleSpi; http://git-wip-us.apache.org/repos/asf/zest-java/blob/a5be013f/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/EntityFunction.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/EntityFunction.java b/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/EntityFunction.java new file mode 100644 index 0000000..a7524db --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/EntityFunction.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.zest.runtime.unitofwork; + +import java.lang.reflect.Type; +import java.util.function.BiFunction; +import org.apache.zest.api.entity.EntityReference; +import org.apache.zest.api.unitofwork.UnitOfWorkFactory; + +import static org.apache.zest.api.util.Classes.RAW_CLASS; + +public class EntityFunction + implements BiFunction<EntityReference, Type, Object> +{ + + private final UnitOfWorkFactory uowf; + + public EntityFunction( UnitOfWorkFactory uowf ) + { + this.uowf = uowf; + } + + @Override + public Object apply( EntityReference entityReference, Type type ) + { + return uowf.currentUnitOfWork().get( RAW_CLASS.apply( type ), entityReference.identity() ); + } +}
