runtime: refine TypeLookup Remove stream terminal operations here and there Remove method that didnât belong here Add caching for frequently called methods
Project: http://git-wip-us.apache.org/repos/asf/zest-java/repo Commit: http://git-wip-us.apache.org/repos/asf/zest-java/commit/d313c132 Tree: http://git-wip-us.apache.org/repos/asf/zest-java/tree/d313c132 Diff: http://git-wip-us.apache.org/repos/asf/zest-java/diff/d313c132 Branch: refs/heads/develop Commit: d313c1329cf83265365ea1dfa2c28b6832847cf8 Parents: b4c2644 Author: Paul Merlin <[email protected]> Authored: Mon Nov 28 15:49:02 2016 +0100 Committer: Paul Merlin <[email protected]> Committed: Mon Nov 28 15:49:02 2016 +0100 ---------------------------------------------------------------------- .../apache/zest/api/structure/TypeLookup.java | 30 ++- .../zest/runtime/structure/ModuleInstance.java | 10 +- .../zest/runtime/structure/TypeLookupImpl.java | 263 +++++++++++-------- .../runtime/unitofwork/ModuleUnitOfWork.java | 2 +- 4 files changed, 185 insertions(+), 120 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zest-java/blob/d313c132/core/api/src/main/java/org/apache/zest/api/structure/TypeLookup.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/structure/TypeLookup.java b/core/api/src/main/java/org/apache/zest/api/structure/TypeLookup.java index ee2f9ec..2ea55bf 100644 --- a/core/api/src/main/java/org/apache/zest/api/structure/TypeLookup.java +++ b/core/api/src/main/java/org/apache/zest/api/structure/TypeLookup.java @@ -27,7 +27,6 @@ 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; public interface TypeLookup @@ -106,7 +105,7 @@ public interface TypeLookup /** * Lookup all Entity Models matching the given Type. * - * <p>Returned Iterable contains, in order, Entity Models that: </p> + * <p>Returned List contains, in order, Entity Models that: </p> * * <ul> * <li>exactly match the given type, in Visibility then Assembly order ;</li> @@ -125,7 +124,7 @@ public interface TypeLookup * * @return All matching Entity Models */ - Iterable<? extends EntityDescriptor> lookupEntityModels( Class<?> type ); + List<EntityDescriptor> lookupEntityModels( Class<?> type ); /** * Lookup first ServiceDescriptor/ImportedServiceDescriptor matching the given Type. @@ -161,15 +160,28 @@ public interface TypeLookup */ List<? extends ModelDescriptor> lookupServiceModels( Type type ); - Stream<? extends ObjectDescriptor> allObjects(); + /** + * @return All visible Objects, in visibility order + */ + Stream<ObjectDescriptor> allObjects(); - Stream<? extends TransientDescriptor> allTransients(); + /** + * @return All visible Transients, in visibility order + */ + Stream<TransientDescriptor> allTransients(); - Stream<? extends ValueDescriptor> allValues(); + /** + * @return All visible Values, in visibility order + */ + Stream<ValueDescriptor> allValues(); - Stream<? extends EntityDescriptor> allEntities(); + /** + * @return All visible Entities, in visibility order + */ + Stream<EntityDescriptor> allEntities(); + /** + * @return All visible Services, in visibility order + */ Stream<? extends ModelDescriptor> allServices(); - - Stream<Class<?>> allVisibleObjects(); } http://git-wip-us.apache.org/repos/asf/zest-java/blob/d313c132/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 96278ed..36a2f46 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 @@ -26,6 +26,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -58,6 +59,7 @@ import org.apache.zest.api.structure.LayerDescriptor; import org.apache.zest.api.structure.Module; import org.apache.zest.api.structure.ModuleDescriptor; import org.apache.zest.api.structure.TypeLookup; +import org.apache.zest.api.type.HasTypes; import org.apache.zest.api.unitofwork.UnitOfWorkException; import org.apache.zest.api.unitofwork.UnitOfWorkFactory; import org.apache.zest.api.util.NullArgumentException; @@ -173,7 +175,8 @@ public class ModuleInstance if( model == null ) { - throw new NoSuchObjectException( mixinType.getName(), name(), typeLookup.allVisibleObjects() ); + throw new NoSuchObjectException( mixinType.getName(), name(), + typeLookup.allObjects().flatMap( HasTypes::types ) ); } InjectionContext injectionContext = new InjectionContext( model.module(), UsesInstance.EMPTY_USES.use( uses ) ); @@ -189,7 +192,8 @@ public class ModuleInstance if( model == null ) { - throw new NoSuchObjectException( instance.getClass().getName(), name(), typeLookup.allVisibleObjects() ); + throw new NoSuchObjectException( instance.getClass().getName(), name(), + typeLookup.allObjects().flatMap( HasTypes::types ) ); } InjectionContext injectionContext = new InjectionContext( model.module(), UsesInstance.EMPTY_USES.use( uses ) ); @@ -398,7 +402,7 @@ public class ModuleInstance //noinspection unchecked return serviceModels.stream() .map( this::findServiceReferenceInstance ) - .filter( ref -> ref != null ) + .filter( Objects::nonNull ) .filter( ref -> ref.hasType( serviceType ) ) .map( ref -> (ServiceReference<T>) ref ) .collect( Collectors.toList() ); http://git-wip-us.apache.org/repos/asf/zest-java/blob/d313c132/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 index a36a65d..f9cc137 100644 --- 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 @@ -25,7 +25,7 @@ import java.lang.reflect.WildcardType; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; -import java.util.stream.Collectors; +import java.util.function.Supplier; import java.util.stream.Stream; import org.apache.zest.api.common.Visibility; import org.apache.zest.api.composite.AmbiguousTypeException; @@ -38,6 +38,7 @@ import org.apache.zest.api.structure.TypeLookup; import org.apache.zest.api.type.HasTypes; import org.apache.zest.api.value.ValueDescriptor; +import static java.util.stream.Collectors.toList; 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; @@ -54,13 +55,18 @@ class TypeLookupImpl private final ModuleDescriptor moduleModel; // Eager instance objects + private final LazyValue<List<ObjectDescriptor>> allObjects; + private final LazyValue<List<TransientDescriptor>> allTransients; + private final LazyValue<List<ValueDescriptor>> allValues; + private final LazyValue<List<EntityDescriptor>> allEntities; + private final LazyValue<List<? extends ModelDescriptor>> allServices; private final ConcurrentHashMap<Class<?>, ObjectDescriptor> objectModels; private final ConcurrentHashMap<Class<?>, TransientDescriptor> transientModels; private final ConcurrentHashMap<Class<?>, ValueDescriptor> valueModels; - private final ConcurrentHashMap<Class<?>, List<? extends EntityDescriptor>> allEntityModels; + private final ConcurrentHashMap<Class<?>, List<EntityDescriptor>> allEntityModels; private final ConcurrentHashMap<Class<?>, EntityDescriptor> unambiguousEntityModels; private final ConcurrentHashMap<Type, ModelDescriptor> serviceModels; - private final ConcurrentHashMap<Type, List<ModelDescriptor>> servicesReferences; + private final ConcurrentHashMap<Type, List<? extends ModelDescriptor>> servicesReferences; /** * Create a new TypeLookup bound to the given moduleModel. @@ -73,6 +79,11 @@ class TypeLookupImpl this.moduleModel = module; // Eager instance objects + allObjects = new LazyValue<>(); + allTransients = new LazyValue<>(); + allValues = new LazyValue<>(); + allEntities = new LazyValue<>(); + allServices = new LazyValue<>(); objectModels = new ConcurrentHashMap<>(); transientModels = new ConcurrentHashMap<>(); valueModels = new ConcurrentHashMap<>(); @@ -102,7 +113,7 @@ class TypeLookupImpl { return objectModels.computeIfAbsent( type, key -> { - List<ObjectDescriptor> allModels = allObjects().collect( Collectors.toList() ); + List<? extends ObjectDescriptor> allModels = getAllObjects(); ObjectDescriptor model = ambiguityMatching( key, allModels, new ExactTypeMatching<>( key ) ); if( model == null ) { @@ -132,7 +143,7 @@ class TypeLookupImpl { return transientModels.computeIfAbsent( type, key -> { - List<TransientDescriptor> allModels = allTransients().collect( Collectors.toList() ); + List<? extends TransientDescriptor> allModels = getAllTransients(); TransientDescriptor model = ambiguityMatching( key, allModels, new ExactTypeMatching<>( key ) ); if( model == null ) { @@ -162,7 +173,7 @@ class TypeLookupImpl { return valueModels.computeIfAbsent( type, key -> { - List<ValueDescriptor> allModels = allValues().collect( Collectors.toList() ); + List<? extends ValueDescriptor> allModels = getAllValues(); ValueDescriptor model = ambiguityMatching( key, allModels, new ExactTypeMatching<>( key ) ); if( model == null ) { @@ -195,7 +206,7 @@ class TypeLookupImpl { return unambiguousEntityModels.computeIfAbsent( type, key -> { - List<EntityDescriptor> allModels = allEntities().collect( Collectors.toList() ); + List<? extends EntityDescriptor> allModels = getAllEntities(); EntityDescriptor model = ambiguityMatching( key, allModels, new ExactTypeMatching<>( key ) ); if( model == null ) { @@ -228,13 +239,13 @@ class TypeLookupImpl * @return All matching Entity Models */ @Override - public Iterable<? extends EntityDescriptor> lookupEntityModels( final Class type ) + public List<EntityDescriptor> lookupEntityModels( final Class type ) { return allEntityModels.computeIfAbsent( type, key -> concat( allEntities().filter( ref -> new ExactTypeMatching<>( key ).test( ref ) ), allEntities().filter( ref -> new AssignableFromTypeMatching<>( key ).test( ref ) ) - ).distinct().collect( Collectors.toList() ) + ).distinct().collect( toList() ) ); } @@ -246,144 +257,163 @@ class TypeLookupImpl } @Override - public List<? extends ModelDescriptor> lookupServiceModels( Type type1 ) + public List<? extends ModelDescriptor> lookupServiceModels( final Type type1 ) { return servicesReferences.computeIfAbsent( type1, type -> { // There is a requirement that "exact match" services must be returned before "assignable match" // services, hence the dual streams instead of a OR filter. - return Stream.concat( - allServices() - .filter( new ExactTypeMatching<>( type ) ), - allServices() - .filter( new AssignableFromTypeMatching<>( type ) ) ) - .distinct() - .collect( Collectors.toList() ); + return Stream.concat( allServices().filter( new ExactTypeMatching<>( type ) ), + allServices().filter( new AssignableFromTypeMatching<>( type ) ) ) + .distinct() + .collect( toList() ); } ); } @Override - public Stream<Class<?>> allVisibleObjects() + public Stream<ObjectDescriptor> allObjects() { - return allObjects().flatMap( HasTypes::types ); + return getAllObjects().stream(); } - @Override - public Stream<? extends ObjectDescriptor> allObjects() + private List<ObjectDescriptor> getAllObjects() { - return concat( moduleModel.objects(), - concat( - concat( - moduleModel.layer().visibleObjects( layer ), - moduleModel.layer().visibleObjects( application ) - ), - moduleModel.layer() - .usedLayers() - .layers() - .flatMap( layer -> layer.visibleObjects( application ) ) - ) + return allObjects.computeIfAbsent( + () -> concat( moduleModel.objects(), + concat( + concat( + moduleModel.layer().visibleObjects( layer ), + moduleModel.layer() + .visibleObjects( application ) + ), + moduleModel.layer() + .usedLayers() + .layers() + .flatMap( layer -> layer.visibleObjects( application ) ) + ) + ).collect( toList() ) ); } @Override - public Stream<? extends TransientDescriptor> allTransients() + public Stream<TransientDescriptor> allTransients() + { + return getAllTransients().stream(); + } + + private List<TransientDescriptor> getAllTransients() { - return concat( moduleModel.transientComposites(), - concat( - concat( - moduleModel.layer().visibleTransients( layer ), - moduleModel.layer().visibleTransients( application ) - ), - moduleModel.layer() - .usedLayers() - .layers() - .flatMap( layer -> layer.visibleTransients( application ) ) - ) + return allTransients.computeIfAbsent( + () -> concat( moduleModel.transientComposites(), + concat( + concat( + moduleModel.layer().visibleTransients( layer ), + moduleModel.layer().visibleTransients( application ) + ), + moduleModel.layer() + .usedLayers() + .layers() + .flatMap( layer -> layer.visibleTransients( application ) ) + ) + ).collect( toList() ) ); } @Override - public Stream<? extends ValueDescriptor> allValues() + public Stream<ValueDescriptor> allValues() { + return getAllValues().stream(); + } - return concat( moduleModel.valueComposites(), - concat( - concat( moduleModel.layer().visibleValues( layer ), - moduleModel.layer().visibleValues( application ) - ), - moduleModel.layer() - .usedLayers() - .layers() - .flatMap( layer1 -> layer1.visibleValues( application ) ) - ) + private List<ValueDescriptor> getAllValues() + { + return allValues.computeIfAbsent( + () -> concat( moduleModel.valueComposites(), + concat( + concat( moduleModel.layer().visibleValues( layer ), + moduleModel.layer().visibleValues( application ) + ), + moduleModel.layer() + .usedLayers() + .layers() + .flatMap( layer1 -> layer1.visibleValues( application ) ) + ) + ).collect( toList() ) ); } @Override - public Stream<? extends EntityDescriptor> allEntities() + public Stream<EntityDescriptor> allEntities() + { + return getAllEntities().stream(); + } + + private List<EntityDescriptor> getAllEntities() { - return concat( moduleModel.entityComposites(), - concat( - concat( - moduleModel.layer().visibleEntities( layer ), - moduleModel.layer().visibleEntities( application ) - ), - moduleModel.layer() - .usedLayers() - .layers() - .flatMap( layer -> layer.visibleEntities( application ) ) - ) + return allEntities.computeIfAbsent( + () -> concat( moduleModel.entityComposites(), + concat( + concat( + moduleModel.layer().visibleEntities( layer ), + moduleModel.layer().visibleEntities( application ) + ), + moduleModel.layer() + .usedLayers() + .layers() + .flatMap( layer -> layer.visibleEntities( application ) ) + ) + ).collect( toList() ) ); } @Override public Stream<? extends ModelDescriptor> allServices() { - Stream<? extends ModelDescriptor> managedServices = - concat( moduleModel.serviceComposites(), - concat( + return getAllServices().stream(); + } + + public List<? extends ModelDescriptor> getAllServices() + { + return allServices.computeIfAbsent( + () -> concat( + concat( moduleModel.serviceComposites(), concat( + concat( + moduleModel.layer().visibleServices( layer ), + moduleModel.layer().visibleServices( application ) + ), moduleModel.layer() - .visibleServices( layer ), - moduleModel.layer() - .visibleServices( application ) - ), - moduleModel.layer() - .usedLayers() - .layers() - .flatMap( layer -> layer.visibleServices( application ) ) - ) - ); - Stream<? extends ModelDescriptor> importedServices = - concat( moduleModel.importedServices(), - concat( + .usedLayers() + .layers() + .flatMap( layer -> layer.visibleServices( application ) ) + ) + ), + concat( moduleModel.importedServices(), concat( + concat( + moduleModel.layer().visibleServices( layer ), + moduleModel.layer().visibleServices( application ) + ), moduleModel.layer() - .visibleServices( layer ), - moduleModel.layer() - .visibleServices( application ) - ), - moduleModel.layer() - .usedLayers() - .layers() - .flatMap( layer -> layer.visibleServices( application ) ) - ) - ); - return concat( managedServices, importedServices ); + .usedLayers() + .layers() + .flatMap( layer -> layer.visibleServices( application ) ) + ) + ) + ).collect( toList() ) + ); } - private <T extends ModelDescriptor> T ambiguityMatching( + private static <T extends ModelDescriptor> T ambiguityMatching( Class type, List<T> modelModules, TypeMatching<T> matching ) { List<T> models = modelModules.stream() - .filter( matching ) - .filter( new SameVisibility<>() ) - .distinct() - .collect( Collectors.toList() ); - + .filter( matching.and( new SameVisibility<>() ) ) + .distinct() + .collect( toList() ); if( models.size() > 1 ) { throw new AmbiguousTypeException( "More than one type matches " + type.getName() + ": " + models + "]" ); @@ -420,7 +450,7 @@ class TypeLookupImpl // First check Foo ParameterizedType parameterizedType = (ParameterizedType) lookedUpType; Type rawType = parameterizedType.getRawType(); - if( !model.types().anyMatch( checkMatch( rawType ) ) ) + if( model.types().noneMatch( checkMatch( rawType ) ) ) { return false; } @@ -438,7 +468,7 @@ class TypeLookupImpl protected abstract Predicate<Type> checkMatch( Type matchTo ); } - private static final class ExactTypeMatching<T extends HasTypes> extends TypeMatching<T> + private static class ExactTypeMatching<T extends HasTypes> extends TypeMatching<T> { private ExactTypeMatching( Type lookedUpType ) { @@ -451,7 +481,7 @@ class TypeLookupImpl } } - private static final class AssignableFromTypeMatching<T extends HasTypes> extends TypeMatching<T> + private static class AssignableFromTypeMatching<T extends HasTypes> extends TypeMatching<T> { private AssignableFromTypeMatching( Type lookedUpType ) { @@ -464,17 +494,16 @@ class TypeLookupImpl // if( matchTo instanceof Class ) { Class<?> clazz = (Class<?>) matchTo; - return candidate -> - !candidate.equals( matchTo ) && clazz.isAssignableFrom( (Class<?>) candidate ); + 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. + * This Predicate will filter out all Models that doesn't have the same visibility as the first one. */ - private class SameVisibility<T extends ModelDescriptor> + private static class SameVisibility<T extends ModelDescriptor> implements Predicate<T> { private Visibility current = null; @@ -490,4 +519,24 @@ class TypeLookupImpl return current == model.visibility(); } } + + private static class LazyValue<T> + { + private volatile T value; + + public T computeIfAbsent( Supplier<T> supplier ) + { + if( value == null ) + { + synchronized( this ) + { + if( value == null ) + { + value = supplier.get(); + } + } + } + return value; + } + } } http://git-wip-us.apache.org/repos/asf/zest-java/blob/d313c132/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/ModuleUnitOfWork.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/ModuleUnitOfWork.java b/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/ModuleUnitOfWork.java index beadcf0..0d1e3bb 100644 --- a/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/ModuleUnitOfWork.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/ModuleUnitOfWork.java @@ -293,7 +293,7 @@ public class ModuleUnitOfWork public <T> T get( Class<T> type, Identity identity ) throws NoSuchEntityTypeException, NoSuchEntityException { - Iterable<? extends EntityDescriptor> models = module.typeLookup().lookupEntityModels( type ); + Iterable<EntityDescriptor> models = module.typeLookup().lookupEntityModels( type ); if( !models.iterator().hasNext() ) {
