You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by pa...@apache.org on 2016/12/03 14:52:27 UTC

[2/3] zest-java git commit: Improved descriptors sorting logic to limit iterations on candidates list.

Improved descriptors sorting logic to limit iterations on candidates list.


Project: http://git-wip-us.apache.org/repos/asf/zest-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/zest-java/commit/7ba5335c
Tree: http://git-wip-us.apache.org/repos/asf/zest-java/tree/7ba5335c
Diff: http://git-wip-us.apache.org/repos/asf/zest-java/diff/7ba5335c

Branch: refs/heads/develop
Commit: 7ba5335c3e5515821e9e6a9820843efd4a0579bb
Parents: e1dccf2
Author: Jean-Michel Tonneau <jm...@alchemytec.com>
Authored: Wed Nov 30 12:18:27 2016 +0000
Committer: Paul Merlin <pa...@apache.org>
Committed: Sat Dec 3 14:46:39 2016 +0100

----------------------------------------------------------------------
 .../zest/runtime/structure/TypeLookupImpl.java  | 102 ++++++++++++++++---
 1 file changed, 86 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zest-java/blob/7ba5335c/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 cd077b0..5eac131 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
@@ -22,6 +22,7 @@ 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.concurrent.ConcurrentHashMap;
 import java.util.function.Predicate;
@@ -152,33 +153,20 @@ class TypeLookupImpl
     @Override
     public List<EntityDescriptor> lookupEntityModels( final Class type )
     {
-        return entityModels.computeIfAbsent( type, key ->
-            concat(
-                allEntities().filter( ref -> new ExactTypeMatching<>( key ).test( ref ) ),
-                allEntities().filter( ref -> new AssignableFromTypeMatching<>( key ).test( ref ) )
-            ).distinct().collect( toList() )
-        );
+        return entityModels.computeIfAbsent( type, key -> new TypeMatchingDescriptors<EntityDescriptor>(key).selectedFrom(allEntities()));
     }
 
     @Override
     public ModelDescriptor lookupServiceModel( Type serviceType )
     {
         return serviceModels.computeIfAbsent( serviceType,
-                                              key -> lookupServiceModels( key ).stream().findFirst().orElse( null ) );
+                                              key -> new BestTypeMatchingDescriptors<ModelDescriptor>(key).selectedFrom(allServices()).bestMatchOrElse(null));
     }
 
     @Override
     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( toList() );
-        } );
+        return servicesReferences.computeIfAbsent( type1, type ->new TypeMatchingDescriptors<ModelDescriptor>(type).selectedFrom(allServices()));
     }
 
     @Override
@@ -450,4 +438,86 @@ class TypeLookupImpl
             return value;
         }
     }
+    
+    private static class TypeMatchingDescriptors<T extends HasTypes> extends ArrayList<T> {
+
+        /**
+         * mutable :-( But performance is an issue here.
+         */
+        private Integer lastMatchingindex;
+        private final ExactTypeMatching<T> exactMatchingPredicate;
+        private final AssignableFromTypeMatching<T> assignablePredicate;
+
+        private TypeMatchingDescriptors(Type type) {
+            this.lastMatchingindex = null;
+            this.exactMatchingPredicate = new ExactTypeMatching<>(type);
+            this.assignablePredicate = new AssignableFromTypeMatching<>(type);
+        }
+
+        TypeMatchingDescriptors<T> selectedFrom(Stream<? extends T> candidates){
+            candidates.forEach(this::smartAddition);
+            return this;
+        }
+        /**
+         * Sorts the descriptors in a common list : matching ones first,
+         * assignable ones follow. The order of arrival is important :
+         * 
+         * "{assignable1, matching1, assignable2,assignable3,matching2,
+         * non-matching-or-assignable}" should result in "{ matching1,
+         * matching2, assignable1, assignable2, assignable3}"
+         */
+        private  void smartAddition(T descriptor) {
+            if (contains(descriptor)) {
+                return;
+            }
+            if ( exactMatchingPredicate.test(descriptor)) {
+                Integer nextMatchingIdx = lastMatchingindex == null ? 0 : lastMatchingindex + 1;
+                add(nextMatchingIdx, descriptor);
+                lastMatchingindex = nextMatchingIdx;
+                return;
+            }
+            if (assignablePredicate.test(descriptor)) {
+                add(descriptor);
+            }
+        }
+
+        private  boolean containsExactMatches() {
+            return lastMatchingindex != null;
+        }
+
+    }
+
+    private static class BestTypeMatchingDescriptors<T extends HasTypes> {
+
+        private TypeMatchingDescriptors<T> descriptors;
+
+        private  BestTypeMatchingDescriptors(Type type) {
+            this(new TypeMatchingDescriptors<>(type));
+        }
+
+        private  BestTypeMatchingDescriptors(TypeMatchingDescriptors<T> descriptors) {
+            this.descriptors = descriptors;
+        }
+
+        BestTypeMatchingDescriptors<T> selectedFrom(Stream<? extends T> candidates) {
+            candidates.forEach(this::smartAddition);
+            return this;
+        }
+        
+        private T bestMatchOrElse(T or) {
+            return !descriptors.isEmpty() ? descriptors.get(0) : or;
+        }
+
+        /**
+         * We want the first matching if exists, the first assignable otherwise.
+         * While there is no matching descriptor, even if we found assignable
+         * ones, we keep searching in case the last element is a matching type.
+         */
+        private void smartAddition(T descriptor) {
+            if (!descriptors.containsExactMatches()) {
+                descriptors.smartAddition(descriptor);
+            }
+        }
+    }
+
 }